|
|
@@ -127,18 +127,25 @@
|
|
127
|
127
|
|
|
128
|
128
|
<!-- 其他标签页 - 保留标签结构但移除未使用的组件 -->
|
|
129
|
129
|
<template v-else-if="tab.name === 'subscribe'">
|
|
|
130
|
+ <subscribe :userNo="customerInfo.customerNo" />
|
|
130
|
131
|
</template>
|
|
131
|
132
|
<template v-else-if="tab.name === 'payment'">
|
|
|
133
|
+ <PayRecord :userNo="customerInfo.customerNo" />
|
|
132
|
134
|
</template>
|
|
133
|
135
|
<template v-else-if="tab.name === 'meterReading'">
|
|
|
136
|
+ <MeterReading :userNo="customerInfo.customerNo" />
|
|
134
|
137
|
</template>
|
|
135
|
138
|
<template v-else-if="tab.name === 'overdue'">
|
|
|
139
|
+ <OweFee :userNo="customerInfo.customerNo" />
|
|
136
|
140
|
</template>
|
|
137
|
141
|
<template v-else-if="tab.name === 'meterInfo'">
|
|
|
142
|
+ <MeterBasicInfo :userNo="customerInfo.customerNo" />
|
|
138
|
143
|
</template>
|
|
139
|
144
|
<template v-else-if="tab.name === 'security'">
|
|
|
145
|
+ <seOrder :userNo="customerInfo.customerNo" />
|
|
140
|
146
|
</template>
|
|
141
|
147
|
<template v-else-if="tab.name === 'ticket'">
|
|
|
148
|
+ <woOrder :userNo="customerInfo.customerNo" />
|
|
142
|
149
|
</template>
|
|
143
|
150
|
</el-tab-pane>
|
|
144
|
151
|
</el-tabs>
|
|
|
@@ -244,11 +251,19 @@ import { getPageListData ,deletePageData } from '@/api/main/system/system';
|
|
244
|
251
|
import request from '@/utils/request';
|
|
245
|
252
|
import { userToAsterisk } from '@/utils/aes';
|
|
246
|
253
|
import useSelectStore from '@/store/commonSelect/common';
|
|
|
254
|
+import { getToken } from '@/utils/auth'
|
|
247
|
255
|
|
|
|
256
|
+import subscribe from '@/components/conInfor/subscribe/index.vue' // 预约记录
|
|
|
257
|
+import PayRecord from '@/components/conInfor/payrecord/index.vue' // 缴费明细
|
|
|
258
|
+import MeterReading from '@/components/conInfor/meterReading/index.vue' // 抄表记录
|
|
|
259
|
+import OweFee from '@/components/conInfor/owefee/index.vue' // 欠费记录
|
|
|
260
|
+import MeterBasicInfo from '@/components/conInfor/meterBasicInfo/index.vue' // 表具信息
|
|
|
261
|
+import seOrder from '@/components/conInfor/seOrder/index.vue' // 安检工单
|
|
|
262
|
+import woOrder from '@/components/conInfor/woOrder/index.vue' // 工单信息
|
|
248
|
263
|
// 标签页状态
|
|
249
|
264
|
const activeName = ref('first');
|
|
250
|
265
|
const isIntelligentFlag = ref(useSelectStore().isIntelligentFlag)
|
|
251
|
|
-
|
|
|
266
|
+const getOpenId = ref('')
|
|
252
|
267
|
// 客户信息数据
|
|
253
|
268
|
const customerInfo = ref({
|
|
254
|
269
|
customerNo: '',
|
|
|
@@ -349,7 +364,24 @@ const userSearchLoading = ref(false);
|
|
349
|
364
|
// 关联患者
|
|
350
|
365
|
const associatedPatient = async () => {
|
|
351
|
366
|
try {
|
|
352
|
|
- ElMessage.warning('请先选择客户');
|
|
|
367
|
+ if (!AssociaPatientId.value) {
|
|
|
368
|
+ ElMessage.warning('请先选择客户');
|
|
|
369
|
+ return;
|
|
|
370
|
+ }
|
|
|
371
|
+ if (!getOpenId.value) {
|
|
|
372
|
+ ElMessage.warning('请先选择聊天对象');
|
|
|
373
|
+ return;
|
|
|
374
|
+ }
|
|
|
375
|
+ const params = {
|
|
|
376
|
+ patientId: AssociaPatientId.value,
|
|
|
377
|
+ openId: getOpenId.value
|
|
|
378
|
+ };
|
|
|
379
|
+ const res = await getPageListData('/patient/patient/associated', params);
|
|
|
380
|
+ if (res.state === 'success') {
|
|
|
381
|
+ ElMessage.success('关联成功');
|
|
|
382
|
+ } else {
|
|
|
383
|
+ ElMessage.error(res.message || '关联失败');
|
|
|
384
|
+ }
|
|
353
|
385
|
} catch (error) {
|
|
354
|
386
|
console.error('关联患者失败:', error);
|
|
355
|
387
|
ElMessage.error('关联失败,请重试');
|
|
|
@@ -497,7 +529,168 @@ function delQuickMsg(rowData) {
|
|
497
|
529
|
console.log('取消删除');
|
|
498
|
530
|
});
|
|
499
|
531
|
}
|
|
|
532
|
+// 搜索关键词
|
|
|
533
|
+const searchKeyword = ref('');
|
|
|
534
|
+const recommendations = ref([]);
|
|
|
535
|
+
|
|
|
536
|
+function searchRecommendations() {
|
|
|
537
|
+ knowledgeLoading.value = true;
|
|
|
538
|
+ if (searchKeyword.value) {
|
|
|
539
|
+ aiKnowledge(searchKeyword.value).then(res => {}).finally(() => {
|
|
|
540
|
+ knowledgeLoading.value = false;
|
|
|
541
|
+ })
|
|
|
542
|
+ } else {
|
|
|
543
|
+ ElMessage({
|
|
|
544
|
+ message: '请输入关键词',
|
|
|
545
|
+ type: 'warning'
|
|
|
546
|
+ });
|
|
|
547
|
+ }
|
|
|
548
|
+}
|
|
|
549
|
+const knowledgeLoading = ref(false)
|
|
|
550
|
+const aiKnowledge = async (text) => {
|
|
|
551
|
+
|
|
|
552
|
+ // 构建对话文本
|
|
|
553
|
+ // let text = '热点问题请注意'
|
|
|
554
|
+ knowledgeObj.value = ''
|
|
|
555
|
+ if (text) {
|
|
|
556
|
+ // 获取AI分析结果
|
|
|
557
|
+ let res = await getKnowledgeDocs(text);
|
|
|
558
|
+ // 移除思考过程
|
|
|
559
|
+ if (knowledgeObj.value) {
|
|
|
560
|
+ const obj = {
|
|
|
561
|
+ content: knowledgeObj.value,
|
|
|
562
|
+ // type: knowledgeObj.value.intention,
|
|
|
563
|
+ source: "AI 推荐",
|
|
|
564
|
+ time: moment().format('HH:mm:ss'), // 当前时间时分秒
|
|
|
565
|
+ }
|
|
|
566
|
+ recommendations.value.splice(0,0,obj)
|
|
|
567
|
+ }
|
|
|
568
|
+
|
|
|
569
|
+ }
|
|
|
570
|
+}
|
|
|
571
|
+const knowledgeObj = ref('')
|
|
|
572
|
+const workflow_run_id = ref('')
|
|
|
573
|
+const getKnowledgeDocs = async (text) => {
|
|
|
574
|
+
|
|
|
575
|
+ // const params = {
|
|
|
576
|
+ // "id": 6,
|
|
|
577
|
+ // "inputs": {"type": "zsk","text":text}
|
|
|
578
|
+ // };
|
|
|
579
|
+
|
|
|
580
|
+ // if (workflow_run_id.value) {
|
|
|
581
|
+ // params.inputs.workflowrunid = workflow_run_id.value
|
|
|
582
|
+ // }
|
|
|
583
|
+ const params = {
|
|
|
584
|
+ "auto_generate_name": false,
|
|
|
585
|
+ "conversation_id": "",
|
|
|
586
|
+ "files": [],
|
|
|
587
|
+ "id": 8,
|
|
|
588
|
+ "inputs": {},
|
|
|
589
|
+ "query": text
|
|
|
590
|
+ };
|
|
|
591
|
+ if (workflow_run_id.value) {
|
|
|
592
|
+ params.conversation_id = workflow_run_id.value
|
|
|
593
|
+ }
|
|
|
594
|
+ try {
|
|
|
595
|
+ // 发送请求
|
|
|
596
|
+ // const url = import.meta.env.VITE_APP_AI_API || 'https://open.bigmodel.cn/api/paas/v4/chat/completions'
|
|
|
597
|
+ // const url = import.meta.env.VITE_APP_BASE_API+'/dify/difyassistant/workflows'
|
|
|
598
|
+ const url = import.meta.env.VITE_APP_BASE_API+ '/dify/difyassistant/chatMessages'
|
|
|
599
|
+ console.log(url,params)
|
|
|
600
|
+ let response = await fetch(url,
|
|
|
601
|
+ {
|
|
|
602
|
+ method: "post",
|
|
|
603
|
+ responseType: "stream",
|
|
|
604
|
+ headers: {
|
|
|
605
|
+ "Content-Type": "application/json",
|
|
|
606
|
+ "Authorization": "Bearer "+getToken(),
|
|
|
607
|
+ },
|
|
|
608
|
+ body: JSON.stringify(params),
|
|
|
609
|
+ }
|
|
|
610
|
+ );
|
|
|
611
|
+
|
|
|
612
|
+ let resultStr = '';
|
|
|
613
|
+
|
|
|
614
|
+ // ok字段判断是否成功获取到数据流
|
|
|
615
|
+ if (!response.ok) {
|
|
|
616
|
+ throw new Error("Network response was not ok");
|
|
|
617
|
+ }
|
|
|
618
|
+ // 用来获取一个可读的流的读取器(Reader)以流的方式处理响应体数据
|
|
|
619
|
+ const reader = response.body.getReader();
|
|
|
620
|
+ // 将流中的字节数据解码为文本字符串
|
|
|
621
|
+ const textDecoder = new TextDecoder();
|
|
|
622
|
+ let result = true;
|
|
|
623
|
+ let sqlValue = ''
|
|
|
624
|
+
|
|
|
625
|
+ while (result) {
|
|
|
626
|
+ // done表示流是否已经完成读取 value包含读取到的数据块
|
|
|
627
|
+ const { done, value } = await reader.read();
|
|
|
628
|
+ if (done) {
|
|
|
629
|
+ result = false;
|
|
|
630
|
+ return resultStr;
|
|
|
631
|
+ break;
|
|
|
632
|
+ }
|
|
|
633
|
+ // 拿到的value就是后端分段返回的数据,大多是以data:开头的字符串
|
|
|
634
|
+ // 需要通过decode方法处理数据块,例如转换为文本或进行其他操作
|
|
|
635
|
+ const chunkText = textDecoder.decode(value).split("\n").forEach((val) => {
|
|
|
636
|
+ if (!val) return;
|
|
|
637
|
+ try {
|
|
|
638
|
+ // 后端返回的流式数据一般都是以data:开头的字符,排除掉data:后就是需要的数据
|
|
|
639
|
+ // 具体返回结构可以跟后端约定
|
|
|
640
|
+ let text = val?.replace("data:", "") || ""
|
|
|
641
|
+ const resultData = JSON.parse(text)
|
|
|
642
|
+ let resultText = resultData.answer || ''
|
|
|
643
|
+ workflow_run_id.value = resultData.conversation_id
|
|
|
644
|
+ knowledgeObj.value += resultText
|
|
|
645
|
+ console.log(knowledgeObj.value)
|
|
|
646
|
+ } catch (err) { }
|
|
|
647
|
+ });
|
|
|
648
|
+ }
|
|
|
649
|
+
|
|
|
650
|
+ } catch (err) {
|
|
|
651
|
+ console.error('获取客户信息异常:', err);
|
|
|
652
|
+ return err;
|
|
|
653
|
+ }
|
|
|
654
|
+}
|
|
|
655
|
+const dealChatMessage = (msg) => {
|
|
|
656
|
+ if (msg.detail && msg.detail.content && isIntelligentFlag.value ==='true') {
|
|
|
657
|
+ aiKnowledge(msg.detail.content)
|
|
|
658
|
+ }
|
|
|
659
|
+
|
|
|
660
|
+}
|
|
|
661
|
+// 获取客户信息详情
|
|
|
662
|
+async function getchatDetail(openId) {
|
|
|
663
|
+ getOpenId.value = openId
|
|
|
664
|
+ console.log(getOpenId.value)
|
|
|
665
|
+ // if (getOpenId.value) window.addEventListener(`ChatMessageEvent-${getOpenId.value}`, dealChatMessage)
|
|
|
666
|
+ if (!getOpenId.value) {
|
|
|
667
|
+ ElMessage.warning('请提供有效的openId');
|
|
|
668
|
+ return;
|
|
|
669
|
+ }
|
|
|
670
|
+
|
|
|
671
|
+ try {
|
|
|
672
|
+ const res = await request.get('/patient/patient', {
|
|
|
673
|
+ params: { openId }
|
|
|
674
|
+ });
|
|
|
675
|
+
|
|
|
676
|
+ if (res.state === 'success' && res.data) {
|
|
|
677
|
+ // 更新客户信息
|
|
|
678
|
+ customerInfo.value = res.data[0];
|
|
|
679
|
+ // 对手机号和身份证号进行掩码处理
|
|
|
680
|
+ customerInfo.value.phoneNumber = customerInfo.value.phoneNumber ? userToAsterisk(customerInfo.value.phoneNumber) : '';
|
|
|
681
|
+ customerInfo.value.idcard = customerInfo.value.idcard ? userToAsterisk(customerInfo.value.idcard) : '';
|
|
|
682
|
+ customerInfo.value.tel = customerInfo.value.tel ? userToAsterisk(customerInfo.value.tel) : '';
|
|
|
683
|
+ } else {
|
|
|
684
|
+ ElMessage.error('获取客户信息失败');
|
|
|
685
|
+ console.error('获取客户信息失败:', res.message);
|
|
|
686
|
+ }
|
|
|
687
|
+ } catch (error) {
|
|
|
688
|
+ ElMessage.error('获取客户信息异常');
|
|
|
689
|
+ console.error('获取客户信息异常:', error);
|
|
|
690
|
+ }
|
|
|
691
|
+}
|
|
500
|
692
|
defineExpose({
|
|
|
693
|
+ getchatDetail,
|
|
501
|
694
|
getQuickMsgList
|
|
502
|
695
|
})
|
|
503
|
696
|
</script>
|