Files
2026-06-04 11:01:29 +08:00

2 lines
17 KiB
JavaScript

import{_ as je,p as Me,q as De,s as Ve,c as g,a as s,b as o,w as c,h as p,v as K,f as X,r as y,E as H,j as Re,x as Se,o as _,e as x,y as J,k as E,t as z,F,i as A,n as ze}from"./index-Dn51426I.js";import{b as h}from"./index-BRvS5RTm.js";import{i as we,L as Le}from"./index-Bn9PLWWT.js";const Ye={class:"dashboard-page"},$e={class:"page-header",style:{display:"flex","justify-content":"space-between","align-items":"flex-end"}},Ce={style:{display:"flex",gap:"12px","align-items":"center"}},Ue={class:"filter-bar"},Ee={class:"two-col-layout"},Oe={class:"table-col"},Be={style:{padding:"10px 40px",background:"rgba(0,0,0,0.2)"}},Pe={style:{"margin-bottom":"8px","font-weight":"bold",color:"var(--text-secondary)"}},Fe={class:"chart-col"},Ae={class:"chart-card"},We={class:"chart-card",style:{"margin-top":"16px"}},Te={class:"filter-bar"},Ne={class:"two-col-layout"},qe={class:"table-col"},Ge={class:"chart-col"},Ke={class:"chart-card"},Xe={class:"chart-card",style:{"margin-top":"16px"}},He={class:"filter-bar"},Je={class:"two-col-layout"},Qe={class:"table-col"},Ze={style:{padding:"10px 40px",background:"rgba(0,0,0,0.2)"}},Ie={style:{"margin-bottom":"8px","font-weight":"bold",color:"var(--text-secondary)"}},et={class:"chart-col"},tt={class:"chart-card"},at={class:"chart-card",style:{"margin-top":"16px"}},lt={class:"filter-bar"},st={class:"content-card",style:{"margin-top":"16px","overflow-x":"auto"}},ot={key:0,class:"matrix-table"},rt={class:"row-header"},dt={class:"total-col"},nt={__name:"Dashboard",setup(it){const Q=p("sales"),pe=p([]),_e=p([]),Z=p(null),I=p(null),ee=p(null),te=p(null),ae=p(null),le=p(null);let R=null,w=null,k=null,j=null,M=null,D=null;const W=p(!1),O=(()=>{const t=new Date,e=new Date;e.setMonth(e.getMonth()-1);const a=l=>String(l).padStart(2,"0"),d=l=>`${l.getFullYear()}-${a(l.getMonth()+1)}-${a(l.getDate())}`;return[d(e),d(t)]})(),L=p(O),V=X({dateRange:O}),me=p([]),fe=p([]),se=p(!1),T=Re(()=>{const t={};return fe.value.forEach(e=>{t[e.sales_id]||(t[e.sales_id]={sales_id:e.sales_id,sales_name:e.sales_name,projects:new Set,rdMap:{},total_hours:0});const a=t[e.sales_id];a.rdMap[e.rd_id]||(a.rdMap[e.rd_id]={rd_name:e.rd_name,total_hours:0,work_days:0}),a.rdMap[e.rd_id].total_hours+=e.total_hours,a.rdMap[e.rd_id].work_days+=e.work_days}),me.value.forEach(e=>{t[e.sales_id]||(t[e.sales_id]={sales_id:e.sales_id,sales_name:e.sales_name,projects:new Set,rdMap:{},total_hours:0}),t[e.sales_id].projects.add(e.client_id),t[e.sales_id].total_hours+=e.total_hours}),Object.values(t).map(e=>({sales_name:e.sales_name,project_count:e.projects.size,rd_count:Object.keys(e.rdMap).length,total_hours:Math.round(e.total_hours*10)/10,rdList:Object.values(e.rdMap).sort((a,d)=>d.total_hours-a.total_hours)}))});async function ve(){se.value=!0;try{const t={};V.dateRange&&(t.start_date=V.dateRange[0],t.end_date=V.dateRange[1]);const[e,a]=await Promise.all([h.getSalesStats(t),h.getSalesDetail(t)]);me.value=e.data,fe.value=a.data,await K();const d=T.value.filter(i=>i.total_hours>0).map(i=>({name:i.sales_name,value:i.total_hours}));$(Z,R,"sales",d);const l=T.value.filter(i=>i.total_hours>0);C(te,j,"sales",l.map(i=>i.sales_name),l.map(i=>i.total_hours))}finally{se.value=!1}}const f=X({dateRange:O,user_id:""}),oe=p([]),re=p(!1),Y=Re(()=>{const t={};return oe.value.forEach(e=>{t[e.user_id]||(t[e.user_id]={name:e.user_name,value:0}),t[e.user_id].value+=e.hours}),Object.values(t).filter(e=>e.value>0)});async function ge(){re.value=!0;try{const t={};f.dateRange&&(t.start_date=f.dateRange[0],t.end_date=f.dateRange[1]),f.user_id&&(t.user_id=f.user_id);const e=await h.getRdStats(t);oe.value=e.data,await K(),$(I,w,"rd",Y.value),C(ae,M,"rd",Y.value.map(a=>a.name),Y.value.map(a=>a.value))}finally{re.value=!1}}const m=X({dateRange:O,sales_id:""}),B=p([]),de=p(!1);async function he(){de.value=!0;try{const t={};m.dateRange&&(t.start_date=m.dateRange[0],t.end_date=m.dateRange[1]),m.sales_id&&(t.sales_id=m.sales_id);const[e,a]=await Promise.all([h.getProjectStats(t),h.getProjectDetail(t)]),d={};a.data.forEach(n=>{d[n.client_id]||(d[n.client_id]=[]),d[n.client_id].push(n)}),B.value=e.data.map(n=>(n.rdList=d[n.client_id]||[],n)),await K();const l=B.value.filter(n=>n.total_hours>0).map(n=>({name:n.client_name,value:n.total_hours}));$(ee,k,"project",l);const i=B.value.filter(n=>n.total_hours>0);C(le,D,"project",i.map(n=>n.client_name),i.map(n=>n.total_hours))}finally{de.value=!1}}function $(t,e,a,d){if(!t.value||t.value.clientWidth===0)return;e&&e.dispose();let l=we(t.value,"dark");a==="sales"&&(R=l),a==="rd"&&(w=l),a==="project"&&(k=l),l.setOption({backgroundColor:"transparent",tooltip:{trigger:"item",formatter:"{b}: {c}h ({d}%)",confine:!0},legend:{type:"scroll",bottom:10,textStyle:{color:"#94a3b8"}},series:[{type:"pie",radius:["35%","65%"],center:["50%","45%"],avoidLabelOverlap:!0,itemStyle:{borderRadius:8,borderColor:"#1e293b",borderWidth:2},label:{color:"#f1f5f9",fontSize:13},emphasis:{label:{show:!0,fontSize:16,fontWeight:"bold"},itemStyle:{shadowBlur:10,shadowOffsetX:0,shadowColor:"rgba(0,0,0,0.5)"}},data:d}]})}function C(t,e,a,d,l){if(!t.value||t.value.clientWidth===0)return;e&&e.dispose();let i=we(t.value,"dark");a==="sales"&&(j=i),a==="rd"&&(M=i),a==="project"&&(D=i),i.setOption({backgroundColor:"transparent",tooltip:{trigger:"axis",formatter:n=>`${n[0].name}: ${n[0].value}h`,confine:!0},grid:{left:"3%",right:"4%",bottom:"15%",containLabel:!0},xAxis:{type:"category",data:d,axisLabel:{color:"#94a3b8",interval:0,rotate:d.length>5?30:0,fontSize:12}},yAxis:{type:"value",name:"工时(h)",axisLabel:{color:"#94a3b8"}},series:[{type:"bar",barMaxWidth:50,data:l,itemStyle:{color:new Le(0,0,0,1,[{offset:0,color:"#818cf8"},{offset:1,color:"#4f46e5"}]),borderRadius:[4,4,0,0]},label:{show:!0,position:"top",color:"#f1f5f9",fontSize:12,formatter:"{c}h"},markLine:a==="rd"&&l.length>0?{data:[{type:"average",name:"平均值"}],lineStyle:{type:"dashed",color:"#f59e0b",width:2},label:{formatter:"平均: {c}h",position:"end",color:"#f59e0b",fontWeight:"bold"}}:void 0}]})}function be(){R==null||R.resize(),w==null||w.resize(),k==null||k.resize(),j==null||j.resize(),M==null||M.resize(),D==null||D.resize()}async function N(t){try{if(t==="all"){W.value=!0;let n={},S="开始",u="至今";L.value&&L.value.length===2&&(n.start_date=L.value[0],n.end_date=L.value[1],S=n.start_date,u=n.end_date);const v=await h.exportAllExcel(n);ne(v.data,`总报表_${S}${u}.xlsx`),H.success("全导成功"),W.value=!1;return}let e={},a="开始",d="至今",l="";t==="sales"?(l="销售视角",V.dateRange&&V.dateRange.length===2&&(e.start_date=V.dateRange[0],e.end_date=V.dateRange[1],a=e.start_date,d=e.end_date)):t==="rd"?(l="研发视角",f.dateRange&&f.dateRange.length===2&&(e.start_date=f.dateRange[0],e.end_date=f.dateRange[1],a=e.start_date,d=e.end_date)):t==="project"&&(l="项目视角",m.dateRange&&m.dateRange.length===2&&(e.start_date=m.dateRange[0],e.end_date=m.dateRange[1],a=e.start_date,d=e.end_date),m.sales_id&&(e.sales_id=m.sales_id));const i=await h.exportExcel(t,e);ne(i.data,`${l}_${a}${d}.xlsx`),H.success("导出成功")}catch{W.value=!1,H.error("导出失败")}}function ne(t,e){const a=URL.createObjectURL(new Blob([t])),d=document.createElement("a");d.href=a,d.download=e,d.click(),URL.revokeObjectURL(a)}Me(Q,t=>{K(()=>{if(t==="sales"){const e=T.value.filter(a=>a.total_hours>0);$(Z,R,"sales",e.map(a=>({name:a.sales_name,value:a.total_hours}))),C(te,j,"sales",e.map(a=>a.sales_name),e.map(a=>a.total_hours))}else if(t==="rd")$(I,w,"rd",Y.value),C(ae,M,"rd",Y.value.map(e=>e.name),Y.value.map(e=>e.value));else if(t==="project"){const e=B.value.filter(a=>a.total_hours>0);$(ee,k,"project",e.map(a=>({name:a.client_name,value:a.total_hours}))),C(le,D,"project",e.map(a=>a.client_name),e.map(a=>a.total_hours))}else t==="matrix"&&ue()})}),De(async()=>{window.addEventListener("resize",be);try{const[t,e]=await Promise.all([h.getSalesUsers(),h.getRdUsers()]);pe.value=t.data,_e.value=e.data}catch{}ve(),ge(),he(),ue()}),Ve(()=>{window.removeEventListener("resize",be),R==null||R.dispose(),w==null||w.dispose(),k==null||k.dispose(),j==null||j.dispose(),M==null||M.dispose(),D==null||D.dispose()});const b=X({dateRange:O}),ie=p(!1),q=p([]),G=p([]);async function ue(){ie.value=!0;try{const t={};b.dateRange&&b.dateRange.length===2&&(t.start_date=b.dateRange[0],t.end_date=b.dateRange[1]);const a=(await h.getSummaryMatrix(t)).data,d=new Set(a.map(u=>u.sub_project?`${u.client_name}-${u.sub_project}`:u.client_name));q.value=[...d].sort();const l={};a.forEach(u=>{const v=u.sub_project?`${u.client_name}-${u.sub_project}`:u.client_name;l[u.user_name]||(l[u.user_name]={}),l[u.user_name][v]=(l[u.user_name][v]||0)+u.hours});const i=Object.entries(l).map(([u,v])=>{const P=Object.values(v).reduce((ce,U)=>ce+U,0);return{label:u,cells:v,total:Math.round(P*10)/10}}),n={};q.value.forEach(u=>{n[u]=Math.round(i.reduce((v,P)=>v+(P.cells[u]||0),0)*10)/10});const S=Math.round(i.reduce((u,v)=>u+v.total,0)*10)/10;i.push({label:"合计",cells:n,total:S}),G.value=i}finally{ie.value=!1}}async function ke(){const t={};let e="开始",a="至今";b.dateRange&&b.dateRange.length===2&&(t.start_date=b.dateRange[0],t.end_date=b.dateRange[1],e=t.start_date,a=t.end_date);const d=await h.exportMatrixExcel(t);ne(d.data,`研发工时汇总_${e}${a}.xlsx`),H.success("导出成功")}return(t,e)=>{const a=y("el-date-picker"),d=y("el-button"),l=y("el-table-column"),i=y("el-table"),n=y("el-tab-pane"),S=y("el-option"),u=y("el-select"),v=y("el-tag"),P=y("el-empty"),ce=y("el-tabs"),U=Se("loading");return _(),g("div",Ye,[s("div",$e,[e[13]||(e[13]=s("div",null,[s("h1",null,"全局统计看板"),s("p",null,"多维度查看工时数据:销售视角 / 研发视角 / 项目视角")],-1)),s("div",Ce,[o(a,{modelValue:L.value,"onUpdate:modelValue":e[0]||(e[0]=r=>L.value=r),type:"daterange","range-separator":"至","start-placeholder":"全部时间起","end-placeholder":"全部时间止","value-format":"YYYY-MM-DD",size:"large"},null,8,["modelValue"]),o(d,{type:"success",onClick:e[1]||(e[1]=r=>N("all")),loading:W.value,size:"large"},{default:c(()=>[...e[12]||(e[12]=[x(" 📊 总导出 (All in One) ",-1)])]),_:1},8,["loading"])])]),o(ce,{modelValue:Q.value,"onUpdate:modelValue":e[11]||(e[11]=r=>Q.value=r),type:"border-card",class:"dashboard-tabs"},{default:c(()=>[o(n,{label:"📈 销售视角",name:"sales"},{default:c(()=>[s("div",Ue,[o(a,{modelValue:V.dateRange,"onUpdate:modelValue":e[2]||(e[2]=r=>V.dateRange=r),type:"daterange","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期","value-format":"YYYY-MM-DD",size:"default"},null,8,["modelValue"]),o(d,{type:"primary",onClick:ve},{default:c(()=>[...e[14]||(e[14]=[x("查询",-1)])]),_:1}),o(d,{onClick:e[3]||(e[3]=r=>N("sales"))},{default:c(()=>[...e[15]||(e[15]=[x("📥 导出该页",-1)])]),_:1})]),s("div",Ee,[s("div",Oe,[e[16]||(e[16]=s("div",{class:"section-title"},"📋 销售人员汇总 (点击展开查看研发明细)",-1)),J((_(),E(i,{data:T.value,stripe:"",style:{width:"100%"},"row-key":"sales_name"},{default:c(()=>[o(l,{type:"expand"},{default:c(r=>[s("div",Be,[s("div",Pe," [ "+z(r.row.sales_name)+" ] 的研发工时消耗明细: ",1),o(i,{data:r.row.rdList,border:"",style:{width:"100%"},size:"small"},{default:c(()=>[o(l,{prop:"rd_name",label:"研发人员",width:"150"}),o(l,{prop:"total_hours",label:"消耗工时(h)",width:"120"}),o(l,{prop:"work_days",label:"工作天数",width:"120"})]),_:1},8,["data"])])]),_:1}),o(l,{prop:"sales_name",label:"销售人员","min-width":"140"}),o(l,{prop:"project_count",label:"项目数","min-width":"100"}),o(l,{prop:"rd_count",label:"涉及研发","min-width":"120"}),o(l,{prop:"total_hours",label:"总消耗工时(h)","min-width":"130",sortable:""})]),_:1},8,["data"])),[[U,se.value]])]),s("div",Fe,[s("div",Ae,[e[17]||(e[17]=s("div",{class:"chart-title"},"销售占用工时占比(饼图)",-1)),s("div",{ref_key:"salesChartRef",ref:Z,class:"big-chart"},null,512)]),s("div",We,[e[18]||(e[18]=s("div",{class:"chart-title"},"各销售工时对比(柱状图)",-1)),s("div",{ref_key:"salesBarRef",ref:te,class:"big-chart"},null,512)])])])]),_:1}),o(n,{label:"👨‍💻 研发视角",name:"rd"},{default:c(()=>[s("div",Te,[o(a,{modelValue:f.dateRange,"onUpdate:modelValue":e[4]||(e[4]=r=>f.dateRange=r),type:"daterange","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期","value-format":"YYYY-MM-DD",size:"default"},null,8,["modelValue"]),o(u,{modelValue:f.user_id,"onUpdate:modelValue":e[5]||(e[5]=r=>f.user_id=r),placeholder:"全部研发",clearable:"",size:"default",style:{width:"150px"}},{default:c(()=>[(_(!0),g(F,null,A(_e.value,r=>(_(),E(S,{key:r.id,label:r.realname,value:r.id},null,8,["label","value"]))),128))]),_:1},8,["modelValue"]),o(d,{type:"primary",onClick:ge},{default:c(()=>[...e[19]||(e[19]=[x("查询",-1)])]),_:1}),o(d,{onClick:e[6]||(e[6]=r=>N("rd"))},{default:c(()=>[...e[20]||(e[20]=[x("📥 导出该页",-1)])]),_:1})]),s("div",Ne,[s("div",qe,[e[21]||(e[21]=s("div",{class:"section-title"},"📋 研发人员填报明细",-1)),J((_(),E(i,{data:oe.value,stripe:"",style:{width:"100%"}},{default:c(()=>[o(l,{prop:"user_name",label:"研发人员","min-width":"120"}),o(l,{prop:"client_name",label:"客户/项目","min-width":"180"}),o(l,{prop:"work_date",label:"日期","min-width":"120"}),o(l,{prop:"hours",label:"工时(h)","min-width":"100"}),o(l,{prop:"remark",label:"备注","min-width":"180"})]),_:1},8,["data"])),[[U,re.value]])]),s("div",Ge,[s("div",Ke,[e[22]||(e[22]=s("div",{class:"chart-title"},"研发人员工时产出占比(饼图)",-1)),s("div",{ref_key:"rdChartRef",ref:I,class:"big-chart"},null,512)]),s("div",Xe,[e[23]||(e[23]=s("div",{class:"chart-title"},"各研发人员工时对比(柱状图)",-1)),s("div",{ref_key:"rdBarRef",ref:ae,class:"big-chart"},null,512)])])])]),_:1}),o(n,{label:"🏢 项目视角",name:"project"},{default:c(()=>[s("div",He,[o(a,{modelValue:m.dateRange,"onUpdate:modelValue":e[7]||(e[7]=r=>m.dateRange=r),type:"daterange","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期","value-format":"YYYY-MM-DD",size:"default",style:{"margin-right":"12px"}},null,8,["modelValue"]),o(u,{modelValue:m.sales_id,"onUpdate:modelValue":e[8]||(e[8]=r=>m.sales_id=r),clearable:"",placeholder:"全部销售",style:{width:"140px","margin-right":"12px"}},{default:c(()=>[(_(!0),g(F,null,A(pe.value,r=>(_(),E(S,{key:r.id,label:r.realname,value:r.id},null,8,["label","value"]))),128))]),_:1},8,["modelValue"]),o(d,{type:"primary",onClick:he},{default:c(()=>[...e[24]||(e[24]=[x("查询",-1)])]),_:1}),o(d,{onClick:e[9]||(e[9]=r=>N("project"))},{default:c(()=>[...e[25]||(e[25]=[x("📥 导出该页",-1)])]),_:1})]),s("div",Je,[s("div",Qe,[e[26]||(e[26]=s("div",{class:"section-title"},"📋 项目总览 (点击展开查看研发明细)",-1)),J((_(),E(i,{data:B.value,stripe:"",style:{width:"100%"},"row-key":"client_id"},{default:c(()=>[o(l,{type:"expand"},{default:c(r=>[s("div",Ze,[s("div",Ie," [ "+z(r.row.client_name)+" ] 的参与研发明细: ",1),o(i,{data:r.row.rdList,border:"",style:{width:"100%"},size:"small"},{default:c(()=>[o(l,{prop:"rd_name",label:"研发人员",width:"150"}),o(l,{prop:"total_hours",label:"消耗工时(h)",width:"120",sortable:""}),o(l,{prop:"work_days",label:"工作天数",width:"120"}),o(l,{prop:"first_date",label:"首次介入",width:"120"}),o(l,{prop:"last_date",label:"最近介入",width:"120"})]),_:1},8,["data"])])]),_:1}),o(l,{prop:"client_name",label:"客户/项目","min-width":"200"}),o(l,{prop:"sales_name",label:"所属销售","min-width":"120"}),o(l,{prop:"client_status",label:"状态","min-width":"90"},{default:c(({row:r})=>[o(v,{type:r.client_status===1?"success":"info",effect:"dark",round:""},{default:c(()=>[x(z(r.client_status===1?"进行中":"已结算"),1)]),_:2},1032,["type"])]),_:1}),o(l,{prop:"total_hours",label:"总工时(h)","min-width":"110",sortable:""}),o(l,{prop:"rd_count",label:"研发人数","min-width":"100"})]),_:1},8,["data"])),[[U,de.value]])]),s("div",et,[s("div",tt,[e[27]||(e[27]=s("div",{class:"chart-title"},"项目工时分布(饼图)",-1)),s("div",{ref_key:"projectChartRef",ref:ee,class:"big-chart"},null,512)]),s("div",at,[e[28]||(e[28]=s("div",{class:"chart-title"},"各项目工时对比(柱状图)",-1)),s("div",{ref_key:"projectBarRef",ref:le,class:"big-chart"},null,512)])])])]),_:1}),o(n,{label:"📊 研发工时汇总",name:"matrix"},{default:c(()=>[s("div",lt,[o(a,{modelValue:b.dateRange,"onUpdate:modelValue":e[10]||(e[10]=r=>b.dateRange=r),type:"daterange","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期","value-format":"YYYY-MM-DD",size:"default"},null,8,["modelValue"]),o(d,{type:"primary",onClick:ue},{default:c(()=>[...e[29]||(e[29]=[x("查询",-1)])]),_:1}),o(d,{onClick:ke},{default:c(()=>[...e[30]||(e[30]=[x("📥 导出该页",-1)])]),_:1})]),J((_(),g("div",st,[G.value.length?(_(),g("table",ot,[s("thead",null,[s("tr",null,[e[31]||(e[31]=s("th",{class:"row-header"},"研发人员",-1)),(_(!0),g(F,null,A(q.value,r=>(_(),g("th",{key:r},z(r),1))),128)),e[32]||(e[32]=s("th",{class:"total-col"},"合计",-1))])]),s("tbody",null,[(_(!0),g(F,null,A(G.value,(r,ye)=>(_(),g("tr",{key:ye,class:ze({"total-row":ye===G.value.length-1})},[s("td",rt,z(r.label),1),(_(!0),g(F,null,A(q.value,xe=>(_(),g("td",{key:xe},z(r.cells[xe]||"-"),1))),128)),s("td",dt,z(r.total),1)],2))),128))])])):(_(),E(P,{key:1,description:"暂无工时数据"}))])),[[U,ie.value]])]),_:1})]),_:1},8,["modelValue"])])}}},mt=je(nt,[["__scopeId","data-v-a0af1b80"]]);export{mt as default};