跨境派

跨境派

跨境派,专注跨境行业新闻资讯、跨境电商知识分享!

当前位置:首页 > 卖家故事 > uniapp 小程序端,使用uni-ai-chat对接百度大模型知识库,保留uni-ai-chat流式响应,删除广告及其他冗余代码

uniapp 小程序端,使用uni-ai-chat对接百度大模型知识库,保留uni-ai-chat流式响应,删除广告及其他冗余代码

时间:2024-04-17 14:10:35 来源:网络cs 作者:康由 栏目:卖家故事 阅读:

标签: 广告  删除  响应  保留  使用  程序  知识  模型 
阅读本书更多章节>>>>

我使用的是uniapp管网的uni-ai-chat插件,查看后续内容前,请先确认是否使用的也是该插件
uniapp官方插件介绍:https://uniapp.dcloud.net.cn/uniCloud/uni-ai-chat.html
插件地址:https://ext.dcloud.net.cn/plugin?name=uni-ai-chat

核心代码
主要就是重写了send方法中的部分逻辑,我这里是前端直接调用的百度的大模型知识库接口,需要将acess_token拼接在url上,这是不安全的,建议后台封装接口后,前端去调后端的接口

async send() {let messages = []// 复制一份,消息列表数据let msgs = JSON.parse(JSON.stringify(this.msgList))// - 获取上下文的代码【start】-// 带总结的消息 indexlet findIndex = [...msgs].reverse().findIndex(item => item.summarize)// console.log('findIndex', findIndex)if (findIndex != -1) {let aiSummaryIndex = msgs.length - findIndex - 1// console.log('aiSummaryIndex', aiSummaryIndex)// 将带总结的消息的 内容 更换成 总结msgs[aiSummaryIndex].content = msgs[aiSummaryIndex].summarize// 拿最后一条带直接的消息作为与ai对话的msg bodymsgs = msgs.splice(aiSummaryIndex)} else {// 如果未总结过就直接从末尾拿10条msgs = msgs.splice(-10)}// 过滤涉敏问题msgs = msgs.filter(msg => !msg.illegal)// - 获取上下文的代码【end】-// 如果:不希望带上上下文;请注释掉 上方:获取上下文的代码【start】-【end】。并添加,代码: msgs = [msgs.pop()]// 根据数据内容设置角色messages = msgs.map(item => {// 角色默认为用户let role = "user"// 如果是ai再根据 是否有总结 来设置角色为 system 还是 assistantif (item.isAi) {role = item.summarize ? 'system' : 'assistant'}return {content: item.content,role}})this.sliceMsgToLastMsg = new SliceMsgToLastMsg(this)const requestTask = uni.request({url: url, //这里我对接的是百度知识库的接口,例:url?access_token=xxxxmethod: 'POST',enableChunked: true,data: {"query": this.content,"plugins": ["uuid-zhishiku"],"verbose": true,"stream": true},success: response => {},fail: () => {},complete: () => {}});requestTask.onChunkReceived(chunk => {const arrayBuffer = chunk.data;const uint8Array = new Uint8Array(arrayBuffer);const str = new TextEncoding.TextDecoder('utf-8').decode(uint8Array);var reciveMsg = '';var msgArr = [];var endMsg = ''//百度的接口正常消息体会有一个is_end字段,其他的消息没有,这里我们不需要其他信息,所以做个过滤,is_end  为true 代表结束消息  if (str.indexOf('is_end') !== -1) {if (str.indexOf('data') !== -1) {//这里有个坑,百度返回的消息是含data:的字符串,冒号右边是json格式,也是我们需要的内容,需要将右边提取出来msgArr = str.split('data: ')reciveMsg = JSON.parse(msgArr[1])//默认每一次将结束句存一次,我也不知道是百度抽风还是我代码问题,有时候结束句会和倒数第二句一起返回,所以默认都把当前的这句存一下endMsg = JSON.parse(msgArr[1])}if (reciveMsg.id) {if (this.sseIndex === 0) {this.msgList.push({isAi: true,content: reciveMsg.result,create_time: Date.now()})} else {this.sliceMsgToLastMsg.addMsg(reciveMsg.result)}//开启流式this.showLastMsg()// 让流式响应计数值递增this.sseIndex++}//这里就是结束句和倒数第二句一起返回的if (msgArr[2]) {endMsg = JSON.parse(msgArr[2])}//结束,立即停止流式if (endMsg && endMsg.is_end) {this.sliceMsgToLastMsg.t = 0this.sseIndex = 0this.content = ''}}})},

完整代码

<template><view class="container"><view class="nav fixed"><view class="mini-status" :style="{'height':statusBarHeight + 'px'}"></view><view class="mini-nav" :style="{'height':titleBarHeight + 'px', 'lineHeight':titleBarHeight + 'px'}"><van-icon name="arrow-left" size="42rpx" @click="handleReturn" /><text>AI智能问答</text></view></view><!-- #ifdef H5 --><view v-if="isWidescreen" class="header">uni-ai-chat</view><!-- #endif --><!-- <text class="noData" v-if="msgList.length === 0">你好,我是云网小智点击下方输入框,试着跟我聊天吧~</text> --><scroll-view :scroll-into-view="scrollIntoView" scroll-y="true" class="msg-list" :enable-flex="true"><view class="default-question"><text class="ai-name">你好,我是小智</text><text class="ai-desc">作为你的智能伙伴,我既能写文案、想点子,又能陪你聊天、答疑解惑。</text><text class="ai-desc">你可以试着问我:</text><view class="question-list"><view @click="defaulSend(item)" :style="'background-image:url('+ques_first+')'"class="question-item" v-for="(item,index) in question" :key="index">{{item}}</view></view><text class="ai-desc">特别说明:回答内容均为Al算法生成,不代表平台官方回复!</text></view><uni-ai-msg ref="msg" v-for="(msg,index) in msgList" :key="index" :msg="msg" @changeAnswer="changeAnswer(index)":show-cursor="index == msgList.length - 1 && msgList.length%2 === 0 && sseIndex":isLastMsg="index == msgList.length - 1" @removeMsg="removeMsg(index)"></uni-ai-msg><template v-if="msgList.length%2 !== 0"><view v-if="requestState == -100" class="retries-box"><text>消息发送失败</text><uni-icons @click="send" color="#d22" type="refresh-filled" class="retries-icon"></uni-icons></view><view class="tip-ai-ing" v-else-if="msgList.length"><text>小智正在思考中...</text></view></template><view @click="closeSseChannel" class="stop-responding" v-if="sseIndex"> ▣ 停止回答</view><view id="last-msg-item" style="height: 1px;"></view></scroll-view><view class="foot-box" :style="{'padding-bottom':footBoxPaddingBottom}"><!-- #ifdef H5 --><view class="pc-menu" v-if="isWidescreen"><image class="menu-image" src="https://minio.ptd.dageek.cn/iip-dev/upload/static/message.png"mode="heightFix"></image></view><!-- #endif --><view class="foot-box-content"><view v-if="!isWidescreen" class="menu"><image src="https://minio.ptd.dageek.cn/iip-dev/upload/static/message.png" class="menu-image"mode="heightFix"></image></view><view class="textarea-box"><textarea v-model="content" :cursor-spacing="15" class="textarea" :auto-height="!isWidescreen"placeholder="请输入要发给小智的内容" :maxlength="-1" :adjust-position="false":disable-default-padding="false" placeholder-class="input-placeholder"></textarea></view><view class="send-btn-box" :title="(msgList.length && msgList.length%2 !== 0) ? '小智正在回复中不能发送':''"><!-- #ifdef H5 --><text v-if="isWidescreen" class="send-btn-tip">↵ 发送 / shift + ↵ 换行</text><!-- #endif --><button @click="beforeSend" :disabled="inputBoxDisabled || !content" class="send"type="primary">发送</button></view></view></view><uni-popup ref="popup" type="top"><view class="box"><text class="title">请选择llm的model</text><radio-group @change="radioChange" class="radio-group"><label class="item" v-for="(item, index) in models" :key="item.value"><radio :value="item.value" :checked="currentModel === item.value" class="radio" /><view class="item-title">{{item.text}}</view></label></radio-group><view class="btn-box"><view @click="cancel" class="btn cancel">取消</view><view @click="confirm" class="btn confirm">确认</view></view></view></uni-popup></view></template><script>let confirmCallback = () => {}import * as TextEncoding from '@/uni_modules/text-encoding-shim/index.js';import mixin from '@/mixins/index.js'// 引入配置文件import config from '@/config.js';// 导入uniCloud云对象task模块import uniCoTask from '@/common/unicloud-co-task.js';// 导入 将多个字消息文本,分割成单个字 分批插入到最末尾的消息中 的类import SliceMsgToLastMsg from './SliceMsgToLastMsg.js';// 收集所有执行云对象的任务列表let uniCoTaskList = []// 定义终止并清空 云对象的任务列表中所有 任务的方法uniCoTaskList.clear = function() {// 执行数组内的所有任务uniCoTaskList.forEach(task => task.abort())// 清空数组uniCoTaskList.slice(0, uniCoTaskList.length)}// 获取广告idconst {adpid} = config// 初始化sse通道let sseChannel = false;// 键盘的shift键是否被按下let shiftKeyPressed = falseexport default {mixins: [mixin],data() {return {models: [{text: "gpt-4",value: "gpt-4"},{text: "gpt-4-0314",value: "gpt-4-0314"},{text: "gpt-4-32k",value: "gpt-4-32k"},{text: "gpt-4-32k-0314",value: "gpt-4-32k-0314"},{text: "gpt-3.5-turbo",value: "gpt-3.5-turbo"},{text: "gpt-3.5-turbo-0301",value: "gpt-3.5-turbo-0301"},{text: "都不选",value: ""}],currentModel: '',// 使聊天窗口滚动到指定元素id的值scrollIntoView: "",// 消息列表数据msgList: [],// 通讯请求状态requestState: 0, //0发送中 100发送成功 -100发送失败// 本地对话是否因积分不足而终止insufficientScore: false,// 输入框的消息内容content: "",// 记录流式响应次数sseIndex: 0,// 是否启用流式响应模式enableStream: true,// 当前屏幕是否为宽屏isWidescreen: false,// 广告位idadpid,llmModel: false,keyboardHeight: 0,//预制问题question: ['工业互联网是什么?','网络安全管理办法是什么?','智改数转是什么?'],ques_first: "https://minio.ptd.dageek.cn/iip-dev/upload/static/ques_first.jpg",ques_follow: "https://minio.ptd.dageek.cn/iip-dev/upload/static/ques_follow.jpg",}},computed: {// 输入框是否禁用inputBoxDisabled() {// 如果正在等待流式响应,则禁用输入框if (this.sseIndex !== 0) {return true} else {return false}// 如果消息列表长度为奇数,则禁用输入框return !!(this.msgList.length && this.msgList.length % 2 !== 0)},// 获取当前环境NODE_ENV() {return process.env.NODE_ENV},footBoxPaddingBottom() {return (this.keyboardHeight || 10) + 'px'}},// 监听msgList变化,将其存储到本地缓存中watch: {msgList: {handler(msgList) {// 将msgList存储到本地缓存中console.log('进行消息缓存');uni.setStorage({"key": "uni-ai-msg","data": msgList})},// 深度监听msgList变化deep: true},insufficientScore(insufficientScore) {uni.setStorage({"key": "uni-ai-chat-insufficientScore","data": insufficientScore})},llmModel(llmModel) {let title = 'uni-ai-chat'if (llmModel) {title += ` (${llmModel})`}// uni.setNavigationBarTitle({title})// #ifdef H5if (this.isWidescreen) {document.querySelector('.header').innerText = title}// #endifuni.setStorage({key: 'uni-ai-chat-llmModel',data: llmModel})}},beforeMount() {// #ifdef H5// 监听屏幕宽度变化,判断是否为宽屏 并设置isWidescreen的值uni.createMediaQueryObserver(this).observe({minWidth: 650,}, matches => {this.isWidescreen = matches;})// #endif},async mounted() {// 获得历史对话记录this.msgList = uni.getStorageSync('uni-ai-msg') || [];if (this.msgList.length > 0) {this.msgList[this.msgList.length - 1].isLast = true}// 获得之前设置的llmModelthis.llmModel = uni.getStorageSync('uni-ai-chat-llmModel')// 获得之前设置的uni-ai-chat-insufficientScorethis.insufficientScore = uni.getStorageSync('uni-ai-chat-insufficientScore') || false// 如果上一次对话中 最后一条消息ai未回复。则一启动就自动重发。let length = this.msgList.lengthif (length) {let lastMsg = this.msgList[length - 1]if (!lastMsg.isAi) {this.send()}}// 在dom渲染完毕后 使聊天窗口滚动到最后一条消息this.$nextTick(() => {this.showLastMsg()})// #ifdef H5//获得消息输入框对象let adjunctKeydown = falseconst textareaDom = document.querySelector('.textarea-box textarea');if (textareaDom) {//键盘按下时textareaDom.onkeydown = e => {// console.log('onkeydown', e.keyCode)if ([16, 17, 18, 93].includes(e.keyCode)) {//按下了shift ctrl alt windows键adjunctKeydown = true;}if (e.keyCode == 13 && !adjunctKeydown) {e.preventDefault()// 执行发送setTimeout(() => {this.beforeSend();}, 300)}};textareaDom.onkeyup = e => {//松开adjunct键if ([16, 17, 18, 93].includes(e.keyCode)) {adjunctKeydown = false;}};// 可视窗口高let initialInnerHeight = window.innerHeight;if (uni.getSystemInfoSync().platform == "ios") {textareaDom.addEventListener('focus', () => {let interval = setInterval(function() {if (window.innerHeight !== initialInnerHeight) {clearInterval(interval)// 触发相应的回调函数document.querySelector('.container').style.height = window.innerHeight + 'px'window.scrollTo(0, 0);this.showLastMsg()}}, 1);})textareaDom.addEventListener('blur', () => {document.querySelector('.container').style.height = initialInnerHeight + 'px'})} else {window.addEventListener('resize', (e) => {this.showLastMsg()})}}// #endif// #ifndef H5uni.onKeyboardHeightChange(e => {this.keyboardHeight = e.height// 在dom渲染完毕后 使聊天窗口滚动到最后一条消息this.$nextTick(() => {this.showLastMsg()})})// #endif},methods: {// 选择默认问题,并发送defaulSend(text) {this.content = textthis.beforeSend()},setLLMmodel() {this.$refs['popup'].open(model => {console.log('model', model);this.llmModel = model})},// 此(惰性)函数,检查是否开通uni-push;决定是否启用enableStreamasync checkIsOpenPush() {try {// 获取推送客户端idawait uni.getPushClientId()// 如果获取成功,则将checkIsOpenPush函数重写为一个空函数this.checkIsOpenPush = () => {}} catch (err) {// 如果获取失败,则将enableStream设置为falsethis.enableStream = false}},// 更新最后一条消息updateLastMsg(param) {let length = this.msgList.lengthif (length === 0) {return}let lastMsg = this.msgList[length - 1]// 如果param是函数,则将最后一条消息作为参数传入该函数if (typeof param == 'function') {let callback = param;callback(lastMsg)} else {// 否则,将参数解构为data和cover两个变量const [data, cover = false] = argumentsif (cover) {lastMsg = data} else {lastMsg = Object.assign(lastMsg, data)}}this.msgList.splice(length - 1, 1, lastMsg)},// 换一个答案async changeAnswer(index) {// 如果问题还在回答中需要先关闭if (this.sseIndex) {this.sseIndex = 0}//删除旧的回答this.content = this.msgList[index-1].contentthis.msgList.pop()this.updateLastMsg({// 防止 偶发答案涉及敏感,重复回答时。提问内容 被卡掉无法重新问illegal: false})this.send()},removeMsg(index) {// 成对删除,如果点中的是 ai 回答的内容,index -= 1if (this.msgList[index].isAi) {index -= 1}// 如果删除的就是正在问的,且问题还在回答中需要先关闭if (this.sseIndex && index == this.msgList.length - 2) {this.closeSseChannel()}this.msgList.splice(index, 2)},async beforeSend() {if (this.inputBoxDisabled) {return uni.showToast({title: '云网小智正在回复中不能发送',icon: 'none'});}// 如果内容为空if (!this.content) {// 弹出提示框return uni.showToast({// 提示内容title: '内容不能为空',// 不显示图标icon: 'none'});}// 将用户输入的消息添加到消息列表中this.msgList.push({// 标记为非人工智能机器人,即:为用户发送的消息isAi: false,// 消息内容content: this.content,// 消息创建时间create_time: Date.now()})// 展示最后一条消息this.showLastMsg()// dom加载完成后 清空文本内容this.$nextTick(() => {this.content = ''})this.send() // 发送消息},async send() {let messages = []// 复制一份,消息列表数据let msgs = JSON.parse(JSON.stringify(this.msgList))// - 获取上下文的代码【start】-// 带总结的消息 indexlet findIndex = [...msgs].reverse().findIndex(item => item.summarize)// console.log('findIndex', findIndex)if (findIndex != -1) {let aiSummaryIndex = msgs.length - findIndex - 1// console.log('aiSummaryIndex', aiSummaryIndex)// 将带总结的消息的 内容 更换成 总结msgs[aiSummaryIndex].content = msgs[aiSummaryIndex].summarize// 拿最后一条带直接的消息作为与ai对话的msg bodymsgs = msgs.splice(aiSummaryIndex)} else {// 如果未总结过就直接从末尾拿10条msgs = msgs.splice(-10)}// 过滤涉敏问题msgs = msgs.filter(msg => !msg.illegal)// - 获取上下文的代码【end】-// 如果:不希望带上上下文;请注释掉 上方:获取上下文的代码【start】-【end】。并添加,代码: msgs = [msgs.pop()]// 根据数据内容设置角色messages = msgs.map(item => {// 角色默认为用户let role = "user"// 如果是ai再根据 是否有总结 来设置角色为 system 还是 assistantif (item.isAi) {role = item.summarize ? 'system' : 'assistant'}return {content: item.content,role}})this.sliceMsgToLastMsg = new SliceMsgToLastMsg(this)const requestTask = uni.request({url: url,//这里我对接的是百度知识库的接口,例:url?access_token=xxxxmethod: 'POST',enableChunked: true,data: {"query": this.content,"plugins": ["uuid-zhishiku"],"verbose": true,"stream": true},success: response => {},fail: () => {},complete: () => {}});requestTask.onChunkReceived(chunk => {const arrayBuffer = chunk.data;const uint8Array = new Uint8Array(arrayBuffer);const str = new TextEncoding.TextDecoder('utf-8').decode(uint8Array);var reciveMsg ='';var msgArr=[];var endMsg =''// 看一下 打印出来的结果if(str.indexOf('is_end') !==-1){if(str.indexOf('data') !==-1){ msgArr = str.split('data: ') reciveMsg =  JSON.parse(msgArr[1]) endMsg =  JSON.parse(msgArr[1])}if(reciveMsg.id){if (this.sseIndex === 0) {this.msgList.push({isAi: true,content: reciveMsg.result,create_time: Date.now()})} else {this.sliceMsgToLastMsg.addMsg(reciveMsg.result)}this.showLastMsg()// 让流式响应计数值递增this.sseIndex++}if(msgArr[2]){endMsg = JSON.parse(msgArr[2])}if(endMsg&&endMsg.is_end){this.sliceMsgToLastMsg.t = 0this.sseIndex = 0this.content =''}}})},closeSseChannel() {// 如果存在消息通道,就关闭消息通道if (sseChannel) {sseChannel.close()// 设置为 false 防止重复调用closeSseChannel时出错sseChannel = falsethis.sliceMsgToLastMsg.end()}// 清空历史网络请求(调用云对象)任务uniCoTaskList.clear()// 将流式响应计数值归零this.sseIndex = 0},// 滚动窗口以显示最新的一条消息showLastMsg() {// 等待DOM更新this.$nextTick(() => {// 将scrollIntoView属性设置为"last-msg-item",以便滚动窗口到最后一条消息this.scrollIntoView = "last-msg-item"// 等待DOM更新,即:滚动完成this.$nextTick(() => {// 将scrollIntoView属性设置为空,以便下次设置滚动条位置可被监听this.scrollIntoView = ""})})},// 清空消息列表clearAllMsg(e) {// 弹出确认清空聊天记录的提示框uni.showModal({title: "确认要清空聊天记录?",content: '本操作不可撤销',complete: (e) => {// 如果用户确认清空聊天记录if (e.confirm) {// 关闭ssh请求this.closeSseChannel()// 将消息列表清空 this.msgList.splice(0, this.msgList.length);}}});},open(callback) {this.currentModel = uni.getStorageSync('uni-ai-chat-llmModel')confirmCallback = callbackconsole.log('打开选择模型窗口');console.log('组件内', this.$refs);this.$refs.popup.open('center')},radioChange(event) {console.log('event', event.detail.value)this.currentModel = event.detail.value},cancel() {this.$refs.popup.close()},confirm() {// console.log(this.models[this.current]);confirmCallback(this.currentModel)this.$refs.popup.close()},}}</script><style lang="scss">.default-question {width: 80%;margin: 0 auto;background: #fff;border-radius: 8px;box-shadow: 0 16px 20px 0 rgba(174, 167, 223, .06);padding: 30rpx;display: flex;flex-direction: column;.ai-name {color: #05073b;font-size: 35rpx;font-weight: 600;}.ai-desc {color: #676c90;font-family: PingFangSC-Regular;font-size: 23rpx;font-weight: 400;text-align: justify;margin-top: 10rpx;line-height: 40rpx;}.question-list {display: flex;flex-direction: column;}.question-item {color: #120649;font-family: PingFangSC-Medium;font-size: 25rpx;font-weight: 500;letter-spacing: 0;padding: 32rpx;background: #f6f8fd;background-size: 100% 100%;margin-top: 10rpx;}}/* #ifdef VUE3 && APP-PLUS */@import "@/components/uni-ai-msg/uni-ai-msg.scss";/* #endif *//* #ifndef APP-NVUE */page,/* #ifdef H5 */.container *,/* #endif */view,textarea,button {display: flex;box-sizing: border-box;}page {height: 100%;width: 100%;}/* #endif */.nav {display: flex;flex-direction: column;}.menu-image {width: 55rpx !important;height: 55rpx !important;}.stop-responding {font-size: 14px;border-radius: 3px;margin-bottom: 15px;background-color: #f0b00a;color: #FFF;width: 90px;height: 30px;line-height: 30px;margin: 0 auto;justify-content: center;margin-bottom: 15px;/* #ifdef H5 */cursor: pointer;/* #endif */}.stop-responding:hover {box-shadow: 0 0 10px #aaa;}.container {height: 100%;background: linear-gradient(180deg, #f5f4f6, #e6ebf7);flex-direction: column;align-items: center;justify-content: center;// border: 1px solid blue;}.foot-box {width: 750rpx;display: flex;flex-direction: column;padding: 10px 0px;background-color: #FFF;}.foot-box-content {justify-content: space-around;align-items: center;}.textarea-box {padding: 8px 10px;background-color: #f9f9f9;border-radius: 5px;}.textarea-box .textarea {max-height: 120px;font-size: 14px;/* #ifndef APP-NVUE */overflow: auto;/* #endif */width: 450rpx;font-size: 14px;}/* #ifdef H5 *//*隐藏滚动条*/.textarea-box .textarea::-webkit-scrollbar {width: 0;}/* #endif */.input-placeholder {color: #bbb;line-height: 18px;}.trash,.send {width: 50px;height: 30px;justify-content: center;align-items: center;flex-shrink: 0;}.trash {width: 30rpx;margin-left: 10rpx;}.menu {justify-content: center;align-items: center;flex-shrink: 0;}.menu-item {width: 30rpx;margin: 0 10rpx;}.send {color: #FFF;border-radius: 4px;display: flex;margin: 0;padding: 0;font-size: 14px;margin-right: 20rpx;}/* #ifndef APP-NVUE */.send::after {display: none;}/* #endif */.msg-list {height: 0; //不可省略,先设置为0 再由flex: 1;撑开才是一个滚动容器flex: 1;width: 750rpx;padding-top: 200rpx;// border: 1px solid red;}.noData {margin-top: 204rpx;text-align: center;width: 750rpx;color: #aaa;font-size: 12px;justify-content: center;}.open-ad-btn-box {justify-content: center;margin: 10px 0;}.tip-ai-ing {align-items: center;flex-direction: column;font-size: 14px;color: #919396;padding: 15px 0;}.uni-link {margin-left: 5px;line-height: 20px;}/* #ifdef H5 */@media screen and (min-width:650px) {.foot-box {border-top: solid 1px #dde0e2;}.container,.container * {max-width: 950px;}.container {box-shadow: 0 0 5px #e0e1e7;height: calc(100vh - 44px);margin: 22px auto;border-radius: 10px;overflow: hidden;background-color: #FAFAFA;}page {background-color: #efefef;}.container .header {height: 44px;line-height: 44px;border-bottom: 1px solid #F0F0F0;width: 100vw;justify-content: center;font-weight: 500;}.content {background-color: #f9f9f9;position: relative;max-width: 90%;}// .copy {// color: #888888;// position: absolute;// right: 8px;// top: 8px;// font-size: 12px;// cursor:pointer;// }// .copy :hover{// color: #4b9e5f;// }.foot-box,.foot-box-content,.msg-list,.msg-item,// .create_time,.noData,.textarea-box,.textarea,textarea-box {width: 100% !important;}.textarea-box,.textarea,textarea,textarea-box {height: 120px;}.foot-box,.textarea-box {background-color: #FFF;}.foot-box-content {flex-direction: column;justify-content: center;align-items: flex-end;padding-bottom: 0;}.pc-menu {padding: 0 10px;}.pc-menu-item {height: 20px;justify-content: center;align-items: center;align-content: center;display: flex;margin-right: 10px;cursor: pointer;}.pc-trash {opacity: 0.8;}.pc-trash image {height: 15px;}.textarea-box,.textarea-box * {// border: 1px solid #000;}.send-btn-box .send-btn-tip {color: #919396;margin-right: 8px;font-size: 12px;line-height: 28px;}}/* #endif */.retries-box {justify-content: center;align-items: center;font-size: 12px;color: #d2071b;}.retries-icon {margin-top: 1px;margin-left: 5px;}/* #ifndef APP-NVUE */.box,/* #ifdef H5 */.box *,/* #endif */radio-group,label {display: flex;box-sizing: border-box;}/* #endif */.box,.title,.btn-box {width: 250px;}.box {background-color: #fff;display: flex;flex-direction: column;align-items: flex-start;padding-bottom: 0;border-radius: 5px;}.title {font-size: 16px;padding: 10px 0;padding-bottom: 5px;font-weight: 400;flex: 1;text-align: center;/* #ifndef APP-NVUE */display: inline-block;/* #endif */}.radio-group {flex-direction: column;padding: 0 15px;}.radio {transform: scale(0.7);}.item {flex-direction: row;margin-bottom: 5px;position: relative;}.item-title {font-size: 14px;color: #555;}.btn-box {/* #ifdef APP-NVUE */border-top: solid 1px #ccc;/* #endif */height: 48px;position: relative;}/* #ifndef APP-NVUE */.btn-box:after {content: ' ';position: absolute;left: 0;top: 0;right: 0;height: 1px;border-top: 1px solid #d5d5d6;color: #d5d5d6;transform-origin: 0 0;transform: scaleY(0.5);}/* #endif */.btn {justify-content: center;align-items: center;width: 150px;/* #ifdef H5 */cursor: pointer;/* #endif */}.confirm {color: #007aff;position: relative;/* #ifdef APP-NVUE */border-left: solid 1px #ccc;/* #endif */}/* #ifndef APP-NVUE */.confirm::before {content: '';position: absolute;left: 0;top: 0;right: 0;background-color: #d5d5d6;height: 48px;width: 1px;/* border-top: 1px solid #d5d5d6; *//* color: #d5d5d6; *//* transform-origin: 0 0; */transform: scaleX(0.5);}/* #endif */</style>
阅读本书更多章节>>>>

本文链接:https://www.kjpai.cn/gushi/2024-04-17/159787.html,文章来源:网络cs,作者:康由,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。

文章评论