diff --git a/.env.development b/.env.development
index fca9954..00c0ba4 100644
--- a/.env.development
+++ b/.env.development
@@ -1,5 +1,5 @@
NODE_ENV= development
-VITE_HTTP_BASE_URL = http://10.39.13.78:8001/api/
+VITE_HTTP_BASE_URL = http://10.39.13.78:8002/api/
# VITE_HTTP_BASE_URL = https://test-weapp-api.linyikj.com.cn/api/
# VITE_HTTP_BASE_URL = https://weapp-api.linyikj.com.cn/api/
VITE_ACCESS_TOKEN_KEY= 'ACCESS_TOKEN_CUSTOMER'
\ No newline at end of file
diff --git a/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.js b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.js
new file mode 100644
index 0000000..7854f14
--- /dev/null
+++ b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.js
@@ -0,0 +1 @@
+"use strict";const l=require("../../common/vendor.js"),o=l.defineComponent({__name:"hs-scroll-indicator",props:["scroll_view"],setup(o){const e=o;let n=l.index.getWindowInfo();const t=l.ref(0);return l.watch((()=>{var l;return null==(l=null==e?void 0:e.scroll_view)?void 0:l.scrollLeft}),(l=>{let o=null==e?void 0:e.scroll_view,r=(null==o?void 0:o.scrollWidth)-(null==n?void 0:n.windowWidth),i=(null==o?void 0:o.scrollLeft)/r*100;t.value=i/100*25})),(l,o)=>({a:`${t.value}%`})}}),e=l._export_sfc(o,[["__scopeId","data-v-808db072"]]);wx.createComponent(e);
diff --git a/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.json b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.json
new file mode 100644
index 0000000..e8cfaaf
--- /dev/null
+++ b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.wxml b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.wxml
new file mode 100644
index 0000000..9312083
--- /dev/null
+++ b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.wxml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.wxss b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.wxss
new file mode 100644
index 0000000..485d100
--- /dev/null
+++ b/dist/build/mp-weixin/components/hs-scroll-indicator/hs-scroll-indicator.wxss
@@ -0,0 +1 @@
+.scroll_indicator_container.data-v-808db072{width:100%}.scroll_indicator.data-v-808db072{background-color:#eee;width:60rpx;margin:0 auto;margin-top:15rpx}.scroll_indicator .indicator.data-v-808db072{background-color:#304483;border-radius:100rpx;width:35rpx;height:8rpx;position:relative}
diff --git a/dist/build/mp-weixin/pages/ai/chat.js b/dist/build/mp-weixin/pages/ai/chat.js
new file mode 100644
index 0000000..0d80aad
--- /dev/null
+++ b/dist/build/mp-weixin/pages/ai/chat.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../common/vendor.js");require("../../common/libraries/request.js");const t=require("../../common/store/useWeAppAuthStore.js");require("../../common/store/useWorkStore.js");const o=require("../../common/libraries/upload.js");if(require("../../gen/Apis.js"),require("../../common/libraries/setTabBar.js"),require("../../common/libraries/apiLoading.js"),!Array){e.resolveComponent("uni-icons")()}Math;const a=e.defineComponent({__name:"chat",setup(a){e.dayjs.extend(e.relativeTime),e.dayjs.locale("zh-cn");const s=t.useWeAppAuthStore(),n=e.ref(""),l=e.ref([]),r=e.ref(!1),i=e.ref([{role:"ai",content:"您好!我是物业客服,有什么可以帮助您的吗?",quickQuestions:[]}]),u=e.ref(!1),c=e.ref("正在输入中...");let m=null,g=e.ref(!1);const d="https://kf-api-test.linyikj.com.cn",p=e.ref(1),v=e.ref(10),y=e.ref(!0),_=e.ref(!1),f=e.ref(""),h=e.ref(0),k=e.ref([]),q=e.ref(""),S=(t,o)=>{e.index.previewImage({current:t,urls:o})},C=t=>{t?e.index.setClipboardData({data:t,success:()=>{e.index.showToast({title:"复制成功",icon:"success"})},fail:()=>{e.index.showToast({title:"复制失败",icon:"none"})}}):e.index.showToast({title:"暂无内容可复制",icon:"none"})},w=t=>{if(!t)return"";try{const o=e.dayjs(t);return o.isValid()?o.fromNow():""}catch(o){return console.error("时间格式化错误:",o),""}},A=()=>{e.nextTick$1((()=>{e.index.pageScrollTo({scrollTop:999999,duration:300})}))},x=async(t=1)=>{var o,a;const n=null==(a=null==(o=s.data)?void 0:o.user)?void 0:a.phone;if(n){if(!_.value)try{_.value=!0;const o=(t-1)*v.value;h.value=o,console.log("分页信息 - 页码:",t,"每页数量:",v.value,"计算出的offset:",o);const a=await e.index.request({url:`${d}/api/public/customer/init`,method:"POST",data:{platform:"property",platform_user_id:n,limit:v.value,offset:o}});if(200===a.statusCode){const e=a.data;let s=[];if(e.conversation&&e.conversation.id?(f.value=e.conversation.id,console.log("获取到会话ID:",f.value)):e.conversation_id?(f.value=e.conversation_id,console.log("获取到会话ID:",f.value)):e.conversations&&e.conversations.id&&(f.value=e.conversations.id,console.log("获取到会话ID:",f.value)),e.messages&&Array.isArray(e.messages)?(s=e.messages.map((e=>{const t={role:"customer"===e.sender_type?"user":"ai",content:e.message||e.content||"",created_at:e.created_at||e.timestamp||(new Date).toISOString()};e.message_type&&(t.message_type=e.message_type);let o=null;return e.image_url&&Array.isArray(e.image_url)?o=e.image_url:e.images&&Array.isArray(e.images)?o=e.images:e.metadata&&e.metadata.image_url&&Array.isArray(e.metadata.image_url)&&(o=e.metadata.image_url),o&&(t.image_url=o,t.images=o),e.metadata&&(t.metadata=e.metadata),t})),console.log("从messages字段获取到历史记录:",s.length)):e.data&&Array.isArray(e.data)?(s=e.data.map((e=>{const t={role:"customer"===e.sender_type?"user":"ai",content:e.message||e.content||"",created_at:e.created_at||e.timestamp||(new Date).toISOString()};e.message_type&&(t.message_type=e.message_type);let o=null;return e.image_url&&Array.isArray(e.image_url)?o=e.image_url:e.images&&Array.isArray(e.images)?o=e.images:e.metadata&&e.metadata.image_url&&Array.isArray(e.metadata.image_url)&&(o=e.metadata.image_url),o&&(t.image_url=o,t.images=o),e.metadata&&(t.metadata=e.metadata),t})),console.log("从data字段获取到历史记录:",s.length)):e.list&&Array.isArray(e.list)&&(s=e.list.map((e=>{const t={role:"customer"===e.sender_type?"user":"ai",content:e.message||e.content||"",created_at:e.created_at||e.timestamp||(new Date).toISOString()};e.message_type&&(t.message_type=e.message_type);let o=null;return e.image_url&&Array.isArray(e.image_url)?o=e.image_url:e.images&&Array.isArray(e.images)?o=e.images:e.metadata&&e.metadata.image_url&&Array.isArray(e.metadata.image_url)&&(o=e.metadata.image_url),o&&(t.image_url=o,t.images=o),e.metadata&&(t.metadata=e.metadata),t})),console.log("从list字段获取到历史记录:",s.length)),1===t){s.length>0?(i.value=s,console.log("第一页历史记录已加载,总共",s.length,"条消息")):(console.log("没有历史记录"),i.value=[]);const e=!y.value;Q(e)&&D(e)}else s.length>0&&setTimeout((()=>{i.value.unshift(...s),console.log("加载更多历史记录,新增",s.length,"条消息,总共",i.value.length,"条")}),300);const n=e.total||e.count||e.total_count||0;y.value=n>i.value.length,p.value=t,t>1&&!y.value&&(console.log("分页加载完成,当前页:",t,"hasMore:",y.value,"展示开场白"),setTimeout((()=>{D(!0)}),500)),console.log("第",t,"页数据加载完成,offset:",o,", limit:",v.value,", 总数据:",n,", 当前已加载:",i.value.length,", 是否有更多:",y.value),1===t&&(setTimeout((()=>{A()}),100),console.log("[Customer] 历史记录加载完成,开始建立WebSocket连接"),T())}else console.error("获取历史记录失败,状态码:",a.statusCode)}catch(l){console.error("获取历史记录异常:",l)}finally{_.value=!1}}else console.log("用户未登录,无法获取历史记录")};e.onPullDownRefresh((async()=>{if(_.value||!y.value)return console.log("正在加载或没有更多数据"),void e.index.stopPullDownRefresh();console.log("触发下拉分页,加载更多历史记录");const t=p.value+1;try{await x(t),await new Promise((e=>setTimeout(e,500)))}catch(o){console.error("加载历史记录失败:",o)}finally{e.index.stopPullDownRefresh()}}));const T=()=>{if(!m)try{const t="wss://kf-api-test.linyikj.com.cn/ws/socket.io/?EIO=4&transport=websocket";console.log("正在建立Socket.IO连接"),console.log("连接URL:",t),m=e.index.connectSocket({url:t,header:{"content-type":"application/json"}}),e.index.onSocketOpen((t=>{console.log("[Customer] WebSocket connected",t),g.value=!0;e.index.sendSocketMessage({data:'40/customer,{"jwt":""}',success:()=>{console.log("[Customer] Socket.IO连接包发送成功"),f.value&&setTimeout((()=>{const t=`42/customer,["join_conversation",{"conversation_id":"${f.value}"}]`;console.log("[Customer] 加入会话房间:",t),e.index.sendSocketMessage({data:t,success:()=>{console.log("[Customer] 成功加入会话房间")},fail:e=>{console.error("[Customer] 加入会话房间失败:",e)}})}),200)},fail:e=>{console.error("[Customer] Socket.IO连接包发送失败:",e)}})})),e.index.onSocketError((e=>{console.error("[Customer] WebSocket error:",e),g.value=!1,m=null})),e.index.onSocketClose((e=>{console.log("[Customer] WebSocket disconnected",e),g.value=!1,m=null})),e.index.onSocketMessage((t=>{console.log("收到WebSocket原始消息:",t),console.log("消息数据类型:",typeof t.data),console.log("消息内容:",t.data);const o=t.data;if("string"==typeof o)if(o.startsWith("42/customer,")){const e=o.substring(12);try{const t=JSON.parse(e);console.log("解析Socket.IO事件:",t),b(t)}catch(a){console.error("解析Socket.IO数据失败:",a,"原始数据:",e)}}else if(o.startsWith("40/customer"))console.log("Socket.IO连接确认");else if(o.startsWith("2"))e.index.sendSocketMessage({data:"3"});else if(o.startsWith("0"))console.log("Socket.IO握手成功");else try{const e=JSON.parse(o);console.log("解析JSON消息:",e),O(e)}catch(a){console.log("非JSON格式的字符串消息:",o)}else"object"==typeof o?(console.log("收到对象类型消息:",o),j(o)):console.log("收到其他类型消息,类型:",typeof o)}))}catch(t){console.error("初始化Socket.IO异常:",t),g.value=!1,m=null}},b=e=>{if(Array.isArray(e)&&e.length>=2){const t=e[0],o=e[1];console.log("[Customer] Socket.IO事件类型:",t,"事件数据:",o),"new_message"===t?W(o):"join_conversation_response"===t?console.log("[Customer] Joined room:",o):"message"===t?W(o):"typing"===t?I(o):console.log("[Customer] 未处理的Socket.IO事件类型:",t)}},O=e=>{console.log("[Customer] 处理JSON消息:",e),"message"===e.type||"new_message"===e.event?W(e.data||e):"typing"===e.type||"typing"===e.event?I(e.data||e):e.message||e.content?W(e):console.log("[Customer] 未识别的JSON消息结构:",e)},j=e=>{console.log("[Customer] 处理对象消息:",e),e.message||e.content||e.text?W(e):void 0!==e.is_typing?I(e):console.log("[Customer] 未识别的对象消息结构:",e)},I=e=>{console.log("[Customer] 处理typing指示器:",e),e.is_typing&&"staff"===e.user_type?(u.value=!0,c.value="客服正在输入..."):u.value=!1},Q=(e=!1)=>0!==k.value.length&&(0===i.value.length||!!(e&&i.value.length>0)),D=(e=!1)=>{if(0===k.value.length)return;if(!Q(e))return;if(i.value.find((e=>"ai"===e.role&&e.quickQuestions&&e.quickQuestions.length>0)))return void console.log("[Customer] 开场白已存在,跳过添加");const t={role:"ai",content:"您好!我是物业客服,有什么可以帮助您的吗?",quickQuestions:k.value,created_at:(new Date).toISOString()};console.log("[Customer] 创建开场白消息,是否最后一页:",e),0===i.value.length?(i.value=[t],console.log("[Customer] 设置开场白为第一条消息")):e&&(i.value.unshift(t),console.log("[Customer] 已加载到最后一页,在第一条消息前面插入开场白"))},W=e=>{if(console.log("[Customer] 处理消息数据:",e),"customer"===e.sender_type||"user"===e.role)return void console.log("[Customer] 过滤掉客户消息");let t="";if(t="string"==typeof e?e:e.message||e.content||e.text||e.body||"收到回复","string"==typeof t&&(t=t.replace(/↵/g,"\n").replace(/\\n/g,"\n")),console.log("[Customer] 收到新消息内容:",t),t===q.value)return console.log("[Customer] 消息与HTTP返回的消息相同,跳过显示"),void(q.value="");u.value=!1;const o={role:"ai",content:t,created_at:e.created_at||e.timestamp||e.time||(new Date).toISOString()};e.suggested_questions&&Array.isArray(e.suggested_questions)&&e.suggested_questions.length>0?o.quickQuestions=e.suggested_questions:e.quickQuestions&&Array.isArray(e.quickQuestions)&&e.quickQuestions.length>0&&(o.quickQuestions=e.quickQuestions),void 0!==e.need_confirmation&&(o.needConfirmation=e.need_confirmation),void 0!==e.confirmation_type&&(o.confirmationType=e.confirmation_type),i.value.push(o),A()},P=(e,t)=>{void 0===e.selectedConfirmation&&(e.selectedConfirmation=t,setTimeout((()=>{n.value=t,F()}),300))},z=async()=>{if(l.value.length>=9)e.index.showToast({title:"最多选择9张图片",icon:"none"});else try{const t=9-l.value.length,a=await o.upload(t,2,["image"]);if(a&&Array.isArray(a)&&a.length>0){const t=a.map((e=>e.url));l.value.push(...t),e.index.showToast({title:"图片上传成功",icon:"success"})}}catch(t){console.error("选择图片失败:",t),e.index.showToast({title:"选择图片失败",icon:"none"})}},F=async()=>{var t,o,a,r,m,p;const v=n.value.trim(),y=l.value.length>0;if(!v&&!y||u.value)return;const _=null==(o=null==(t=s.data)?void 0:t.user)?void 0:o.phone,h=null==(r=null==(a=s.data)?void 0:a.selected_house)?void 0:r.asset_projects_id,k=null==(p=null==(m=s.data)?void 0:m.selected_house)?void 0:p.full_name;if(!_||!h)return void e.index.showToast({title:"请先登录并绑定房屋",icon:"none"});g.value||(T(),await new Promise((e=>setTimeout(e,1e3))));const S=l.value;let C="text";y&&v?C="mixed":y&&!v&&(C="image");const w={role:"user",content:v||"",created_at:(new Date).toISOString(),message_type:C,image_url:S.length>0?S:void 0,images:S.length>0?S:void 0};i.value.push(w),n.value="",l.value=[],A(),v&&v.includes("查询")?c.value="正在查询中请稍后...":c.value="正在输入中...",u.value=!0;try{const t=await e.index.request({url:`${d}/api/public/chat`,method:"POST",data:{platform:"property",message:v||"",tenant_project_id:h,tenant_project_name:k||"",platform_user_id:_,conversation_id:f.value,message_type:C,image_url:S.length>0?S:void 0},header:{"Content-Type":"application/json"}});if(200!==t.statusCode)throw new Error("请求失败");{const e=t.data;console.log("[Customer] HTTP接口响应数据:",e);let o=null,a=[],s=!1,n=null;if(e.reply&&"string"==typeof e.reply?(o=e.reply,a=e.suggested_questions||[],s=e.need_confirmation||!1,n=e.confirmation_type||null):e.reply&&e.reply.message?(o=e.reply.message,a=e.reply.suggested_questions||e.suggested_questions||[],s=e.reply.need_confirmation||e.need_confirmation||!1,n=e.reply.confirmation_type||e.confirmation_type||null):e.reply&&e.reply.content?(o=e.reply.content,a=e.reply.suggested_questions||e.suggested_questions||[],s=e.reply.need_confirmation||e.need_confirmation||!1,n=e.reply.confirmation_type||e.confirmation_type||null):e.message?(o=e.message,a=e.suggested_questions||[],s=e.need_confirmation||!1,n=e.confirmation_type||null):e.content?(o=e.content,a=e.suggested_questions||[],s=e.need_confirmation||!1,n=e.confirmation_type||null):e.answer?(o=e.answer,a=e.suggested_questions||[],s=e.need_confirmation||!1,n=e.confirmation_type||null):e.response?(o=e.response,a=e.suggested_questions||[],s=e.need_confirmation||!1,n=e.confirmation_type||null):"string"==typeof e&&(o=e),o){console.log("[Customer] HTTP接口返回回答消息:",o),console.log("[Customer] 建议问题:",a),console.log("[Customer] 需要确认:",s,"确认类型:",n);let e=o;"string"==typeof e&&(e=e.replace(/↵/g,"\n").replace(/\\n/g,"\n")),q.value=e,u.value=!1,i.value.push({role:"ai",content:e,created_at:(new Date).toISOString(),quickQuestions:a.length>0?a:void 0,needConfirmation:s,confirmationType:n}),A()}else console.log("[Customer] 消息发送成功,等待WebSocket回复")}}catch(x){console.error("发送消息失败:",x),e.index.showToast({title:"发送失败,请稍后重试",icon:"none"}),i.value.push({role:"ai",content:"抱歉,网络连接出现问题,请稍后再试。"}),u.value=!1,A()}};return e.onUnmounted((()=>{(m||g.value)&&(e.index.closeSocket(),m=null,g.value=!1,console.log("页面卸载,WebSocket连接已关闭"))})),e.onLoad((async()=>{k.value=await(async()=>{try{const t=await e.index.request({url:`${d}/api/public/quick-questions`,method:"GET"});if(200===t.statusCode){const e=t.data;let o=[];return e.data&&Array.isArray(e.data)?o=e.data.map((e=>e.question||e.title||e.text||e)):e.questions&&Array.isArray(e.questions)?o=e.questions.map((e=>e.question||e.title||e.text||e)):Array.isArray(e)&&(o=e.map((e=>e.question||e.title||e.text||e))),console.log("获取到开场白按钮数据:",o),o}return console.error("获取开场白数据失败,状态码:",t.statusCode),[]}catch(t){return console.error("获取开场白数据异常:",t),[]}})(),console.log("页面加载时已获取开场白按钮数据:",k.value.length),x(1)})),(t,o)=>e.e({a:e.f(i.value,((t,o,a)=>{return e.e({a:"ai"===t.role},(t.role,{}),{b:t.image_url&&t.image_url.length>0},t.image_url&&t.image_url.length>0?{c:e.f(t.image_url,((o,a,s)=>({a:o,b:e.o((e=>S(o,t.image_url)),a),c:a}))),d:1===t.image_url.length?"widthFix":"aspectFill",e:1===t.image_url.length?1:""}:t.images&&t.images.length>0?{g:e.f(t.images,((o,a,s)=>({a:o,b:e.o((e=>S(o,t.images)),a),c:a}))),h:1===t.images.length?"widthFix":"aspectFill",i:1===t.images.length?1:""}:t.metadata&&t.metadata.image_url&&t.metadata.image_url.length>0?{k:e.f(t.metadata.image_url,((o,a,s)=>({a:o,b:e.o((e=>S(o,t.metadata.image_url)),a),c:a}))),l:1===t.metadata.image_url.length?"widthFix":"aspectFill",m:1===t.metadata.image_url.length?1:""}:{},{f:t.images&&t.images.length>0,j:t.metadata&&t.metadata.image_url&&t.metadata.image_url.length>0,n:t.content&&t.content.trim()},t.content&&t.content.trim()?{o:e.f((s=t.content,s&&"string"==typeof s?s.split("\n").filter((e=>""!==e.trim())):[""]),((t,o,a)=>({a:e.t(t),b:"text-"+o})))}:{},{p:t.quickQuestions&&t.quickQuestions.length>0},t.quickQuestions&&t.quickQuestions.length>0?{q:e.f(t.quickQuestions,((t,o,a)=>({a:e.t(t),b:o,c:e.o((e=>(e=>{n.value=e,F()})(t)),o)})))}:{},{r:t.needConfirmation},t.needConfirmation?{s:"是"===t.selectedConfirmation?1:"",t:void 0!==t.selectedConfirmation?1:"",v:e.o((e=>P(t,"是")),o),w:"否"===t.selectedConfirmation?1:"",x:void 0!==t.selectedConfirmation?1:"",y:e.o((e=>P(t,"否")),o)}:{},{z:t.created_at&&!t.quickQuestions},t.created_at&&!t.quickQuestions?e.e({A:"ai"===t.role},"ai"===t.role?{B:e.o((e=>C(t.content)),o)}:{},{C:e.t(w(t.created_at)),D:"user"===t.role},"user"===t.role?{E:e.o((e=>C(t.content)),o)}:{}):{},{F:o,G:`msg-${o}`,H:e.n("user"===t.role?"user-message":"ai-message")});var s})),b:u.value},u.value?{c:e.t(c.value)}:{},{d:l.value.length>0},l.value.length>0?e.e({e:e.f(l.value,((t,o,a)=>({a:t,b:"d335cb2c-0-"+a,c:e.o((e=>(e=>{l.value.splice(e,1)})(o)),o),d:o}))),f:e.p({type:"closeempty",size:"14",color:"#fff"}),g:l.value.length<9},l.value.length<9?{h:e.p({type:"plus",size:"30",color:"#999"}),i:e.o(z)}:{}):{},{j:e.o((e=>r.value=!0)),k:e.o((e=>r.value=!1)),l:e.o(F),m:n.value,n:e.o((e=>n.value=e.detail.value)),o:!n.value.trim()&&!r.value&&0===l.value.length},n.value.trim()||r.value||0!==l.value.length?{}:{p:e.p({type:"camera",size:"24",color:"#666"}),q:e.o(z)},{r:(n.value.trim()||r.value||l.value.length>0)&&!u.value},(n.value.trim()||r.value||l.value.length>0)&&!u.value?{s:e.p({type:"paperplane-filled",size:"20",color:"#fff"}),t:e.o(F)}:{},{v:u.value},u.value?{w:e.p({type:"spinner-cycle",size:"20",color:"#ccc"})}:{})}}),s=e._export_sfc(a,[["__scopeId","data-v-d335cb2c"]]);wx.createPage(s);
diff --git a/dist/build/mp-weixin/pages/ai/chat.json b/dist/build/mp-weixin/pages/ai/chat.json
new file mode 100644
index 0000000..6a4ac11
--- /dev/null
+++ b/dist/build/mp-weixin/pages/ai/chat.json
@@ -0,0 +1,8 @@
+{
+ "navigationBarTitleText": "客服服务",
+ "enablePullDownRefresh": true,
+ "backgroundTextStyle": "dark",
+ "usingComponents": {
+ "uni-icons": "../../uni_modules/uni-icons/components/uni-icons/uni-icons"
+ }
+}
\ No newline at end of file
diff --git a/dist/build/mp-weixin/pages/ai/chat.wxml b/dist/build/mp-weixin/pages/ai/chat.wxml
new file mode 100644
index 0000000..6187251
--- /dev/null
+++ b/dist/build/mp-weixin/pages/ai/chat.wxml
@@ -0,0 +1 @@
+{{line.a}}{{question.a}}是否{{message.C}}{{c}}添加图片
\ No newline at end of file
diff --git a/dist/build/mp-weixin/pages/ai/chat.wxss b/dist/build/mp-weixin/pages/ai/chat.wxss
new file mode 100644
index 0000000..1b3b5e0
--- /dev/null
+++ b/dist/build/mp-weixin/pages/ai/chat.wxss
@@ -0,0 +1 @@
+.chat-container.data-v-d335cb2c{display:flex;flex-direction:column;min-height:100vh;width:100vw;background-color:#f5f5f5}.chat-messages.data-v-d335cb2c{width:100%;padding:30rpx 20rpx;padding-bottom:calc(200rpx + env(safe-area-inset-bottom));box-sizing:border-box;flex:1}.message-item.data-v-d335cb2c{display:flex;width:100%;box-sizing:border-box;margin-bottom:30rpx;animation:fadeIn-d335cb2c .3s ease-in}.message-item.user-message.data-v-d335cb2c{justify-content:flex-end;align-items:flex-start}.message-item.user-message .message-content-wrapper.data-v-d335cb2c{align-items:flex-end}.message-item.user-message .message-content.data-v-d335cb2c{background-color:#1c64f2;color:#fff;margin-right:0;flex-shrink:0}.message-item.user-message .message-content .message-images.data-v-d335cb2c{margin-bottom:0}.message-item.user-message .message-content .message-images .message-image-item.data-v-d335cb2c{border-radius:8rpx}.message-item.user-message .message-time.data-v-d335cb2c{color:#999;font-size:22rpx;margin-top:6rpx;text-align:right;min-width:80rpx}.message-item.user-message .message-meta.data-v-d335cb2c{display:flex;align-items:center;justify-content:flex-end;margin-top:6rpx;gap:8rpx;flex-direction:row}.message-item.ai-message.data-v-d335cb2c,.message-item.ai-message .message-content-wrapper.data-v-d335cb2c{align-items:flex-start}.message-item.ai-message .message-content.data-v-d335cb2c{background-color:#fff;color:#333;margin-left:12rpx;margin-right:0;flex-shrink:0}.message-item.ai-message .message-time.data-v-d335cb2c{color:#999;font-size:22rpx;min-width:80rpx}.message-item.ai-message .message-meta.data-v-d335cb2c{display:flex;align-items:center;justify-content:flex-start;margin-top:6rpx;gap:8rpx;margin-left:12rpx;flex-direction:row}.message-item.ai-message .message-avatar.data-v-d335cb2c{margin-right:0;flex-shrink:0}@keyframes fadeIn-d335cb2c{0%{opacity:0;transform:translateY(10rpx)}to{opacity:1;transform:translateY(0)}}.message-avatar.data-v-d335cb2c{width:60rpx;height:60rpx;border-radius:50%;overflow:hidden;flex-shrink:0}.message-avatar image.data-v-d335cb2c{width:100%;height:100%}.message-avatar .user-avatar-image.data-v-d335cb2c{width:100%;height:100%;border-radius:50%}.message-avatar .user-avatar.data-v-d335cb2c{width:100%;height:100%;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);display:flex;align-items:center;justify-content:center;color:#fff;font-size:24rpx;font-weight:500}.message-content-wrapper.data-v-d335cb2c{display:flex;flex-direction:column;max-width:calc(100vw - 100rpx)}.message-content.data-v-d335cb2c{padding:20rpx 24rpx;border-radius:16rpx;font-size:28rpx;line-height:1.5;word-wrap:break-word;word-break:break-all;box-sizing:border-box}.message-content.loading.data-v-d335cb2c{opacity:.7}.message-content.data-v-d335cb2c:has(.message-images){padding:12rpx}.user-message .message-content.data-v-d335cb2c:has(.message-images){padding:8rpx;background-color:transparent}.message-content view.data-v-d335cb2c{display:block;width:100%;word-wrap:break-word;word-break:break-all}.message-content view.data-v-d335cb2c:not(:last-child){margin-bottom:8rpx}.message-content text.data-v-d335cb2c{display:inline;word-wrap:break-word;word-break:break-all}.quick-questions.data-v-d335cb2c{margin-top:16rpx;display:flex;flex-direction:column;gap:12rpx;padding-left:12rpx}.question-btn.data-v-d335cb2c{background-color:#f0f7ff;border:1px solid #d0e3ff;border-radius:12rpx;padding:16rpx 20rpx;font-size:26rpx;color:#1c64f2;line-height:1.4;transition:all .2s ease}.question-btn.data-v-d335cb2c:active{background-color:#e6f2ff;transform:scale(.98)}.question-btn text.data-v-d335cb2c{display:block;word-wrap:break-word;word-break:break-all}.confirmation-buttons.data-v-d335cb2c{margin-top:16rpx;display:flex;gap:16rpx;justify-content:flex-start;padding-left:12rpx}.confirmation-btn.data-v-d335cb2c{width:38rpx;border-radius:12rpx;padding:16rpx 32rpx;font-size:28rpx;line-height:1.4;text-align:center;transition:all .2s ease;background-color:#fff;color:#000;border:1px solid #e5e5e5}.confirmation-btn.data-v-d335cb2c:active:not(.disabled){transform:scale(.98)}.confirmation-btn.selected.data-v-d335cb2c{background-color:#1c64f2;color:#fff;border-color:#1c64f2}.confirmation-btn.disabled.data-v-d335cb2c{opacity:.6;cursor:not-allowed}.confirmation-btn text.data-v-d335cb2c{display:block;font-weight:500}.chat-input-area.data-v-d335cb2c{position:fixed;bottom:0;left:0;right:0;background-color:#fff;border-top:1px solid #e5e5e5;padding:20rpx;padding-bottom:calc(20rpx + env(safe-area-inset-bottom));z-index:100}.input-container.data-v-d335cb2c{display:flex;align-items:center;background-color:#f5f5f5;border-radius:50rpx;padding:10rpx 20rpx}.message-input.data-v-d335cb2c{flex:1;height:70rpx;font-size:28rpx;padding:0 20rpx;background-color:transparent}.send-button.data-v-d335cb2c{width:70rpx;height:70rpx;background:linear-gradient(135deg,#1c64f2 0%,#0e4aa7 100%);border-radius:50%;display:flex;align-items:center;justify-content:center;margin-left:20rpx}.send-button.disabled.data-v-d335cb2c{opacity:.5;pointer-events:none}.upload-button.data-v-d335cb2c{width:70rpx;height:70rpx;background-color:#f5f5f5;border-radius:50%;display:flex;align-items:center;justify-content:center;margin-left:20rpx}.image-preview-area.data-v-d335cb2c{margin-bottom:20rpx;padding:0 20rpx}.image-preview-list.data-v-d335cb2c{display:flex;flex-wrap:wrap;gap:16rpx}.image-preview-item.data-v-d335cb2c{position:relative;width:120rpx;height:120rpx;border-radius:12rpx;overflow:hidden}.image-preview-item.add-more-button.data-v-d335cb2c{background-color:#f5f5f5;border:2rpx dashed #ddd;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer}.image-preview-item.add-more-button.data-v-d335cb2c:active{background-color:#e8e8e8}.preview-image.data-v-d335cb2c{width:100%;height:100%}.add-more-text.data-v-d335cb2c{font-size:22rpx;color:#999;margin-top:8rpx}.remove-image.data-v-d335cb2c{position:absolute;top:8rpx;right:8rpx;width:40rpx;height:40rpx;background-color:rgba(0,0,0,.6);border-radius:50%;display:flex;align-items:center;justify-content:center}.message-images.data-v-d335cb2c{display:flex;flex-wrap:wrap;gap:12rpx;margin-bottom:12rpx;max-width:500rpx}.user-message .message-images.data-v-d335cb2c{margin-bottom:0}.message-image-item.data-v-d335cb2c{border-radius:12rpx;overflow:hidden}.message-image-item.single-image.data-v-d335cb2c{max-width:500rpx;width:500rpx!important;height:auto!important}.user-message .message-image-item.single-image.data-v-d335cb2c{max-width:450rpx;width:450rpx!important}.message-image-item.data-v-d335cb2c:not(.single-image){width:200rpx;height:200rpx}.message-image.data-v-d335cb2c{width:100%;height:100%;display:block}.message-text-line.data-v-d335cb2c{margin-bottom:4rpx}.message-text-line.data-v-d335cb2c:last-child{margin-bottom:0}.copy-button.data-v-d335cb2c{width:32rpx;height:32rpx;display:flex;align-items:center;justify-content:center;border-radius:4rpx;transition:background-color .2s ease}.copy-button.data-v-d335cb2c:active{background-color:rgba(0,0,0,.05)}.copy-button .copy-icon.data-v-d335cb2c{width:26rpx;height:26rpx;opacity:.7}
diff --git a/dist/build/mp-weixin/static/svg/copy.svg b/dist/build/mp-weixin/static/svg/copy.svg
new file mode 100644
index 0000000..a89dd25
--- /dev/null
+++ b/dist/build/mp-weixin/static/svg/copy.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/app.js b/dist/dev/mp-weixin/app.js
index dd43528..35aeff4 100644
--- a/dist/dev/mp-weixin/app.js
+++ b/dist/dev/mp-weixin/app.js
@@ -14,7 +14,7 @@ if (!Math) {
"./pages/transfer/index.js";
"./pages/forward/index.js";
"./pages/me/index.js";
- "./pages/ai/index.js";
+ "./pages/ai/chat.js";
"./pages/web_view/index.js";
"./WORKORDER/list/index.js";
"./WORKORDER/add/index.js";
diff --git a/dist/dev/mp-weixin/app.json b/dist/dev/mp-weixin/app.json
index 546c583..1b68f9d 100644
--- a/dist/dev/mp-weixin/app.json
+++ b/dist/dev/mp-weixin/app.json
@@ -5,7 +5,7 @@
"pages/transfer/index",
"pages/forward/index",
"pages/me/index",
- "pages/ai/index",
+ "pages/ai/chat",
"pages/web_view/index"
],
"subPackages": [
diff --git a/dist/dev/mp-weixin/common/libraries/request.js b/dist/dev/mp-weixin/common/libraries/request.js
index e8175b2..1dcb1ce 100644
--- a/dist/dev/mp-weixin/common/libraries/request.js
+++ b/dist/dev/mp-weixin/common/libraries/request.js
@@ -3,7 +3,7 @@ const common_vendor = require("../vendor.js");
const common_store_useWeAppAuthStore = require("../store/useWeAppAuthStore.js");
const http = new common_vendor.Request();
http.setConfig((config) => {
- config.baseURL = "http://10.39.13.78:8001/api/";
+ config.baseURL = "http://10.39.13.78:8002/api/";
config.header = {
...config.header
};
diff --git a/dist/dev/mp-weixin/common/vendor.js b/dist/dev/mp-weixin/common/vendor.js
index 63a1be1..d0a79b6 100644
--- a/dist/dev/mp-weixin/common/vendor.js
+++ b/dist/dev/mp-weixin/common/vendor.js
@@ -11045,6 +11045,7 @@ const onLoad = /* @__PURE__ */ createHook(ON_LOAD);
const onUnload = /* @__PURE__ */ createHook(ON_UNLOAD);
const onPageScroll = /* @__PURE__ */ createHook(ON_PAGE_SCROLL);
const onReachBottom = /* @__PURE__ */ createHook(ON_REACH_BOTTOM);
+const onPullDownRefresh = /* @__PURE__ */ createHook(ON_PULL_DOWN_REFRESH);
const onShareTimeline = /* @__PURE__ */ createHook(ON_SHARE_TIMELINE);
const onShareAppMessage = /* @__PURE__ */ createHook(ON_SHARE_APP_MESSAGE);
var toString = Object.prototype.toString;
@@ -14669,17 +14670,20 @@ exports.isRef = isRef;
exports.mixin = mixin;
exports.mpMixin = mpMixin;
exports.n = n;
+exports.nextTick$1 = nextTick$1;
exports.o = o;
exports.onHide = onHide;
exports.onLaunch = onLaunch;
exports.onLoad = onLoad;
exports.onMounted = onMounted;
exports.onPageScroll = onPageScroll;
+exports.onPullDownRefresh = onPullDownRefresh;
exports.onReachBottom = onReachBottom;
exports.onShareAppMessage = onShareAppMessage;
exports.onShareTimeline = onShareTimeline;
exports.onShow = onShow;
exports.onUnload = onUnload;
+exports.onUnmounted = onUnmounted;
exports.openType = openType;
exports.p = p;
exports.props = props$k;
diff --git a/dist/dev/mp-weixin/pages/ai/chat.js b/dist/dev/mp-weixin/pages/ai/chat.js
new file mode 100644
index 0000000..30a3801
--- /dev/null
+++ b/dist/dev/mp-weixin/pages/ai/chat.js
@@ -0,0 +1,926 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+require("../../common/libraries/request.js");
+const common_store_useWeAppAuthStore = require("../../common/store/useWeAppAuthStore.js");
+require("../../common/store/useWorkStore.js");
+const common_libraries_upload = require("../../common/libraries/upload.js");
+require("../../gen/Apis.js");
+require("../../common/libraries/setTabBar.js");
+require("../../common/libraries/apiLoading.js");
+if (!Array) {
+ const _easycom_uni_icons2 = common_vendor.resolveComponent("uni-icons");
+ _easycom_uni_icons2();
+}
+const _easycom_uni_icons = () => "../../uni_modules/uni-icons/components/uni-icons/uni-icons.js";
+if (!Math) {
+ _easycom_uni_icons();
+}
+const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
+ __name: "chat",
+ setup(__props) {
+ common_vendor.dayjs.extend(common_vendor.relativeTime);
+ common_vendor.dayjs.locale("zh-cn");
+ const auth = common_store_useWeAppAuthStore.useWeAppAuthStore();
+ const inputMessage = common_vendor.ref("");
+ const selectedImages = common_vendor.ref([]);
+ const isInputFocused = common_vendor.ref(false);
+ const messages = common_vendor.ref([
+ {
+ role: "ai",
+ content: "您好!我是物业客服,有什么可以帮助您的吗?",
+ quickQuestions: []
+ }
+ ]);
+ const loading = common_vendor.ref(false);
+ const loadingText = common_vendor.ref("正在输入中...");
+ let socketTask = null;
+ let isConnected = common_vendor.ref(false);
+ const API_BASE_URL = "https://kf-api-test.linyikj.com.cn";
+ const WS_BASE_URL = "wss://kf-api-test.linyikj.com.cn";
+ const currentPage = common_vendor.ref(1);
+ const pageSize = common_vendor.ref(10);
+ const hasMore = common_vendor.ref(true);
+ const isLoadingHistory = common_vendor.ref(false);
+ const conversationId = common_vendor.ref("");
+ const currentOffset = common_vendor.ref(0);
+ const quickQuestionsData = common_vendor.ref([]);
+ const lastMessageContent = common_vendor.ref("");
+ const getQuickQuestions = async () => {
+ try {
+ const response = await common_vendor.index.request({
+ url: `${API_BASE_URL}/api/public/quick-questions`,
+ method: "GET"
+ });
+ if (response.statusCode === 200) {
+ const result = response.data;
+ let quickQuestions = [];
+ if (result.data && Array.isArray(result.data)) {
+ quickQuestions = result.data.map(
+ (item) => item.question || item.title || item.text || item
+ );
+ } else if (result.questions && Array.isArray(result.questions)) {
+ quickQuestions = result.questions.map(
+ (item) => item.question || item.title || item.text || item
+ );
+ } else if (Array.isArray(result)) {
+ quickQuestions = result.map((item) => item.question || item.title || item.text || item);
+ }
+ console.log("获取到开场白按钮数据:", quickQuestions);
+ return quickQuestions;
+ } else {
+ console.error("获取开场白数据失败,状态码:", response.statusCode);
+ return [];
+ }
+ } catch (error) {
+ console.error("获取开场白数据异常:", error);
+ return [];
+ }
+ };
+ const formatMessageContent = (content) => {
+ if (!content || typeof content !== "string") {
+ return [""];
+ }
+ return content.split("\n").filter((line) => line.trim() !== "");
+ };
+ const previewImage = (currentImage, images) => {
+ common_vendor.index.previewImage({
+ current: currentImage,
+ urls: images
+ });
+ };
+ const copyMessage = (content) => {
+ if (!content) {
+ common_vendor.index.showToast({
+ title: "暂无内容可复制",
+ icon: "none"
+ });
+ return;
+ }
+ common_vendor.index.setClipboardData({
+ data: content,
+ success: () => {
+ common_vendor.index.showToast({
+ title: "复制成功",
+ icon: "success"
+ });
+ },
+ fail: () => {
+ common_vendor.index.showToast({
+ title: "复制失败",
+ icon: "none"
+ });
+ }
+ });
+ };
+ const formatTime = (timeStr) => {
+ if (!timeStr)
+ return "";
+ try {
+ const date = common_vendor.dayjs(timeStr);
+ if (!date.isValid()) {
+ return "";
+ }
+ return date.fromNow();
+ } catch (e) {
+ console.error("时间格式化错误:", e);
+ return "";
+ }
+ };
+ const scrollToBottom = () => {
+ common_vendor.nextTick$1(() => {
+ common_vendor.index.pageScrollTo({
+ scrollTop: 999999,
+ duration: 300
+ });
+ });
+ };
+ const getHistoryMessages = async (page = 1) => {
+ var _a, _b;
+ const userPhone = (_b = (_a = auth.data) == null ? void 0 : _a.user) == null ? void 0 : _b.phone;
+ if (!userPhone) {
+ console.log("用户未登录,无法获取历史记录");
+ return;
+ }
+ if (isLoadingHistory.value) {
+ return;
+ }
+ try {
+ isLoadingHistory.value = true;
+ const offset = (page - 1) * pageSize.value;
+ currentOffset.value = offset;
+ console.log("分页信息 - 页码:", page, "每页数量:", pageSize.value, "计算出的offset:", offset);
+ const response = await common_vendor.index.request({
+ url: `${API_BASE_URL}/api/public/customer/init`,
+ method: "POST",
+ data: {
+ platform: "property",
+ platform_user_id: userPhone,
+ //userPhone
+ limit: pageSize.value,
+ offset
+ }
+ });
+ if (response.statusCode === 200) {
+ const result = response.data;
+ let historyMessages = [];
+ if (result.conversation && result.conversation.id) {
+ conversationId.value = result.conversation.id;
+ console.log("获取到会话ID:", conversationId.value);
+ } else if (result.conversation_id) {
+ conversationId.value = result.conversation_id;
+ console.log("获取到会话ID:", conversationId.value);
+ } else if (result.conversations && result.conversations.id) {
+ conversationId.value = result.conversations.id;
+ console.log("获取到会话ID:", conversationId.value);
+ }
+ if (result.messages && Array.isArray(result.messages)) {
+ historyMessages = result.messages.map((item) => {
+ const message = {
+ role: item.sender_type === "customer" ? "user" : "ai",
+ content: item.message || item.content || "",
+ created_at: item.created_at || item.timestamp || new Date().toISOString()
+ };
+ if (item.message_type) {
+ message.message_type = item.message_type;
+ }
+ let imageUrlData = null;
+ if (item.image_url && Array.isArray(item.image_url)) {
+ imageUrlData = item.image_url;
+ } else if (item.images && Array.isArray(item.images)) {
+ imageUrlData = item.images;
+ } else if (item.metadata && item.metadata.image_url && Array.isArray(item.metadata.image_url)) {
+ imageUrlData = item.metadata.image_url;
+ }
+ if (imageUrlData) {
+ message.image_url = imageUrlData;
+ message.images = imageUrlData;
+ }
+ if (item.metadata) {
+ message.metadata = item.metadata;
+ }
+ return message;
+ });
+ console.log("从messages字段获取到历史记录:", historyMessages.length);
+ } else if (result.data && Array.isArray(result.data)) {
+ historyMessages = result.data.map((item) => {
+ const message = {
+ role: item.sender_type === "customer" ? "user" : "ai",
+ content: item.message || item.content || "",
+ created_at: item.created_at || item.timestamp || new Date().toISOString()
+ };
+ if (item.message_type) {
+ message.message_type = item.message_type;
+ }
+ let imageUrlData = null;
+ if (item.image_url && Array.isArray(item.image_url)) {
+ imageUrlData = item.image_url;
+ } else if (item.images && Array.isArray(item.images)) {
+ imageUrlData = item.images;
+ } else if (item.metadata && item.metadata.image_url && Array.isArray(item.metadata.image_url)) {
+ imageUrlData = item.metadata.image_url;
+ }
+ if (imageUrlData) {
+ message.image_url = imageUrlData;
+ message.images = imageUrlData;
+ }
+ if (item.metadata) {
+ message.metadata = item.metadata;
+ }
+ return message;
+ });
+ console.log("从data字段获取到历史记录:", historyMessages.length);
+ } else if (result.list && Array.isArray(result.list)) {
+ historyMessages = result.list.map((item) => {
+ const message = {
+ role: item.sender_type === "customer" ? "user" : "ai",
+ content: item.message || item.content || "",
+ created_at: item.created_at || item.timestamp || new Date().toISOString()
+ };
+ if (item.message_type) {
+ message.message_type = item.message_type;
+ }
+ let imageUrlData = null;
+ if (item.image_url && Array.isArray(item.image_url)) {
+ imageUrlData = item.image_url;
+ } else if (item.images && Array.isArray(item.images)) {
+ imageUrlData = item.images;
+ } else if (item.metadata && item.metadata.image_url && Array.isArray(item.metadata.image_url)) {
+ imageUrlData = item.metadata.image_url;
+ }
+ if (imageUrlData) {
+ message.image_url = imageUrlData;
+ message.images = imageUrlData;
+ }
+ if (item.metadata) {
+ message.metadata = item.metadata;
+ }
+ return message;
+ });
+ console.log("从list字段获取到历史记录:", historyMessages.length);
+ }
+ if (page === 1) {
+ if (historyMessages.length > 0) {
+ messages.value = historyMessages;
+ console.log("第一页历史记录已加载,总共", historyMessages.length, "条消息");
+ } else {
+ console.log("没有历史记录");
+ messages.value = [];
+ }
+ const isFirstPageLastPage = !hasMore.value;
+ if (checkShouldShowQuickQuestions(isFirstPageLastPage)) {
+ addQuickQuestionsToFirstAIMessage(isFirstPageLastPage);
+ }
+ } else {
+ if (historyMessages.length > 0) {
+ setTimeout(() => {
+ messages.value.unshift(...historyMessages);
+ console.log(
+ "加载更多历史记录,新增",
+ historyMessages.length,
+ "条消息,总共",
+ messages.value.length,
+ "条"
+ );
+ }, 300);
+ }
+ }
+ const totalItems = result.total || result.count || result.total_count || 0;
+ hasMore.value = totalItems > messages.value.length;
+ currentPage.value = page;
+ if (page > 1 && !hasMore.value) {
+ console.log("分页加载完成,当前页:", page, "hasMore:", hasMore.value, "展示开场白");
+ setTimeout(() => {
+ addQuickQuestionsToFirstAIMessage(true);
+ }, 500);
+ }
+ console.log(
+ "第",
+ page,
+ "页数据加载完成,offset:",
+ offset,
+ ", limit:",
+ pageSize.value,
+ ", 总数据:",
+ totalItems,
+ ", 当前已加载:",
+ messages.value.length,
+ ", 是否有更多:",
+ hasMore.value
+ );
+ if (page === 1) {
+ setTimeout(() => {
+ scrollToBottom();
+ }, 100);
+ console.log("[Customer] 历史记录加载完成,开始建立WebSocket连接");
+ initWebSocket();
+ }
+ } else {
+ console.error("获取历史记录失败,状态码:", response.statusCode);
+ }
+ } catch (error) {
+ console.error("获取历史记录异常:", error);
+ } finally {
+ isLoadingHistory.value = false;
+ }
+ };
+ common_vendor.onPullDownRefresh(async () => {
+ if (isLoadingHistory.value || !hasMore.value) {
+ console.log("正在加载或没有更多数据");
+ common_vendor.index.stopPullDownRefresh();
+ return;
+ }
+ console.log("触发下拉分页,加载更多历史记录");
+ const nextPage = currentPage.value + 1;
+ try {
+ await getHistoryMessages(nextPage);
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ } catch (error) {
+ console.error("加载历史记录失败:", error);
+ } finally {
+ common_vendor.index.stopPullDownRefresh();
+ }
+ });
+ const initWebSocket = () => {
+ if (socketTask) {
+ return;
+ }
+ try {
+ const wsUrl = `${WS_BASE_URL}/ws/socket.io/?EIO=4&transport=websocket`;
+ console.log("正在建立Socket.IO连接");
+ console.log("连接URL:", wsUrl);
+ socketTask = common_vendor.index.connectSocket({
+ url: wsUrl,
+ header: {
+ "content-type": "application/json"
+ }
+ });
+ common_vendor.index.onSocketOpen((res) => {
+ console.log("[Customer] WebSocket connected", res);
+ isConnected.value = true;
+ const connectPacket = '40/customer,{"jwt":""}';
+ common_vendor.index.sendSocketMessage({
+ data: connectPacket,
+ success: () => {
+ console.log("[Customer] Socket.IO连接包发送成功");
+ if (conversationId.value) {
+ setTimeout(() => {
+ const joinMessage = `42/customer,["join_conversation",{"conversation_id":"${conversationId.value}"}]`;
+ console.log("[Customer] 加入会话房间:", joinMessage);
+ common_vendor.index.sendSocketMessage({
+ data: joinMessage,
+ success: () => {
+ console.log("[Customer] 成功加入会话房间");
+ },
+ fail: (error) => {
+ console.error("[Customer] 加入会话房间失败:", error);
+ }
+ });
+ }, 200);
+ }
+ },
+ fail: (error) => {
+ console.error("[Customer] Socket.IO连接包发送失败:", error);
+ }
+ });
+ });
+ common_vendor.index.onSocketError((error) => {
+ console.error("[Customer] WebSocket error:", error);
+ isConnected.value = false;
+ socketTask = null;
+ });
+ common_vendor.index.onSocketClose((res) => {
+ console.log("[Customer] WebSocket disconnected", res);
+ isConnected.value = false;
+ socketTask = null;
+ });
+ common_vendor.index.onSocketMessage((res) => {
+ console.log("收到WebSocket原始消息:", res);
+ console.log("消息数据类型:", typeof res.data);
+ console.log("消息内容:", res.data);
+ const data = res.data;
+ if (typeof data === "string") {
+ if (data.startsWith("42/customer,")) {
+ const payload = data.substring("42/customer,".length);
+ try {
+ const parsedData = JSON.parse(payload);
+ console.log("解析Socket.IO事件:", parsedData);
+ handleSocketEvent(parsedData);
+ } catch (e) {
+ console.error("解析Socket.IO数据失败:", e, "原始数据:", payload);
+ }
+ } else if (data.startsWith("40/customer")) {
+ console.log("Socket.IO连接确认");
+ } else if (data.startsWith("2")) {
+ common_vendor.index.sendSocketMessage({
+ data: "3"
+ });
+ } else if (data.startsWith("0")) {
+ console.log("Socket.IO握手成功");
+ } else {
+ try {
+ const jsonData = JSON.parse(data);
+ console.log("解析JSON消息:", jsonData);
+ handleJsonMessage(jsonData);
+ } catch (e) {
+ console.log("非JSON格式的字符串消息:", data);
+ }
+ }
+ } else if (typeof data === "object") {
+ console.log("收到对象类型消息:", data);
+ handleObjectMessage(data);
+ } else {
+ console.log("收到其他类型消息,类型:", typeof data);
+ }
+ });
+ } catch (error) {
+ console.error("初始化Socket.IO异常:", error);
+ isConnected.value = false;
+ socketTask = null;
+ }
+ };
+ const handleSocketEvent = (parsedData) => {
+ if (Array.isArray(parsedData) && parsedData.length >= 2) {
+ const eventType = parsedData[0];
+ const eventData = parsedData[1];
+ console.log("[Customer] Socket.IO事件类型:", eventType, "事件数据:", eventData);
+ if (eventType === "new_message") {
+ processMessage(eventData);
+ } else if (eventType === "join_conversation_response") {
+ console.log("[Customer] Joined room:", eventData);
+ } else if (eventType === "message") {
+ processMessage(eventData);
+ } else if (eventType === "typing") {
+ processTypingIndicator(eventData);
+ } else {
+ console.log("[Customer] 未处理的Socket.IO事件类型:", eventType);
+ }
+ }
+ };
+ const handleJsonMessage = (jsonData) => {
+ console.log("[Customer] 处理JSON消息:", jsonData);
+ if (jsonData.type === "message" || jsonData.event === "new_message") {
+ processMessage(jsonData.data || jsonData);
+ } else if (jsonData.type === "typing" || jsonData.event === "typing") {
+ processTypingIndicator(jsonData.data || jsonData);
+ } else if (jsonData.message || jsonData.content) {
+ processMessage(jsonData);
+ } else {
+ console.log("[Customer] 未识别的JSON消息结构:", jsonData);
+ }
+ };
+ const handleObjectMessage = (objData) => {
+ console.log("[Customer] 处理对象消息:", objData);
+ if (objData.message || objData.content || objData.text) {
+ processMessage(objData);
+ } else if (objData.is_typing !== void 0) {
+ processTypingIndicator(objData);
+ } else {
+ console.log("[Customer] 未识别的对象消息结构:", objData);
+ }
+ };
+ const processTypingIndicator = (typingData) => {
+ console.log("[Customer] 处理typing指示器:", typingData);
+ if (typingData.is_typing && typingData.user_type === "staff") {
+ loading.value = true;
+ loadingText.value = "客服正在输入...";
+ } else {
+ loading.value = false;
+ }
+ };
+ const checkShouldShowQuickQuestions = (isLastPage = false) => {
+ if (quickQuestionsData.value.length === 0) {
+ return false;
+ }
+ if (messages.value.length === 0) {
+ return true;
+ }
+ if (isLastPage && messages.value.length > 0) {
+ return true;
+ }
+ return false;
+ };
+ const addQuickQuestionsToFirstAIMessage = (isLastPage = false) => {
+ if (quickQuestionsData.value.length === 0) {
+ return;
+ }
+ if (!checkShouldShowQuickQuestions(isLastPage)) {
+ return;
+ }
+ const existingWelcomeMessage = messages.value.find(
+ (msg) => msg.role === "ai" && msg.quickQuestions && msg.quickQuestions.length > 0
+ );
+ if (existingWelcomeMessage) {
+ console.log("[Customer] 开场白已存在,跳过添加");
+ return;
+ }
+ const welcomeMessage = {
+ role: "ai",
+ content: "您好!我是物业客服,有什么可以帮助您的吗?",
+ quickQuestions: quickQuestionsData.value,
+ created_at: new Date().toISOString()
+ };
+ console.log("[Customer] 创建开场白消息,是否最后一页:", isLastPage);
+ if (messages.value.length === 0) {
+ messages.value = [welcomeMessage];
+ console.log("[Customer] 设置开场白为第一条消息");
+ } else if (isLastPage) {
+ messages.value.unshift(welcomeMessage);
+ console.log("[Customer] 已加载到最后一页,在第一条消息前面插入开场白");
+ }
+ };
+ const processMessage = (messageData) => {
+ console.log("[Customer] 处理消息数据:", messageData);
+ if (messageData.sender_type === "customer" || messageData.role === "user") {
+ console.log("[Customer] 过滤掉客户消息");
+ return;
+ }
+ let messageContent = "";
+ if (typeof messageData === "string") {
+ messageContent = messageData;
+ } else {
+ messageContent = messageData.message || messageData.content || messageData.text || messageData.body || "收到回复";
+ }
+ if (typeof messageContent === "string") {
+ messageContent = messageContent.replace(/↵/g, "\n").replace(/\\n/g, "\n");
+ }
+ console.log("[Customer] 收到新消息内容:", messageContent);
+ if (messageContent === lastMessageContent.value) {
+ console.log("[Customer] 消息与HTTP返回的消息相同,跳过显示");
+ lastMessageContent.value = "";
+ return;
+ }
+ loading.value = false;
+ const newMessage = {
+ role: "ai",
+ content: messageContent,
+ created_at: messageData.created_at || messageData.timestamp || messageData.time || new Date().toISOString()
+ };
+ if (messageData.suggested_questions && Array.isArray(messageData.suggested_questions) && messageData.suggested_questions.length > 0) {
+ newMessage.quickQuestions = messageData.suggested_questions;
+ } else if (messageData.quickQuestions && Array.isArray(messageData.quickQuestions) && messageData.quickQuestions.length > 0) {
+ newMessage.quickQuestions = messageData.quickQuestions;
+ }
+ if (messageData.need_confirmation !== void 0) {
+ newMessage.needConfirmation = messageData.need_confirmation;
+ }
+ if (messageData.confirmation_type !== void 0) {
+ newMessage.confirmationType = messageData.confirmation_type;
+ }
+ messages.value.push(newMessage);
+ scrollToBottom();
+ };
+ const handleQuickQuestion = (question) => {
+ inputMessage.value = question;
+ handleSendMessage();
+ };
+ const handleConfirmation = (message, confirmation) => {
+ if (message.selectedConfirmation !== void 0) {
+ return;
+ }
+ message.selectedConfirmation = confirmation;
+ setTimeout(() => {
+ inputMessage.value = confirmation;
+ handleSendMessage();
+ }, 300);
+ };
+ const chooseImage = async () => {
+ const maxImages = 9;
+ if (selectedImages.value.length >= maxImages) {
+ common_vendor.index.showToast({
+ title: "最多选择9张图片",
+ icon: "none"
+ });
+ return;
+ }
+ try {
+ const remainingCount = maxImages - selectedImages.value.length;
+ const uploadResult = await common_libraries_upload.upload(remainingCount, 2, ["image"]);
+ if (uploadResult && Array.isArray(uploadResult) && uploadResult.length > 0) {
+ const imageUrls = uploadResult.map((item) => item.url);
+ selectedImages.value.push(...imageUrls);
+ common_vendor.index.showToast({
+ title: "图片上传成功",
+ icon: "success"
+ });
+ }
+ } catch (error) {
+ console.error("选择图片失败:", error);
+ common_vendor.index.showToast({
+ title: "选择图片失败",
+ icon: "none"
+ });
+ }
+ };
+ const removeImage = (index) => {
+ selectedImages.value.splice(index, 1);
+ };
+ const handleSendMessage = async () => {
+ var _a, _b, _c, _d, _e, _f;
+ const message = inputMessage.value.trim();
+ const hasImages = selectedImages.value.length > 0;
+ if (!message && !hasImages || loading.value)
+ return;
+ const userPhone = (_b = (_a = auth.data) == null ? void 0 : _a.user) == null ? void 0 : _b.phone;
+ const projectId = (_d = (_c = auth.data) == null ? void 0 : _c.selected_house) == null ? void 0 : _d.asset_projects_id;
+ const projectName = (_f = (_e = auth.data) == null ? void 0 : _e.selected_house) == null ? void 0 : _f.full_name;
+ if (!userPhone || !projectId) {
+ common_vendor.index.showToast({
+ title: "请先登录并绑定房屋",
+ icon: "none"
+ });
+ return;
+ }
+ if (!isConnected.value) {
+ initWebSocket();
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
+ }
+ const uploadedImages = selectedImages.value;
+ let messageType = "text";
+ if (hasImages && message) {
+ messageType = "mixed";
+ } else if (hasImages && !message) {
+ messageType = "image";
+ }
+ const userMessage = {
+ role: "user",
+ content: message || "",
+ // 纯图片时传空字符串
+ created_at: new Date().toISOString(),
+ message_type: messageType,
+ image_url: uploadedImages.length > 0 ? uploadedImages : void 0,
+ images: uploadedImages.length > 0 ? uploadedImages : void 0
+ };
+ messages.value.push(userMessage);
+ inputMessage.value = "";
+ selectedImages.value = [];
+ scrollToBottom();
+ if (message && message.includes("查询")) {
+ loadingText.value = "正在查询中请稍后...";
+ } else {
+ loadingText.value = "正在输入中...";
+ }
+ loading.value = true;
+ try {
+ const response = await common_vendor.index.request({
+ url: `${API_BASE_URL}/api/public/chat`,
+ method: "POST",
+ data: {
+ platform: "property",
+ message: message || "",
+ // 纯图片时传空字符串
+ tenant_project_id: projectId,
+ tenant_project_name: projectName || "",
+ platform_user_id: userPhone,
+ conversation_id: conversationId.value,
+ message_type: messageType,
+ image_url: uploadedImages.length > 0 ? uploadedImages : void 0
+ },
+ header: {
+ "Content-Type": "application/json"
+ }
+ });
+ if (response.statusCode === 200) {
+ const result = response.data;
+ console.log("[Customer] HTTP接口响应数据:", result);
+ let httpReplyMessage = null;
+ let suggestedQuestions = [];
+ let needConfirmation = false;
+ let confirmationType = null;
+ if (result.reply && typeof result.reply === "string") {
+ httpReplyMessage = result.reply;
+ suggestedQuestions = result.suggested_questions || [];
+ needConfirmation = result.need_confirmation || false;
+ confirmationType = result.confirmation_type || null;
+ } else if (result.reply && result.reply.message) {
+ httpReplyMessage = result.reply.message;
+ suggestedQuestions = result.reply.suggested_questions || result.suggested_questions || [];
+ needConfirmation = result.reply.need_confirmation || result.need_confirmation || false;
+ confirmationType = result.reply.confirmation_type || result.confirmation_type || null;
+ } else if (result.reply && result.reply.content) {
+ httpReplyMessage = result.reply.content;
+ suggestedQuestions = result.reply.suggested_questions || result.suggested_questions || [];
+ needConfirmation = result.reply.need_confirmation || result.need_confirmation || false;
+ confirmationType = result.reply.confirmation_type || result.confirmation_type || null;
+ } else if (result.message) {
+ httpReplyMessage = result.message;
+ suggestedQuestions = result.suggested_questions || [];
+ needConfirmation = result.need_confirmation || false;
+ confirmationType = result.confirmation_type || null;
+ } else if (result.content) {
+ httpReplyMessage = result.content;
+ suggestedQuestions = result.suggested_questions || [];
+ needConfirmation = result.need_confirmation || false;
+ confirmationType = result.confirmation_type || null;
+ } else if (result.answer) {
+ httpReplyMessage = result.answer;
+ suggestedQuestions = result.suggested_questions || [];
+ needConfirmation = result.need_confirmation || false;
+ confirmationType = result.confirmation_type || null;
+ } else if (result.response) {
+ httpReplyMessage = result.response;
+ suggestedQuestions = result.suggested_questions || [];
+ needConfirmation = result.need_confirmation || false;
+ confirmationType = result.confirmation_type || null;
+ } else if (typeof result === "string") {
+ httpReplyMessage = result;
+ }
+ if (httpReplyMessage) {
+ console.log("[Customer] HTTP接口返回回答消息:", httpReplyMessage);
+ console.log("[Customer] 建议问题:", suggestedQuestions);
+ console.log("[Customer] 需要确认:", needConfirmation, "确认类型:", confirmationType);
+ let formattedMessage = httpReplyMessage;
+ if (typeof formattedMessage === "string") {
+ formattedMessage = formattedMessage.replace(/↵/g, "\n").replace(/\\n/g, "\n");
+ }
+ lastMessageContent.value = formattedMessage;
+ loading.value = false;
+ messages.value.push({
+ role: "ai",
+ content: formattedMessage,
+ created_at: new Date().toISOString(),
+ quickQuestions: suggestedQuestions.length > 0 ? suggestedQuestions : void 0,
+ needConfirmation,
+ confirmationType
+ });
+ scrollToBottom();
+ } else {
+ console.log("[Customer] 消息发送成功,等待WebSocket回复");
+ }
+ } else {
+ throw new Error("请求失败");
+ }
+ } catch (error) {
+ console.error("发送消息失败:", error);
+ common_vendor.index.showToast({
+ title: "发送失败,请稍后重试",
+ icon: "none"
+ });
+ messages.value.push({
+ role: "ai",
+ content: "抱歉,网络连接出现问题,请稍后再试。"
+ });
+ loading.value = false;
+ scrollToBottom();
+ }
+ };
+ common_vendor.onUnmounted(() => {
+ if (socketTask || isConnected.value) {
+ common_vendor.index.closeSocket();
+ socketTask = null;
+ isConnected.value = false;
+ console.log("页面卸载,WebSocket连接已关闭");
+ }
+ });
+ common_vendor.onLoad(async () => {
+ quickQuestionsData.value = await getQuickQuestions();
+ console.log("页面加载时已获取开场白按钮数据:", quickQuestionsData.value.length);
+ getHistoryMessages(1);
+ });
+ return (_ctx, _cache) => {
+ return common_vendor.e({
+ a: common_vendor.f(messages.value, (message, index, i0) => {
+ return common_vendor.e({
+ a: message.role === "ai"
+ }, message.role === "ai" ? {} : {}, {
+ b: message.image_url && message.image_url.length > 0
+ }, message.image_url && message.image_url.length > 0 ? {
+ c: common_vendor.f(message.image_url, (image, imgIndex, i1) => {
+ return {
+ a: image,
+ b: common_vendor.o(($event) => previewImage(image, message.image_url), imgIndex),
+ c: imgIndex
+ };
+ }),
+ d: message.image_url.length === 1 ? "widthFix" : "aspectFill",
+ e: message.image_url.length === 1 ? 1 : ""
+ } : message.images && message.images.length > 0 ? {
+ g: common_vendor.f(message.images, (image, imgIndex, i1) => {
+ return {
+ a: image,
+ b: common_vendor.o(($event) => previewImage(image, message.images), imgIndex),
+ c: imgIndex
+ };
+ }),
+ h: message.images.length === 1 ? "widthFix" : "aspectFill",
+ i: message.images.length === 1 ? 1 : ""
+ } : message.metadata && message.metadata.image_url && message.metadata.image_url.length > 0 ? {
+ k: common_vendor.f(message.metadata.image_url, (image, imgIndex, i1) => {
+ return {
+ a: image,
+ b: common_vendor.o(($event) => previewImage(image, message.metadata.image_url), imgIndex),
+ c: imgIndex
+ };
+ }),
+ l: message.metadata.image_url.length === 1 ? "widthFix" : "aspectFill",
+ m: message.metadata.image_url.length === 1 ? 1 : ""
+ } : {}, {
+ f: message.images && message.images.length > 0,
+ j: message.metadata && message.metadata.image_url && message.metadata.image_url.length > 0,
+ n: message.content && message.content.trim()
+ }, message.content && message.content.trim() ? {
+ o: common_vendor.f(formatMessageContent(message.content), (line, lineIndex, i1) => {
+ return {
+ a: common_vendor.t(line),
+ b: "text-" + lineIndex
+ };
+ })
+ } : {}, {
+ p: message.quickQuestions && message.quickQuestions.length > 0
+ }, message.quickQuestions && message.quickQuestions.length > 0 ? {
+ q: common_vendor.f(message.quickQuestions, (question, qIndex, i1) => {
+ return {
+ a: common_vendor.t(question),
+ b: qIndex,
+ c: common_vendor.o(($event) => handleQuickQuestion(question), qIndex)
+ };
+ })
+ } : {}, {
+ r: message.needConfirmation
+ }, message.needConfirmation ? {
+ s: message.selectedConfirmation === "是" ? 1 : "",
+ t: message.selectedConfirmation !== void 0 ? 1 : "",
+ v: common_vendor.o(($event) => handleConfirmation(message, "是"), index),
+ w: message.selectedConfirmation === "否" ? 1 : "",
+ x: message.selectedConfirmation !== void 0 ? 1 : "",
+ y: common_vendor.o(($event) => handleConfirmation(message, "否"), index)
+ } : {}, {
+ z: message.created_at && !message.quickQuestions
+ }, message.created_at && !message.quickQuestions ? common_vendor.e({
+ A: message.role === "ai"
+ }, message.role === "ai" ? {
+ B: common_vendor.o(($event) => copyMessage(message.content), index)
+ } : {}, {
+ C: common_vendor.t(formatTime(message.created_at)),
+ D: message.role === "user"
+ }, message.role === "user" ? {
+ E: common_vendor.o(($event) => copyMessage(message.content), index)
+ } : {}) : {}, {
+ F: index,
+ G: `msg-${index}`,
+ H: common_vendor.n(message.role === "user" ? "user-message" : "ai-message")
+ });
+ }),
+ b: loading.value
+ }, loading.value ? {
+ c: common_vendor.t(loadingText.value)
+ } : {}, {
+ d: selectedImages.value.length > 0
+ }, selectedImages.value.length > 0 ? common_vendor.e({
+ e: common_vendor.f(selectedImages.value, (image, index, i0) => {
+ return {
+ a: image,
+ b: "b15798f7-0-" + i0,
+ c: common_vendor.o(($event) => removeImage(index), index),
+ d: index
+ };
+ }),
+ f: common_vendor.p({
+ type: "closeempty",
+ size: "14",
+ color: "#fff"
+ }),
+ g: selectedImages.value.length < 9
+ }, selectedImages.value.length < 9 ? {
+ h: common_vendor.p({
+ type: "plus",
+ size: "30",
+ color: "#999"
+ }),
+ i: common_vendor.o(chooseImage)
+ } : {}) : {}, {
+ j: common_vendor.o(($event) => isInputFocused.value = true),
+ k: common_vendor.o(($event) => isInputFocused.value = false),
+ l: common_vendor.o(handleSendMessage),
+ m: inputMessage.value,
+ n: common_vendor.o(($event) => inputMessage.value = $event.detail.value),
+ o: !inputMessage.value.trim() && !isInputFocused.value && selectedImages.value.length === 0
+ }, !inputMessage.value.trim() && !isInputFocused.value && selectedImages.value.length === 0 ? {
+ p: common_vendor.p({
+ type: "camera",
+ size: "24",
+ color: "#666"
+ }),
+ q: common_vendor.o(chooseImage)
+ } : {}, {
+ r: (inputMessage.value.trim() || isInputFocused.value || selectedImages.value.length > 0) && !loading.value
+ }, (inputMessage.value.trim() || isInputFocused.value || selectedImages.value.length > 0) && !loading.value ? {
+ s: common_vendor.p({
+ type: "paperplane-filled",
+ size: "20",
+ color: "#fff"
+ }),
+ t: common_vendor.o(handleSendMessage)
+ } : {}, {
+ v: loading.value
+ }, loading.value ? {
+ w: common_vendor.p({
+ type: "spinner-cycle",
+ size: "20",
+ color: "#ccc"
+ })
+ } : {});
+ };
+ }
+});
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-b15798f7"], ["__file", "/Users/zsq/Sources/github/2025property-pay/pay-customer/src/pages/ai/chat.vue"]]);
+wx.createPage(MiniProgramPage);
diff --git a/dist/dev/mp-weixin/pages/ai/chat.json b/dist/dev/mp-weixin/pages/ai/chat.json
new file mode 100644
index 0000000..832d9d0
--- /dev/null
+++ b/dist/dev/mp-weixin/pages/ai/chat.json
@@ -0,0 +1,6 @@
+{
+ "navigationBarTitleText": "客服服务",
+ "usingComponents": {
+ "uni-icons": "../../uni_modules/uni-icons/components/uni-icons/uni-icons"
+ }
+}
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/ai/chat.wxml b/dist/dev/mp-weixin/pages/ai/chat.wxml
new file mode 100644
index 0000000..acf2ece
--- /dev/null
+++ b/dist/dev/mp-weixin/pages/ai/chat.wxml
@@ -0,0 +1 @@
+{{line.a}}{{question.a}}是否{{message.C}}{{c}}添加图片
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/ai/chat.wxss b/dist/dev/mp-weixin/pages/ai/chat.wxss
new file mode 100644
index 0000000..a777aed
--- /dev/null
+++ b/dist/dev/mp-weixin/pages/ai/chat.wxss
@@ -0,0 +1,375 @@
+.chat-container.data-v-b15798f7 {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ width: 100vw;
+ background-color: #f5f5f5;
+}
+.chat-messages.data-v-b15798f7 {
+ width: 100%;
+ padding: 30rpx 20rpx;
+ padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
+ box-sizing: border-box;
+ flex: 1;
+}
+.message-item.data-v-b15798f7 {
+ display: flex;
+ width: 100%;
+ box-sizing: border-box;
+ margin-bottom: 30rpx;
+ animation: fadeIn-b15798f7 0.3s ease-in;
+}
+.message-item.user-message.data-v-b15798f7 {
+ justify-content: flex-end;
+ align-items: flex-start;
+}
+.message-item.user-message .message-content-wrapper.data-v-b15798f7 {
+ align-items: flex-end;
+}
+.message-item.user-message .message-content.data-v-b15798f7 {
+ background-color: #1c64f2;
+ color: #fff;
+ margin-right: 0;
+ flex-shrink: 0;
+}
+.message-item.user-message .message-content .message-images.data-v-b15798f7 {
+ margin-bottom: 0;
+}
+.message-item.user-message .message-content .message-images .message-image-item.data-v-b15798f7 {
+ border-radius: 8rpx;
+}
+.message-item.user-message .message-time.data-v-b15798f7 {
+ color: #999;
+ font-size: 22rpx;
+ margin-top: 6rpx;
+ text-align: right;
+ min-width: 80rpx;
+}
+.message-item.user-message .message-meta.data-v-b15798f7 {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ margin-top: 6rpx;
+ gap: 8rpx;
+ flex-direction: row;
+}
+.message-item.ai-message.data-v-b15798f7 {
+ align-items: flex-start;
+}
+.message-item.ai-message .message-content-wrapper.data-v-b15798f7 {
+ align-items: flex-start;
+}
+.message-item.ai-message .message-content.data-v-b15798f7 {
+ background-color: #fff;
+ color: #333;
+ margin-left: 12rpx;
+ margin-right: 0;
+ flex-shrink: 0;
+}
+.message-item.ai-message .message-time.data-v-b15798f7 {
+ color: #999;
+ font-size: 22rpx;
+ min-width: 80rpx;
+}
+.message-item.ai-message .message-meta.data-v-b15798f7 {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ margin-top: 6rpx;
+ gap: 8rpx;
+ margin-left: 12rpx;
+ flex-direction: row;
+}
+.message-item.ai-message .message-avatar.data-v-b15798f7 {
+ margin-right: 0;
+ flex-shrink: 0;
+}
+@keyframes fadeIn-b15798f7 {
+from {
+ opacity: 0;
+ transform: translateY(10rpx);
+}
+to {
+ opacity: 1;
+ transform: translateY(0);
+}
+}
+.message-avatar.data-v-b15798f7 {
+ width: 60rpx;
+ height: 60rpx;
+ border-radius: 50%;
+ overflow: hidden;
+ flex-shrink: 0;
+}
+.message-avatar image.data-v-b15798f7 {
+ width: 100%;
+ height: 100%;
+}
+.message-avatar .user-avatar-image.data-v-b15798f7 {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+}
+.message-avatar .user-avatar.data-v-b15798f7 {
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-size: 24rpx;
+ font-weight: 500;
+}
+.message-content-wrapper.data-v-b15798f7 {
+ display: flex;
+ flex-direction: column;
+ max-width: calc(100vw - 100rpx);
+}
+.message-content.data-v-b15798f7 {
+ padding: 20rpx 24rpx;
+ border-radius: 16rpx;
+ font-size: 28rpx;
+ line-height: 1.5;
+ word-wrap: break-word;
+ word-break: break-all;
+ box-sizing: border-box;
+}
+.message-content.loading.data-v-b15798f7 {
+ opacity: 0.7;
+}
+.message-content.data-v-b15798f7:has(.message-images) {
+ padding: 12rpx;
+}
+.user-message .message-content.data-v-b15798f7:has(.message-images) {
+ padding: 8rpx;
+ background-color: transparent;
+}
+.message-content view.data-v-b15798f7 {
+ display: block;
+ width: 100%;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+.message-content view.data-v-b15798f7:not(:last-child) {
+ margin-bottom: 8rpx;
+}
+.message-content text.data-v-b15798f7 {
+ display: inline;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+.quick-questions.data-v-b15798f7 {
+ margin-top: 16rpx;
+ display: flex;
+ flex-direction: column;
+ gap: 12rpx;
+ padding-left: 12rpx;
+}
+.question-btn.data-v-b15798f7 {
+ background-color: #f0f7ff;
+ border: 1px solid #d0e3ff;
+ border-radius: 12rpx;
+ padding: 16rpx 20rpx;
+ font-size: 26rpx;
+ color: #1c64f2;
+ line-height: 1.4;
+ transition: all 0.2s ease;
+}
+.question-btn.data-v-b15798f7:active {
+ background-color: #e6f2ff;
+ transform: scale(0.98);
+}
+.question-btn text.data-v-b15798f7 {
+ display: block;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+.confirmation-buttons.data-v-b15798f7 {
+ margin-top: 16rpx;
+ display: flex;
+ gap: 16rpx;
+ justify-content: flex-start;
+ padding-left: 12rpx;
+}
+.confirmation-btn.data-v-b15798f7 {
+ width: 38rpx;
+ border-radius: 12rpx;
+ padding: 16rpx 32rpx;
+ font-size: 28rpx;
+ line-height: 1.4;
+ text-align: center;
+ transition: all 0.2s ease;
+ background-color: #fff;
+ color: #000;
+ border: 1px solid #e5e5e5;
+}
+.confirmation-btn.data-v-b15798f7:active:not(.disabled) {
+ transform: scale(0.98);
+}
+.confirmation-btn.selected.data-v-b15798f7 {
+ background-color: #1c64f2;
+ color: #fff;
+ border-color: #1c64f2;
+}
+.confirmation-btn.disabled.data-v-b15798f7 {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+.confirmation-btn text.data-v-b15798f7 {
+ display: block;
+ font-weight: 500;
+}
+.chat-input-area.data-v-b15798f7 {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: #fff;
+ border-top: 1px solid #e5e5e5;
+ padding: 20rpx 20rpx;
+ padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
+ z-index: 100;
+}
+.input-container.data-v-b15798f7 {
+ display: flex;
+ align-items: center;
+ background-color: #f5f5f5;
+ border-radius: 50rpx;
+ padding: 10rpx 20rpx;
+}
+.message-input.data-v-b15798f7 {
+ flex: 1;
+ height: 70rpx;
+ font-size: 28rpx;
+ padding: 0 20rpx;
+ background-color: transparent;
+}
+.send-button.data-v-b15798f7 {
+ width: 70rpx;
+ height: 70rpx;
+ background: linear-gradient(135deg, #1c64f2 0%, #0e4aa7 100%);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-left: 20rpx;
+}
+.send-button.disabled.data-v-b15798f7 {
+ opacity: 0.5;
+ pointer-events: none;
+}
+.upload-button.data-v-b15798f7 {
+ width: 70rpx;
+ height: 70rpx;
+ background-color: #f5f5f5;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-left: 20rpx;
+}
+.image-preview-area.data-v-b15798f7 {
+ margin-bottom: 20rpx;
+ padding: 0 20rpx;
+}
+.image-preview-list.data-v-b15798f7 {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+}
+.image-preview-item.data-v-b15798f7 {
+ position: relative;
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 12rpx;
+ overflow: hidden;
+}
+.image-preview-item.add-more-button.data-v-b15798f7 {
+ background-color: #f5f5f5;
+ border: 2rpx dashed #ddd;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+}
+.image-preview-item.add-more-button.data-v-b15798f7:active {
+ background-color: #e8e8e8;
+}
+.preview-image.data-v-b15798f7 {
+ width: 100%;
+ height: 100%;
+}
+.add-more-text.data-v-b15798f7 {
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 8rpx;
+}
+.remove-image.data-v-b15798f7 {
+ position: absolute;
+ top: 8rpx;
+ right: 8rpx;
+ width: 40rpx;
+ height: 40rpx;
+ background-color: rgba(0, 0, 0, 0.6);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.message-images.data-v-b15798f7 {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12rpx;
+ margin-bottom: 12rpx;
+ max-width: 500rpx;
+}
+.user-message .message-images.data-v-b15798f7 {
+ margin-bottom: 0;
+}
+.message-image-item.data-v-b15798f7 {
+ border-radius: 12rpx;
+ overflow: hidden;
+}
+.message-image-item.single-image.data-v-b15798f7 {
+ max-width: 500rpx;
+ width: 500rpx !important;
+ height: auto !important;
+}
+.user-message .message-image-item.single-image.data-v-b15798f7 {
+ max-width: 450rpx;
+ width: 450rpx !important;
+}
+.message-image-item.data-v-b15798f7:not(.single-image) {
+ width: 200rpx;
+ height: 200rpx;
+}
+.message-image.data-v-b15798f7 {
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+.message-text-line.data-v-b15798f7 {
+ margin-bottom: 4rpx;
+}
+.message-text-line.data-v-b15798f7:last-child {
+ margin-bottom: 0;
+}
+.copy-button.data-v-b15798f7 {
+ width: 32rpx;
+ height: 32rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4rpx;
+ transition: background-color 0.2s ease;
+}
+.copy-button.data-v-b15798f7:active {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+.copy-button .copy-icon.data-v-b15798f7 {
+ width: 26rpx;
+ height: 26rpx;
+ opacity: 0.7;
+}
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/ai/index.js b/dist/dev/mp-weixin/pages/ai/index.js
deleted file mode 100644
index e9078af..0000000
--- a/dist/dev/mp-weixin/pages/ai/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-"use strict";
-const common_vendor = require("../../common/vendor.js");
-require("../../common/libraries/request.js");
-require("../../common/store/useWeAppAuthStore.js");
-require("../../common/store/useWorkStore.js");
-require("../../gen/Apis.js");
-require("../../common/libraries/setTabBar.js");
-require("../../common/libraries/apiLoading.js");
-const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
- __name: "index",
- setup(__props) {
- common_vendor.onShow(async (e) => {
- const curPages = getCurrentPages()[0];
- if (typeof curPages.getTabBar === "function" && curPages.getTabBar()) {
- curPages.getTabBar().setData({
- selected: 1
- // 表示当前菜单的索引,该值在不同的页面表示不同
- });
- }
- });
- return (_ctx, _cache) => {
- return {};
- };
- }
-});
-const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__file", "/Users/zsq/Sources/github/2025property-pay/pay-customer/src/pages/ai/index.vue"]]);
-wx.createPage(MiniProgramPage);
diff --git a/dist/dev/mp-weixin/pages/ai/index.json b/dist/dev/mp-weixin/pages/ai/index.json
deleted file mode 100644
index ca79faf..0000000
--- a/dist/dev/mp-weixin/pages/ai/index.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "navigationBarTitleText": "智能管家",
- "usingComponents": {}
-}
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/ai/index.wxml b/dist/dev/mp-weixin/pages/ai/index.wxml
deleted file mode 100644
index 9966095..0000000
--- a/dist/dev/mp-weixin/pages/ai/index.wxml
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/ai/index.wxss b/dist/dev/mp-weixin/pages/ai/index.wxss
deleted file mode 100644
index c8f5c6f..0000000
--- a/dist/dev/mp-weixin/pages/ai/index.wxss
+++ /dev/null
@@ -1,26 +0,0 @@
-#dify-chatbot-bubble-button {
- background-color: #1c64f2 !important;
-}
-#dify-chatbot-bubble-window {
- width: 24rem !important;
- height: 40rem !important;
-}
-page {
- background-color: #f8f8f8;
-}
-.contact_btn {
- border: none !important;
- background-color: transparent;
- padding: 0;
- line-height: 1;
- color: inherit;
- font-size: inherit;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- outline: none;
- box-shadow: none;
-}
-button:after {
- border: none !important;
-}
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/index/components/AiInput.js b/dist/dev/mp-weixin/pages/index/components/AiInput.js
index e02c590..6c8ce93 100644
--- a/dist/dev/mp-weixin/pages/index/components/AiInput.js
+++ b/dist/dev/mp-weixin/pages/index/components/AiInput.js
@@ -1,6 +1,5 @@
"use strict";
const common_vendor = require("../../../common/vendor.js");
-const common_libraries_naviHelper = require("../../../common/libraries/naviHelper.js");
require("../../../common/libraries/getPageConfig.js");
require("../../../common/store/useWeAppAuthStore.js");
require("../../../gen/Apis.js");
@@ -20,16 +19,18 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
__name: "AiInput",
setup(__props) {
const handleInputChange = () => {
- common_libraries_naviHelper.showToast("该功能在当前项目暂未开放,敬请期待!");
+ common_vendor.index.navigateTo({
+ url: "/pages/ai/chat"
+ });
};
return (_ctx, _cache) => {
return {
- a: common_vendor.o(handleInputChange),
- b: common_vendor.p({
+ a: common_vendor.p({
type: "arrow-right",
size: "20",
color: "#666"
- })
+ }),
+ b: common_vendor.o(handleInputChange)
};
};
}
diff --git a/dist/dev/mp-weixin/pages/index/components/AiInput.wxml b/dist/dev/mp-weixin/pages/index/components/AiInput.wxml
index 6cf4ab7..4dbddc8 100644
--- a/dist/dev/mp-weixin/pages/index/components/AiInput.wxml
+++ b/dist/dev/mp-weixin/pages/index/components/AiInput.wxml
@@ -1 +1 @@
-
\ No newline at end of file
+ 点击联系在线客服
\ No newline at end of file
diff --git a/dist/dev/mp-weixin/pages/index/components/AiInput.wxss b/dist/dev/mp-weixin/pages/index/components/AiInput.wxss
index d4ec827..f96e216 100644
--- a/dist/dev/mp-weixin/pages/index/components/AiInput.wxss
+++ b/dist/dev/mp-weixin/pages/index/components/AiInput.wxss
@@ -42,8 +42,8 @@
justify-content: space-between;
background-color: #fff;
border-radius: 100rpx;
- padding: 0 20rpx;
- width: 100%;
+ padding: 15rpx 20rpx;
+ margin: 5rpx 30rpx;
}
.ai_contents .ai_contents_input .ai_input.data-v-b68fefb8 {
flex: 1;
diff --git a/dist/dev/mp-weixin/static/svg/copy.svg b/dist/dev/mp-weixin/static/svg/copy.svg
new file mode 100644
index 0000000..a89dd25
--- /dev/null
+++ b/dist/dev/mp-weixin/static/svg/copy.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/pages.json b/src/pages.json
index b59f5b5..10e7f8f 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -35,9 +35,9 @@
}
},
{
- "path": "pages/ai/index",
+ "path": "pages/ai/chat",
"style": {
- "navigationBarTitleText": "智能管家"
+ "navigationBarTitleText": "客服服务"
}
},
{
diff --git a/src/pages/index/components/AiInput.vue b/src/pages/index/components/AiInput.vue
index a8aa2dc..4757f6d 100644
--- a/src/pages/index/components/AiInput.vue
+++ b/src/pages/index/components/AiInput.vue
@@ -5,20 +5,16 @@
HI,遇到什么问题了,可以问我哦~
-
+