Files
2026-08-10 17:46:04 +08:00

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