Files
xuetang/server/public/admin/assets/index-CmBK5rYu.js
T
2026-09-08 11:40:15 +08:00

4 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{L as ge,d as he,i as ye,aj as ke,R as we,Z as Ne,Q as Ce,P as xe,W as De,N as Ve,M as $e,E as R}from"./element-plus-Bm2jcHo4.js";import{a3 as Y,a8 as Me,M as Se,N as Ee,k as Le,Z as ze,a2 as Fe,a9 as Oe,d as I,w as Re,i as Te}from"./@element-plus/icons-vue-8Um_rfcd.js";import{H as Ue}from"./vue-echarts-BNtg2q_G.js";import{a as Pe}from"./first_visit-Ifm9U8v6.js";import{f as H,b as je,aP as Be,ak as d,I as u,J as e,a as s,aN as r,O as b,H as D,G as L,F as C,ap as V,A as $}from"./@vue/runtime-core-C6bnekPw.js";import{y as c,r as Z,n as z}from"./@vue/reactivity-DiY1c2vO.js";import{Q as a,o as x,p as G}from"./@vue/shared-mAAVTE9n.js";import{_ as Ae}from"./index-CJJeyIXM.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./resize-detector-G6vbKCU7.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.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"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const We={class:"doctor-dashboard","element-loading-text":"正在汇总医生经营数据"},Ye={class:"page-heading"},Ie={class:"heading-copy"},Ze={class:"heading-mark"},Ge={class:"heading-actions"},He={class:"scope-chip"},Qe={key:0,class:"update-time"},qe={class:"filter-strip"},Je={class:"filter-item filter-item--time"},Ke={key:0,class:"filter-item"},Xe={class:"filter-item"},et={class:"filter-item filter-item--status"},tt={class:"view-switch"},lt={class:"metric-grid","aria-label":"医生经营核心指标"},nt={class:"metric-card metric-card--teal"},at={class:"metric-icon"},ot={class:"metric-card metric-card--green"},st={class:"metric-icon"},it={class:"metric-card metric-card--indigo"},rt={class:"metric-icon"},dt={class:"metric-card metric-card--blue"},ut={class:"metric-icon"},ct={class:"metric-card metric-card--orange"},mt={class:"metric-icon"},_t={class:"metric-card metric-card--cyan"},pt={class:"metric-icon"},vt={class:"two-column-grid"},ft={class:"panel ranking-panel"},bt={class:"panel-heading"},gt={key:0,class:"bar-list"},ht=["title"],yt={class:"bar-track"},kt={class:"panel ranking-panel"},wt={class:"panel-heading"},Nt={key:0,class:"bar-list"},Ct=["title"],xt={class:"bar-track"},Dt={class:"analytics-grid"},Vt={class:"panel trend-panel"},$t={class:"panel-heading"},Mt={class:"panel-heading alert-heading"},St={class:"threshold-control"},Et={key:0,class:"alert-list"},Lt={class:"alert-doctor"},zt={class:"alert-data"},Ft={class:"alert-rate"},Ot={key:1,class:"alert-empty"},Rt={key:1,class:"panel detail-panel"},Tt={class:"panel-heading"},Ut={key:0,class:"warning-mark"},Pt={class:"money-text"},jt={class:"data-note"},Bt=H({name:"firstVisitDoctorDashboardPage"}),At=H({...Bt,setup(Wt){const T=()=>({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:[]}),o=Z(T()),M=z(!1),k=z("overview"),g=z(!1),i=Z({time_type:"month",active_only:1,alert_threshold:15}),h=z([]),Q=[{label:"今日",value:"today"},{label:"昨天",value:"yesterday"},{label:"本周",value:"week"},{label:"本月",value:"month"},{label:"自定义",value:"custom"}],q=[{label:"仅活跃医生",value:1},{label:"全部医生",value:0}],J=[10,15,20,30],K={label:"name",value:"id",children:"children"},X=$(()=>Math.max(0,...o.rankings.amounts.map(l=>Number(l.value)||0))),U=$(()=>o.rows.filter(l=>F(l))),P=$(()=>o.rows.filter(l=>!F(l))),ee=$(()=>i.doctor_id||g.value?o.rows:U.value),te=$(()=>({animationDuration:450,grid:{left:20,right:20,top:18,bottom:18,containLabel:!0},tooltip:{trigger:"axis",valueFormatter:l=>S(l)},xAxis:{type:"category",boundaryGap:!1,data:o.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=>re(l)},splitLine:{lineStyle:{color:"#eef2f5"}}},series:[{name:"成交金额",type:"line",smooth:!0,symbol:"circle",symbolSize:5,data:o.trend.amounts,lineStyle:{color:"#139a8c",width:3},itemStyle:{color:"#ffffff",borderColor:"#139a8c",borderWidth:2},areaStyle:{color:"rgba(19,154,140,.08)"}}]}));async function p(){M.value=!0;try{const l={time_type:i.time_type,active_only:i.active_only??1,alert_threshold:Number(i.alert_threshold||15)};if(i.time_type==="custom"&&(l.start_date=h.value[0]||"",l.end_date=h.value[1]||"",!l.start_date||!l.end_date)){R.warning("请选择自定义日期范围");return}i.dept_id&&(l.dept_id=Number(i.dept_id)),i.doctor_id&&(l.doctor_id=Number(i.doctor_id));const t=await Pe(l);Object.assign(o,T(),t||{})}catch(l){R.error((l==null?void 0:l.message)||"医生看板加载失败,请稍后重试")}finally{M.value=!1}}function le(){if(i.time_type!=="custom"){h.value=[],p();return}h.value.length===2&&p()}function ne(){i.time_type==="custom"&&h.value.length===2&&p()}function ae(){delete i.doctor_id,p()}function oe(){delete i.doctor_id,p()}function v(l){return Number(l||0).toLocaleString("zh-CN",{maximumFractionDigits:0})}function S(l){return${Number(l||0).toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2})}`}function se(l){return${Number(l||0).toLocaleString("zh-CN",{minimumFractionDigits:0,maximumFractionDigits:2})}`}function ie(l){return l==null?"—":S(l)}function y(l){return l==null?"—":`${Number(l).toFixed(1)}%`}function re(l){return Math.abs(l)>=1e4?`${(l/1e4).toFixed(l>=1e5?0:1)}万`:`${Math.round(l)}`}function de(l,t){return t<=0?"0%":`${Math.max(3,Math.min(100,Number(l||0)/t*100))}%`}function ue(l){return`${Math.max(0,Math.min(100,Number(l)||0))}%`}function ce(l){return l==null?"conversion-rate is-neutral":Number(l)<Number(i.alert_threshold||15)?"conversion-rate is-low":"conversion-rate is-good"}function F(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 me({row:l}){return j(l)?"is-conversion-warning":F(l)?"":"is-zero-data"}async function _e(l){i.doctor_id=Number(l.doctor_id),k.value="overview",g.value=!1,await p(),window.scrollTo({top:0,behavior:"smooth"})}function B(l){return`"${String(l??"").replace(/"/g,'""')}"`}function pe(){if(!o.rows.length){R.warning("当前范围暂无可导出的医生数据");return}const l=["医生","状态","预约","面诊","接诊","接诊率","成交金额","过号","取消"],t=o.rows.map(_=>[_.doctor_name,_.status==="disabled"?"停用":"活跃",_.appointment_total,_.interview_count,_.order_count,y(_.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"}),w=URL.createObjectURL(m),N=document.createElement("a");N.href=w,N.download=`医生看板_${o.meta.start_date}_${o.meta.end_date}.csv`,N.click(),URL.revokeObjectURL(w)}return je(p),(l,t)=>{const m=he,w=ye,N=ke,_=we,ve=Ne,A=Ce,W=xe,O=De,f=Ve,fe=$e,be=ge;return Be((d(),u("div",We,[e("header",Ye,[e("div",Ie,[e("span",Ze,[s(m,null,{default:r(()=>[s(c(Y))]),_:1})]),t[9]||(t[9]=e("div",null,[e("h1",null,"医生看板"),e("p",null,"从挂号、预约、面诊到接诊成交,统一观察医生经营表现")],-1))]),e("div",Ge,[e("span",He,[s(m,null,{default:r(()=>[s(c(Me))]),_:1}),b(a(o.meta.scope_label||"数据范围"),1)]),o.meta.generated_at?(d(),u("span",Qe,"更新于 "+a(o.meta.generated_at),1)):D("",!0),s(w,{icon:c(Se),loading:M.value,onClick:p},{default:r(()=>[...t[10]||(t[10]=[b("刷新",-1)])]),_:1},8,["icon","loading"]),s(w,{icon:c(Ee),onClick:pe},{default:r(()=>[...t[11]||(t[11]=[b("导出",-1)])]),_:1},8,["icon"])])]),e("section",qe,[e("div",Je,[t[12]||(t[12]=e("span",null,"时间范围",-1)),s(N,{modelValue:i.time_type,"onUpdate:modelValue":t[0]||(t[0]=n=>i.time_type=n),options:Q,onChange:le},null,8,["modelValue"]),i.time_type==="custom"?(d(),L(_,{key:0,modelValue:h.value,"onUpdate:modelValue":t[1]||(t[1]=n=>h.value=n),type:"daterange","value-format":"YYYY-MM-DD","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期",class:"date-range-picker",clearable:!1,onChange:ne},null,8,["modelValue"])):D("",!0)]),o.filters.can_filter_department?(d(),u("div",Ke,[t[13]||(t[13]=e("span",null,"所属部门",-1)),s(ve,{modelValue:i.dept_id,"onUpdate:modelValue":t[2]||(t[2]=n=>i.dept_id=n),data:o.filters.departments,props:K,"node-key":"id",clearable:"",filterable:"","check-strictly":"","default-expand-all":"",placeholder:"全部可见部门",class:"dept-select",onChange:ae},null,8,["modelValue","data"])])):D("",!0),e("div",Xe,[t[14]||(t[14]=e("span",null,"医生",-1)),s(W,{modelValue:i.doctor_id,"onUpdate:modelValue":t[3]||(t[3]=n=>i.doctor_id=n),clearable:"",filterable:"",placeholder:"全部医生",class:"doctor-select",onChange:p},{default:r(()=>[(d(!0),u(C,null,V(o.filters.doctors,n=>(d(),L(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",et,[t[15]||(t[15]=e("span",null,"医生范围",-1)),s(N,{modelValue:i.active_only,"onUpdate:modelValue":t[4]||(t[4]=n=>i.active_only=n),options:q,onChange:oe},null,8,["modelValue"])]),e("div",tt,[e("button",{class:x({active:k.value==="overview"}),onClick:t[5]||(t[5]=n=>k.value="overview")},"诊断总览",2),e("button",{class:x({active:k.value==="detail"}),onClick:t[6]||(t[6]=n=>k.value="detail")},"医生明细",2)])]),e("section",lt,[e("article",nt,[e("div",at,[s(m,null,{default:r(()=>[s(c(Le))]),_:1})]),e("div",null,[t[16]||(t[16]=e("span",null,"总预约",-1)),e("strong",null,a(v(o.summary.registration_total)),1),t[17]||(t[17]=e("small",null,"已支付且实收金额大于 0、低于 10 元的订单",-1))])]),e("article",ot,[e("div",st,[s(m,null,{default:r(()=>[s(c(ze))]),_:1})]),e("div",null,[t[18]||(t[18]=e("span",null,"总面诊",-1)),e("strong",null,a(v(o.summary.interview_count)),1),e("small",null,"过号 "+a(v(o.summary.missed_count))+" · 取消 "+a(v(o.summary.cancelled_count)),1)])]),e("article",it,[e("div",rt,[s(m,null,{default:r(()=>[s(c(Fe))]),_:1})]),e("div",null,[t[19]||(t[19]=e("span",null,"总诊单",-1)),e("strong",null,a(v(o.summary.order_count)),1),e("small",null,"接诊转化率 "+a(y(o.summary.receive_conversion_rate)),1)])]),e("article",dt,[e("div",ut,[s(m,null,{default:r(()=>[s(c(Oe))]),_:1})]),e("div",null,[t[20]||(t[20]=e("span",null,"总成交金额",-1)),e("strong",null,a(S(o.summary.deal_amount)),1),e("small",null,"客单价 "+a(ie(o.summary.avg_order_amount)),1)])]),e("article",ct,[e("div",mt,[s(m,null,{default:r(()=>[s(c(Y))]),_:1})]),e("div",null,[t[21]||(t[21]=e("span",null,"总接诊率",-1)),e("strong",null,a(y(o.summary.receive_conversion_rate)),1),e("small",null,"总接诊 "+a(v(o.summary.order_count))+" ÷ 总面诊 "+a(v(o.summary.interview_count)),1)])]),e("article",_t,[e("div",pt,[s(m,null,{default:r(()=>[s(c(I))]),_:1})]),e("div",null,[t[22]||(t[22]=e("span",null,"预约完成率",-1)),e("strong",null,a(y(o.summary.appointment_completion_rate)),1),e("small",null,"总预约 "+a(v(o.summary.appointment_total))+" · "+a(o.meta.doctor_count)+" 位有数据医生",1)])])]),k.value==="overview"?(d(),u(C,{key:0},[e("section",vt,[e("article",ft,[e("div",bt,[t[23]||(t[23]=e("div",null,[e("h2",null,"成交金额 TOP"),e("p",null,"按有效诊单金额从高到低")],-1)),e("span",null,a(o.meta.time_label),1)]),o.rankings.amounts.length?(d(),u("div",gt,[(d(!0),u(C,null,V(o.rankings.amounts,(n,E)=>(d(),u("div",{key:`amount-${n.doctor_id}`,class:"bar-row"},[e("b",null,a(E+1),1),e("span",{title:n.name},a(n.name),9,ht),e("div",yt,[e("i",{class:"is-blue",style:G({width:de(n.value,X.value)})},null,4)]),e("strong",null,a(S(n.value)),1)]))),128))])):(d(),L(O,{key:1,"image-size":52,description:"当前范围暂无成交金额"}))]),e("article",kt,[e("div",wt,[t[24]||(t[24]=e("div",null,[e("h2",null,"接诊转化率 TOP"),e("p",null,"有效诊单数 ÷ 完成面诊数")],-1)),e("span",null,a(o.meta.time_label),1)]),o.rankings.conversion.length?(d(),u("div",Nt,[(d(!0),u(C,null,V(o.rankings.conversion,(n,E)=>(d(),u("div",{key:`rate-${n.doctor_id}`,class:"bar-row"},[e("b",null,a(E+1),1),e("span",{title:n.name},a(n.name),9,Ct),e("div",xt,[e("i",{class:"is-teal",style:G({width:ue(n.value)})},null,4)]),e("strong",null,a(y(n.value)),1)]))),128))])):(d(),L(O,{key:1,"image-size":52,description:"当前范围暂无转化数据"}))])]),e("section",Dt,[e("article",Vt,[e("div",$t,[e("div",null,[t[25]||(t[25]=e("h2",null,"近 30 天成交金额趋势",-1)),e("p",null,a(o.trend.start_date)+" 至 "+a(o.trend.end_date),1)]),t[26]||(t[26]=e("span",null,"单位:元",-1))]),s(c(Ue),{class:"trend-chart",option:te.value,autoresize:""},null,8,["option"])])]),e("section",{class:x(["panel alert-panel",{"has-alerts":o.alerts.length}])},[e("div",Mt,[e("div",null,[e("h2",null,[s(m,null,{default:r(()=>[s(c(Re))]),_:1}),t[27]||(t[27]=b("需关注医生",-1))]),t[28]||(t[28]=e("p",null,"仅对完成过面诊的医生计算接诊转化预警",-1))]),e("div",St,[t[29]||(t[29]=e("span",null,"接诊转化率低于",-1)),s(W,{modelValue:i.alert_threshold,"onUpdate:modelValue":t[7]||(t[7]=n=>i.alert_threshold=n),class:"threshold-select",onChange:p},{default:r(()=>[(d(),u(C,null,V(J,n=>s(A,{key:n,label:`${n}%`,value:n},null,8,["label","value"])),64))]),_:1},8,["modelValue"])])]),o.alerts.length?(d(),u("div",Et,[(d(!0),u(C,null,V(o.alerts,n=>(d(),u("div",{key:n.doctor_id,class:"alert-row"},[t[30]||(t[30]=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",zt,"面诊 "+a(n.interview_count)+" / 接诊 "+a(n.order_count),1),e("p",null,a(n.suggestion),1),e("strong",Ft,a(y(n.rate)),1)]))),128))])):(d(),u("div",Ot,[s(m,null,{default:r(()=>[s(c(I))]),_:1}),b(" 当前范围内暂无低于 "+a(i.alert_threshold)+"% 的医生 ",1)]))],2)],64)):(d(),u("section",Rt,[e("div",Tt,[t[31]||(t[31]=e("div",null,[e("h2",null,"医生明细 · 按成交金额排序"),e("p",null,"低于接诊率预警线的医生整行标红,过号与取消分别展示")],-1)),e("span",null,a(U.value.length)+" 位有数据医生",1)]),s(fe,{data:ee.value,class:"detail-table","default-sort":{prop:"deal_amount",order:"descending"},"row-class-name":me},{empty:r(()=>[s(O,{description:"当前权限和筛选范围内暂无医生数据"})]),default:r(()=>[s(f,{prop:"doctor_name",label:"医生","min-width":"130",fixed:"left",sortable:""},{default:r(({row:n})=>[e("strong",null,a(n.doctor_name),1)]),_:1}),s(f,{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}),s(f,{prop:"appointment_total",label:"预约","min-width":"90",sortable:""}),s(f,{prop:"interview_count",label:"面诊","min-width":"90",sortable:""}),s(f,{prop:"order_count",label:"接诊","min-width":"90",sortable:""}),s(f,{prop:"receive_conversion_rate",label:"接诊率","min-width":"110",sortable:""},{default:r(({row:n})=>[e("span",{class:x(ce(n.receive_conversion_rate))},[j(n)?(d(),u("span",Ut,"△")):D("",!0),b(a(y(n.receive_conversion_rate)),1)],2)]),_:1}),s(f,{prop:"deal_amount",label:"成交金额","min-width":"135",sortable:""},{default:r(({row:n})=>[e("strong",Pt,a(se(n.deal_amount)),1)]),_:1}),s(f,{label:"过号/取消","min-width":"110"},{default:r(({row:n})=>[b(a(v(n.appointment_missed))+"/"+a(v(n.appointment_cancelled)),1)]),_:1}),s(f,{label:"操作","min-width":"90",fixed:"right"},{default:r(({row:n})=>[s(w,{class:"detail-action",type:"primary",link:"",onClick:E=>_e(n)},{default:r(()=>[...t[32]||(t[32]=[b("详情",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"]),!i.doctor_id&&P.value.length?(d(),u("button",{key:0,type:"button",class:"zero-doctor-toggle",onClick:t[8]||(t[8]=n=>g.value=!g.value)},[e("span",null,a(g.value?"▾":"▸"),1),b(" "+a(g.value?"收起":"已隐藏")+" "+a(P.value.length)+" 位无业务数据医生"+a(g.value?"":"(点击展开)"),1)])):D("",!0)])),e("footer",jt,[s(m,null,{default:r(()=>[s(c(Te))]),_:1}),e("span",null,a(o.meta.registration_rule)+""+a(o.meta.appointment_rule)+""+a(o.meta.performance_rule)+"。",1)])])),[[be,M.value]])}}}),Sl=Ae(At,[["__scopeId","data-v-2e596eda"]]);export{Sl as default};