Files
zyt/server/public/admin/assets/qywx-BfvccofO.js
T
2026-04-21 18:02:27 +08:00

2 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{K as Mt,J as Ht,T as Kt,i as Bt,D as Ft,B as Ot,C as Rt,M as Gt,N as Jt,q as Qt,r as Wt,L as Xt,g as Yt,P as Zt,Q as te,V as ee,ab as le,ac as se,R as ae,e as ne,a9 as oe,aa as ie}from"./element-plus-B0TQYp6r.js";import{_ as re}from"./index.vue_vue_type_script_setup_true_lang-CwcSYDOM.js";import{w as mt}from"./@vue/runtime-dom-iFk_KP8y.js";import{X as ue,K as ct,S as de}from"./@element-plus/icons-vue-BAMXcVym.js";import{u as me}from"./usePaging-B_C_SZ2Z.js";import{r as C,i as A,_ as ce}from"./index-FMAV3lC6.js";import{f as fe,b as _e,d as pe,ak as m,I as f,a as l,aN as s,J as o,H as T,F as U,ap as j,O as i,aP as ye,G as h,A as Z}from"./@vue/runtime-core-C0pg79pw.js";import{r as M,y as p,a as ge,o as N}from"./@vue/reactivity-BIbyPIZJ.js";import{Q as r,p as ve,o as xe}from"./@vue/shared-mAAVTE9n.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./lodash-D3kF6u-c.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-CYz6RFzi.js";import"./pinia-Ba_jX6-d.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-DIKi2bJB.js";import"./@vueuse/shared-D8934tfB.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CZvD9OL_.js";import"./tslib-BDyQ-Jie.js";import"./zrender-BQyIY4j9.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-BVMzZUvF.js";function be(E){return C.get({url:"/qywx.customer/lists",params:E})}function we(){return C.post({url:"/qywx.customer/sync"})}function Se(){return C.get({url:"/qywx.customer/stats"})}function he(){return C.get({url:"/qywx.customer/todayArrival"})}function ke(E){return C.get({url:"/qywx.customer/todayArrivalList",params:E})}function Ce(){return C.get({url:"/qywx.customer/getSyncSettings"})}function Ee(E){return C.post({url:"/qywx.customer/saveSyncSettings",params:E})}const Ve={class:"qywx-customer-page p-4"},Ae={class:"flex items-center justify-between"},Te={class:"flex gap-2"},Ne={class:"grid grid-cols-4 gap-4 mb-4"},qe={class:"text-2xl font-bold text-primary"},ze={class:"flex items-center justify-between mb-1"},Ie={key:0,class:"text-xs text-gray-400"},De={class:"flex items-end gap-2"},$e={class:"text-2xl font-bold text-success leading-none"},Le=["title"],Pe={class:"mt-2 pt-2 border-t border-gray-100"},Ue={class:"text-lg font-semibold text-gray-800"},je={class:"text-sm font-medium"},Me={class:"flex items-center gap-2"},He={class:"font-medium"},Ke={class:"text-xs text-gray-400"},Be={key:0},Fe={key:1,class:"text-gray-400"},Oe={class:"flex justify-end mt-4"},Re={class:"flex items-center justify-between w-full pr-4"},Ge={class:"flex items-center gap-3"},Je={class:"px-1"},Qe={key:0,class:"mb-3"},We={class:"flex flex-wrap gap-1"},Xe={class:"flex items-start gap-2"},Ye={class:"flex-1 min-w-0"},Ze={class:"text-sm font-medium truncate"},tl={class:"text-xs text-gray-500 mt-0.5"},el={key:0,class:"ml-2"},ll={key:1,class:"ml-2 text-emerald-500"},sl={key:3,class:"mt-3 text-center"},al={key:0},nl={key:1,class:"text-gray-400"},ol=fe({__name:"qywx",setup(E){const q=N(!1),z=N(!1),J=N(!1),_=N(null),x=M({total:0,today:0,today_follow_staff:0,lastSync:"",syncStatus:"idle",syncStatusText:"未同步"}),ft=Z(()=>{switch(x.syncStatus){case"success":return"success";case"syncing":return"warning";case"failed":return"danger";default:return"info"}}),y=M({auto_sync:!1,interval:3600}),S=M({name:"",follow_user:""}),g=M({total:0,recent_time:0,hourly:new Array(24).fill(0),by_state:[]}),I=N(!1),H=N(!1),c=M({total:0,page_no:1,page_size:20,lists:[]}),_t=new Date().getHours(),pt=Z(()=>Math.max(1,...g.hourly));function yt(e){if(e<=0)return"2px";const t=e/pt.value;return Math.max(4,Math.round(t*32))+"px"}const gt=Z(()=>{const e=[];return g.hourly.forEach((t,n)=>{t>0&&e.push(`${String(n).padStart(2,"0")}:00 · ${t}`)}),e.length?e.join(" "):"今天还没有人进入"});async function K(e=!1){try{const t=await he();t&&(g.total=Number(t.total??0),g.recent_time=Number(t.recent_time??0),g.hourly=Array.isArray(t.hourly)&&t.hourly.length===24?t.hourly.map(n=>Number(n)||0):new Array(24).fill(0),g.by_state=Array.isArray(t.by_state)?t.by_state:[])}catch(t){console.error("加载今日进入分布失败",t)}e&&I.value&&(c.page_no=1,c.lists=[],await Q())}async function Q(){H.value=!0;try{const e=await ke({page_no:c.page_no,page_size:c.page_size});if(e){c.total=Number(e.total??0);const t=Array.isArray(e.lists)?e.lists:[];c.page_no===1?c.lists=t:c.lists.push(...t)}}catch(e){console.error("加载今日进入明细失败",e)}finally{H.value=!1}}async function tt(){I.value=!0,c.page_no=1,c.lists=[],await Promise.all([K(!1),Q()])}async function vt(){c.lists.length>=c.total||(c.page_no+=1,await Q())}function xt(e){if(!e||e<=0)return"";const t=new Date(e<1e12?e*1e3:e);return`${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}function bt(e){if(!e||e<=0)return"—";const t=new Date(e<1e12?e*1e3:e);return`${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}:${String(t.getSeconds()).padStart(2,"0")}`}let D=null,B=null;function W(){B!==null&&(clearInterval(B),B=null)}async function wt(e){return be(e)}const{pager:$,getLists:F,resetPage:X,resetParams:St}=me({fetchFun:wt,params:S});function ht(){S.name="",S.follow_user="",St()}function kt(){W();let e=0;B=window.setInterval(async()=>{e+=1,await O(),await F(),(x.syncStatus!=="syncing"||e>=120)&&(W(),q.value=!1,e>=120&&x.syncStatus==="syncing"?A.msgWarning("长时间仍为「同步中」,请刷新页面或查看服务器 runtime/log/qywx_sync.log(可能未安装 CLI php 或禁用了 exec"):x.syncStatus==="failed"&&A.msgError("同步失败,请查看服务器 runtime/log/qywx_sync.log 或后台同步状态"))},3e3)}async function et(e){const t=(e==null?void 0:e.silent)===!0;q.value=!0;try{const n=await we();t||A.msgSuccess((n==null?void 0:n.message)||"操作成功"),await O(),await F(),n!=null&&n.background?kt():q.value=!1}catch(n){const d=(n==null?void 0:n.message)||(n==null?void 0:n.msg)||"同步失败";(!t||!String(d).includes("正在执行"))&&A.msgError(d),q.value=!1}}async function O(){try{const e=await Se();e&&typeof e=="object"&&Object.assign(x,e)}catch(e){console.error("加载统计失败",e)}}async function Ct(){try{const e=await Ce();e&&typeof e=="object"&&Object.assign(y,e),y.auto_sync&&lt()}catch(e){console.error("加载同步设置失败",e)}}async function Et(){try{await Ee(y),A.msgSuccess("保存成功"),z.value=!1,st(),y.auto_sync&&lt()}catch(e){A.msgError((e==null?void 0:e.message)||"保存失败")}}function lt(){D||(D=window.setInterval(()=>{et({silent:!0})},y.interval*1e3))}function st(){D&&(clearInterval(D),D=null)}function Vt(e){_.value=e,J.value=!0}function at(e){const t=String((e==null?void 0:e.admin_name)??"").trim(),n=String((e==null?void 0:e.userid)??"").trim(),d=String((e==null?void 0:e.name)??"").trim();return t||(d&&n?`${d}${n}`:d||n||"—")}function R(e){const t=String((e==null?void 0:e.admin_name)??"").trim(),n=String((e==null?void 0:e.userid)??"").trim(),d=[];return t&&d.push("后台:"+t),n&&d.push("企微:"+n),d.join("")}function nt(e){if(!e)return null;const t=Number(e.external_first_add_time??0);if(t>0)return t;const n=e.follow_users;if(Array.isArray(n)&&n.length>0){let d=0;for(const b of n){const v=Number((b==null?void 0:b.createtime)??0);v>0&&(d===0||v<d)&&(d=v)}if(d>0)return d}return e.create_time??null}function G(e){if(e===""||e===null||e===void 0)return"—";const t=Number(e),n=typeof e=="string"&&/^\d+$/.test(e.trim());let d;return typeof e=="number"?d=e<1e12?e*1e3:e:!Number.isNaN(t)&&n?d=t<1e12?t*1e3:t:d=new Date(e).getTime(),Number.isNaN(d)?"—":new Date(d).toLocaleString("zh-CN")}let L=null;function At(){L===null&&(L=window.setInterval(()=>{O(),K(I.value)},3e4))}function Tt(){L!==null&&(clearInterval(L),L=null)}return _e(()=>{F(),O(),Ct(),K(!1),At()}),pe(()=>{st(),W(),Tt()}),(e,t)=>{const n=Bt,d=Mt,b=Ht,v=Kt,ot=Rt,P=Ot,it=Ft,rt=Qt,k=Jt,ut=Wt,Nt=Gt,qt=re,zt=Yt,V=te,It=Zt,dt=ee,Dt=se,$t=le,Lt=ae,Pt=ne,w=ie,Ut=oe,jt=Xt;return m(),f("div",Ve,[l(b,{shadow:"never",class:"mb-4"},{header:s(()=>[o("div",Ae,[t[15]||(t[15]=o("span",{class:"text-lg font-semibold"},"企业微信客户管理",-1)),o("div",Te,[l(n,{type:"success",plain:"",onClick:tt},{icon:s(()=>[l(p(ue))]),default:s(()=>[t[12]||(t[12]=i(" 今日进入明细 ",-1))]),_:1}),l(n,{type:"primary",loading:q.value,onClick:t[0]||(t[0]=a=>et())},{icon:s(()=>[l(p(ct))]),default:s(()=>[t[13]||(t[13]=i(" 立即同步 ",-1))]),_:1},8,["loading"]),l(n,{onClick:t[1]||(t[1]=a=>z.value=!0)},{icon:s(()=>[l(p(de))]),default:s(()=>[t[14]||(t[14]=i(" 同步设置 ",-1))]),_:1})])])]),default:s(()=>[l(d,{title:"功能说明",type:"info",closable:!1,class:"mb-4"},{default:s(()=>[...t[16]||(t[16]=[o("div",{class:"text-sm"},[o("p",null,"自动从企业微信同步外部联系人(客户)信息,包括客户基本信息、跟进人等。"),o("p",{class:"mt-1"},"同步后的数据可用于患者信息匹配和自动关联。")],-1)])]),_:1}),o("div",Ne,[l(b,{shadow:"hover"},{default:s(()=>[t[17]||(t[17]=o("div",{class:"text-gray-500 text-sm mb-1"},"总客户数",-1)),o("div",qe,r(x.total),1)]),_:1}),l(b,{shadow:"hover",class:"today-arrival-card cursor-pointer",onClick:tt},{default:s(()=>[o("div",ze,[t[18]||(t[18]=o("span",{class:"text-gray-500 text-sm"},"今日新增",-1)),g.recent_time?(m(),f("span",Ie," 最近 "+r(xt(g.recent_time)),1)):T("",!0)]),o("div",De,[o("div",$e,r(x.today),1),t[19]||(t[19]=o("div",{class:"text-xs text-gray-400 pb-1"},"人",-1))]),o("div",{class:"hourly-bars mt-2",title:gt.value},[(m(!0),f(U,null,j(g.hourly,(a,u)=>(m(),f("div",{key:u,class:xe(["hourly-bar",{"is-empty":a===0,"is-current":u===p(_t)}]),style:ve({height:yt(a)})},null,6))),128))],8,Le),o("div",Pe,[t[20]||(t[20]=o("div",{class:"text-gray-500 text-xs mb-0.5"},"今日跟进人合计",-1)),o("div",Ue,r(x.today_follow_staff),1)])]),_:1}),l(b,{shadow:"hover"},{default:s(()=>[t[21]||(t[21]=o("div",{class:"text-gray-500 text-sm mb-1"},"最后同步",-1)),o("div",je,r(x.lastSync||"未同步"),1)]),_:1}),l(b,{shadow:"hover"},{default:s(()=>[t[22]||(t[22]=o("div",{class:"text-gray-500 text-sm mb-1"},"同步状态",-1)),l(v,{type:ft.value,size:"small"},{default:s(()=>[i(r(x.syncStatusText),1)]),_:1},8,["type"])]),_:1})])]),_:1}),l(b,{shadow:"never"},{default:s(()=>[l(it,{model:S,inline:"",class:"mb-4"},{default:s(()=>[l(P,{label:"客户名称"},{default:s(()=>[l(ot,{modelValue:S.name,"onUpdate:modelValue":t[2]||(t[2]=a=>S.name=a),placeholder:"搜索客户名称",clearable:"",onKeyup:mt(p(X),["enter"])},null,8,["modelValue","onKeyup"])]),_:1}),l(P,{label:"跟进人"},{default:s(()=>[l(ot,{modelValue:S.follow_user,"onUpdate:modelValue":t[3]||(t[3]=a=>S.follow_user=a),placeholder:"跟进人姓名",clearable:"",onKeyup:mt(p(X),["enter"])},null,8,["modelValue","onKeyup"])]),_:1}),l(P,null,{default:s(()=>[l(n,{type:"primary",onClick:p(X)},{default:s(()=>[...t[23]||(t[23]=[i("查询",-1)])]),_:1},8,["onClick"]),l(n,{onClick:ht},{default:s(()=>[...t[24]||(t[24]=[i("重置",-1)])]),_:1})]),_:1})]),_:1},8,["model"]),ye((m(),h(Nt,{data:p($).lists,stripe:""},{default:s(()=>[l(k,{label:"客户信息","min-width":"200"},{default:s(({row:a})=>[o("div",Me,[l(rt,{size:40,src:a.avatar},null,8,["src"]),o("div",null,[o("div",He,r(a.name),1),o("div",Ke,r(a.external_userid),1)])])]),_:1}),l(k,{label:"类型",width:"80"},{default:s(({row:a})=>[l(v,{size:"small"},{default:s(()=>[i(r(a.type===1?"微信":"企微"),1)]),_:2},1024)]),_:1}),l(k,{label:"性别",width:"60"},{default:s(({row:a})=>[i(r(a.gender===1?"男":a.gender===2?"女":"未知"),1)]),_:1}),l(k,{label:"跟进人","min-width":"150"},{default:s(({row:a})=>[a.follow_users&&a.follow_users.length?(m(),f("div",Be,[(m(!0),f(U,null,j(a.follow_users,(u,Y)=>(m(),h(ut,{key:(u.userid||"")+"-"+Y,disabled:!R(u),content:R(u),placement:"top"},{default:s(()=>[l(v,{size:"small",class:"mr-1 mb-1"},{default:s(()=>[i(r(at(u)),1)]),_:2},1024)]),_:2},1032,["disabled","content"]))),128))])):(m(),f("span",Fe,"—"))]),_:1}),l(k,{label:"添加时间",width:"160"},{default:s(({row:a})=>[i(r(G(nt(a))),1)]),_:1}),l(k,{label:"更新时间",width:"160"},{default:s(({row:a})=>[i(r(G(a.update_time)),1)]),_:1}),l(k,{label:"操作",width:"120",fixed:"right"},{default:s(({row:a})=>[l(n,{type:"primary",link:"",onClick:u=>Vt(a)},{default:s(()=>[...t[25]||(t[25]=[i("查看详情",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[jt,p($).loading]]),o("div",Oe,[l(qt,{modelValue:p($),"onUpdate:modelValue":t[4]||(t[4]=a=>ge($)?$.value=a:null),onChange:p(F)},null,8,["modelValue","onChange"])])]),_:1}),l(dt,{modelValue:z.value,"onUpdate:modelValue":t[8]||(t[8]=a=>z.value=a),title:"同步设置",width:"500px"},{footer:s(()=>[l(n,{onClick:t[7]||(t[7]=a=>z.value=!1)},{default:s(()=>[...t[27]||(t[27]=[i("取消",-1)])]),_:1}),l(n,{type:"primary",onClick:Et},{default:s(()=>[...t[28]||(t[28]=[i("保存",-1)])]),_:1})]),default:s(()=>[l(it,{model:y,"label-width":"120px"},{default:s(()=>[l(P,{label:"自动同步"},{default:s(()=>[l(zt,{modelValue:y.auto_sync,"onUpdate:modelValue":t[5]||(t[5]=a=>y.auto_sync=a)},null,8,["modelValue"]),t[26]||(t[26]=o("div",{class:"text-xs text-gray-400 mt-1"}," 开启后将定时自动同步企业微信客户数据 ",-1))]),_:1}),l(P,{label:"同步间隔"},{default:s(()=>[l(It,{modelValue:y.interval,"onUpdate:modelValue":t[6]||(t[6]=a=>y.interval=a),disabled:!y.auto_sync},{default:s(()=>[l(V,{label:"每小时",value:3600}),l(V,{label:"每2小时",value:7200}),l(V,{label:"每4小时",value:14400}),l(V,{label:"每6小时",value:21600}),l(V,{label:"每12小时",value:43200}),l(V,{label:"每天",value:86400})]),_:1},8,["modelValue","disabled"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"]),l(Pt,{modelValue:I.value,"onUpdate:modelValue":t[10]||(t[10]=a=>I.value=a),title:"今日进入明细",direction:"rtl",size:"520px","destroy-on-close":!1},{header:s(()=>[o("div",Re,[o("div",Ge,[t[29]||(t[29]=o("span",{class:"text-base font-semibold"},"今日进入明细",-1)),l(v,{type:"success",effect:"plain"},{default:s(()=>[i("共 "+r(c.total)+" 人",1)]),_:1})]),l(n,{link:"",type:"primary",loading:H.value,onClick:t[9]||(t[9]=a=>K(!0))},{icon:s(()=>[l(p(ct))]),default:s(()=>[t[30]||(t[30]=i(" 刷新 ",-1))]),_:1},8,["loading"])])]),default:s(()=>{var a;return[o("div",Je,[l(d,{type:"info",closable:!1,class:"mb-3","show-icon":""},{title:s(()=>[...t[31]||(t[31]=[o("span",{class:"text-xs"}," 一次推送 = 一个人进来;数据来源为企微回调流水表(INSERT IGNORE 幂等),与客户同步解耦,数字零误差。 ",-1)])]),_:1}),(a=g.by_state)!=null&&a.length?(m(),f("div",Qe,[t[32]||(t[32]=o("div",{class:"text-xs text-gray-500 mb-1"},"今日推广渠道 Top",-1)),o("div",We,[(m(!0),f(U,null,j(g.by_state,u=>(m(),h(v,{key:u.state||"_",size:"small",effect:"light",type:"success"},{default:s(()=>[i(r(u.state||"(无 state")+" · "+r(u.count),1)]),_:2},1024))),128))])])):T("",!0),c.lists.length?(m(),h($t,{key:1,class:"mt-2"},{default:s(()=>[(m(!0),f(U,null,j(c.lists,u=>(m(),h(Dt,{key:u.id,timestamp:bt(u.event_time),placement:"top",type:"success",hollow:!1},{default:s(()=>[o("div",Xe,[l(rt,{size:32,src:u.customer_avatar||void 0},{default:s(()=>[i(r((u.customer_name||"?").slice(0,1)),1)]),_:2},1032,["src"]),o("div",Ye,[o("div",Ze,r(u.customer_name||u.external_userid||"(未知客户)"),1),o("div",tl,[o("span",null,"接待:"+r(u.admin_name||u.user_id||"—"),1),u.state?(m(),f("span",el,[t[33]||(t[33]=i(" 渠道:",-1)),l(v,{size:"small",type:"info",effect:"plain"},{default:s(()=>[i(r(u.state),1)]),_:2},1024)])):T("",!0),u.welcome_code?(m(),f("span",ll,"欢迎语")):T("",!0)])])])]),_:2},1032,["timestamp"]))),128))]),_:1})):(m(),h(Lt,{key:2,description:"今天还没有人进入","image-size":80})),c.total>c.lists.length?(m(),f("div",sl,[l(n,{loading:H.value,size:"small",onClick:vt},{default:s(()=>[i(" 加载更多(还剩 "+r(c.total-c.lists.length)+" ",1)]),_:1},8,["loading"])])):T("",!0)])]}),_:1},8,["modelValue"]),l(dt,{modelValue:J.value,"onUpdate:modelValue":t[11]||(t[11]=a=>J.value=a),title:"客户详情",width:"600px"},{default:s(()=>[_.value?(m(),h(Ut,{key:0,column:2,border:""},{default:s(()=>[l(w,{label:"客户名称"},{default:s(()=>[i(r(_.value.name),1)]),_:1}),l(w,{label:"External ID"},{default:s(()=>[i(r(_.value.external_userid),1)]),_:1}),l(w,{label:"性别"},{default:s(()=>[i(r(_.value.gender===1?"男":_.value.gender===2?"女":"未知"),1)]),_:1}),l(w,{label:"类型"},{default:s(()=>[i(r(_.value.type===1?"微信用户":"企业微信用户"),1)]),_:1}),l(w,{label:"企业名称",span:2},{default:s(()=>[i(r(_.value.corp_name||"—"),1)]),_:1}),l(w,{label:"职位",span:2},{default:s(()=>[i(r(_.value.position||"—"),1)]),_:1}),l(w,{label:"添加时间",span:2},{default:s(()=>[i(r(G(nt(_.value))),1)]),_:1}),l(w,{label:"更新时间",span:2},{default:s(()=>[i(r(G(_.value.update_time)),1)]),_:1}),l(w,{label:"跟进人",span:2},{default:s(()=>{var a;return[(a=_.value.follow_users)!=null&&a.length?(m(),f("div",al,[(m(!0),f(U,null,j(_.value.follow_users,(u,Y)=>(m(),h(ut,{key:(u.userid||"")+"-"+Y,disabled:!R(u),content:R(u),placement:"top"},{default:s(()=>[l(v,{size:"small",class:"mr-1 mb-1"},{default:s(()=>[i(r(at(u)),1)]),_:2},1024)]),_:2},1032,["disabled","content"]))),128))])):(m(),f("span",nl,"—"))]}),_:1})]),_:1})):T("",!0)]),_:1},8,["modelValue"])])}}}),Rl=ce(ol,[["__scopeId","data-v-80cc5404"]]);export{Rl as default};