You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

752 lines
19 KiB

<template>
<view class="detail">
<!-- <view class="Content BorderBox Width100">
<top-title
:is-show-left="true"
:title="'智能排查'"
:rightWidth="40"
class="custom_bg"
>
<template slot="right">
<image
:src="$.imgurl + '/knowledge.png'"
mode=""
class="knowledge"
@click="goToKnowledge"
></image>
</template>
</top-title>
</view> -->
<!-- <headerNavBar title="智能排查" :isBack="true">
<template v-slot:right>
<image :src="$.imgurl + '/knowledge.png'" mode="" class="knowledge" @click="goToKnowledge"></image>
</template>
</headerNavBar> -->
<view class="stepBox">
<view class="step" v-for="(item, index) in tablist" :key="index">
<view class="stepItem">
<view
:class="{
stepCircleActive: index <= active,
stepCircle: index > active,
}"
>{{ index + 1 }}
</view>
<view
class="stepText"
:style="{ color: index <= active ? '#000000' : '#bcc3cd' }"
>{{ item.title }}
</view>
</view>
<view v-if="index !== 3" class="circles">
<view
:class="{ circleActive: index < active, circle: index >= active }"
v-for="i in 8"
:key="i"
>
</view>
</view>
</view>
</view>
<scroll-view
scroll-y="true"
:scroll-top="scrollTop"
:style="{
height: isExpanded ? 'calc(100% - 350rpx)' : 'calc(100% - 250rpx)',
}"
class="chatlist"
ref="scrollView"
@click="clickContent"
>
<view
:class="['bar', item.answerId == '0' ? 'currAnswer' : '']"
v-for="(item, index) in msgList"
:key="item.id"
>
<image
:src="
item.answerId == '0' ? '/static/self.png' : '/static/left_user.png'
"
class="img"
/>
<view class="content">
<zeroMarkdownView :markdown="item.data" />
<!-- <ua-markdown :source="mdvalue" /> -->
<view class="btnBox">
<view
class="btn"
@click="handleBtn(text)"
v-for="(text, index) in item.options"
>{{ text }}</view
>
</view>
</view>
</view>
<view class="loading-animation" v-if="loading">
<view class="bounce-dot"></view>
<view class="bounce-dot"></view>
<view class="bounce-dot"></view>
</view>
</scroll-view>
<view
class="input-wrapper"
:class="{ 'input-wrapper-expanded': isExpanded }"
>
<view class="topContent">
<input
class="uni-input"
placeholder="请输入内容"
:value="inputValue"
@confirm="handleSend"
@input="onKeyInput"
/>
<uni-icons
class="uni-icon"
type="plus"
size="30"
@click="handlePlus"
></uni-icons>
</view>
<view v-if="isExpanded" class="expanded">
<view @click="chooseImage" class="expandedItem">
<uni-icons class="camera-icon" type="image" size="28"></uni-icons>
<view>照片</view>
</view>
<view class="expandedItem" style="margin-top: 6px">
<image src="../../static/video.png" class="video"></image>
<view>视频</view>
</view>
</view>
</view>
</view>
</template>
<script>
import AbortController from "abort-controller/dist/abort-controller";
import TopTitle from "../../components/top-title.vue";
// import headerNavBar from '../../components/headerNavBar/headerNavBar.vue'
import zeroMarkdownView from "../../components/zeroMarkdownView/zeroMarkdownView.vue";
// import {
// EventSourcePolyfill
// } from 'event-source-polyfill';
import $ from "../../common/globalJs/globalJs.js";
import { fetchEventSource } from "@microsoft/fetch-event-source";
// import {
// baseUrl
// } from '../../utils/config.js';
export default {
components: {
TopTitle,
zeroMarkdownView,
},
data() {
return {
active: 0,
tablist: [
{
title: "信息确认",
},
{
title: "排查指引",
},
{
title: "隐患补充",
},
{
title: "工单生成",
},
],
inputValue: "",
es: null,
msgList: [],
loading: true,
streamLoading: true,
scrollTop: 0,
title: "",
isExpanded: false,
allContent: "",
params: {},
tabkey: 0,
};
},
onLoad(options) {
let params = options;
this.params = params;
let str = "";
if (params.roadName) {
str += "路段名:" + params.roadName;
this.title = params.roadName + "智能排查";
}
if (params.id) {
str += ",id:" + params.id; //params.id
}
console.log(params);
if (params.id == 12121212) {
this.queryChat("开始隐患排查," + str);
} else {
this.SSE("开始隐患排查," + str, "1");
// if(this.msgListA.length==0){
// this.SSE("开始隐患排查," + str, '1')
// }else{
// this.loading = false
// this.scrollBottom();
// }
}
},
onUnload() {
if (this.es) {
this.es.close();
this.es = null;
}
},
// computed: {
// msgListA: {
// get() {
// return this.$store.state.msgList;
// },
// set(value) {
// this.$store.commit('setMSg_List', value);
// }
// }
// },
methods: {
// 建立SSE长连接
SSE(voiceText, answerId) {
const ctrl = new AbortController();
console.log(ctrl.signal);
fetchEventSource($.chatUrl + "/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: ["text/event-stream", "application/json"],
},
body: JSON.stringify({
voiceText,
sceneFlag: "",
sessionId: "",
multiType: "",
userId: this.params.userId,
deptId: this.params.deptId,
stream: true,
type: 1,
id: this.params.id,
taskId: this.params.taskId,
sectionId: this.params.sectionId,
sectionType: this.params.sectionType,
}),
signal: ctrl.signal,
openWhenHidden: true,
onopen: () => {},
onmessage: (ev) => {
console.log(ev);
this.loading = true;
const res = JSON.parse(ev.data);
if (res?.code == 200 && res.result) {
console.log(res.result.data.tabkey);
console.log(res.result.data);
this.tabkey = res.result.data.tabkey;
if (this.tabkey - 1 != this.active) {
this.active = this.tabkey - 1 > 0 ? this.tabkey - 1 : 0;
}
if (this.msgList.length == 0) {
this.msgList = [
{
answerId,
data: res.result.data.content,
},
];
} else {
// debugger
//回答
if (this.msgList[this.msgList.length - 1].answerId == "1") {
//最后一个是回答
this.msgList[this.msgList.length - 1].data +=
res.result.data.content;
} else {
//最后一个是问题
this.msgList = [
...this.msgList,
{
answerId: "1",
data: res.result.data.content,
},
];
}
}
// debugger
this.scrollBottom();
}
},
onclose: () => {
console.log(1111);
this.loading = false;
if (this.isExpanded) {
this.isExpanded = !this.isExpanded;
}
},
onerror(error) {
console.log("error", error);
throw error;
},
});
},
async queryChat(voiceText) {
// console.log(voiceText,"voiceText");
this.loading = true;
const [err, res] = await uni.request({
// url: 'http://10.16.3.159:8777/api/local_doc_qa/local_doc_chat',
url: $.chatUrl + "/chat",
dataType: "json",
method: "POST",
// responseType: 'arraybuffer',
headers: {
// 'Accept': 'text/event-stream',
"content-type": "application/json",
},
data: {
voiceText,
sceneFlag: "",
sessionId: this.sessionId,
id: this.id,
multiType: "",
userId: "admin1",
deptId: "3702000000",
type: 1,
stream: false,
// "user_id": "zzp",
// "kb_ids": ["KBa80ea15e786241eca70a20f136f4e34c"],
// "question": "隐患排查流程是什么",
// "streaming": true,
// "history": []
},
});
if (res && res.data && res.data.code == 200) {
// console.log('request success', res.data)
const { result = {} } = res.data;
const { data = {} } = result;
if (data.tabkey - 1 != this.active) {
this.active = data.tabkey - 1 > 0 ? data.tabkey - 1 : 0;
}
if (data.content) {
this.changeMsgList(
data.answerId || "1",
data.content,
data.answerOptions
);
}
this.loading = false;
if (this.isExpanded) {
this.isExpanded = !this.isExpanded;
}
} else {
if (err) {
console.log("request fail", err.errMsg);
}
uni.showToast({
title: "查询失败",
icon: "error",
duration: 2000,
});
}
},
// 输入框
onKeyInput(event) {
this.inputValue = event.detail.value;
},
addQuestion(q, answerId) {
const newQuestion = {
answerId,
data: q,
};
this.msgList.push(newQuestion); // 将问题添加到消息列表
// this.$store.commit('setMSg_List', this.msgList);
this.scrollBottom();
},
scrollBottom() {
this.$nextTick(() => {
const height =
this.$refs.scrollView &&
this.$refs.scrollView.$refs &&
this.$refs.scrollView.$refs.content
? this.$refs.scrollView.$refs.content.scrollHeight
: 0;
this.scrollTop = height;
});
},
// 发送
handleSend(text) {
if (!this.inputValue & !text) {
uni.showToast({
title: "请输入内容",
icon: "closeempty",
duration: 2000,
});
}
if (text || this.inputValue) {
if (this.params.id == 12121212) {
this.changeMsgList("0", this.inputValue || text);
this.queryChat(this.inputValue || text);
this.scrollBottom();
} else {
this.addQuestion(this.inputValue || text, "0");
this.SSE(this.inputValue || text, "0");
}
this.inputValue = "";
}
},
// 更新列表信息
changeMsgList(answerId, data, answerOptions) {
let id = 1;
if (this.msgList.length > 0) {
id = this.msgList[this.msgList.length - 1].id + 1;
}
if (answerId == "1") {
// 后台返回来的消息
let newdata = "";
let index = 0;
const timer = setInterval(() => {
console.log(this.msgList);
newdata = newdata += data[index];
if (this.msgList?.filter((item) => item.id == id).length == 0) {
this.msgList = [
...this.msgList,
{
id,
answerId,
data: newdata,
// options: answerOptions // ['东南西北','东北','东南北','东南西北'] answerOptions
},
];
} else {
this.msgList[this.msgList.length - 1].data = newdata;
}
index += 1;
this.$nextTick(() => {
const height =
this.$refs.scrollView &&
this.$refs.scrollView.$refs &&
this.$refs.scrollView.$refs.content
? this.$refs.scrollView.$refs.content.scrollHeight
: 0;
this.scrollTop = height;
});
if (newdata == data) {
this.msgList[this.msgList.length - 1].options = answerOptions;
clearInterval(timer);
}
}, 50);
} else {
this.msgList = [
...this.msgList,
{
id,
answerId,
data,
},
];
this.$nextTick(() => {
const height =
this.$refs.scrollView &&
this.$refs.scrollView.$refs &&
this.$refs.scrollView.$refs.content
? this.$refs.scrollView.$refs.content.scrollHeight
: 0;
this.scrollTop = height;
});
}
},
handlePlus() {
this.isExpanded = !this.isExpanded;
},
// 快捷回复
handleBtn(text) {
this.handleSend(text);
},
clickContent() {
if (this.isExpanded) {
this.isExpanded = !this.isExpanded;
}
},
goToKnowledge() {
uni.navigateTo({
url: "/pages/home/knowledge",
// url: `/pages/home/knowledge?params=${encodeURIComponent(JSON.stringify(this.$route.query.params))}`
});
},
// 选择图片
chooseImage() {
uni.chooseImage({
count: 6, //默认9
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["album"], //从相册选择
success: (res) => {
if (res.tempFilePaths && res.tempFilePaths.length) {
let str = "";
for (let i = 0; i < res.tempFilePaths.length; i++) {
str += `![图${i + 1}](${res.tempFilePaths[i]})`;
}
if (this.id == 12121212) {
this.changeMsgList("0", str);
this.queryChat(res.tempFilePaths);
} else {
this.addQuestion(str, "0");
this.SSE(res.tempFilePaths, "0");
}
}
},
});
},
},
};
</script>
<style scoped lang="scss">
.detail {
width: 100%;
margin: auto;
height: 100vh;
overflow: hidden;
.knowledge {
width: 40rpx;
height: 40rpx;
}
.stepBox {
width: 100%;
// height: 150rpx;
margin-top: 10rpx;
display: flex;
justify-content: center;
align-items: center;
background-color: #ffffff;
.step {
display: flex;
.stepItem {
display: flex;
flex-direction: column;
align-items: center;
}
.circles {
display: flex;
// justify-content: space-between;
padding: 22px 0;
.circle {
width: 4rpx;
height: 4rpx;
border-radius: 50%;
background-color: #e9edf5;
margin: 0 1px;
}
.circleActive {
width: 4rpx;
height: 4rpx;
border-radius: 50%;
background-color: #ccc;
margin: 0 1px;
}
}
.stepCircle {
width: 60rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 50%;
background-color: #e9edf5;
color: #a0abbd;
text-align: center;
margin-bottom: 10rpx;
}
.stepCircleActive {
width: 50rpx;
height: 50rpx;
line-height: 50rpx;
border-radius: 50%;
background-color: #295cbc;
color: #ffffff;
text-align: center;
margin-bottom: 4rpx;
border: 5px solid #c6d8fc;
}
.stepText {
font-size: 16px;
color: #bcc3cd;
}
}
}
.chatlist {
width: 96%;
margin: auto;
// height: calc(100% - 340rpx);
background-color: #f0f2f7;
.bar {
width: 100%;
display: flex;
margin-bottom: 40rpx;
overflow: hidden;
.btnBox {
display: flex;
justify-content: flex-end;
.btn {
color: #497cca;
background-color: #d8e3f8;
display: flex;
padding: 2rpx 20rpx;
margin: 10rpx;
border-radius: 4rpx;
}
}
.img {
width: 80rpx;
height: 80rpx;
margin-top: 15rpx;
}
.content {
display: inline-block;
max-width: 80%;
border: 1px solid #ddd;
border-radius: 5px;
padding: 0;
margin: 15rpx 20rpx 0 20rpx;
// flex: 1;
overflow: hidden;
background-color: #ffffff;
._img {
max-width: 80%;
}
}
&.currAnswer {
flex-direction: row-reverse;
.content {
background-color: #cce0ff;
}
}
}
}
.input-wrapper {
display: flex;
width: 100%;
margin: 20rpx auto 0 auto;
height: 80rpx;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
border-top: 1px solid #e2e4e9;
bottom: 1px solid #e2e4e9;
padding: 20rpx 20rpx 0 20rpx;
.topContent {
display: flex;
width: 100%;
}
.expanded {
background-color: #f5f7fa;
display: flex;
.expandedItem {
width: 106rpx;
height: 106rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
.camera-icon {
margin-top: 5px;
}
}
.video {
width: 60rpx;
height: 60rpx;
}
}
}
.input-wrapper-expanded {
height: 200rpx;
}
.uni-input {
height: 56rpx;
line-height: 56rpx;
font-size: 30rpx;
padding: 0rpx 10rpx;
flex: 1;
background-color: #fff;
}
.uni-icon {
font-family: uniicons;
font-size: 48rpx;
font-weight: normal;
font-style: normal;
width: 48rpx;
height: 48rpx;
line-height: 48rpx;
color: #999999;
margin: 0 10rpx;
}
.loading-animation {
display: flex;
justify-content: center;
margin-top: 0;
.bounce-dot {
width: 20rpx;
height: 20rpx;
margin: 10rpx;
background-color: #666;
border-radius: 50%;
animation: bounce 1.4s infinite both;
&:nth-child(2) {
animation-delay: 0.2s;
}
&:nth-child(3) {
animation-delay: 0.4s;
}
}
}
}
@keyframes bounce {
0%,
80%,
100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
</style>