猜你想问接口联调

master
wujingling0908 2 weeks ago
parent b9ff01e056
commit 16391a2eef
  1. 235
      patch.txt
  2. 183
      src/components/chat-new.vue
  3. 1
      src/components/footer-bar-input.vue
  4. 125
      src/components/hot-question-new.vue
  5. 1
      src/main.js
  6. 1
      src/store/app.js
  7. 3
      src/utils/https.js
  8. 2
      src/utils/index.js
  9. 28
      src/utils/sensors.js
  10. 421
      src/views/chat.vue

@ -0,0 +1,235 @@
*** Begin Patch
*** Update File: D:\code\taibao\customAgent\src\views\chat.vue
@@ -421,10 +421,14 @@
}
}
-// 北极星SDK鉴权
-function initBxSDK() {
+
+// 北极星SDK鉴权
+const initBxSDK = () => {
setConfig({
url: isProd() ? "life-open.cpic.com.cn/fop/ui/poc/shumeng/h5" : "life-open-sit.cpic.com.cn/fop/ui/poc/shumeng/h5",
deb: "false",
})
}
- // 异步微信鉴权方法
- function async initWxAuth(versionNo1) {
+
+// 异步微信鉴权方法
+const initWxAuth = async (versionNo1) => {
try {
- // 异步获取微信配置参数
- const res = await this.getWxAuthConfig(versionNo1);
+ // 异步获取微信配置参数
+ const res = await getWxAuthConfig(versionNo1);
if (!res.success) {
@@ -459,8 +463,9 @@
}
}
- // 获取微信鉴权配置参数
- function async getWxAuthConfig(versionNo1) {
+// 获取微信鉴权配置参数
+const getWxAuthConfig = async (versionNo1) => {
const v1 = versionNo1
try {
@@ -471,3 +476,3 @@
const encryptUrl = Encrypt(key, iv, url)
- const response = await this.("thirdPartyAuth/getGwResultByUrl", {
+ const response = await Post("thirdPartyAuth/getGwResultByUrl", {
url: encryptUrl
@@ -486,48 +491,35 @@
// 微信鉴权成功后的回调
-function onWxAuthSuccess() {
+const onWxAuthSuccess = () => {
console.log('微信鉴权成功');
- Toast('wx.ready回调')
+ showToast('wx.ready回调')
}
-function disableShare() {
- var that = this;
+
+const disableShare = () => {
try {
//禁止分享
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener(
"WeixinJSBridgeReady",
- that.onBridgeReady(),
+ onBridgeReady,
false
);
} else if (document.attachEvent) {
- document.attachEvent("WeixinJSBridgeReady", that.onBridgeReady());
- document.attachEvent("onWeixinJSBridgeReady", that.onBridgeReady());
+ document.attachEvent("WeixinJSBridgeReady", onBridgeReady);
+ document.attachEvent("onWeixinJSBridgeReady", onBridgeReady);
}
} else {
- that.onBridgeReady();
+ onBridgeReady();
}
} catch (error) {
console.log("禁止分享hideOptionMenu", error.message);
}
}
-function onBridgeReady() {
+
+const onBridgeReady = () => {
WeixinJSBridge.call("hideOptionMenu");
}
-//链接人工客服
-function transferLabor() {
- var that = this;
- let sendParmas = {
- reqAndResType: "1", //1文本 2图片 3问提评价
- msgType: "01", //01文本 02图片
- msgText: "转接寿险人工客服",
- msgSource: this.manualService, //1机器人 2人工
- cmd: "ZJSXRGFW",
- // qaId: item.qaId, // 2022.03需求记录
- };
-
- // let current = event.currentTarget;
-
- //统计转人工 8月28日
- // this.statisticsTransferLabor(item);
-
- // 如果当前websocket链接已存在
- if (
- this.. &&
- this...readyState != this...CLOSED
- ) {
- // console.log(res)
- Toast("当前已经在人工会话中");
- // current.disabled = true;
- return;
- }
-
- //http接口
- var transferToast = Toast.loading({
- message: "转接中...",
- duration: 0,
- loadingType: "spinner",
- forbidClick: true,
- });
-
- this.
- .dispatch("transferCustomer", sendParmas)
- .then((res) => {
- transferToast.clear();
- // console.log(res)
- // current.disabled = true;
- // //用户行为统计 start
- // this.getUserBehavior(item.qaId, '5', 'ZJSXRGFW'); // 延期
- // //用户行为统计 end
-
- //我要转人工
- if (res.cmd === "ZJSXRGFWCONNECTION") {
- //初始化websocket 如果当前还是机器人
- that.setWebsocket(); //转人工
- return;
- }
-
- //其他消息 直接展示消息列表中
- this.set_chatList(res);
- //滚动到底部
- this.scrollTopBody();
- })
- .catch((err) => {
- transferToast.clear();
- console.log(err);
- });
-}
-//建立websocket
-function setWebsocket() {
- var that = this;
- try {
- //http接口
- var socketToast = Toast.loading({
- message: "连接中...",
- duration: 0,
- loadingType: "spinner",
- forbidClick: true,
- });
-
- //建立websocket
- this..initWebSocket(() => {
- that.
- .dispatch("setConnectToEasemob")
- .then((res) => {
- socketToast.clear();
- // if(res.connection){//机器人转人工
- // that.set_manualService(res.msgSource);
- // }
-
- // //用户行为统计 start
- // that.getUserBehavior(item.qaId, "5", "ZJSXRGFW");
- // //用户行为统计 end
- })
- .catch((err) => {
- socketToast.clear();
- console.log(err);
- });
- });
- } catch (err) {
- console.log(err.message);
- }
-}
-function scrollTopBody() {
- setTimeout(() => {
- //滚动到底部
- try {
- this.mescrollContent.scrollTop =
- this.mescrollContent.scrollHeight || 0;
- } catch (error) {
- console.log(error.message);
- }
- }, 300);
-}
-function loadSdk(){
+
+// 加载SDK
+const loadSdk = () => {
const script = document.createElement('script');
- this.("config/mydConfig", {})
+ Post("config/mydConfig", {})
.then((res) => {
@@ -538,3 +530,3 @@
script.onload = () => {
- this.set_sdkLoaded(true)
+ store.set_sdkLoaded?.(true)
console.log('SDK successed');
@@ -549,5 +541,6 @@
})
}
-//获取高温用户弹窗数据
-function getHotUserData(){
- this.("product/tip/select")
+
+// 获取高温用户弹窗数据
+const getHotUserData = () => {
+ Get("product/tip/select")
.then((res) => {
@@ -559,3 +552,3 @@
if (res.data.rhetoricString && res.data.productTipEntityList.length > 0) {
- this.set_hotUserData(hotUserData);
+ store.set_hotUserData?.(hotUserData);
}
@@ -563,7 +556,7 @@
const now = new Date();
const clickTime = \-\-\ \:\:\;
- const userId = this.userId;
- const source = this.source;
- const sessionId = this.sessionId;
+ const userId = store.userId;
+ const source = store.source;
+ const sessionId = store.sessionId;
// 调用埋点接口
- this.("product/record/save", {
+ Post("product/record/save", {
userId: userId,
*** End Patch

@ -1,17 +1,22 @@
<script setup>
import { ref, computed, inject, watch, nextTick } from 'vue'
import { ref, computed, inject, watch, nextTick, onMounted } from 'vue'
import { showToast } from 'vant';
import footerBarInput from '@/components/footer-bar-input.vue'
import hotQuestionNew from '@/components/hot-question-new.vue'
import { messageSend } from '@/utils/api'
defineOptions({
name: 'chat-new',
})
import { Post } from '@/utils/https'
const store = inject('appStore', null)
const chatArr = inject('chatArr', ref([]))
const isChatLoading = inject('isChatLoading', ref(false))
const mainContainerRef = ref(null)
const welcomeWord = ref('下午好,张先生')
const welcomeSubWord = ref('我是您的服务管家皮卡丘')
const abstractList = ref([
const businessHandleInfo = ref({})
const abstractList = computed(() => [
{
title: '保障状态',
num: 3,
@ -22,22 +27,39 @@ const abstractList = ref([
},
{
title: '待办任务',
num: 3,
num: businessHandleInfo.value?.contents?.length || 0,
text: '待办需处理',
unit: '个',
btnText: '去处理',
btnBg: 'linear-gradient(111deg, #ff752a 44%, #feb52d 136%)',
},
{
title: '待办任务',
num: 3,
text: '待办需处理',
unit: '个',
title: '权益领取',
num: 0,
text: '生存金权益',
unit: '项',
btnText: '去领取',
btnBg: 'linear-gradient(261deg, #2ed0c6 3%, #08b7ac 65%)',
},
])
const askList = ref(['贷款到期可以先还利息吗?', '查询已交费总额', '保单能领多少钱?'])
].filter(item => item.num > 0))
const businessHandle = () => {
if (
store.source == "95270000" ||
store.source == "95320000" ||
store.source == "95350000" ||
store.source == "95810000"
) {
Post("notify/info", { userInfoId: store.userId })
.then((res) => {
if (res.data?.contents.length > 0) {
businessHandleInfo.value = res.data;
}
})
.catch((error) => {
console.log(error);
});
}
}
function getItemText(item) {
return item?.message?.[0]?.options?.label || ''
@ -62,15 +84,9 @@ function sendText(text) {
function handleAskClick(item) {
sendText(item)
}
watch(
() => chatArr.value.length,
async () => {
await nextTick()
const el = mainContainerRef.value
if (el) el.scrollTop = el.scrollHeight
},
)
onMounted(async () => {
businessHandle()
})
</script>
<template>
@ -80,31 +96,22 @@ watch(
<div class="welcome-title">{{ welcomeWord }}</div>
<div class="sub-title">{{ welcomeSubWord }}</div>
</div>
<div class="abstract-con">
<div class="abstract-con" v-if="abstractList.length">
<div class="title">
<span>今日皮卡丘摘要</span><img src="@/assets/images/chat/star.svg" alt="" srcset="" />
</div>
<div class="list">
<div
:class="`item ${(abstractList || []).length === 1 ? 'singleItem' : ''}`"
v-for="(item, index) in abstractList || []"
:key="index"
>
<div :class="`item ${(abstractList || []).length === 1 ? 'singleItem' : ''}`"
v-for="(item, index) in abstractList || []" :key="index">
<div>
<div class="title">{{ item.title }}</div>
<div
class="content"
:style="{ display: (abstractList || []).length > 2 ? 'block' : 'flex' }"
>
<div class="content" :style="{ display: (abstractList || []).length > 2 ? 'block' : 'flex' }">
<div class="nums">
<div class="num">
{{ item.num }}<span>{{ item.unit }}</span>
</div>
</div>
<div
class="text"
:style="{ marginTop: (abstractList || []).length > 2 ? '8rem' : '0' }"
>
<div class="text" :style="{ marginTop: (abstractList || []).length > 2 ? '8rem' : '0' }">
{{ item.text }}
</div>
</div>
@ -113,24 +120,10 @@ watch(
</div>
</div>
</div>
<div class="ask-con">
<div
class="item"
v-for="(item, index) in askList"
:key="index"
@click="handleAskClick(item)"
>
<div class="icon"><span>#</span></div>
<span>{{ item }}</span>
<img src="@/assets/images/chat/line.svg" alt="" />
</div>
</div>
<hotQuestionNew />
<div class="message-con" v-if="chatArr.length || showTyping">
<div
v-for="(item, index) in chatArr"
:key="index"
:class="['msg-item', item.type === 'user' ? 'from-user' : 'from-bot']"
>
<div v-for="(item, index) in chatArr" :key="index"
:class="['msg-item', item.type === 'user' ? 'from-user' : 'from-bot']">
<div class="bubble">{{ getItemText(item) }}</div>
</div>
<div class="msg-item from-bot" v-if="showTyping">
@ -156,6 +149,7 @@ watch(
display: flex;
flex-direction: column;
padding: 12rem;
.chat-footer {
flex-shrink: 0;
margin: 12rem -12rem -12rem;
@ -163,11 +157,14 @@ watch(
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.main-container {
flex: 1;
overflow: auto;
.welcome-con {
padding: 23rem 8rem;
.welcome-title {
font-family: PingFang SC;
font-size: 20rem;
@ -183,6 +180,7 @@ watch(
text-fill-color: transparent;
margin-bottom: 4rem;
}
.sub-title {
font-family: PingFang SC;
font-size: 18rem;
@ -198,6 +196,7 @@ watch(
text-fill-color: transparent;
}
}
.abstract-con {
flex-direction: column;
justify-content: center;
@ -212,6 +211,7 @@ watch(
backdrop-filter: blur(10rem);
border-radius: 12rem;
.title {
font-family: PingFang SC;
font-size: 16rem;
@ -222,15 +222,18 @@ watch(
/* 科个中性/正文-标题 17204D */
/* 样式描述:用于正文标题 */
color: #17204d;
img {
width: 20rem;
margin-left: 4.6rem;
}
}
.list {
margin-top: 13rem;
display: flex;
gap: 8rem;
.item {
display: flex;
flex-direction: column;
@ -257,6 +260,7 @@ watch(
/* 科个中性/正文-副标题 7E849F */
color: #7e849f;
}
.content {
.nums {
font-family: DIN-Medium;
@ -267,10 +271,12 @@ watch(
font-variation-settings: 'opsz' auto;
color: #17204d;
.num {
display: flex;
align-items: flex-end;
}
span {
font-family: PingFang SC;
font-size: 12rem;
@ -284,6 +290,7 @@ watch(
color: #17204d;
}
}
.text {
font-family: PingFang SC;
font-size: 12rem;
@ -297,12 +304,13 @@ watch(
align-self: flex-end;
}
}
.btn {
border-radius: 100rem;
font-family: PingFang SC;
font-size: 14rem;
font-weight: 500;
line-height: 21rem;
line-height: 19rem;
text-align: center;
letter-spacing: 0rem;
@ -312,13 +320,16 @@ watch(
cursor: pointer;
}
}
.singleItem {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
> div {
>div {
margin-left: 36rem;
.title {
font-family: PingFang SC;
font-size: 14rem;
@ -332,6 +343,7 @@ watch(
color: #17204d;
margin-bottom: 4rem;
}
.content {
.nums {
font-size: 12rem;
@ -343,6 +355,7 @@ watch(
font-family: PingFang SC;
font-weight: 500;
color: #17204d;
span {
color: #7e849f;
margin-left: 0;
@ -353,69 +366,16 @@ watch(
}
}
}
.ask-con {
display: flex;
flex-direction: column;
gap: 10rem;
margin-top: 16rem;
.item {
border-radius: 24rem;
display: flex;
// flex-direction: column;
// justify-content: center;
padding: 6rem 16rem 6rem 6rem;
gap: 12rem;
background: #f9fbff;
box-sizing: border-box;
border: 1rem solid rgba(255, 255, 255, 0.9);
width: fit-content;
cursor: pointer;
.icon {
width: 30rem;
height: 30rem;
min-width: 30rem;
border-radius: 186rem;
opacity: 1;
background: #fcfdfd;
box-shadow: 0rem 4rem 10rem 0rem #e7effd;
text-align: center;
span {
line-height: 30rem;
font-size: 14rem;
font-variation-settings: 'opsz' auto;
background: linear-gradient(100deg, #38afff 27%, #025cea 101%);
font-weight: 600;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
display: inline-block;
}
}
> span {
font-family: PingFang SC;
font-size: 14rem;
font-weight: normal;
line-height: 31rem;
letter-spacing: 0rem;
/* 科个中性/正文-标题 17204D */
/* 样式描述:用于正文标题 */
color: #17204d;
}
}
}
.message-con {
display: flex;
flex-direction: column;
gap: 12rem;
margin-top: 16rem;
.msg-item {
display: flex;
.bubble {
max-width: 80%;
padding: 10rem 14rem;
@ -428,46 +388,57 @@ watch(
word-break: break-all;
}
}
.from-user {
justify-content: flex-end;
.bubble {
background: linear-gradient(266deg, #025cea 0%, #3f8cf8 100%);
color: #ffffff;
border-radius: 12rem 12rem 4rem 12rem;
}
}
.from-bot {
justify-content: flex-start;
.bubble {
background: #fcfdfd;
box-shadow: 0rem 4rem 10rem 0rem #e7effd;
border-radius: 12rem 12rem 12rem 4rem;
}
}
.typing {
display: flex;
align-items: center;
gap: 5rem;
span {
width: 6rem;
height: 6rem;
border-radius: 50%;
background: #7e849f;
animation: typing-blink 1s infinite;
&:nth-child(2) {
animation-delay: 0.2s;
}
&:nth-child(3) {
animation-delay: 0.4s;
}
}
}
@keyframes typing-blink {
0%,
80%,
100% {
opacity: 0.2;
}
40% {
opacity: 1;
}

@ -479,7 +479,6 @@ function clickSendMessage() {
sendFlag.value = !sendFlag.value
emoticonClick.value = false
sendMessage.value = ''
// 新架构:用户消息卡片入 chatArr,USER_TEXT 事件发送,机器人回复经 SSE 下发
store?.pushUserMessage?.(elInputValue)
messageSend(elInputValue).catch((err) => {

@ -0,0 +1,125 @@
<script setup>
import { ref, computed, inject, watch, nextTick, onMounted } from 'vue'
import { showToast } from 'vant';
import { Post } from '@/utils/https'
const store = inject('appStore', null)
const questionList = ref([])
const initHotQuestion = async () => {
let param = {
userInfoId: store.userId || '',
category: 3,
source: store.source || '',
planCode: store.planCode || '',
sceneId: store.userInfo.sceneId || "",
};
Post("config/activity", param)
.then((res) => {
if (res.code && res.code != 0) {
showToast(res.msg);
return;
}
questionList.value = (res?.data || []).slice(0,3);
// this.renderR();
// this.initViewState();
// 获取一体化领取后更新hotList重新更新
// this.initHotQuestionYTH((ythRes) => {
// if (Array.isArray(ythRes) && Array.isArray(questionList.value)) {
// // 合并数组并根据name去重
// // const mergedList = [...ythRes,...this.hotList]
// // const uniqueMap = new Map()
// // mergedList.forEach(item => {
// // // 使用name作为唯一标识符,如果已存在则不覆盖(保留第一次出现的)
// // if(!uniqueMap.has(item.name)){
// // uniqueMap.set(item.name, item)
// // }
// // })
// // this.hotList = Array.from(uniqueMap.values())
// questionList.value = [...ythRes, ...questionList.value]
// }
// this.renderR();
// this.initViewState();
// })
})
.catch((error) => {
console.log(error);
});
}
const handleAskClick=(record)=>{
// store.setAskRecord(record)
}
onMounted(async () => {
await initHotQuestion()
})
</script>
<template>
<div class="ask-con">
<div class="item" v-for="(item, index) in questionList" :key="index" @click="handleAskClick(item)">
<div class="icon"><span>#</span></div>
<span>{{ item.name }}</span>
<img src="@/assets/images/chat/line.svg" alt="" />
</div>
</div>
</template>
<style scoped lang="scss">
.ask-con {
display: flex;
flex-direction: column;
gap: 10rem;
margin-top: 16rem;
.item {
border-radius: 24rem;
display: flex;
// flex-direction: column;
// justify-content: center;
padding: 6rem 16rem 6rem 6rem;
gap: 12rem;
background: #f9fbff;
box-sizing: border-box;
border: 1rem solid rgba(255, 255, 255, 0.9);
width: fit-content;
cursor: pointer;
.icon {
width: 30rem;
height: 30rem;
min-width: 30rem;
border-radius: 186rem;
opacity: 1;
background: #fcfdfd;
box-shadow: 0rem 4rem 10rem 0rem #e7effd;
text-align: center;
span {
line-height: 30rem;
font-size: 14rem;
font-variation-settings: 'opsz' auto;
background: linear-gradient(100deg, #38afff 27%, #025cea 101%);
font-weight: 600;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
display: inline-block;
}
}
>span {
font-family: PingFang SC;
font-size: 14rem;
font-weight: normal;
line-height: 31rem;
letter-spacing: 0rem;
/* 科个中性/正文-标题 17204D */
/* 样式描述:用于正文标题 */
color: #17204d;
}
}
}
</style>

@ -49,7 +49,6 @@ function getRem(pwidth, prem) {
oWidth = minWidth
}
console.log('计算 rem - 屏幕宽度:', oWidth, '基准宽度:', pwidth, '基准字号:', prem)
html.style.fontSize = (oWidth / pwidth) * prem + 'px'
}

@ -684,6 +684,7 @@ export const useAppStore = defineStore('app', () => {
setIntegratedUser,
setHxSessionId,
setShowHumanAppraise,
set_data: setShowHumanAppraise
}
})
export default useAppStore

@ -135,7 +135,7 @@ axios.interceptors.response.use(
// 请求成功
(res) => {
if (res.data.code === 10001) {
appStore().del_token()
appStore().delToken()
sessionStorage.removeItem('token') // 删除已经失效或过期的token(不删除也可以,因为登录后覆盖)
// 如果没有展示返回头部的话去掉弹窗按钮
@ -270,7 +270,6 @@ export function Get(url, params) {
export function Post(url, params) {
return new Promise((resolve, reject) => {
url = base.baseUrl + url
console.log('url', url, base);
axios
.post(url, params)
.then((res) => {

@ -372,7 +372,7 @@ export function getHost() {
export function Encrypt(Okey, Oiv, payload) {
const key = CryptoJS.enc.Utf8.parse(Okey);
const iv = CryptoJS.enc.Utf8.parse(Oiv);
let srcs = srcs = CryptoJS.enc.Utf8.parse(payload)
let srcs = CryptoJS.enc.Utf8.parse(payload)
const encrypted = CryptoJS.AES.encrypt(srcs, key, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
const base64str = CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
// return encrypted.ciphertext.toString().toUpperCase();

@ -0,0 +1,28 @@
import sensors from 'sa-sdk-javascript'
// 神策埋点 初始化全局
let server_url = 'https://sc.cpic.com.cn/sa?project=SXTOC';// 生产环境环境神策接入地址
let host = window.location.host;
const ISLOG = ['production', 'prod'].includes(process.env.NODE_ENV);
if (host.indexOf('uat') > -1 || host.indexOf('sit') > -1 || host.indexOf('localhost') > -1) {
server_url = 'https://sc-sit.cpic.com.cn:443/sa?project=SXXT' // 测试环境神策接入地址
}
console.log("神策接入地址环境", server_url);
sensors.init({
server_url: server_url,
is_track_single_page: true, // 单页应用页面浏览事件采集(url改变就触发)
show_log: false, // 控制台显示数据开
heatmap: {
//是否开启点击图,default 表示开启,自动采集 $WebClick 事件,可以设置 'not_collect' 表示关闭。
clickmap: 'default',
//是否开启触达注意力图,not_collect 表示关闭,不会自动采集 $WebStay 事件,可以设置 'default' 表示开启。
scroll_notice_map: 'default'
}
});
sensors.quick('autoTrack') // 首次触发页面加载事件 $pageview
export default sensors

@ -6,26 +6,31 @@
:isWX="isWX"
:lostChatInfoNum="lostChatInfoNum"
/> -->
<chat-new />
<chat-new v-if="isToken" />
<!-- <human-appraise-popup /> -->
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted } from 'vue'
import { useAppStore } from '@/store/app.js'
import { showLoadingToast, closeToast } from 'vant'
import { useRouter } from 'vue-router'
import { Post } from '@/utils/https'
import {
showLoadingToast,
closeToast,
showDialog,
showConfirmDialog,
showToast,
} from 'vant'
import { Post, Get } from '@/utils/https'
import chatMain from '@/components/chat-main.vue'
import chatNew from '@/components/chat-new.vue'
// import HumanAppraisePopup from "@/components/human-appraise-popup.vue";
import Utils from '@/utils/utils'
import sensors from '@/utils/sensors'
import { Decryption, DecryptionECB, Encrypt, isDev, isProd } from '@/utils'
// 状态管理
const store = useAppStore()
const router = useRouter()
console.log(store, 'store')
const {
setSource,
setUserInfo,
@ -44,10 +49,6 @@ const isWX = ref(false)
const lostChatInfoNum = ref(0)
const urlParams = ref({})
// 计算属性
const userInfo = computed(() => store.userInfo)
const source = computed(() => store.source)
// 生命周期
onMounted(async () => {
var liccsAds = localStorage.getItem('liccsAds') // 记录用户弹窗提示
@ -92,7 +93,6 @@ onMounted(async () => {
}
isWX.value = Utils.isWeiXin()
console.log(setSource,store)
setUserInfo(userInfo);//用户信息
setSource(urlParams.value.ht || ""); //来源
setNotitle(urlParams.value.notitle || ""); //是否展示头部
@ -103,7 +103,9 @@ onMounted(async () => {
setHtmlExtParams(urlParams.value.htmlExtParams || ""); //扩展参数
setComplaint(urlParams.value.complaint || ""); //扩展参数
setNavigationCorpus(urlParams.value.navigationCorpus || ""); //扩展参数
wx.miniProgram.getEnv((res) => {
console.log(res,'res');
})
// 渠道校验
let checkToast = null
try {
@ -116,10 +118,9 @@ onMounted(async () => {
const checkRes = await Post('config/downSource', {
source: urlParams.value.ht || '95810000',
})
console.log(checkToast,'checkToast');
checkToast.close()
if (checkRes.code === 0 && checkRes.data !== null) {
Dialog.alert({
showDialog({
title: '提示',
message: checkRes.data.toast,
confirmButtonText: '确定',
@ -143,11 +144,220 @@ onMounted(async () => {
const initToken = async () => {
try {
const res = await getToken()
const data = res?.data
if (!data) {
throw new Error('获取用户信息失败:接口未返回 data')
}
// Pinia setup store 会自动解包 ref,组件内直接通过 action 更新即可。
store.setUserId(data.userId || '')
store.setSource(data.source || urlParams.value.ht || '')
store.setPlanCode(data.planCode || '')
store.setSessionId(data.sessionId || '')
store.setToken(data.token || '')
store.setManualService(data.msgSource ?? 1)
store.setMsgStatus(data.msgStatus || '')
store.setIsLostMessage(data.isLostChatInfo || '')
const elderChannels = ['95460000', '95290000', '95830000']
const isElder = Boolean(data.eldCustomer)
if (elderChannels.includes(data.source)) {
store.setElder(isElder)
if (!isElder && data.source === '95460000') {
window.location.href = Utils.changeURLArg(window.location.href, 'ht', '95270000')
}
}
const nextUserInfo = {
...(store.userInfo || {}),
versionNo1: data.versionNo1 || '',
versionHFHZ: data.versionHFHZ || '',
encryptPid: data.encryptPid || '',
pid: data.pid || '',
sourceUserId: data.sourceUserId || '',
encryptPhone: data.encryptPhone || '',
eldCustomer: isElder,
vip: data.vip,
planCode: data.planCode || '',
entryIdnum: data.entryIdnum || '',
entryOpenid: data.entryOpenid || '',
sourceName: data.sourceName || '',
blacklistFlag: data.blacklistFlag || '',
}
store.setUserInfo(nextUserInfo)
if (nextUserInfo.blacklistFlag === '1' && nextUserInfo.bpErrorContent) {
const query = new URLSearchParams({
ht: urlParams.value.ht || '',
openid: urlParams.value.openid || '',
})
history.replaceState({}, '', `${window.location.origin}${window.location.pathname}?${query}`)
}
// 尚未提供 setter 的少量 Pinia state 可以直接赋值,Pinia 会同步更新其内部 ref。
store.flagType = data.flagType || ''
store.setGaokeUser(Boolean(data.gaokeUser))
store.setHotUser(Boolean(data.gaowenUser))
store.mydFlag = Boolean(data.manyiduWhite)
store.setIntegratedUser(Boolean(data.white))
store.setReviewRestricted(Boolean(data.reviewRestricted))
store.setBranchCompany(data.branchCompany || '')
store.setBpErrorInfo(data.bpErrorInfo || [])
isToken.value = true
// 其他逻辑...
lostChatInfoNum.value = data.lostChatInfoNum || 0
if (store.hotUser) {
getHotUserData()
}
// 微信鉴权异步执行,不阻塞 token 初始化主流程。
if (((Utils.isWeiXin() && !Utils.isMiniProgram()) || isDev()) && nextUserInfo.versionNo1) {
initWxAuth(nextUserInfo.versionNo1).catch((error) => {
console.warn('微信鉴权异步执行失败:', error)
})
}
try {
if (isElder && data.elderlyData && nextUserInfo.versionNo1) {
const year = new Date().getFullYear()
const versionNo = DecryptionECB(
`${year}${year}${year}${year}`,
nextUserInfo.versionNo1,
)
const decrypted = Decryption(
versionNo.substring(0, 16),
versionNo.substring(16, 32),
data.elderlyData,
)
store.asrConfig = JSON.parse(decrypted.slice(1, -1))
}
} catch (error) {
console.warn('获取 ASR 配置失败:', error)
}
const deviceFingerprintSwitch = Boolean(data.deviceFingerprintSwitch)
if (deviceFingerprintSwitch) {
initBxSDK()
}
loadSdk()
void Post('config/getAllProvinces', {})
.then((response) => store.setPcaData(response?.data || []))
.catch((error) => console.warn('获取省市区数据失败:', error))
void Post('config/getQueueNumberTimeSource', {})
.then((response) => {
const sources = response?.data || []
store.setChannelReform(Array.isArray(sources) && sources.includes(data.source))
})
.catch((error) => console.warn('获取排队等待时间试点渠道失败:', error))
if (data.bpErrorCode) {
void callStoreAction('brokenPointCall', {
reqAndResType: '1',
msgText: data.bpErrorContent || '',
msgSource: data.msgSource,
bpErrorCode: data.bpErrorCode,
bpErrorContent: data.bpErrorContent,
})
}
if (data.msgSource == 2) {
if (store.userId) {
void callStoreAction('initWebSocket')
} else {
showConfirmDialog({
title: '初始化提示',
message: '初始化会话失败,请检查网络或页面必要参数;点击“确定”重新建立会话。',
})
.then(() => Utils.AppReloadHtml())
.catch(() => Utils.closeWindow())
}
void Post('HumanChat/humanChatIsQA', { sessionId: data.sessionId })
.then((response) => store.setIsHumanChat(response?.data || false))
.catch((error) => console.warn('获取人工会话状态失败:', error))
}
sensors.quick('isReady', () => {
sensors.login(String(store.userId || ''))
sensors.track('yykfPageInit', {
...nextUserInfo,
source: data.source || '',
})
})
if (deviceFingerprintSwitch && typeof globalThis.getBrowserID === 'function') {
try {
globalThis.getBrowserID(
'ozpw1c5ce6x6mx60pyz2o496frzgrnt6zlmj',
'h5_lpxlwwuyro',
'',
(matchId) => {
sensors.track('yykfDeviceFingerprint', {
matchId: matchId || 'NULL',
userId: data.userId || 'NULL',
source: data.sourceName || 'NULL',
encryptPid: data.pid || 'NULL',
encryptPhone: data.encryptPhone || 'NULL',
})
},
)
} catch (error) {
console.warn('获取设备指纹失败:', error)
}
}
// 关爱版自动转人工。对应 action 迁入 Pinia 后会直接执行;未迁移时不会阻断初始化。
if (isElder && elderChannels.includes(data.source) && String(store.manualService) !== '2') {
setTimeout(() => {
void callStoreAction('transferCustomer', {
reqAndResType: '1',
msgType: '01',
msgText: '转接寿险人工客服',
msgSource: store.manualService,
cmd: 'ZJSXRGFW',
})
}, 50)
}
const currentSource = data.source || urlParams.value.ht || ''
if (urlParams.value.bqQuestion && currentSource === '95810000') {
store.setIsBqCalcClaim(true)
const msgSource = data.msgSource || store.manualService || '1'
const isManual = String(msgSource) === '2' || String(store.manualService) === '2'
const sendParams = {
reqAndResType: '1',
msgText: urlParams.value.bqQuestion,
msgSource: String(msgSource),
questionType: '11',
}
const sendQuestion = () =>
callStoreAction(isManual ? 'sendmessageContent' : 'sendingRobot', sendParams)
if (isManual) {
setTimeout(sendQuestion, 500)
} else {
void sendQuestion()
}
}
} catch (error) {
console.error(error)
isToken.value = false
console.error('初始化 token 失败:', error)
}
}
const callStoreAction = (actionName, payload) => {
const action = store[actionName]
if (typeof action !== 'function') {
console.warn(`Pinia action ${actionName} 尚未迁移,已跳过本次调用`)
return Promise.resolve(null)
}
return Promise.resolve(action(payload)).catch((error) => {
console.warn(`Pinia action ${actionName} 执行失败:`, error)
return null
})
}
const getToken = async () => {
@ -198,10 +408,8 @@ const getToken = async () => {
params.userId = decodeURIComponent(urlParams.value.appTicket).replace(/ /g, '+')
}
showLoadingToast({ message: '加载中...', duration: 0, loadingType: 'spinner', forbidClick: true })
console.log('Post', Post)
try {
const res = await Post('user/info', params)
console.log('res', res)
closeToast()
return res
} catch (error) {
@ -210,8 +418,181 @@ const getToken = async () => {
throw error
}
}
// 北极星SDK鉴权
const initBxSDK = () => {
// store.setConfig({
// url: isProd() ? "life-open.cpic.com.cn/fop/ui/poc/shumeng/h5" : "life-open-sit.cpic.com.cn/fop/ui/poc/shumeng/h5",
// deb: "false",
// })
}
// 异步微信鉴权方法
const initWxAuth = async (versionNo1) => {
try {
// 异步获取微信配置参数
const res = await getWxAuthConfig(versionNo1);
if (!res.success) {
console.warn('微信配置获取失败,跳过鉴权');
showToast('微信鉴权失败')
return;
}
const wxConfig = res.result
// document.addEventListener('WeixinOpenTagsError', function (e) {
// // console.error(e.detail.errMsg); // 无法使用开放标签的错误原因,需回退兼容。仅无法使用开放标签,JS-SDK其他功能不受影响
// Toast('开放标签错误=' + e.detail.errMsg)
// });
// 检查微信JS-SDK是否可用
if (typeof wx === 'undefined' || !wx || typeof wx.config !== 'function') {
console.error('微信JS-SDK未正确加载');
showToast('微信JS-SDK加载失败');
return;
}
// 配置微信JS-SDK
wx.config({
debug: false, // 生产环境关闭调试模式
appId: wxConfig.appId, // 必填,服务号的唯一标识
timestamp: wxConfig.timestamp, // 必填,生成签名的时间戳
nonceStr: wxConfig.nonceStr, // 必填,生成签名的随机串
signature: wxConfig.signature, // 必填,签名
jsApiList: ['previewImage'], // 必填,需要使用的JS接口列表
openTagList: ['wx-open-launch-weapp'] // 可选,需要使用的开放标签列表
});
// 鉴权成功回调
wx.ready(() => {
console.log('微信JS-SDK鉴权成功');
// this.onWxAuthSuccess();
});
// 鉴权失败回调
wx.error((res) => {
console.warn('微信JS-SDK鉴权失败:', res);
// Toast(`微信授权失败: ${JSON.stringify(res)}`);
});
} catch (error) {
console.warn('微信鉴权初始化失败:', error);
showToast('微信初始化失败');
}
}
// 获取微信鉴权配置参数
const getWxAuthConfig = async (versionNo1) => {
const v1 = versionNo1
try {
const url = encodeURIComponent(window.location.href.split('#')[0])
const year = new Date().getFullYear()
const versionNo1 = DecryptionECB(`${year}${year}${year}${year}`, v1)
const key = versionNo1.substring(0, 16)
const iv = versionNo1.substring(16, 32)
const encryptUrl = Encrypt(key, iv, url)
const response = await Post("thirdPartyAuth/getGwResultByUrl", {
url: encryptUrl
});
if (response.code === 0 && response.data) {
return response.data;
} else {
console.warn('获取微信配置失败:', response.msg);
return null;
}
} catch (error) {
console.warn('微信配置接口调用失败:', error);
return null;
}
}
// 微信鉴权成功后的回调
const onWxAuthSuccess = () => {
console.log('微信鉴权成功');
showToast('wx.ready回调')
}
const disableShare = () => {
try {
//禁止分享
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener(
"WeixinJSBridgeReady",
onBridgeReady(),
false
);
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady", onBridgeReady());
document.attachEvent("onWeixinJSBridgeReady", onBridgeReady());
}
} else {
onBridgeReady();
}
} catch (error) {
console.log("禁止分享hideOptionMenu", error.message);
}
}
const onBridgeReady = () => {
WeixinJSBridge.call("hideOptionMenu");
}
const loadSdk = () => {
const script = document.createElement('script');
Post("config/mydConfig", {})
.then((res) => {
if (!!res.data && !!res.data.data) {
script.src = res.data.data.url + '?t=' + new Date().getTime()
}
script.onload = () => {
store.setSdkLoaded?.(true)
console.log('SDK successed');
};
script.onerror = () => {
console.error('Failed to load SDK');
};
document.head.appendChild(script)
})
.catch((error) => {
console.log(error);
})
}
//获取高温用户弹窗数据
const getHotUserData = () => {
Get("product/tip/select")
.then((res) => {
if (res.code === 0 && res.data) {
// 接口返回 rhetoricString 话术,productTipEntityList 产品列表
const hotUserData = {
tips: res.data.rhetoricString || '',
productList: res.data.productTipEntityList || []
};
if (res.data.rhetoricString && res.data.productTipEntityList.length > 0) {
store.setHotUserData?.(hotUserData);
}
// 获取当前时间戳
const now = new Date();
const clickTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
const userId = store.userId;
const source = store.source;
const sessionId = store.sessionId;
// 调用埋点接口
Post("product/record/save", {
userId: userId,
productName: "",
productCode: "",
channel: source,
sessionId: sessionId,
clickTime: clickTime,
buttonName: ""
}).then((res) => {
console.log("高温用户初始化埋点成功", res);
}).catch((error) => {
console.log("高温用户初始化埋点失败", error);
});
}
})
.catch((error) => {
console.log('获取高温用户弹窗数据失败', error);
});
}
</script>
<style scoped>
/* 样式保持不变 */
</style>

Loading…
Cancel
Save