mirror of
http://112.124.100.131/ebiz-ai/ebiz-base-ai.git
synced 2025-12-06 17:36:48 +08:00
feat(AI-new): 优化聊天组件并添加新功能
- 重构 chat-new 组件,优化输入框和发送按钮逻辑 - 新增单次请求管控功能,改进多次请求处理 - 优化消息渲染逻辑,处理未闭合标签问题 - 调整卡片样式,增加新图标 - 更新路由配置,修改页面标题
This commit is contained in:
BIN
public/family.png
Normal file
BIN
public/family.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 337 KiB |
BIN
public/heart.png
Normal file
BIN
public/heart.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/note.png
Normal file
BIN
public/note.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
public/security.png
Normal file
BIN
public/security.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/thumbsup.png
Normal file
BIN
public/thumbsup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -1,18 +1,22 @@
|
||||
.card {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
justify-content: flex-start;
|
||||
gap: 5%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.card > div {
|
||||
line-height: 0;
|
||||
/* height: fit-content; */
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card > div > img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
width: 70px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.card > section > :nth-child(1) {
|
||||
@@ -27,5 +31,22 @@
|
||||
|
||||
.card > section > :nth-child(2) > div {
|
||||
background-color: #0065ff;
|
||||
padding: 5px;
|
||||
padding: 1px 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 选择遇到的第一个 div */
|
||||
.render-container > div:nth-of-type(1) > img {
|
||||
width: 100%;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.render-container > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
gap: 5px;
|
||||
}
|
||||
.render-container > div > img {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Vue from 'vue'
|
||||
import "./assets/sass/card.css"
|
||||
import App from './App.vue'
|
||||
import Router from './router'
|
||||
import Store from './store'
|
||||
|
||||
@@ -51,7 +51,7 @@ export default [
|
||||
name: 'productRecommend',
|
||||
component: () => import('@/views/AI-new/views/productRecommend/index.vue'),
|
||||
meta: {
|
||||
title: '产品推荐助手',
|
||||
title: '产品推荐助手-保障型',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<!-- 输入框 or 按住说话提示 -->
|
||||
<div class="input-wrapper">
|
||||
<input v-if="!isVoiceMode" type="text" v-model="newMessage" placeholder="你有什么想知道的?"
|
||||
@keyup.enter="sendMessage" />
|
||||
@keyup.enter="beforeSend" />
|
||||
<div v-else class="voice-hint-container" :class="{ disabled: messageStatus === 'send' }"
|
||||
@mousedown="startRecording" @selectstart="() => false" @mouseup="stopRecording" @mouseleave="stopRecording"
|
||||
@touchend="stopRecording" @touchstart="startRecording">
|
||||
@@ -25,11 +25,11 @@
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</div>
|
||||
<!-- <div class="hint-text" v-if='!isRecording'>按住说话</div>-->
|
||||
<!--<div class="hint-text" v-if='!isRecording'>按住说话</div>-->
|
||||
</div>
|
||||
<!-- 发送按钮 -->
|
||||
<button @click="sendMessage" :disabled="messageStatus === 'send'"
|
||||
:class="{ disabled: messageStatus === 'send' }" class="active send">
|
||||
<button @click="beforeSend" :disabled="messageStatus === 'send'"
|
||||
:class="{ disabled: messageStatus === 'send' }" class="ml10 active send">
|
||||
发送
|
||||
</button>
|
||||
</div>
|
||||
@@ -39,24 +39,13 @@
|
||||
<span v-else class="ml15 mr5 input-icon">⌨</span> -->
|
||||
</button>
|
||||
</footer>
|
||||
<!-- <section class="section pb10" > -->
|
||||
<!-- <button @click="deepInternet" :class="{ active: isDeep }">
|
||||
<svg-icon icon-class="think" class-name="chat-icon"></svg-icon>
|
||||
深度思考
|
||||
</button> -->
|
||||
<!-- 发送按钮 -->
|
||||
<!-- <button @click="sendMessage" :disabled="messageStatus === 'send'"
|
||||
:class="{ disabled: messageStatus === 'send' }" class="mr10 active send fs16">
|
||||
发送
|
||||
</button> -->
|
||||
<!-- </section> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SvgIcon from '@/components/svg-icon/index.vue'
|
||||
import { audioToText, gwcsChat, chatProduct } from '@/api/generatedApi'
|
||||
import { audioToText, gwcsChat } from '@/api/generatedApi'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -95,10 +84,16 @@ export default {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// action: {
|
||||
// type: String,
|
||||
// default: 'normal_chat',
|
||||
// }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requestSingle: undefined,
|
||||
// 管控单次请求,当 abort 之后, while 后面的会进行重复请求
|
||||
single: false,
|
||||
isThink: false,
|
||||
newMessage: '',
|
||||
isRecording: false,
|
||||
@@ -108,7 +103,10 @@ export default {
|
||||
isVoiceMode: false,
|
||||
answerMap: '',
|
||||
currentMessage: null,
|
||||
|
||||
messageInfo: {
|
||||
is_complete: false.toString(),
|
||||
information: '',
|
||||
},
|
||||
// 打字机相关
|
||||
typingText: '',
|
||||
typingQueue: [],
|
||||
@@ -118,6 +116,14 @@ export default {
|
||||
typingTimeout: null,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isTyping(value) {
|
||||
// 通过 typing 控制发送的状态
|
||||
// console.log(`typing status change `, value)
|
||||
if (!value) this.$emit('update:messageStatus', 'stop')
|
||||
else this.$emit('update:messageStatus', 'send')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deepInternet() {
|
||||
this.$emit('update:isDeep', !this.isDeep)
|
||||
@@ -152,19 +158,19 @@ export default {
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
hasTreasureBox() {
|
||||
chatProduct({ query: this.newMessage })
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
this.messageStatus = 'stop'
|
||||
this.messages.push({ type: 'box', text: this.newMessage, detail: res.content })
|
||||
this.newMessage = ''
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.messageStatus = 'stop'
|
||||
})
|
||||
},
|
||||
// hasTreasureBox() {
|
||||
// chatProduct({ query: this.newMessage })
|
||||
// .then((res) => {
|
||||
// if (res) {
|
||||
// this.messageStatus = 'stop'
|
||||
// this.messages.push({ type: 'box', text: this.newMessage, detail: res.content })
|
||||
// this.newMessage = ''
|
||||
// }
|
||||
// })
|
||||
// .catch(() => {
|
||||
// this.messageStatus = 'stop'
|
||||
// })
|
||||
// },
|
||||
stopRecording() {
|
||||
if (this.mediaRecorder && this.isRecording) {
|
||||
this.mediaRecorder.stop()
|
||||
@@ -207,21 +213,22 @@ export default {
|
||||
axiosGetAiChat() {
|
||||
const abortController = new AbortController()
|
||||
this.requestSingle = abortController
|
||||
let message = {
|
||||
is_complete: false.toString(),
|
||||
information: this.newMessage,
|
||||
}
|
||||
this.messageInfo.information = this.single ? this.messageInfo.information : this.newMessage
|
||||
|
||||
this.currentMessage = JSON.parse(JSON.stringify(message))
|
||||
// 重置 answerMap
|
||||
this.answerMap = ''
|
||||
|
||||
this.currentMessage = JSON.parse(JSON.stringify(this.messageInfo))
|
||||
let params = {
|
||||
appType: "gwcsHelper",
|
||||
conversationId: "",
|
||||
message: JSON.stringify(message),
|
||||
message: JSON.stringify(this.messageInfo),
|
||||
user: "gwcs-test",
|
||||
inputs: {}
|
||||
inputs: {},
|
||||
// action: this.action
|
||||
}
|
||||
this.currentMessage = {
|
||||
...message,
|
||||
...this.messageInfo,
|
||||
type: 'bot',
|
||||
text: '',
|
||||
think: '',
|
||||
@@ -230,28 +237,37 @@ export default {
|
||||
isLike: false,
|
||||
isDisLike: false,
|
||||
}
|
||||
this.messages.push(this.currentMessage)
|
||||
|
||||
if (this.single) {
|
||||
// this.messages[this.messages.length - 1]
|
||||
|
||||
this.messages.splice(this.messages.length - 1, 1, this.currentMessage)
|
||||
} else {
|
||||
this.messages.push(this.currentMessage)
|
||||
}
|
||||
// 如果有自定义参数
|
||||
if (this.chatData) {
|
||||
for (let k in this.chatData) {
|
||||
params[k] = this.chatData[k]
|
||||
}
|
||||
}
|
||||
if (this.$route.query.compareId) {
|
||||
params.compareResult = JSON.parse(sessionStorage.getItem('results'))
|
||||
}
|
||||
// if (this.$route.query.compareId) {
|
||||
// params.compareResult = JSON.parse(sessionStorage.getItem('results'))
|
||||
// }
|
||||
this.newMessage = ''
|
||||
fetch(gwcsChat(), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
signal: abortController.signal,
|
||||
body: JSON.stringify(params),
|
||||
timeout: 60000,
|
||||
})
|
||||
.then(async (res) => {
|
||||
this.newMessage = ''
|
||||
await this.processStreamResponse(res)
|
||||
this.single = false
|
||||
})
|
||||
.catch((err) => {
|
||||
// debugger
|
||||
this.$emit('update:messageStatus', 'stop')
|
||||
})
|
||||
},
|
||||
@@ -264,6 +280,8 @@ export default {
|
||||
const reader = response.body.getReader()
|
||||
let buffer = ''
|
||||
while (true) {
|
||||
// if (this.single) break
|
||||
|
||||
try {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
@@ -286,12 +304,30 @@ export default {
|
||||
if (!cleanLine) return null
|
||||
const data = JSON.parse(cleanLine)
|
||||
// console.log(data)
|
||||
// console.log(data)
|
||||
if (data.answer) {
|
||||
this.answerMap += data.answer
|
||||
const match = /<is_complete>([^<]*)(?:<\/is_complete>)?/.exec(data.answer)
|
||||
if (match && match[1] === 'true') {
|
||||
|
||||
const is_complete = /<is_complete>([^<]*)(?:<\/is_complete>)?/.exec(this.answerMap)
|
||||
const information = /<information>([^<]*)(?:<\/information>)?/.exec(this.answerMap)
|
||||
const text = /<text>([^<]*)(?:<\/text>)?/.exec(this.answerMap)
|
||||
// console.log(`is_complete, information, text`, is_complete, information, text)
|
||||
|
||||
// const isCompleteRes = is_complete.some(item => item === 'true')
|
||||
|
||||
this.messageInfo.information = information ? information[1].trim() : this.newMessage
|
||||
this.messageInfo.is_complete = is_complete ? is_complete[1].trim() : 'false'
|
||||
if (is_complete && is_complete[1] === 'true' && text && text[1].trim() === '') {
|
||||
// alert("message end")
|
||||
|
||||
this.requestSingle.abort()
|
||||
// setTimeout(() => {
|
||||
// debugger
|
||||
// this.$emit('update:messageStatus', 'send')
|
||||
this.single = true
|
||||
// debugger
|
||||
this.axiosGetAiChat()
|
||||
// }, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,9 +360,10 @@ export default {
|
||||
},
|
||||
updateMessageContent(parse) {
|
||||
let { event, answer, isThink } = parse
|
||||
if (event === 'message_end') {
|
||||
this.$emit('update:messageStatus', 'stop')
|
||||
}
|
||||
// 会导致发送按钮提前高亮展示
|
||||
// if (event === 'message_end') {
|
||||
// this.$emit('update:messageStatus', 'stop')
|
||||
// }
|
||||
if (!this.currentMessage || !answer) return
|
||||
if (event !== 'message') return
|
||||
// console.log(parse);
|
||||
@@ -342,7 +379,6 @@ export default {
|
||||
},
|
||||
startTypingAnimation() {
|
||||
this.isTyping = true
|
||||
|
||||
const typeNextChar = () => {
|
||||
if (this.typingQueue.length === 0) {
|
||||
this.isTyping = false
|
||||
@@ -353,8 +389,7 @@ export default {
|
||||
const chunk = this.typingQueue.shift()
|
||||
// console.log(this.messages);
|
||||
|
||||
const chars = /* chunk.answer.split('') */ Array.from(chunk.answer)
|
||||
// console.log(chars);
|
||||
const chars = Array.from(chunk.answer)
|
||||
|
||||
const isThink = chunk.isThink
|
||||
// 内部递归函数,用于逐字输出当前块
|
||||
@@ -365,6 +400,7 @@ export default {
|
||||
return
|
||||
}
|
||||
const char = chars.shift() || ''
|
||||
// if (this.single)
|
||||
this.$set(this.currentMessage, isThink ? 'think' : 'text', this.currentMessage[isThink ? 'think' : 'text'] + char)
|
||||
const delay = this.getTypingDelay(char)
|
||||
setTimeout(outputChar, delay)
|
||||
@@ -381,26 +417,23 @@ export default {
|
||||
}
|
||||
return this.typingSpeed
|
||||
},
|
||||
sendMessage() {
|
||||
beforeSend() {
|
||||
if (this.messageStatus === 'send') return
|
||||
if (this.newMessage.trim() === '') return
|
||||
this.newMessage = this.newMessage.replace(/<[^>]+>/g, '')
|
||||
this.messages.push({ type: 'user', text: this.newMessage })
|
||||
this.$emit('update:messageStatus', 'send')
|
||||
if (this.newMessage.includes('工具箱')) {
|
||||
this.hasTreasureBox()
|
||||
return
|
||||
}
|
||||
this.$emit('update:autoScrollEnabled', true)
|
||||
this.axiosGetAiChat()
|
||||
this.sendMessage()
|
||||
},
|
||||
cellClick(item) {
|
||||
this.newMessage = item.title
|
||||
this.messages.push({ type: 'user', text: this.newMessage })
|
||||
this.sendMessage()
|
||||
},
|
||||
sendMessage() {
|
||||
this.$emit('update:messageStatus', 'send')
|
||||
this.$emit('update:autoScrollEnabled', true)
|
||||
this.axiosGetAiChat()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -517,7 +550,7 @@ $primary-trans-color: rgba(135, 162, 208, 0.5);
|
||||
}
|
||||
|
||||
input {
|
||||
width: 110%;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
background: #fff;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<p v-html="md.render(message.think)" v-if="message.think && message.showThink" class="thinkText" />
|
||||
</span>
|
||||
<div style="width: 100%">
|
||||
<p v-html="render(message)"></p>
|
||||
<p v-html="render(message)" class='render-container'></p>
|
||||
<span class="speakLoadingToast pv10" v-if="!filterVisible(message)">
|
||||
<van-loading type="spinner" :color="primaryColor" size="20px" />
|
||||
</span>
|
||||
@@ -79,25 +79,33 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
render(message) {
|
||||
// this.filterVisible(message);
|
||||
|
||||
// console.log(md.render(message.text));
|
||||
return md.render(this.filterVisible(message))
|
||||
},
|
||||
setProductName(e) {
|
||||
this.$emit('setProductName', e)
|
||||
},
|
||||
filterVisible(message) {
|
||||
// 捕获 不包含 < 的后置标签 ( .*>)
|
||||
let _text = message.text.replace(/(?<![/|<])^\w*>/g, '')
|
||||
// 把 未闭合的标签替换成空白
|
||||
_text = _text.replace(/<\/\w*$/g, '')
|
||||
return _text
|
||||
if (!message.text.startsWith('<')) {
|
||||
return message.text
|
||||
}
|
||||
// 只把 text 标签内容渲染
|
||||
const match = /<text>([^<]*)(?:<\/text>)?/.exec(message.text)
|
||||
return match ? match[1] : ''
|
||||
let match = /<text>([^<]*)(?:<\/text>)?/.exec(message.text)
|
||||
let text = match ? match[1] : ''
|
||||
// 捕获 不包含 < 的后置标签 ( .*>)
|
||||
text = text.replace(/(?<![/|<])^\w*>/g, '')
|
||||
// 把 未闭合的标签替换成空白
|
||||
text = text.replace(/<\/\w*$/g, '')
|
||||
console.log(text);
|
||||
|
||||
return text
|
||||
},
|
||||
showThink(message) {
|
||||
this.$set(message, 'showThink', !message.showThink)
|
||||
|
||||
console.log(message.showThink)
|
||||
},
|
||||
// 处理点赞和踩的逻辑
|
||||
@@ -113,6 +121,9 @@ export default {
|
||||
this.$emit('update-message', { ...message })
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
window.md = md
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<chatMessage ref="chatMessage" :messages.sync="messages" :messageStatus.sync="messageStatus" :is-deep.sync="isDeep"
|
||||
:conversation-id.sync="conversationId" :is-searching.sync="isSearching" :product-name.sync="productName"
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @getIsThink="getIsThink"></chatMessage>
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @getIsThink="getIsThink" action="normal_chat"></chatMessage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
|
||||
<chatMessage :messages.sync="messages" :messageStatus.sync="messageStatus" :is-deep.sync="isDeep"
|
||||
:conversation-id.sync="conversationId" :is-searching.sync="isSearching" :product-name.sync="productName"
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @getIsThink="getIsThink"></chatMessage>
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @getIsThink="getIsThink" action="chat"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Icon, NavBar } from 'vant'
|
||||
import messageComponent from '@/views/AI/components/message.vue'
|
||||
import messageComponent from '@/views/AI-new/components/message.vue'
|
||||
import SvgIcon from '@/components/svg-icon/index.vue'
|
||||
import HotProducts from '@/views/AI-new/components/HotProducts.vue'
|
||||
import sticky from '@/views/AI/components/sticky.vue'
|
||||
@@ -67,17 +67,7 @@ export default {
|
||||
sessionStorage.removeItem('results')
|
||||
this.messages.push({
|
||||
type: 'bot',
|
||||
text: `
|
||||
这里是产品知识小助手,请告诉我您想要了解哪个产品?也可以输入以下信息,我帮您进行精准查询:
|
||||
|
||||
1.投保规则
|
||||
|
||||
2.保障责任
|
||||
|
||||
3.增值服务
|
||||
|
||||
您可以直接向我提问~
|
||||
`,
|
||||
text: `这里是产品知识小助手,请告诉我您想要了解哪个产品?也可以输入以下信息,我帮您进行精准查询:\n\n1.投保规则\n\n2.保障责任\n\n3.增值服务\n\n您可以直接向我提问~`,
|
||||
})
|
||||
} else {
|
||||
// 可以调用接口展示 名字 或者存在session里
|
||||
@@ -136,8 +126,7 @@ export default {
|
||||
watch: {
|
||||
messages: {
|
||||
handler() {
|
||||
console.log(this.messages, 'messages');
|
||||
|
||||
// console.log(this.messages, 'messages');
|
||||
this.$nextTick(() => this.scrollToBottom())
|
||||
},
|
||||
deep: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="chat-page">
|
||||
<van-nav-bar title="产品推荐助手" left-text="返回" left-arrow @click-left="$router.history.go(-1)" />
|
||||
<van-nav-bar title="产品推荐助手-保障型" left-text="返回" left-arrow @click-left="$router.history.go(-1)" />
|
||||
<sticky :hotList="hotList" :productName="productName" :messagesList.sync="messages"
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @setProductName="setProductName"
|
||||
:isDisabled="messageStatus === 'send'" :conversationId="conversationId"></sticky>
|
||||
@@ -21,13 +21,14 @@
|
||||
|
||||
<chatMessage :messages.sync="messages" :messageStatus.sync="messageStatus" :is-deep.sync="isDeep"
|
||||
:conversation-id.sync="conversationId" :is-searching.sync="isSearching" :product-name.sync="productName"
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @getIsThink="getIsThink"></chatMessage>
|
||||
:autoScrollEnabled.sync="autoScrollEnabled" @getIsThink="getIsThink" action="product_recommend">
|
||||
</chatMessage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Icon, NavBar } from 'vant'
|
||||
import messageComponent from '@/views/AI/components/message.vue'
|
||||
import messageComponent from '@/views/AI-new/components/message.vue'
|
||||
import SvgIcon from '@/components/svg-icon/index.vue'
|
||||
import HotProducts from '@/views/AI-new/components/HotProducts.vue'
|
||||
import sticky from '@/views/AI/components/sticky.vue'
|
||||
@@ -67,29 +68,16 @@ export default {
|
||||
sessionStorage.removeItem('results')
|
||||
this.messages.push({
|
||||
type: 'bot',
|
||||
text: `
|
||||
这里是产品推荐小助手,请告诉我以下客户的信息, 我帮您精准推荐:
|
||||
|
||||
1.如果您需要推荐保障类产品,您可以告诉我以下信息:
|
||||
|
||||
• 客户需要哪类保障?(重疾/医疗/意外)
|
||||
|
||||
• 客户的年龄、性别、有无既往病症
|
||||
|
||||
• 客户的保障场景(住院医疗/百万医疗/出行意外/综合意外/
|
||||
|
||||
交通意外)
|
||||
|
||||
2.如果您需要推荐理财储蓄类产品,您可以告诉我以下信息:
|
||||
|
||||
• 客户主要目标是什么?(财富升值/子女教育/资产传承/养老保障)
|
||||
|
||||
• 客户的年龄、性别、年收入、风险承受能力
|
||||
`,
|
||||
text: `这里是产品推荐小助手,请告诉我以下客户的信息, 我帮您精准推荐:\n\n1.如果您需要推荐保障类产品,您可以告诉我以下信息:
|
||||
\n\n• 客户需要哪类保障?(重疾/医疗/意外)
|
||||
\n\n• 客户的年龄、性别、有无既往病症
|
||||
\n\n• 客户的保障场景(住院医疗/百万医疗/出行意外/综合意外/交通意外)
|
||||
\n\n2.如果您需要推荐理财储蓄类产品,您可以告诉我以下信息:
|
||||
\n\n• 客户主要目标是什么?(财富升值/子女教育/资产传承/养老保障)
|
||||
\n\n• 客户的年龄、性别、年收入、风险承受能力`,
|
||||
})
|
||||
} else {
|
||||
// 可以调用接口展示 名字 或者存在session里
|
||||
|
||||
let sesstions = JSON.parse(sessionStorage.getItem('results')).productResults
|
||||
console.log(sesstions)
|
||||
let text = sesstions.map((item) => {
|
||||
|
||||
@@ -50,7 +50,7 @@ export default {
|
||||
[
|
||||
{ title: "产品助手", icon: 'product', path: '/productAssistant' },
|
||||
{ title: "产品知识助手", icon: 'product', path: '/productKnowledge' },
|
||||
{ title: "产品推荐助手", icon: 'product', path: '/productRecommend' },
|
||||
{ title: "产品推荐助手-保障型", icon: 'product', path: '/productRecommend' },
|
||||
],
|
||||
[
|
||||
{ title: 'AI智能助手', icon: 'product', path: '/chatPage' },
|
||||
|
||||
Reference in New Issue
Block a user