| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800 |
- <template>
- <view>
- <image class="page-bg" src="https://cos.his.cdwjyyh.com/fs/20250506/730750385fab4dd5a8a268b1550c81d6.png"
- mode="widthFix" style="width: 100%;"></image>
- <view class="nav-bar" :style="{height: `calc(88rpx + ${statusBarHeight}px)`}">
- <view class="statusBar" :style="{height: statusBarHeight + 'px'}"></view>
- <image class="nav-bg" src="https://cos.his.cdwjyyh.com/fs/20250506/730750385fab4dd5a8a268b1550c81d6.png"
- mode="widthFix"></image>
- <view class="nav-bar-box">
- <view class="uni-page-head-hd es-mr-24" @click="$navBack()">
- <uni-icons type="left" size="26" color="#000000"></uni-icons>
- </view>
- <view class="nav-bar-left">
- <image
- :src="roleInfo.avatar||'https://fs-1319721001.cos.ap-chongqing.myqcloud.com/fs/20240229/be32b8d2ae9f497297d10327656bb43c.png'"
- mode="aspectFill"></image>
- <view class="nav-bar-head">
- <view class="nav-bar-name textOne">{{roleName}}</view>
- <view class="textOne" v-show="roleInfo.title">{{roleInfo.title}}</view>
- </view>
- <!-- <uni-icons type="more-filled" size="26" style="flex-shrink: 0;" color="#000000"></uni-icons> -->
- </view>
- </view>
- </view>
- <scroll-view class="msg-scroll" :scroll-top="scrollTop" scroll-y="true" :scroll-with-animation="true">
- <view class="container-body" :style="{paddingTop: `calc(100rpx + ${statusBarHeight}px)`}">
- <view class="banner-box" v-if="roleInfo.imageUrl||roleInfo.textDescription">
- <image :src="roleInfo.imageUrl" mode="aspectFill"></image>
- <view class="banner-txt" v-show="roleInfo.textDescription">{{roleInfo.textDescription}}</view>
- </view>
- <view class="ques-box" v-if="quesList&&quesList.length>0">
- <view v-for="(ques,i) in quesList" :key="i" @click="handleQues(ques)">{{ques}}</view>
- </view>
- <view class="TUI-message-list es-mt-24" @touchstart="handleTouchStart">
- <view v-for="(item, index) in historyList" :key="item.id" :id="'view' + item.id">
- <view :class="item.type == 1 ? 'msg-item my-msg':'msg-item ai-msg'">
- <image v-if="item.type == 1" class="avatar"
- :src="userInfo.avatar||'https://fs-1319721001.cos.ap-chongqing.myqcloud.com/fs/20240229/1d7eb0607a074892964dd32e8735e540.jpg'"
- mode="aspectFill"></image>
- <image v-if="item.type != 1" class="avatar"
- :src="roleInfo.avatar||'https://fs-1319721001.cos.ap-chongqing.myqcloud.com/fs/20240229/be32b8d2ae9f497297d10327656bb43c.png'"
- mode="aspectFill"></image>
- <view>
- <view class="msg-text">
- <uaMarkdown :source="item.content" :showLine="false" style="font-size: 32rpx" />
- </view>
- <view class="x-f" style="align-items: center;">
- <view v-if="item.type != 1&&item.content" class="x-c copybtn" @click="copyData(item.content)"><u-icon
- name="file-text" color="#FF5C03" size="20"
- style="margin-right: 5rpx;"></u-icon>复制</view>
- </view>
- </view>
- </view>
- </view>
- <view v-for="(item, index) in msgs" :key="item.id" :id="'view' + item.id">
- <view :class="item.type == 1 ? 'msg-item my-msg':'msg-item ai-msg'">
- <image v-if="item.type == 1" class="avatar"
- :src="userInfo.avatar||'https://fs-1319721001.cos.ap-chongqing.myqcloud.com/fs/20240229/1d7eb0607a074892964dd32e8735e540.jpg'"
- mode="aspectFill"></image>
- <image v-if="item.type != 1" class="avatar"
- :src="roleInfo.avatar||'https://fs-1319721001.cos.ap-chongqing.myqcloud.com/fs/20240229/be32b8d2ae9f497297d10327656bb43c.png'"
- mode="aspectFill"></image>
- <view>
- <view class="msg-text">
- <uaMarkdown :source="item.content" :showLine="false" style="font-size: 32rpx" />
- </view>
- <view class="x-f" style="align-items: center;">
- <view v-if="item.type != 1&&item.content" class="x-c copybtn" @click="copyData(item.content)"><u-icon
- name="file-text" color="#FF5C03" size="20"
- style="margin-right: 5rpx;"></u-icon>复制</view>
- <view style="margin-top: 6px;margin-left: 10rpx;" v-if="item.retry==1" @click="handleInput()">
- <u-icon name="reload" color="#999" size="20" labelPos="right" labelSize="24rpx" label="重试"></u-icon>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </scroll-view>
- <view class="chatinput">
- <u--input placeholder="请输入想要咨询的问题" border="none" v-model.trim="inputText" clearable
- @confirm="handleInputClick"></u--input>
- <!-- <image src="/static/images/update_pic_icon.png" mode="aspectFill" class="icon" @click="choosePic">
- </image> -->
- <image src="/static/images/send_message_icon.png" mode="aspectFill" class="icon2"
- :style="{opacity:isFirst==0&&inputText?1:0.7}" @click="handleInputClick"></image>
- </view>
- </view>
- </template>
- <script>
- import uaMarkdown from "@/components/ua2-markdown/ua-markdown.vue"
- import {
- getSessionDetailInfo,
- replyAppUserContent,
- getAiJsonMsgCount
- } from "@/api/ai.js"
- export default {
- components: {
- uaMarkdown
- },
- data() {
- return {
- sessionId: '',
- statusBarHeight: uni.getSystemInfoSync().statusBarHeight,
- roleName: '',
- chatList: [],
- quesList: [],
- roleInfo: {},
- inputText: '',
- triggered: false,
- isCompleted: false,
- scrollTop: 0,
- scrollInto: '', // 用于 scroll-into-view
- oldMessageTime: 0,
- roleId: null,
- msgTimes: null, // 5 分钟无消息定时器
- isSocketOpen: false,
- socket: null,
- isSend: true,
- userInfo: {},
- doctorId: '',
- msgEnd: false,
- msgs: [],
- source: '',
- maxReconnect: 1,
- reconnectCount: 2,
- reconnecting: false,
- needResend: false, // 是否有待重发消息
- resendText: '', // 待重发内容
- idleClose: false, //是否5分钟自动断开
- isFirst: 0,
- idleTimer: null,
- reportPlaceholderId:'',
- replyId:'',
- startTime: '',
- endTime: '',
- deviceId: '',
- isRefresh: '',
- historyList:[],
- isInitReportAi: 0
- }
- },
- onLoad(options) {
- this.source = options.source || ''
- // if (this.source !== 'healthWeekReport') uni.removeStorageSync('aiSuggestion')
- this.roleName = options.roleName || ''
- this.roleId = options.roleId || ''
- this.userInfo = uni.getStorageSync('userInfo') ? JSON.parse(uni.getStorageSync('userInfo')) : {}
- this.getSessionDetailInfo(options.sessionId)
- this.sessionId = options.sessionId || null
- this.isFirst = this.source == 'healthWeekReport'?1:0
- if(this.source == 'healthWeekReport') {
- const id = 'report_placeholder_' + Date.now()
- this.reportPlaceholderId = id
- this.startTime = options.startTime
- this.endTime = options.endTime
- this.deviceId = options.deviceId
- this.isRefresh = options.isRefresh
- // this.sessionId = null
- this.getAiJsonMsgCount(id)
- } else {
- this.initSocket(1)
- }
- uni.onKeyboardHeightChange(this.boardHeightChange);
- },
- onReady() {
- // this.scrollToBottom()
- },
- onUnload() {
- uni.$emit('getSessionId')
- uni.offKeyboardHeightChange(this.boardHeightChange);
- if (this.socket) {
- this.maxReconnect = 0
- this.socket.close();
- this.socket = null
- }
- clearTimeout(this.idleTimer) // 原 clearInterval(this.msgTimes) // 会话结束清占位
- },
- onBackPress() {
- uni.$emit('getSessionId')
- if (this.socket) {
- this.maxReconnect = 0
- this.socket.close();
- this.socket = null
- }
- clearTimeout(this.idleTimer)
- },
- methods: {
- boardHeightChange:function(res){
- this.scrollToBottom()
- },
- /* ---------- 页面交互 ---------- */
- back() {
- uni.navigateBack()
- },
- getAiJsonMsgCount(id) {
- const param = {
- startTime: this.startTime,
- endTime: this.endTime,
- message: uni.getStorageSync('aiSuggestion')||'',
- userId: this.userInfo.userId,
- roleId: this.roleId,
- }
- getAiJsonMsgCount(param).then(res=>{
- if(res.code==200&&res.count<1) {
- this.isInitReportAi = 1
- this.addMsg(2, '报告解读中...', 1, 0,id)
- this.initSocket(1)
- }else {
- this.isFirst = 0
- this.isInitReportAi = 0
- this.reportPlaceholderId = ''
- this.initSocket()
- }
- })
- },
- handleQues(ques) {
- this.inputText = ques
- this.handleInputClick()
- },
- handleInputClick(){
- if(this.isFirst==1){
- uni.showToast({
- title: '报告解读中,请稍后',
- icon: 'none'
- });
- return
- }
- this.handleInput()
- },
- handleInput() {
- // 1. 输入为空直接 return
- if (!this.inputText.trim()&&this.isFirst !=1) return;
- // 2. 连接断了 -> 走原有重连逻辑
- if (!this.isSocketOpen) {
- this.isSend = true
- this.idleClose = false
- this.trySend();
- return;
- }
- // 3. 连接正常,但对方还在回复
- if (!this.isSend) {
- uni.showToast({
- title: '对方正在回复,请稍等',
- icon: 'none'
- });
- return; // 直接阻断,不继续往下走
- }
- // 4. 真正发消息
- this.trySend();
- },
- /* ---------- 发送控制 ---------- */
- trySend() {
- const text = this.isFirst ==1&&this.source=='healthWeekReport' ? uni.getStorageSync('aiSuggestion') :this.inputText.trim() || this.resendText
- if (!text) return
- // 1. 链路不通 → 立即重连
- if (!this.isSocketOpen) {
- if (this.reconnecting) {
- uni.showToast({
- title: '正在重连,请稍候',
- icon: 'none'
- })
- return
- }
- this.reconnecting = true
- // uni.showToast({
- // title: '网络断开,正在重连…',
- // icon: 'none'
- // })
- if (this.socket) {
- this.socket.close();
- this.socket = null
- }
- this.initSocket()
- return
- }
- // 2. 有待重发内容优先发
- if (this.needResend) {
- this.resendText = ''
- this.needResend = false
- this.sendMsg(text)
- } else {
- this.sendMsg(text)
- }
- },
- /* ---------- WebSocket ---------- */
- initSocket(type) {
- let that = this
- if (this.socket) return // 并发短路
- const userId = this.userInfo.userId
- let url = this.source == 'healthWeekReport' ? '/app/replyAppUserWebSocket/' : '/app/interestAiWebSocket/'
- this.socket = uni.connectSocket({
- url: getApp().globalData.aiWSUrl + url + userId,
- multiple: true,
- success: res => {
- console.log('WebSocket连接已打开1!', Date.now());
- that.isSocketOpen = true
- },
- error: res => {
- console.log(res)
- },
- })
- this.socket.onOpen(() => {
- console.log('WebSocket 已打开2', Date.now())
- this.isSocketOpen = true
- this.reconnectCount = 0
- this.reconnecting = false
- // console.log("this.isFirst!=1&&this.replyId=",this.isFirst,this.replyId)
- if(this.isFirst ==1&&this.source=='healthWeekReport'&&this.isInitReportAi==1) {
- // console.log('healthWeekReport')
- this.handleInput()
- }
- if(this.isFirst!=1&&this.replyId){
- // console.log("网络异常,请重新发送")
- this.isSend = true
- this.addMsg(2, '网络异常,请重新发送', 2)
- }
- })
- this.socket.onMessage(res => {
- if (!res.data || res.data.trim() === '') return
- if(res.data=='[无视]') {
- return
- }
- // console.log('WebSocket onMessage2=========', res)
- this.isSend = true
- let data = res.data
- this.addMsg(2, data, 2)
- })
- this.socket.onClose(() => {
- this.isSocketOpen = false
- console.log('WebSocket 已关闭', Date.now())
- this.socket = null
- this.reconnecting = false
- this.isSend = true
- if (this.idleTimer) clearTimeout(this.idleTimer)
- if(this.isFirst ==1&&this.source=='healthWeekReport') {
- this.addMsg(2, '报告解读失败', 2,1,this.reportPlaceholderId)
- return
- }
- if (this.idleClose) return;
- if(this.maxReconnect == 0) return;
- this.reconnectCount++
- console.log("this.reconnectCount",this.reconnectCount)
- if (this.reconnectCount <= this.maxReconnect) {
- setTimeout(() => this.initSocket(), 5000)
- } else {
- // if(this.isFirst ==1&&this.source=='healthWeekReport') {
- // this.addMsg(2, '报告解读失败', 2,1,this.reportPlaceholderId)
- // }
- uni.showToast({
- title: '网络异常,请手动重试',
- icon: 'none',
- duration: 3000
- })
- }
- })
- this.socket.onError(() => {
- console.log('WebSocket 错误', Date.now())
- this.isSocketOpen = false
- this.socket = null
- this.reconnecting = false
- this.isSend = true
- // this.clearHeart()
- if (this.msgTimes) {
- clearInterval(this.msgTimes);
- this.msgTimes = null
- }
- })
- },
- /* ---------- 发送/重试 ---------- */
- sendMsg(text) {
- if (!this.isSocketOpen || !this.isSend) return
- const data = {
- userId: this.userInfo.userId,
- roleId: this.roleId,
- nickName: this.userInfo.nickName,
- avatar: this.userInfo.avatar,
- roleName: this.roleName,
- message: text,
- sessionId: this.sessionId,
- // isFirst: this.isFirst,//去掉
- startTime: this.startTime,
- endTime: this.endTime,
- deviceId: this.deviceId,
- isRefresh: this.isRefresh,
- }
- // console.log('data报告解读中', JSON.stringify(data))
- this.socket.send({
- data: JSON.stringify(data),
- success: () => {
- if(this.isFirst !=1) {
- this.addMsg(1, text, 1)
- const id = 'replyId_' + Date.now()
- this.replyId = id
- this.addMsg(2, '正在思考中…', 1, 0)
- }
- this.isSend = false
- this.inputText = '' // 只有成功才清空
- },
- fail: () => {
- // 进入待重发模式
- this.needResend = true
- this.resendText = text
- this.isSend = true
- if(this.isFirst ==1&&this.source=='healthWeekReport') {
- this.addMsg(2, '报告解读失败', 2,1,this.reportPlaceholderId)
- uni.showToast({
- title: '发送失,请重试',
- icon: 'none'
- })
- return
- }
- uni.showToast({
- title: '发送失,请重新发送',
- icon: 'none'
- })
- }
- })
- },
- addHistoryList(type, content, inputType, retry = 0,pid) {
- // console.log("=addMsg===inputType==",content,inputType)
- const id = pid||Date.now() + '_' + Math.random().toString(36).slice(2, 8)
- const obj = {
- type,
- content,
- retry,
- id
- }
- this.historyList.push(obj)
- this.scrollToBottom()
- },
- addMsg(type, content, inputType, retry = 0,pid) {
- // console.log("=addMsg===inputType==",content,inputType)
- const id = pid||Date.now() + '_' + Math.random().toString(36).slice(2, 8)
- const obj = {
- type,
- content,
- retry,
- id
- }
- if (inputType == 2) {
- if(this.reportPlaceholderId) {
- // console.log("===pid",pid)
- this.isFirst = pid?1:0
- const idx = this.msgs.findIndex(m => m.id == this.reportPlaceholderId)
- if (idx > -1) {
- this.$set(this.msgs, idx, {
- ...this.msgs[idx],
- retry:retry,
- content:content
- })
- }
- this.reportPlaceholderId = pid?this.reportPlaceholderId:''
- } else {
- // console.log("=33333==",obj,this.msgs)
- if (this.msgs.length) this.msgs.pop();
- this.msgs.push(obj);
- this.replyId = ''
- }
- } else if (inputType == 1) {
- this.msgs.push(obj)
- }
- this.scrollToBottom()
- // 重置 5 分钟空闲计时
- if (this.idleTimer) clearTimeout(this.idleTimer)
- this.idleTimer = setTimeout(() => {
- this.idleClose = true
- if (this.socket) this.socket.close();
- }, 5 * 60 * 1000)
- },
- /* ---------- 初始数据 ---------- */
- getSessionDetailInfo(sessionId) {
- getSessionDetailInfo(sessionId, this.roleId).then(res => {
- if (res.code == 200) {
- const chatList = res.chatList || []
- this.roleInfo = res.roleInfo || {}
- this.roleName = this.roleInfo.roleName || ''
- this.quesList = this.roleInfo.wordList ? this.roleInfo.wordList.split('||') : []
- // if (this.source !== 'healthWeekReport') {
- const list = []
- if (this.source !== 'healthWeekReport'&&this.roleInfo.welcomeMessage) {
- list.push({
- sendType: 2,
- content: this.roleInfo.welcomeMessage
- })
- }
- list.push(...chatList)
- list.forEach(v => this.addHistoryList(v.sendType, v.content, 1))
- // }
- } else {
- uni.showToast({
- title: res.msg,
- icon: 'none'
- })
- this.scrollToBottom()
- }
- }).catch(() => {
- this.scrollToBottom()
- })
- },
- /* ---------- 工具 ---------- */
- clearAllTimer() {
- clearTimeout(this.idleTimer)
- this.idleTimer = null
- },
- handleTouchStart() {
- // uni.hideKeyboard()
- // this.$nextTick(() => this.scrollToBottom())
- },
-
- /* ---------- 滚动 ---------- */
- scrollToBottom() {
- setTimeout(() => {
- uni.createSelectorQuery()
- .in(this)
- .select('.msg-scroll') // scroll-view 本身
- .boundingClientRect(scrollRect => {
- uni.createSelectorQuery()
- .in(this)
- .select('.container-body') // 内容区
- .boundingClientRect(bodyRect => {
- if (scrollRect && bodyRect) {
- // 内容高 - 滚动容器高 = 需要滚动的距离
- const max = bodyRect.height - scrollRect.height;
- this.scrollTop = max < 0 ? 0 : max;
- }
- })
- .exec();
- })
- .exec();
- }, 500);
- },
-
- /* ---------- 剪切板 ---------- */
- copyData(data) {
- uni.setClipboardData({
- data,
- success: () => uni.showToast({
- title: '复制成功',
- icon: 'none'
- }),
- fail: () => uni.showToast({
- title: '复制失败',
- icon: 'none'
- })
- })
- },
-
- }
- }
- </script>
- <style scoped lang="scss">
- @mixin u-flex($flexD, $alignI, $justifyC) {
- display: flex;
- flex-direction: $flexD;
- align-items: $alignI;
- justify-content: $justifyC;
- }
- ::v-deep .msg-text {
- p {
- white-space: pre-line;
- }
- }
- .copybtn {
- margin-top: 12rpx;
- font-family: PingFang SC, PingFang SC;
- font-weight: 500;
- font-size: 28rpx;
- color: #FF5C03;
- background-color: #ffe2d1;
- padding: 4rpx 10rpx;
- border-radius: 10rpx;
- display: inline-flex;
- }
- .nav-bar {
- position: fixed;
- z-index: 9999;
- top: 0;
- left: 0;
- width: 100%;
- overflow: hidden;
- .nav-bg {
- width: 100%;
- height: 100%;
- position: absolute;
- left: 0;
- top: 0;
- z-index: 1;
- background-color: #fff;
- }
- &-box {
- position: relative;
- padding: 0 24rpx;
- @include u-flex(row, center, flex-start);
- height: 88rpx;
- box-sizing: border-box;
- z-index: 3;
- }
- &-left {
- width: 100%;
- @include u-flex(row, center, flex-start);
- overflow: hidden;
- image {
- flex-shrink: 0;
- width: 64rpx;
- height: 64rpx;
- border-radius: 12rpx 12rpx 12rpx 12rpx;
- }
- }
- &-name {
- font-family: PingFang SC, PingFang SC;
- font-weight: 600;
- font-size: 28rpx;
- color: #222222;
- }
- &-head {
- flex: 1;
- overflow: hidden;
- margin-left: 22rpx;
- margin-right: 22rpx;
- font-family: PingFang SC, PingFang SC;
- font-weight: 400;
- font-size: 23rpx;
- color: #999999;
- }
- }
- .page-bg {
- position: absolute;
- top: 0;
- left: 0;
- }
- .container-body {
- position: relative;
- padding: 32rpx 30rpx;
- z-index: 2;
- @include u-flex(column, flex-star, center);
- .banner-box {
- width: 100%;
- min-width: 686rpx;
- overflow: hidden;
- background: rgba(255, 255, 255, 0.9);
- border-radius: 24rpx 24rpx 24rpx 24rpx;
- border: 4rpx solid #FFFFFF;
- box-sizing: border-box;
- image {
- width: 100%;
- min-width: 690rpx;
- height: 264rpx;
- background: #f7f7f7;
- }
- }
- .banner-txt {
- padding: 32rpx;
- font-family: PingFang SC, PingFang SC;
- font-weight: 400;
- font-size: 32rpx;
- color: #333333;
- word-break: break-all;
- }
- .ques-box {
- @include u-flex(row, flex-star, flex-star);
- flex-wrap: wrap;
- margin: 22rpx -8rpx -10rpx;
- view {
- padding: 12rpx 36rpx;
- background: #FFFFFF;
- border-radius: 16rpx 16rpx 16rpx 16rpx;
- border: 1rpx solid #ECECEC;
- font-family: PingFang SC, PingFang SC;
- font-weight: 500;
- font-size: 28rpx;
- color: #333333;
- margin: 10rpx 8rpx;
- }
- }
- }
- .chatinput {
- position: fixed;
- left: 32rpx;
- right: 32rpx;
- z-index: 999;
- bottom: calc(var(--window-bottom) + 24rpx);
- height: 96rpx;
- background-color: green;
- background: #FFFFFF;
- box-shadow: 0rpx 8rpx 21rpx 0rpx rgba(0, 0, 0, 0.1);
- border-radius: 24rpx 24rpx 24rpx 24rpx;
- @include u-flex(row, center, center);
- padding: 0 24rpx;
- box-sizing: border-box;
- .icon {
- height: 48rpx;
- width: 48rpx;
- margin-left: 32rpx;
- }
- .icon2 {
- height: 56rpx;
- width: 56rpx;
- margin-left: 32rpx;
- }
- }
- .msg-scroll {
- height: calc(100vh - var(--window-bottom) - 120rpx);
- }
- .TUI-message-list {
- width: 100%;
- box-sizing: border-box;
- .time-container {
- font-family: PingFang SC, PingFang SC;
- font-weight: 400;
- font-size: 24rpx;
- color: #999999;
- padding: 36rpx 0;
- margin: 10px;
- text-align: center;
- }
- .avatar {
- flex-shrink: 0;
- width: 88rpx;
- height: 88rpx;
- background: #FFFFFF;
- border-radius: 12rpx 12rpx 12rpx 12rpx;
- }
- .msg-item {
- margin-bottom: 24rpx;
- }
- .ai-msg {
- @include u-flex(row, flex-start, flex-start);
- .avatar {
- margin-right: 24rpx;
- }
- .msg-text {
- border-radius: 0rpx 24rpx 24rpx 24rpx;
- }
- }
- .my-msg {
- @include u-flex(row-reverse, flex-start, flex-start);
- .avatar {
- margin-left: 24rpx;
- }
- .msg-text {
- border-radius: 24rpx 0 24rpx 24rpx;
- background: #FEC75C;
- }
- }
- .msg-text {
- padding: 24rpx 24rpx 0 24rpx;
- background: #FFFFFF;
- overflow: hidden;
- }
- }
- </style>
|