| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- <template>
- <view class="wanl-chat">
- <view @touchstart="hideDrawer">
- <scroll-view class="cu-chat" scroll-y="true" :scroll-with-animation="scrollAnimation" :scroll-top="scrollTop"
- :scroll-into-view="scrollToView" upper-threshold="50">
- <view v-for="(row, index) in msgList" :key="index" :id="'msg' + row.id">
- <!-- 自己的消息 -->
- <view class="cu-item self" v-if="parseInt(row.form.id) === parseInt(user_id)">
- <view class="main" v-if="row.message.type == 'text'">
- <view class="content bg-green"><rich-text :nodes="row.message.content.text"></rich-text></view>
- </view>
- <!-- 图片消息 -->
- <view class="main" v-if="row.message.type == 'img'">
- <image :src="row.message.content.url" @tap="showPic(row.message)"
- :style="{ width: row.message.content.w + 'px', height: row.message.content.h + 'px' }"></image>
- </view>
- <!-- 语音消息 -->
- <view class="main" v-if="row.message.type == 'voice'" @tap="playVoice(row.message)"
- :class="playMsgid == row.message.id ? 'play' : ''">
- <view class="action text-bold text-grey" style="padding-right: 2rpx;">
- {{ row.message.content.length }}
- <text class="wlIcon-miao"></text>
- </view>
- <view class="content bg-green">
- <text :style="{ width: row.message.content.length * 6 + 'rpx' }"></text>
- <text class="wlIcon-yuyinyou text-xxl padding-left-xl"></text>
- </view>
- </view>
- <view class="cu-avatar round"
- :style="{ backgroundImage: 'url(' + buildOssUrl(row.form.avatar, 44, 44, 2, 'avatar') + ')' }"></view>
- </view>
- <!-- 对方的消息 -->
- <view class="cu-item" v-else>
- <view class="cu-avatar round" :style="{ backgroundImage: 'url(' + buildOssUrl(row.form.avatar) + ')' }"
- v-if="row.form.avatar"></view>
- <view class="cu-avatar round" :style="{ backgroundImage: 'url(' + appLogo + ')' }" v-else></view>
- <!-- 文字消息 -->
- <view class="main" v-if="row.message.type == 'text'">
- <view class="content"><rich-text :nodes="row.message.content.text"></rich-text></view>
- </view>
- <!-- 列表消息 -->
- <view class="main" v-if="row.message.type == 'list'">
- <view class="content">
- <view class="list">
- <view v-if="row.message.content.length > 0">
- <view>
- {{ $t('service.askQuestion') }}
- <view class="ai solid-top solid-bottom">
- <view v-for="(item, index) in row.message.content" :key="item.id"
- @tap="aiSend(item.keywords ? item.keywords : this.$t('service.noKeywords'))" class="text-cut">
- <text>{{ item.title }}</text></view>
- </view>
- </view>
- <view>
- {{ $t('service.notMatch') }} <text class="click-here"
- @tap="aiSend(this.$t('service.artificialService'))">{{ $t('service.clickHere') }}</text>{{ $t('service.orReplyHuman') }}
- </view>
- </view>
- <view v-else>
- {{ $t('service.noHelpContent') }}<text class="click-here"
- @tap="aiSend(this.$t('service.artificialService'))">{{ $t('service.clickHere') }}</text>{{ $t('service.orReplyHuman') }}
- </view>
- </view>
- </view>
- </view>
- <!-- 文章消息 -->
- <view class="main" v-if="row.message.type == 'article'"
- @tap="onDetails(row.message.content.id, row.message.content.title)">
- <view class="content">
- <view style="width: 100%;">
- <view>
- {{ row.message.content.title }}
- </view>
- <view class="article solid-top">
- <rich-text :nodes="row.message.content.content"></rich-text>
- </view>
- </view>
- </view>
- </view>
- <!-- 图片消息 -->
- <view class="main" v-if="row.message.type == 'img'">
- <image :src="row.message.content.url" @tap="showPic(row.message)"
- :style="{ width: row.message.content.w + 'px', height: row.message.content.h + 'px' }"></image>
- </view>
- <view class="date">{{ timeToChat(row.createtime) }} </view>
- </view>
- </view>
- </scroll-view>
- </view>
- <!-- 抽屉栏 -->
- <view class="popup-layer" :class="{ showLayer: popupLayerClass }" @touchmove.stop.prevent="discard">
- <!-- 表情 -->
- <view :class="{ hidden: hideEmoji }">
- <view class="emoji">
- <scroll-view class="emojinav" scroll-x scroll-with-animation>
- <view class="item">
- <view :class="item == TabCur ? 'emojibg' : ''" v-for="(item, index) in emojiList.categories" :key="index"
- @tap="tabSelect" :data-id="item"
- :style="{ backgroundImage: 'url(' + emojiList.groups[item][0].url + ')' }"></view>
- </view>
- </scroll-view>
- <!-- 列表 -->
- <scroll-view v-for="(emoji, groups) in emojiList.groups" :key="groups" v-if="TabCur == groups" class="subject"
- scroll-y scroll-with-animation>
- <view class="item grid margin-bottom text-center col-5">
- <view v-for="(item, index) in emoji" :key="index" @tap="addEmoji(item.value)"
- :style="{ backgroundImage: 'url(' + item.url + ')' }"></view>
- </view>
- </scroll-view>
- </view>
- </view>
- <!-- 更多功能-->
- <view class="solid-top" :class="{ hidden: hideMore }">
- <view class="opmenu solid-top">
- <view class="box" @tap="chooseImage">
- <view class="icon"><text class="wlIcon-tupian1"></text></view>
- <text class="text-sm">{{ $t('service.photos') }}</text>
- </view>
- <!-- #ifndef H5 -->
- <view class="box" @tap="camera">
- <view class="icon"><text class="wlIcon-31paishexuanzhong"></text></view>
- <text class="text-sm">{{ $t('service.camera') }}</text>
- </view>
- <!-- #endif -->
- </view>
- </view>
- </view>
- <!-- 底部输入栏 -->
- <view class="input-box" :class="{ emptybottom: emptybottom, showLayer: popupLayerClass}" @touchmove.stop.prevent="discard">
- <!-- H5下不能录音,输入栏布局改动一下 -->
- <!-- #ifndef H5 -->
- <view class="voice"><view :class="isVoice ? 'wlIcon-jianpanqiehuan' : 'wlIcon-yuyin'" @tap="switchVoice"></view></view>
- <!-- #endif -->
- <!-- #ifdef H5 -->
- <view class="more" @tap="showMore"><view class="wlIcon-yuanquanjiahao"></view></view>
- <!-- #endif -->
- <view class="textbox">
- <view
- class="voice-mode"
- :class="[isVoice ? '' : 'hidden', recording ? 'recording' : '']"
- @touchstart="voiceBegin"
- @touchmove.stop.prevent="voiceIng"
- @touchend="voiceEnd"
- @touchcancel="voiceCancel"
- >
- {{ voiceTis }}
- </view>
- <view class="text-mode" :class="isVoice ? 'hidden' : ''">
- <view class="box">
- <textarea auto-height="true" maxlength="300" :show-confirm-bar="false" cursor-spacing="90" v-model="textMsg" @focus="textareaFocus" @blur="textareaBlur" @confirm="sendText" />
- </view>
- <view class="em" @tap="chooseEmoji"><view class="wlIcon-biaoqing2"></view></view>
- </view>
- </view>
- <!-- #ifndef H5 -->
- <view class="more" @tap="showMore" style="margin-right: -12rpx;"><view class="wlIcon-yuanquanjiahao"></view></view>
- <!-- #endif -->
- <view class="send" :class="isVoice ? 'hidden' : ''" @tap="sendText">
- <text class="wlIcon-zhifeiji" v-if="textMsg"></text>
- <text class="wlIcon-fasong" v-else></text>
- </view>
- </view>
- <!-- 录音UI效果 -->
- <view class="record" :class="recording ? '' : 'hidden'">
- <view class="ing" :class="willStop ? 'hidden' : ''">
- <view class="wlIcon-huatong01"></view>
- </view>
- <view class="cancel" :class="willStop ? '' : 'hidden'">
- <view class="wlIcon-shanchu2"></view>
- </view>
- <view class="tis" :class="willStop ? 'change' : ''">{{ recordTis }}</view>
- </view>
- </view>
- </template>
- <script>
- const emotions = require('@/static/json/emotions.json')
- import { mapState } from 'vuex'
- import { buildOssUrl } from '@/core/media/oss-url'
- import { getUploadConfig } from '@/features/mall/gateway/chat'
- export default {
- data() {
- return {
- user_id: parseInt(this.$store.state.user.id),
- avatar: this.$store.state.user.avatar,
- nickname: this.$store.state.user.nickname,
- to_id: 0,
- textMsg: '',
- scrollAnimation: false,
- scrollTop: 0,
- scrollToView: '',
- msgList: [],
- msgImgList: [],
- emptybottom: false,
- // #ifndef H5
- RECORDER: uni.getRecorderManager(),
- // #endif
- isVoice: false,
- voiceTis: this.$t('service.holdToSpeak'),
- recordTis: this.$t('service.slideUpToCancel'),
- recording: false,
- willStop: false,
- initPoint: { identifier: 0, Y: 0 },
- recordTimer: null,
- recordLength: 0,
- AUDIO: uni.createInnerAudioContext(),
- playMsgid: null,
- VoiceTimer: null,
- popupLayerClass: false,
- hideMore: true,
- TabCur: this.$t('service.default'),
- hideEmoji: true,
- emojiList: this.emojiData(),
- QnUrl: ''
- }
- },
- computed: {
- ...mapState({
- appLogo: state => (state.common && state.common.appConfig && state.common.appConfig.logo) || ''
- })
- },
- onLoad(option) {
- this.loadData()
- this.AUDIO.onEnded(res => {
- this.playMsgid = null
- })
- // #ifndef H5
- this.RECORDER.onStart(e => {
- this.recordBegin(e)
- })
- this.RECORDER.onStop(e => {
- this.recordEnd(e)
- })
- // #endif
- uni.$on('onService', this.onChat)
- },
- onShow() {
- this.scrollTop = 9999999
- },
- onUnload() {
- uni.$off('onService', this.onChat)
- },
- methods: {
- buildOssUrl,
- async loadData() {
- await uni.request({
- url: '/wanlshop/chat/hello',
- method: 'POST',
- data: {
- id: 1,
- type: 'service',
- form_id: this.user_id
- }
- })
- },
- async sendMsg(content, type) {
- let lastid = 2
- if (this.msgList.length) {
- lastid = this.msgList[this.msgList.length - 1].id
- lastid++
- }
- let data = {
- id: lastid,
- type: 'service',
- to_id: this.to_id,
- form: {
- id: this.user_id,
- avatar: this.avatar,
- name: this.nickname
- },
- message: {
- type: type,
- content: content
- },
- createtime: parseInt(new Date().getTime() / 1000)
- }
- this.onChat(JSON.parse(JSON.stringify(data)), true)
- await uni.request({
- url: '/wanlshop/chat/service',
- method: 'POST',
- data: data
- })
- },
- onChat(msg, type) {
- if (!type) {
- this.to_id = msg.form.id
- if (msg.form.hasOwnProperty('name')) {
- uni.setNavigationBarTitle({ title: msg.form.name })
- }
- }
- if (msg.message.type == 'list') {
- this.addListMsg(msg)
- }
- if (msg.message.type == 'article') {
- this.addArticleMsg(msg)
- }
- if (msg.message.type == 'text') {
- this.addTextMsg(msg)
- }
- if (msg.message.type == 'voice') {
- this.addVoiceMsg(msg)
- }
- if (msg.message.type == 'img') {
- this.addImgMsg(msg)
- }
- if (msg.message.type == 'end') {
- uni.showToast({ title: msg.message.content, icon: 'none' })
- }
- this.$nextTick(() => {
- this.scrollToView = 'msg' + msg.id
- })
- },
- addListMsg(msg) {
- this.msgList.push(msg)
- },
- addArticleMsg(msg) {
- this.msgList.push(msg)
- },
- addTextMsg(msg) {
- msg.message.content.text = this.replaceEmoji(msg.message.content.text)
- this.msgList.push(msg)
- },
- addVoiceMsg(msg) {
- this.msgList.push(msg)
- },
- addImgMsg(msg) {
- msg.message.content = this.setPicSize(msg.message.content)
- this.msgImgList.push(msg.message.content.url)
- this.msgList.push(msg)
- },
- chooseImage() {
- this.getImage('album')
- },
- camera() {
- this.getImage('camera')
- },
- getImage(type) {
- this.hideDrawer()
- uni.chooseImage({
- sourceType: [type],
- sizeType: ['original', 'compressed'],
- success: async res => {
- try {
- const updata = await getUploadConfig()
- for (let i = 0; i < res.tempFilePaths.length; i++) {
- uni.getImageInfo({
- src: res.tempFilePaths[i],
- success: image => {
- uni.uploadFile({
- url: updata.uploadurl,
- filePath: image.path,
- name: 'file',
- formData: updata.storage == 'local' ? null : updata.multipart,
- success: data => {
- this.sendMsg({ url: JSON.parse(data.data).data.fullurl, w: image.width, h: image.height }, 'img')
- },
- fail: error => {
- uni.showToast({ title: JSON.parse(error.data).msg, icon: 'none' })
- }
- })
- }
- })
- }
- } catch (e) {
- console.error('uploadConfig error:', e)
- }
- }
- })
- },
- sendText() {
- this.hideDrawer()
- if (!this.textMsg) return
- let msg = { text: this.textMsg }
- this.sendMsg(msg, 'text')
- this.textMsg = ''
- },
- aiSend(text) {
- this.sendMsg({ text: text }, 'text')
- },
- showPic(message) {
- uni.previewImage({
- indicator: 'none',
- current: message.content.url,
- urls: this.msgImgList
- })
- },
- playVoice(message) {
- this.playMsgid = message.id
- this.AUDIO.src = message.content.url
- this.$nextTick(() => {
- this.AUDIO.play()
- })
- },
- voiceBegin(e) {
- if (e.touches.length > 1) return
- this.initPoint.Y = e.touches[0].clientY
- this.initPoint.identifier = e.touches[0].identifier
- this.RECORDER.start({ format: 'mp3' })
- },
- recordBegin(e) {
- this.recording = true
- this.voiceTis = this.$t('service.releaseToEnd')
- this.recordLength = 0
- this.recordTimer = setInterval(() => {
- this.recordLength++
- }, 1000)
- },
- voiceCancel() {
- this.recording = false
- this.voiceTis = this.$t('service.holdToSpeak')
- this.recordTis = this.$t('service.slideUpToCancel')
- this.willStop = true
- this.RECORDER.stop()
- },
- voiceIng(e) {
- if (!this.recording) return
- let touche = e.touches[0]
- if (this.initPoint.Y - touche.clientY >= uni.upx2px(200)) {
- this.willStop = true
- this.recordTis = this.$t('service.releaseToCancel')
- } else {
- this.willStop = false
- this.recordTis = this.$t('service.slideUpToCancel')
- }
- },
- voiceEnd(e) {
- if (!this.recording) return
- this.recording = false
- this.voiceTis = this.$t('service.holdToSpeak')
- this.recordTis = this.$t('service.slideUpToCancel')
- this.RECORDER.stop()
- },
- async recordEnd(e) {
- clearInterval(this.recordTimer)
- if (!this.willStop) {
- try {
- const updata = await getUploadConfig()
- uni.uploadFile({
- url: updata.uploadurl,
- filePath: e.tempFilePath,
- name: 'file',
- formData: updata.storage == 'local' ? null : updata.multipart,
- header: {
- token: this.$store.state.user.token
- },
- success: data => {
- let msg = { length: 0, url: JSON.parse(data.data).data.fullurl }
- msg.length = this.recordLength % 60
- if (msg.length > 0) {
- this.sendMsg(msg, 'voice')
- }
- },
- fail: error => {
- uni.showToast({ title: JSON.parse(error.data).msg, icon: 'none' })
- }
- })
- } catch (err) {
- console.error('upload voice error:', err)
- }
- }
- this.willStop = false
- },
- switchVoice() {
- this.hideDrawer()
- this.isVoice = this.isVoice ? false : true
- },
- emojiData() {
- var groups = {},
- categories = [],
- map = {}
- emotions.forEach(emotion => {
- var cate = emotion.category.length > 0 ? emotion.category : '默認'
- if (!groups[cate]) {
- groups[cate] = []
- categories.push(cate)
- }
- groups[cate].push(emotion)
- map[emotion.phrase] = emotion.icon
- })
- return { groups, categories, map }
- },
- replaceEmoji(str) {
- if (!str) return ''
- let replacedStr = str
- Object.keys(this.emojiList.map).forEach(key => {
- if (str.indexOf(key) !== -1) {
- const url = this.emojiList.map[key]
- if (url) {
- replacedStr = replacedStr.split(key).join('<img src="' + url + '" style="width:18px;vertical-align:middle;">')
- }
- }
- })
- return replacedStr.replace(/(\r\n)|(\n)/g, '<br>')
- },
- tabSelect(e) {
- this.TabCur = e.currentTarget.dataset.id
- },
- setPicSize(content) {
- let maxW = uni.upx2px(350)
- let maxH = uni.upx2px(350)
- if (content.w > maxW || content.h > maxH) {
- let scale = content.w / content.h
- content.w = scale > 1 ? maxW : maxH * scale
- content.h = scale > 1 ? maxW / scale : maxH
- }
- return content
- },
- showMore() {
- this.isVoice = false
- this.hideEmoji = true
- if (this.hideMore) {
- this.hideMore = false
- this.openDrawer()
- } else {
- this.hideDrawer()
- }
- },
- openDrawer() {
- this.emptybottom = true
- this.popupLayerClass = true
- },
- hideDrawer() {
- this.emptybottom = false
- this.popupLayerClass = false
- setTimeout(() => {
- this.hideMore = true
- this.hideEmoji = true
- }, 150)
- },
- chooseEmoji() {
- this.hideMore = true
- if (this.hideEmoji) {
- this.hideEmoji = false
- this.openDrawer()
- } else {
- this.hideDrawer()
- }
- },
- addEmoji(em) {
- this.textMsg += em
- },
- textareaFocus() {
- this.emptybottom = true
- if (this.popupLayerClass && this.hideMore == false) {
- this.hideDrawer()
- }
- },
- textareaBlur() {
- this.emptybottom = false
- },
- onDetails(id, title) {
- uni.navigateTo({ url: `/pages/article/details?id=${id}&title=${title}` })
- },
- timeToChat(timestamp) {
- if (!timestamp) return ''
- const date = new Date(timestamp * 1000)
- const now = new Date()
- const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
- const msgDate = new Date(date.getFullYear(), date.getMonth(), date.getDate())
- const diffDays = Math.floor((today - msgDate) / (1000 * 60 * 60 * 24))
- const hours = date.getHours().toString().padStart(2, '0')
- const minutes = date.getMinutes().toString().padStart(2, '0')
- if (diffDays === 0) return hours + ':' + minutes
- if (diffDays === 1) return this.$t('service.yesterday') + ' ' + hours + ':' + minutes
- const month = (date.getMonth() + 1).toString().padStart(2, '0')
- const day = date.getDate().toString().padStart(2, '0')
- return month + '/' + day + ' ' + hours + ':' + minutes
- },
- discard() {
- return
- }
- }
- }
- </script>
- <style>
- .cu-chat .cu-item>.main {
- margin: 0 20rpx;
- }
- .cu-chat .cu-item>.main .content:after {
- width: 0;
- height: 0;
- }
- .cu-chat .cu-item>.main .content {
- font-size: 30rpx;
- border-radius: 10rpx 30rpx 30rpx 30rpx;
- }
- .cu-chat .cu-item.self>.main .content {
- border-radius: 30rpx 10rpx 30rpx 30rpx;
- }
- .cu-chat .cu-item>.main .content .article {
- margin-top: 10rpx;
- padding-top: 10rpx;
- width: 100%;
- overflow: hidden;
- }
- .cu-chat .cu-item>.main .content .list {
- width: 100%;
- font-size: 28rpx;
- }
- .cu-chat .cu-item>.main .content .list text {
- color: #FF6A00;
- }
- .cu-chat .cu-item>.main .content .list .ai {
- padding: 16rpx 0;
- margin: 16rpx 0;
- line-height: 1.5;
- }
- .cu-chat .cu-item [class*='wlIcon-'] {
- font-size: 34rpx;
- }
- .opmenu {
- display: flex;
- margin-top: 2rpx;
- color: #4c4c4c;
- }
- .opmenu .box {
- padding-top: 35rpx;
- padding-left: 50rpx;
- text-align: center;
- }
- .opmenu .box .icon {
- height: 130rpx;
- width: 130rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- justify-items: center;
- background-color: #ffffff;
- border-radius: 20rpx;
- font-size: 70rpx;
- margin-bottom: 10rpx;
- }
- .hidden {
- display: none !important;
- }
- .popup-layer {
- transition: all 0.15s linear;
- width: 100%;
- height: 480rpx;
- background-color: #f7f7fa;
- position: fixed;
- z-index: 2000;
- top: 100%;
- }
- .popup-layer.showLayer {
- transform: translate3d(0, -480rpx, 0);
- }
- .popup-layer .emoji .emojinav {
- background-color: #f8f8f8;
- }
- .popup-layer .emoji .emojinav .item {
- display: flex;
- align-items: center;
- height: 100rpx;
- padding-left: 10rpx;
- }
- .popup-layer .emoji .emojinav .item .emojibg {
- background-color: #dedede;
- }
- .popup-layer .emoji .emojinav .item>view {
- margin: 0 25rpx;
- width: 60rpx;
- height: 60rpx;
- border-radius: 18rpx;
- background-repeat: no-repeat;
- background-size: 80%;
- background-position: center;
- }
- .popup-layer .emoji .subject {
- height: 380rpx;
- background-color: #f1f1f1;
- }
- .popup-layer .emoji .subject .item {
- padding: 25rpx;
- }
- .popup-layer .emoji .subject .item>view {
- background-repeat: no-repeat;
- background-size: 56%;
- background-position: center;
- width: 12.5%;
- height: 100rpx;
- }
- .input-box {
- width: 100%;
- min-height: 100rpx;
- padding-bottom: env(safe-area-inset-bottom);
- background-color: #f7f7fa;
- display: flex;
- align-items: flex-end;
- position: fixed;
- z-index: 2000;
- bottom: -2rpx;
- transition: all 0.15s linear;
- }
- .input-box [class*='wlIcon-'] {
- font-size: 50rpx;
- color: #4c4c4c;
- }
- .input-box .wlIcon-zhifeiji {
- color: #fe6600;
- }
- .input-box.showLayer {
- transform: translate3d(0, -480rpx, 0);
- }
- .input-box .voice,
- .input-box .more {
- flex-shrink: 0;
- width: 90rpx;
- height: 100rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .input-box .send {
- flex-shrink: 0;
- width: 90rpx;
- height: 100rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .input-box .send .btn {
- width: 110rpx;
- height: 70rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- border-radius: 16rpx;
- font-size: 32rpx;
- }
- .input-box .textbox {
- width: 100%;
- }
- .input-box .textbox .voice-mode {
- width: calc(100% - 2upx);
- height: 80rpx;
- margin: 10rpx 0;
- border-radius: 16rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 28rpx;
- background-color: #fff;
- color: #555;
- }
- .input-box .textbox .voice-mode.recording {
- background-color: #e5e5e5;
- }
- .input-box .textbox .text-mode {
- width: 100%;
- min-height: 80rpx;
- margin: 10rpx 0;
- display: flex;
- background-color: #ffffff;
- border-radius: 16rpx;
- }
- .input-box .textbox .text-mode .box {
- width: 100%;
- padding-left: 30rpx;
- min-height: 80rpx;
- display: flex;
- align-items: center;
- }
- .input-box .textbox .text-mode .box textarea {
- width: 100%;
- }
- .input-box .textbox .text-mode .em {
- flex-shrink: 0;
- width: 80rpx;
- padding-left: 10rpx;
- height: 80rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .record {
- width: 39vw;
- height: 39vw;
- position: fixed;
- top: 35%;
- left: 30%;
- background-color: rgba(0, 0, 0, 0.8);
- border-radius: 40rpx;
- }
- .record .ing {
- width: 100%;
- height: 30vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- @keyframes volatility {
- 0% {
- background-position: 0% 130%;
- }
- 20% {
- background-position: 0% 150%;
- }
- 30% {
- background-position: 0% 155%;
- }
- 40% {
- background-position: 0% 160%;
- }
- 50% {
- background-position: 0% 145%;
- }
- 70% {
- background-position: 0% 150%;
- }
- 80% {
- background-position: 0% 170%;
- }
- 90% {
- background-position: 0% 160%;
- }
- 100% {
- background-position: 0% 135%;
- }
- }
- .record .ing [class*='wlIcon'] {
- background-image: linear-gradient(to bottom, #ffffff, #565656 50%);
- background-size: 100% 200%;
- animation: volatility 1.5s ease-in-out -1.5s infinite alternate;
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- font-size: 140rpx;
- padding-top: 40rpx;
- color: #f09b37;
- }
- .record .cancel {
- width: 100%;
- height: 30vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .record .cancel [class*='wlIcon'] {
- color: #fff;
- font-size: 150rpx;
- }
- .record .tis {
- width: 100%;
- height: 10vw;
- display: flex;
- justify-content: center;
- font-size: 24rpx;
- color: #fff;
- }
- .record .tis.change {
- color: #f09b37;
- }
- .content {
- width: 100%;
- }
- .content .msg-list,
- .cu-chat {
- position: absolute;
- top: 0;
- bottom: 100rpx;
- bottom: calc(env(safe-area-inset-bottom) + 100rpx);
- }
- .loading {
- display: flex;
- justify-content: center;
- }
- @keyframes stretchdelay {
- 0%,
- 40%,
- 100% {
- transform: scaleY(0.6);
- }
- 20% {
- transform: scaleY(1);
- }
- }
- .loading .spinner {
- margin: 20upx 0;
- width: 60upx;
- height: 100upx;
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .loading .spinner view {
- background-color: #dadada;
- height: 50upx;
- width: 6upx;
- border-radius: 6upx;
- animation: stretchdelay 1.2s infinite ease-in-out;
- }
- .loading .spinner .rect2 {
- animation-delay: -1.1s;
- }
- .loading .spinner .rect3 {
- animation-delay: -1s;
- }
- .loading .spinner .rect4 {
- animation-delay: -0.9s;
- }
- .loading .spinner .rect5 {
- animation-delay: -0.8s;
- }
- .emptybottom {
- padding-bottom: 0 !important;
- }
- </style>
|