提交 a0bf4c43 编写于 作者: DCloud_JSON's avatar DCloud_JSON

1.0.17

上级 d47ae269
## 1.0.17(2023-05-29)
- 新增 显示代码行号
- 修复 代码块显示样式错误的问题
- 修复 部分情况下广告位不能正确显示的问题
## 1.0.16(2023-05-26) ## 1.0.16(2023-05-26)
- 更新 默认不启用(注释掉)广告组件`uni-ad-rewarded-video` - 更新 默认不启用(注释掉)广告组件`uni-ad-rewarded-video`
## 1.0.15(2023-05-26) ## 1.0.15(2023-05-26)
......
@import "@/lib/highlight/github-dark.min.css"; @import "@/lib/highlight/github-dark.min.css";
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
.rich-text-box {
max-width: 100%;
}
.rich-text-box ::v-deep pre.hljs { .rich-text-box ::v-deep pre.hljs {
padding: 5px 8px; padding: 5px 8px;
margin: 5px 0; margin: 5px 0;
......
...@@ -8,9 +8,8 @@ ...@@ -8,9 +8,8 @@
<image class="avatar" :src="msg.isAi?'../../static/uni-ai.png':'../../static/avatar.png'" mode="widthFix"></image> <image class="avatar" :src="msg.isAi?'../../static/uni-ai.png':'../../static/avatar.png'" mode="widthFix"></image>
</view> </view>
<view class="content"> <view class="content">
<view class="rich-text-box" :class="{'show-cursor':showCursor}" ref="rich-text-box"> <view class="rich-text-box" :class="{'show-cursor':showCursor}" ref="rich-text-box">
<rich-text v-if="nodes&&nodes.length" space="nbsp" :nodes="nodes"></rich-text> <rich-text v-if="nodes&&nodes.length" space="nbsp" :nodes="nodes" @itemclick="trOnclick"></rich-text>
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view class="copy-box" :style="{left,top}"> <view class="copy-box" :style="{left,top}">
...@@ -18,17 +17,15 @@ ...@@ -18,17 +17,15 @@
</view> </view>
<!-- #endif --> <!-- #endif -->
</view> </view>
<view v-if="isLastMsg && adpid && msg.insufficientScore">
<text style="color: red;">
<view v-if="msgIndex == msgIndexList.length-1 && adpid && msg.insufficientScore"> 默认不启用广告组件(被注释),如需使用,请"去掉注释"(“重新运行”后生效)
<view style="flex-direction: column;color: red;"> 位置:/components/uni-ai-msg/uni-ai-msg.vue 第28行,或全局搜索 uni-ad-rewarded-video
<view>默认不启用广告组件(被注释),如需使用,请"去掉注释"</view> </text>
<view>位置:/components/uni-ai-msg/uni-ai-msg.vue 第28行,或全局搜索 uni-ad-rewarded-video</view>
</view>
<!-- <uni-ad-rewarded-video :adpid="adpid" @onAdClose="onAdClose"></uni-ad-rewarded-video> --> <!-- <uni-ad-rewarded-video :adpid="adpid" @onAdClose="onAdClose"></uni-ad-rewarded-video> -->
</view> </view>
</view> </view>
<uni-icons v-if="msgIndex == msgIndexList.length-1 && !msg.isAi && msg.state != 100 && msgStateIcon(msg)" <uni-icons v-if="isLastMsg && !msg.isAi && msg.state != 100 && msgStateIcon(msg)"
@click="msg.state == -100 ? retriesSendMsg() : ''" :color="msg.state===0?'#999':'#d22'" @click="msg.state == -100 ? retriesSendMsg() : ''" :color="msg.state===0?'#999':'#d22'"
:type="msgStateIcon(msg)" class="msgStateIcon"> :type="msgStateIcon(msg)" class="msgStateIcon">
</uni-icons> </uni-icons>
...@@ -45,7 +42,9 @@ ...@@ -45,7 +42,9 @@
adpid adpid
} = config } = config
import {msgList} from '@/pages/chat/msgList.js'; import {
msgList
} from '@/pages/chat/msgList.js';
// 引入markdown-it库 // 引入markdown-it库
import MarkdownIt from '@/lib/markdown-it.min.js'; import MarkdownIt from '@/lib/markdown-it.min.js';
...@@ -59,6 +58,9 @@ ...@@ -59,6 +58,9 @@
// console.log('hljs--',hljs); // console.log('hljs--',hljs);
// console.log('hljs--',hljs.getLanguage('js')); // console.log('hljs--',hljs.getLanguage('js'));
// 为复制代码功能保留代码内容
let codeDataList = []
// 初始化 MarkdownIt库 // 初始化 MarkdownIt库
const markdownIt = MarkdownIt({ const markdownIt = MarkdownIt({
// 在源码中启用 HTML 标签 // 在源码中启用 HTML 标签
...@@ -68,20 +70,41 @@ ...@@ -68,20 +70,41 @@
// if (lang && hljs.getLanguage(lang)) { // if (lang && hljs.getLanguage(lang)) {
// console.error('lang', lang) // console.error('lang', lang)
// try { // try {
// return '<pre class="hljs" style="padding: 5px 8px;margin: 5px 0;overflow: auto;"><code>' + // return '<pre class="hljs" style="padding: 5px 8px;margin: 5px 0;overflow: auto;display: block;"><code>' +
// hljs.highlight('lang', str, true).value + // hljs.highlight('lang', str, true).value +
// '</code></pre>'; // '</code></pre>';
// } catch (__) {} // } catch (__) {}
// } // }
// 经过highlight.js处理后的html
let preCode = ""
try { try {
return '<pre class="hljs" style="padding: 5px 8px;margin: 5px 0;overflow: auto;"><code>' + preCode = hljs.highlightAuto(str).value
hljs.highlightAuto(str).value + } catch (err) {
'</code></pre>'; // console.log('err',err);
} catch (__) {} preCode = markdownIt.utils.escapeHtml(str);
}
return '<pre class="hljs" style="padding: 5px 8px;margin: 5px 0;overflow: auto;"><code>' + // 以换行进行分割
markdownIt.utils.escapeHtml(str) + '</code></pre>'; const lines = preCode.split(/\n/).slice(0, -1)
// 添加自定义行号
let html = lines.map((item, index) => {
// 去掉空行
if( item == ''){
return ''
}
return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' + item +'</li>'
}).join('')
html = '<ol>' + html + '</ol>'
// #ifdef APP || H5
// // 复制功能~未完待续
// let tmpDom = document.createElement('div')
// tmpDom.innerHTML = html
// codeDataList.push(tmpDom.innerText)
// let codeDataIndex = Date.now()
// html = `<a class="copy-btn" code-data-index="${codeDataList.length - 1}" style="float:right;">复制</a>` + html
// #endif
return `<pre class="hljs" style="padding: 5px 8px;margin: 5px 0;overflow: auto;display: block;"><code>${html}</code></pre>`;
} }
}) })
...@@ -93,10 +116,10 @@ ...@@ -93,10 +116,10 @@
left: "-100px", left: "-100px",
// 悬浮的复制按钮的上边距 // 悬浮的复制按钮的上边距
top: "-100px", top: "-100px",
msg:{ msg: {
content:"" content: ""
}, },
msgIndexList:0, msgIndexList: 0,
adpid adpid
}; };
}, },
...@@ -138,24 +161,30 @@ ...@@ -138,24 +161,30 @@
return false return false
} }
}, },
msgIndex:{ msgIndex: {
type: Number, type: Number,
default () { default () {
return false return false
} }
},
isLastMsg: {
type: Boolean,
default () {
return false
}
} }
}, },
computed: { computed: {
md(){ md() {
return this.msg.content return this.msg.content
}, },
nodes() { nodes() {
let htmlString = '' let htmlString = ''
// 修改转换结果的htmlString值 用于正确给界面增加鼠标闪烁的效果 // 修改转换结果的htmlString值 用于正确给界面增加鼠标闪烁的效果
// 判断markdown中代码块标识符的数量是否为偶数 // 判断markdown中代码块标识符的数量是否为偶数
if(this.md.split("```").length%2){ if (this.md.split("```").length % 2) {
htmlString = markdownIt.render(this.md + ' \n <span class="cursor">|</span>'); htmlString = markdownIt.render(this.md + ' \n <span class="cursor">|</span>');
}else{ } else {
htmlString = markdownIt.render(this.md) + ' \n <span class="cursor">|</span>'; htmlString = markdownIt.render(this.md) + ' \n <span class="cursor">|</span>';
} }
...@@ -172,6 +201,40 @@ ...@@ -172,6 +201,40 @@
} }
}, },
methods: { methods: {
// 根据消息状态返回对应的图标
msgStateIcon(msg) {
switch (msg.state) {
case 0:
// 发送中
return 'spinner-cycle'
break;
case -100:
// 发送失败
return 'refresh-filled'
break;
case -200:
// 禁止发送(内容不合法)
return 'info-filled'
break;
default:
// 默认不返回任何图标
return false
break;
}
},
trOnclick(e){
// console.log(e);
// let {attrs} = e.detail.node
// console.log({attrs});
// let {"code-data-index":codeDataIndex,"class":className} = attrs
// if(className == 'copy-btn'){
// console.log('codeDataList[codeDataIndex]',codeDataList[codeDataIndex]);
// uni.setClipboardData({
// data:codeDataList[codeDataIndex],
// showToast:false
// })
// }
},
// #ifdef H5 // #ifdef H5
// 复制文本内容到系统剪切板 // 复制文本内容到系统剪切板
copy() { copy() {
...@@ -196,6 +259,7 @@ ...@@ -196,6 +259,7 @@
display: flex; display: flex;
box-sizing: border-box; box-sizing: border-box;
} }
/* #endif */ /* #endif */
.userInfo { .userInfo {
...@@ -238,7 +302,7 @@ ...@@ -238,7 +302,7 @@
.content { .content {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
max-width: 550rpx; max-width: 85%;
/* #endif */ /* #endif */
background-color: #FFF; background-color: #FFF;
border-radius: 5px; border-radius: 5px;
...@@ -252,24 +316,20 @@ ...@@ -252,24 +316,20 @@
} }
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
.content {
display: inline;
}
.content ::v-deep rich-text { .content ::v-deep rich-text {
max-width: 550rpx; max-width: 100%;
overflow: auto; overflow: auto;
} }
code .l:before {
/* #endif */ color: #516363;
position: absolute;
/* #ifdef H5 */ left: 15px;
.content * { content: counter(step);
display: inline; counter-increment: step;
} }
/* #endif */ /* #endif */
.reverse { .reverse {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
......
{ {
"id": "uni-ai-chat", "id": "uni-ai-chat",
"name": "uni-ai-chat", "name": "uni-ai-chat",
"version": "1.0.16", "version": "1.0.17",
"description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体", "description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<text class="noData" v-if="msgLength === 0">没有对话记录</text> <text class="noData" v-if="msgLength === 0">没有对话记录</text>
<scroll-view :scroll-into-view="scrollIntoView" scroll-y="true" class="msg-list" :enable-flex="true"> <scroll-view :scroll-into-view="scrollIntoView" scroll-y="true" class="msg-list" :enable-flex="true">
<uni-ai-msg ref="msg" v-for="(msgIndex,index) in msgLength" :key="index" :msgIndex="index" <uni-ai-msg ref="msg" v-for="(msgIndex,index) in msgLength" :key="index" :msgIndex="index"
:show-cursor="index == msgLength - 1 && msgLength%2 === 0 && sseIndex"></uni-ai-msg> :show-cursor="index == msgLength - 1 && msgLength%2 === 0 && sseIndex" :isLastMsg="index == msgLength - 1"></uni-ai-msg>
<view class="tip-ai-ing" v-if="msgLength && msgLength%2 !== 0"> <view class="tip-ai-ing" v-if="msgLength && msgLength%2 !== 0">
<text>uni-ai正在思考中...</text> <text>uni-ai正在思考中...</text>
<view v-if="NODE_ENV == 'development' && !enableStream"> <view v-if="NODE_ENV == 'development' && !enableStream">
...@@ -27,11 +27,11 @@ ...@@ -27,11 +27,11 @@
<view v-if="!isWidescreen" class="trash"> <view v-if="!isWidescreen" class="trash">
<uni-icons @click="clear" type="trash" size="24" color="#888"></uni-icons> <uni-icons @click="clear" type="trash" size="24" color="#888"></uni-icons>
</view> </view>
<view class="textarea-box"> <view class="textarea-box" @click="focus = true">
<textarea v-model="content" :cursor-spacing="15" class="textarea" :auto-height="!isWidescreen" <textarea v-model="content" :cursor-spacing="15" class="textarea" :auto-height="!isWidescreen"
@keyup.shift="onKeyup('shift')" @keydown.shift="onKeydown('shift')" @keyup.shift="onKeyup('shift')" @keydown.shift="onKeydown('shift')"
@keydown.enter="onKeydown('enter')" :disabled="inputBoxDisabled" @keydown.enter="onKeydown('enter')" :disabled="inputBoxDisabled"
:placeholder="placeholderText" :maxlength="-1" :focus="focus" :placeholder="placeholderText" :maxlength="-1" :focus="focus" @blur="focus = false"
placeholder-class="input-placeholder"></textarea> placeholder-class="input-placeholder"></textarea>
</view> </view>
<view class="send-btn-box"> <view class="send-btn-box">
...@@ -127,7 +127,6 @@ ...@@ -127,7 +127,6 @@
// #endif // #endif
msgList: { msgList: {
handler(msgList) { handler(msgList) {
let msgLength = msgList.length let msgLength = msgList.length
if (msgLength != this.msgLength) { if (msgLength != this.msgLength) {
this.msgLength = msgLength this.msgLength = msgLength
...@@ -135,7 +134,6 @@ ...@@ -135,7 +134,6 @@
this.updateLastMsg(msgList[msgLength - 1]) this.updateLastMsg(msgList[msgLength - 1])
}) })
} }
// 将msgList存储到本地缓存中 // 将msgList存储到本地缓存中
uni.setStorage({ uni.setStorage({
"key": "uni-ai-msg", "key": "uni-ai-msg",
...@@ -146,6 +144,16 @@ ...@@ -146,6 +144,16 @@
deep: true deep: true
} }
}, },
beforeMount() {
// #ifdef H5
// 监听屏幕宽度变化,判断是否为宽屏 并设置isWidescreen的值
uni.createMediaQueryObserver(this).observe({
minWidth: 650,
}, matches => {
this.isWidescreen = matches;
})
// #endif
},
async mounted() { async mounted() {
// 如果存在广告位id且用户token未过期 // 如果存在广告位id且用户token未过期
...@@ -201,16 +209,6 @@ ...@@ -201,16 +209,6 @@
this.showLastMsg() this.showLastMsg()
}) })
// #ifdef H5
// 监听屏幕宽度变化,判断是否为宽屏 并设置isWidescreen的值
uni.createMediaQueryObserver(this).observe({
minWidth: 650,
}, matches => {
this.isWidescreen = matches;
})
// #endif
// 兼容 Vue3下textarea不支持@keydown // 兼容 Vue3下textarea不支持@keydown
// #ifdef H5 && VUE3 // #ifdef H5 && VUE3
//获得消息输入框对象 //获得消息输入框对象
...@@ -641,27 +639,6 @@ ...@@ -641,27 +639,6 @@
}) })
}) })
}, },
// 根据消息状态返回对应的图标
msgStateIcon(msg) {
switch (msg.state) {
case 0:
// 发送中
return 'spinner-cycle'
break;
case -100:
// 发送失败
return 'refresh-filled'
break;
case -200:
// 禁止发送(内容不合法)
return 'info-filled'
break;
default:
// 默认不返回任何图标
return false
break;
}
},
// 清空消息列表 // 清空消息列表
clear() { clear() {
// 弹出确认清空聊天记录的提示框 // 弹出确认清空聊天记录的提示框
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册