Files
zyt/server/public/admin/assets/index-B0TIOqJT.js
T
2026-08-05 11:55:10 +08:00

4 lines
16 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{o as K,ap as pe,ac as ve,bi as be,q as r,r as u,s as e,v as o,D as d,u as _,cF as fe,w as he,cO as ge,L as v,T as a,P as S,by as ye,K as ke,bz as we,cP as Ne,bK as xe,F as N,G as $,O as z,bn as Ce,bm as $e,ae as x,ce as De,cl as Ve,cE as Le,cQ as Se,at as q,t as F,bB as Ee,cJ as Me,cR as ze,bk as Fe,bj as Oe,cg as Re,ba as G,M as O,p as D,E as I}from"./.pnpm-Bie2Sx_u.js";import{a as Te}from"./first_visit-QY1EjRaI.js";import{_ as Ue}from"./index-BwhoO6F6.js";const Be={class:"doctor-dashboard","element-loading-text":"正在汇总医生经营数据"},je={class:"page-heading"},Pe={class:"heading-copy"},Ae={class:"heading-mark"},We={class:"heading-actions"},qe={class:"scope-chip"},Ge={key:0,class:"update-time"},Ie={class:"filter-strip"},Ke={class:"filter-item filter-item--time"},He={key:0,class:"filter-item"},Je={class:"filter-item"},Qe={class:"filter-item filter-item--status"},Ze={class:"view-switch"},Xe={class:"metric-grid","aria-label":"医生经营核心指标"},Ye={class:"metric-card metric-card--teal"},et={class:"metric-icon"},tt={class:"metric-card metric-card--green"},lt={class:"metric-icon"},nt={class:"metric-card metric-card--indigo"},at={class:"metric-icon"},st={class:"metric-card metric-card--blue"},ot={class:"metric-icon"},it={class:"metric-card metric-card--cyan"},rt={class:"metric-icon"},dt={class:"two-column-grid"},ut={class:"panel ranking-panel"},ct={class:"panel-heading"},mt={key:0,class:"bar-list"},_t=["title"],pt={class:"bar-track"},vt={class:"panel ranking-panel"},bt={class:"panel-heading"},ft={key:0,class:"bar-list"},ht=["title"],gt={class:"bar-track"},yt={class:"two-column-grid analytics-grid"},kt={class:"panel funnel-panel"},wt={class:"funnel-wrap"},Nt={class:"funnel-insight"},xt={class:"panel trend-panel"},Ct={class:"panel-heading"},$t={class:"panel-heading alert-heading"},Dt={class:"threshold-control"},Vt={key:0,class:"alert-list"},Lt={class:"alert-doctor"},St={class:"alert-data"},Et={class:"alert-rate"},Mt={key:1,class:"alert-empty"},zt={key:1,class:"panel detail-panel"},Ft={class:"panel-heading"},Ot={key:0,class:"warning-mark"},Rt={class:"money-text"},Tt={class:"data-note"},Ut=K({name:"firstVisitDoctorDashboardPage"}),Bt=K({...Ut,setup(jt){const R=()=>({meta:{time_type:"month",time_label:"本月",start_date:"",end_date:"",generated_at:"",scope_value:4,scope_label:"",scope_kind:"",selected_dept_name:"",selected_doctor_name:"",doctor_count:0,appointment_rule:"",performance_rule:""},filters:{departments:[],doctors:[],can_filter_department:!0},summary:{appointment_total:0,interview_count:0,order_count:0,deal_amount:0,avg_order_amount:null,appointment_completion_rate:null,receive_conversion_rate:null,missed_count:0,cancelled_count:0},rankings:{amounts:[],conversion:[]},funnel:[],trend:{start_date:"",end_date:"",dates:[],labels:[],amounts:[]},alerts:[],alert_threshold:15,rows:[]}),s=G(R()),V=O(!1),C=O("overview"),y=O(!1),i=G({time_type:"month",active_only:1,alert_threshold:15}),H=[{label:"今日",value:"today"},{label:"本周",value:"week"},{label:"本月",value:"month"}],J=[{label:"仅活跃医生",value:1},{label:"全部医生",value:0}],Q=[10,15,20,30],Z={label:"name",value:"id",children:"children"},X=D(()=>Math.max(0,...s.rankings.amounts.map(l=>Number(l.value)||0))),T=D(()=>s.rows.filter(l=>E(l))),U=D(()=>s.rows.filter(l=>!E(l))),Y=D(()=>i.doctor_id||y.value?s.rows:T.value),B=D(()=>{const l=s.funnel;let t={label:"暂无可比阶段",value:0},c=-1;for(let m=0;m<l.length-1;m++){const f=Math.max(0,Number(l[m].value)-Number(l[m+1].value));f>c&&(c=f,t={label:`${l[m].label}${l[m+1].label}`,value:f})}return t}),ee=D(()=>({animationDuration:450,grid:{left:20,right:20,top:18,bottom:18,containLabel:!0},tooltip:{trigger:"axis",valueFormatter:l=>L(l)},xAxis:{type:"category",boundaryGap:!1,data:s.trend.labels,axisLine:{lineStyle:{color:"#dfe5eb"}},axisTick:{show:!1},axisLabel:{color:"#7e8a9b",fontSize:10,interval:4}},yAxis:{type:"value",splitNumber:4,axisLabel:{color:"#8793a2",fontSize:10,formatter:l=>se(l)},splitLine:{lineStyle:{color:"#eef2f5"}}},series:[{name:"成交金额",type:"line",smooth:!0,symbol:"circle",symbolSize:5,data:s.trend.amounts,lineStyle:{color:"#139a8c",width:3},itemStyle:{color:"#ffffff",borderColor:"#139a8c",borderWidth:2},areaStyle:{color:"rgba(19,154,140,.08)"}}]}));async function g(){V.value=!0;try{const l={time_type:i.time_type,active_only:i.active_only??1,alert_threshold:Number(i.alert_threshold||15)};i.dept_id&&(l.dept_id=Number(i.dept_id)),i.doctor_id&&(l.doctor_id=Number(i.doctor_id));const t=await Te(l);Object.assign(s,R(),t||{})}catch(l){I.error((l==null?void 0:l.message)||"医生看板加载失败,请稍后重试")}finally{V.value=!1}}function te(){delete i.doctor_id,g()}function le(){delete i.doctor_id,g()}function b(l){return Number(l||0).toLocaleString("zh-CN",{maximumFractionDigits:0})}function L(l){return${Number(l||0).toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2})}`}function ne(l){return${Number(l||0).toLocaleString("zh-CN",{minimumFractionDigits:0,maximumFractionDigits:2})}`}function ae(l){return l==null?"—":L(l)}function k(l){return l==null?"—":`${Number(l).toFixed(1)}%`}function se(l){return Math.abs(l)>=1e4?`${(l/1e4).toFixed(l>=1e5?0:1)}万`:`${Math.round(l)}`}function oe(l,t){return t<=0?"0%":`${Math.max(3,Math.min(100,Number(l||0)/t*100))}%`}function ie(l){return`${Math.max(0,Math.min(100,Number(l)||0))}%`}function re(l){return l==null?"conversion-rate is-neutral":Number(l)<Number(i.alert_threshold||15)?"conversion-rate is-low":"conversion-rate is-good"}function E(l){return Number(l.appointment_total||0)>0||Number(l.interview_count||0)>0||Number(l.order_count||0)>0||Number(l.deal_amount||0)>0||Number(l.appointment_missed||0)>0||Number(l.appointment_cancelled||0)>0}function j(l){return Number(l.interview_count||0)>0&&Number(l.receive_conversion_rate||0)<Number(i.alert_threshold||15)}function de({row:l}){return j(l)?"is-conversion-warning":E(l)?"":"is-zero-data"}async function ue(l){i.doctor_id=Number(l.doctor_id),C.value="overview",y.value=!1,await g(),window.scrollTo({top:0,behavior:"smooth"})}function P(l){return`"${String(l??"").replace(/"/g,'""')}"`}function ce(){if(!s.rows.length){I.warning("当前范围暂无可导出的医生数据");return}const l=["医生","状态","挂号","面诊","接诊","接诊率","成交金额","过号","取消"],t=s.rows.map(p=>[p.doctor_name,p.status==="disabled"?"停用":"活跃",p.appointment_total,p.interview_count,p.order_count,k(p.receive_conversion_rate),p.deal_amount,p.appointment_missed,p.appointment_cancelled].map(P).join(",")),c=new Blob([`\uFEFF${l.map(P).join(",")}
${t.join(`
`)}`],{type:"text/csv;charset=utf-8"}),m=URL.createObjectURL(c),f=document.createElement("a");f.href=m,f.download=`医生看板_${s.meta.start_date}_${s.meta.end_date}.csv`,f.click(),URL.revokeObjectURL(m)}return pe(g),(l,t)=>{const c=he,m=ke,f=Ne,p=xe,A=Ce,W=$e,M=Ee,h=Fe,me=Oe,_e=be;return ve((r(),u("div",Be,[e("header",je,[e("div",Pe,[e("span",Ae,[o(c,null,{default:d(()=>[o(_(fe))]),_:1})]),t[8]||(t[8]=e("div",null,[e("h1",null,"医生看板"),e("p",null,"从挂号、面诊到接诊成交,统一观察医生经营表现")],-1))]),e("div",We,[e("span",qe,[o(c,null,{default:d(()=>[o(_(ge))]),_:1}),v(a(s.meta.scope_label||"数据范围"),1)]),s.meta.generated_at?(r(),u("span",Ge,"更新于 "+a(s.meta.generated_at),1)):S("",!0),o(m,{icon:_(ye),loading:V.value,onClick:g},{default:d(()=>[...t[9]||(t[9]=[v("刷新",-1)])]),_:1},8,["icon","loading"]),o(m,{icon:_(we),onClick:ce},{default:d(()=>[...t[10]||(t[10]=[v("导出",-1)])]),_:1},8,["icon"])])]),e("section",Ie,[e("div",Ke,[t[11]||(t[11]=e("span",null,"时间范围",-1)),o(f,{modelValue:i.time_type,"onUpdate:modelValue":t[0]||(t[0]=n=>i.time_type=n),options:H,onChange:g},null,8,["modelValue"])]),s.filters.can_filter_department?(r(),u("div",He,[t[12]||(t[12]=e("span",null,"所属部门",-1)),o(p,{modelValue:i.dept_id,"onUpdate:modelValue":t[1]||(t[1]=n=>i.dept_id=n),data:s.filters.departments,props:Z,"node-key":"id",clearable:"",filterable:"","check-strictly":"","default-expand-all":"",placeholder:"全部可见部门",class:"dept-select",onChange:te},null,8,["modelValue","data"])])):S("",!0),e("div",Je,[t[13]||(t[13]=e("span",null,"医生",-1)),o(W,{modelValue:i.doctor_id,"onUpdate:modelValue":t[2]||(t[2]=n=>i.doctor_id=n),clearable:"",filterable:"",placeholder:"全部医生",class:"doctor-select",onChange:g},{default:d(()=>[(r(!0),u(N,null,$(s.filters.doctors,n=>(r(),z(A,{key:n.id,value:Number(n.id),label:`${n.name}${Number(n.disable)===1?"(停用)":""}`},null,8,["value","label"]))),128))]),_:1},8,["modelValue"])]),e("div",Qe,[t[14]||(t[14]=e("span",null,"医生范围",-1)),o(f,{modelValue:i.active_only,"onUpdate:modelValue":t[3]||(t[3]=n=>i.active_only=n),options:J,onChange:le},null,8,["modelValue"])]),e("div",Ze,[e("button",{class:x({active:C.value==="overview"}),onClick:t[4]||(t[4]=n=>C.value="overview")},"诊断总览",2),e("button",{class:x({active:C.value==="detail"}),onClick:t[5]||(t[5]=n=>C.value="detail")},"医生明细",2)])]),e("section",Xe,[e("article",Ye,[e("div",et,[o(c,null,{default:d(()=>[o(_(De))]),_:1})]),e("div",null,[t[15]||(t[15]=e("span",null,"总挂号",-1)),e("strong",null,a(b(s.summary.appointment_total)),1),e("small",null,"完成 "+a(b(s.summary.interview_count))+" · 完成率 "+a(k(s.summary.appointment_completion_rate)),1)])]),e("article",tt,[e("div",lt,[o(c,null,{default:d(()=>[o(_(Ve))]),_:1})]),e("div",null,[t[16]||(t[16]=e("span",null,"总面诊",-1)),e("strong",null,a(b(s.summary.interview_count)),1),e("small",null,"过号 "+a(b(s.summary.missed_count))+" · 取消 "+a(b(s.summary.cancelled_count)),1)])]),e("article",nt,[e("div",at,[o(c,null,{default:d(()=>[o(_(Le))]),_:1})]),e("div",null,[t[17]||(t[17]=e("span",null,"总诊单",-1)),e("strong",null,a(b(s.summary.order_count)),1),e("small",null,"接诊转化率 "+a(k(s.summary.receive_conversion_rate)),1)])]),e("article",st,[e("div",ot,[o(c,null,{default:d(()=>[o(_(Se))]),_:1})]),e("div",null,[t[18]||(t[18]=e("span",null,"总成交金额",-1)),e("strong",null,a(L(s.summary.deal_amount)),1),e("small",null,"客单价 "+a(ae(s.summary.avg_order_amount)),1)])]),e("article",it,[e("div",rt,[o(c,null,{default:d(()=>[o(_(q))]),_:1})]),e("div",null,[t[19]||(t[19]=e("span",null,"挂号完成率",-1)),e("strong",null,a(k(s.summary.appointment_completion_rate)),1),e("small",null,a(s.meta.time_label)+" · "+a(s.meta.doctor_count)+" 位有数据医生",1)])])]),C.value==="overview"?(r(),u(N,{key:0},[e("section",dt,[e("article",ut,[e("div",ct,[t[20]||(t[20]=e("div",null,[e("h2",null,"成交金额 TOP"),e("p",null,"按有效诊单金额从高到低")],-1)),e("span",null,a(s.meta.time_label),1)]),s.rankings.amounts.length?(r(),u("div",mt,[(r(!0),u(N,null,$(s.rankings.amounts,(n,w)=>(r(),u("div",{key:`amount-${n.doctor_id}`,class:"bar-row"},[e("b",null,a(w+1),1),e("span",{title:n.name},a(n.name),9,_t),e("div",pt,[e("i",{class:"is-blue",style:F({width:oe(n.value,X.value)})},null,4)]),e("strong",null,a(L(n.value)),1)]))),128))])):(r(),z(M,{key:1,"image-size":52,description:"当前范围暂无成交金额"}))]),e("article",vt,[e("div",bt,[t[21]||(t[21]=e("div",null,[e("h2",null,"接诊转化率 TOP"),e("p",null,"有效诊单数 ÷ 完成面诊数")],-1)),e("span",null,a(s.meta.time_label),1)]),s.rankings.conversion.length?(r(),u("div",ft,[(r(!0),u(N,null,$(s.rankings.conversion,(n,w)=>(r(),u("div",{key:`rate-${n.doctor_id}`,class:"bar-row"},[e("b",null,a(w+1),1),e("span",{title:n.name},a(n.name),9,ht),e("div",gt,[e("i",{class:"is-teal",style:F({width:ie(n.value)})},null,4)]),e("strong",null,a(k(n.value)),1)]))),128))])):(r(),z(M,{key:1,"image-size":52,description:"当前范围暂无转化数据"}))])]),e("section",yt,[e("article",kt,[t[23]||(t[23]=e("div",{class:"panel-heading"},[e("div",null,[e("h2",null,"经营转化漏斗"),e("p",null,"挂号 → 面诊 → 接诊 → 成交")]),e("span",null,"人数 / 单数")],-1)),e("div",wt,[(r(!0),u(N,null,$(s.funnel,(n,w)=>(r(),u("div",{key:n.key,class:x(["funnel-stage",`stage-${w+1}`]),style:F({width:`${100-w*15}%`})},[e("span",null,a(n.label),1),e("strong",null,a(b(n.value)),1)],6))),128))]),e("div",Nt,[t[22]||(t[22]=v(" 最大流失发生在 ",-1)),e("strong",null,a(B.value.label),1),v(",流失 "+a(b(B.value.value)),1)])]),e("article",xt,[e("div",Ct,[e("div",null,[t[24]||(t[24]=e("h2",null,"近 30 天成交金额趋势",-1)),e("p",null,a(s.trend.start_date)+" 至 "+a(s.trend.end_date),1)]),t[25]||(t[25]=e("span",null,"单位:元",-1))]),o(_(Me),{class:"trend-chart",option:ee.value,autoresize:""},null,8,["option"])])]),e("section",{class:x(["panel alert-panel",{"has-alerts":s.alerts.length}])},[e("div",$t,[e("div",null,[e("h2",null,[o(c,null,{default:d(()=>[o(_(ze))]),_:1}),t[26]||(t[26]=v("需关注医生",-1))]),t[27]||(t[27]=e("p",null,"仅对完成过面诊的医生计算接诊转化预警",-1))]),e("div",Dt,[t[28]||(t[28]=e("span",null,"接诊转化率低于",-1)),o(W,{modelValue:i.alert_threshold,"onUpdate:modelValue":t[6]||(t[6]=n=>i.alert_threshold=n),class:"threshold-select",onChange:g},{default:d(()=>[(r(),u(N,null,$(Q,n=>o(A,{key:n,label:`${n}%`,value:n},null,8,["label","value"])),64))]),_:1},8,["modelValue"])])]),s.alerts.length?(r(),u("div",Vt,[(r(!0),u(N,null,$(s.alerts,n=>(r(),u("div",{key:n.doctor_id,class:"alert-row"},[t[29]||(t[29]=e("span",{class:"alert-icon"},"!",-1)),e("div",Lt,[e("strong",null,a(n.doctor_name),1),e("small",null,a(n.department_name),1)]),e("span",{class:x(["severity",`is-${n.severity}`])},a(n.severity==="high"?"重点关注":"低于阈值"),3),e("span",St,"面诊 "+a(n.interview_count)+" / 接诊 "+a(n.order_count),1),e("p",null,a(n.suggestion),1),e("strong",Et,a(k(n.rate)),1)]))),128))])):(r(),u("div",Mt,[o(c,null,{default:d(()=>[o(_(q))]),_:1}),v(" 当前范围内暂无低于 "+a(i.alert_threshold)+"% 的医生 ",1)]))],2)],64)):(r(),u("section",zt,[e("div",Ft,[t[30]||(t[30]=e("div",null,[e("h2",null,"医生明细 · 按成交金额排序"),e("p",null,"低于接诊率预警线的医生整行标红,过号与取消分别展示")],-1)),e("span",null,a(T.value.length)+" 位有数据医生",1)]),o(me,{data:Y.value,class:"detail-table","default-sort":{prop:"deal_amount",order:"descending"},"row-class-name":de},{empty:d(()=>[o(M,{description:"当前权限和筛选范围内暂无医生数据"})]),default:d(()=>[o(h,{prop:"doctor_name",label:"医生","min-width":"130",fixed:"left",sortable:""},{default:d(({row:n})=>[e("strong",null,a(n.doctor_name),1)]),_:1}),o(h,{prop:"status",label:"状态","min-width":"90",sortable:""},{default:d(({row:n})=>[e("span",{class:x(["status-pill",{disabled:n.status==="disabled"}])},a(n.status==="disabled"?"停用":"活跃"),3)]),_:1}),o(h,{prop:"appointment_total",label:"挂号","min-width":"90",sortable:""}),o(h,{prop:"interview_count",label:"面诊","min-width":"90",sortable:""}),o(h,{prop:"order_count",label:"接诊","min-width":"90",sortable:""}),o(h,{prop:"receive_conversion_rate",label:"接诊率","min-width":"110",sortable:""},{default:d(({row:n})=>[e("span",{class:x(re(n.receive_conversion_rate))},[j(n)?(r(),u("span",Ot,"△")):S("",!0),v(a(k(n.receive_conversion_rate)),1)],2)]),_:1}),o(h,{prop:"deal_amount",label:"成交金额","min-width":"135",sortable:""},{default:d(({row:n})=>[e("strong",Rt,a(ne(n.deal_amount)),1)]),_:1}),o(h,{label:"过号/取消","min-width":"110"},{default:d(({row:n})=>[v(a(b(n.appointment_missed))+"/"+a(b(n.appointment_cancelled)),1)]),_:1}),o(h,{label:"操作","min-width":"90",fixed:"right"},{default:d(({row:n})=>[o(m,{class:"detail-action",type:"primary",link:"",onClick:w=>ue(n)},{default:d(()=>[...t[31]||(t[31]=[v("详情",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"]),!i.doctor_id&&U.value.length?(r(),u("button",{key:0,type:"button",class:"zero-doctor-toggle",onClick:t[7]||(t[7]=n=>y.value=!y.value)},[e("span",null,a(y.value?"▾":"▸"),1),v(" "+a(y.value?"收起":"已隐藏")+" "+a(U.value.length)+" 位无业务数据医生"+a(y.value?"":"(点击展开)"),1)])):S("",!0)])),e("footer",Tt,[o(c,null,{default:d(()=>[o(_(Re))]),_:1}),e("span",null,a(s.meta.appointment_rule)+""+a(s.meta.performance_rule)+"。",1)])])),[[_e,V.value]])}}}),qt=Ue(Bt,[["__scopeId","data-v-e03dcb60"]]);export{qt as default};