- profile_upsert now merges top-level keys (info/resume/zongce are independent sub-documents); previously any page saving its own slice silently wiped the other two (profile save lost zongce rules, assessment save lost resume, resume save lost zongce) - ZcItem gains recordIds: aggregated cap items (wcap/ccap/kcap/gcap/hcap) expose the records they aggregate, so the evidence gallery scored/unscored badge works (matchedIds was always empty before) - add regression coverage notes; www rebuilt
7 lines
23 KiB
JavaScript
7 lines
23 KiB
JavaScript
import{c as $,f as O,j as e,E as H,w as U,u as k,d as C,r as u,g as y,x as W,y as J,B as j,P as E,I as g,z as Y,C as A,A as V,D as B,F as X,m as S,l as Q,T as q,H as Z,J as z,K as M,S as T,M as D}from"./index-i50OZQTj.js";import{C as w,a as G,b as F}from"./card-D8TWS3Zn.js";import{u as ee,i as K,a as P}from"./useChart-B6jW3CzL.js";import{u as se,i as te,b as ae,a as re,c as ne,d as le,e as ie,f as oe}from"./echarts-BIWefrIc.js";/**
|
|
* @license lucide-react v0.475.0 - ISC
|
|
*
|
|
* This source code is licensed under the ISC license.
|
|
* See the LICENSE file in the root directory of this source tree.
|
|
*/const de=[["rect",{width:"16",height:"20",x:"4",y:"2",rx:"2",key:"1nb95v"}],["line",{x1:"8",x2:"16",y1:"6",y2:"6",key:"x4nwl0"}],["line",{x1:"16",x2:"16",y1:"14",y2:"18",key:"wjye3r"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M12 18h.01",key:"mhygvu"}],["path",{d:"M8 18h.01",key:"lrp35t"}]],R=$("Calculator",de);se([te,ae,re,ne,le,ie,oe]);function ce(l){const s=/^(\d{4})-(\d{4})/.exec(l);return s?s[1]+"~"+s[2]+" 学年":"其他学期"}function xe(l,s,r){const o=n=>{if(n.grade_point!=null)return n.grade_point;if(s&&n.score!=null){const a=s.find(i=>n.score>=i.min&&(n.score<i.max||i.max>=100&&n.score<=i.max));if(a&&a.gp!=null){if(a.gpTop!=null){const i=a.max>=100?a.max:a.max-1,d=(a.gpTop-a.gp)/Math.max(1,i-a.min);return Math.round((a.gp+(n.score-a.min)*d)*100)/100}return a.gp}}return null},h=n=>r?r[n.category??"其他"]??r.其他??1:1,x=l.map(n=>({...n,grade_point:o(n)})).filter(n=>n.grade_point!=null&&n.credit>0);if(!x.length)return null;const p=x.reduce((n,a)=>n+a.credit,0),m=x.reduce((n,a)=>n+a.grade_point*h(a)*a.credit,0);return Math.round(m/p*100)/100}function Ce(){const l=ee(),s=O({queryKey:["grades"],queryFn:D}),r=s.data,o=K("2"),h=K("3"),x=P(()=>{const n=((r==null?void 0:r.overall.tier_dist)??[]).filter(a=>a.count>0);return{tooltip:{trigger:"item"},legend:{orient:"vertical",right:8,top:"middle",itemGap:10,textStyle:{color:o,fontSize:11},itemWidth:10,itemHeight:10},series:[{type:"pie",radius:["48%","72%"],center:["34%","50%"],label:{show:!1},data:n.map(a=>({name:a.label,value:a.count,itemStyle:{color:a.color}}))}]}},[r,l]),p=P(()=>{const n=(r==null?void 0:r.overall.gpa_trend)??[];return{grid:{left:8,right:8,top:36,bottom:6,containLabel:!0},tooltip:{trigger:"axis"},legend:{top:0,left:"center",itemGap:16,textStyle:{color:o,fontSize:11},itemWidth:14,itemHeight:8},xAxis:{type:"category",data:n.map(a=>a.term),axisLine:{lineStyle:{color:h}},axisTick:{show:!1},axisLabel:{color:h,fontSize:10}},yAxis:[{type:"value",min:0,max:100,splitLine:{lineStyle:{color:"rgba(128,138,155,0.15)"}},axisLabel:{color:h,fontSize:10}},{type:"value",min:0,max:5,splitLine:{show:!1},axisLabel:{color:h,fontSize:10}}],series:[{name:"加权平均分",type:"bar",barMaxWidth:18,itemStyle:{color:"#3056d3",borderRadius:[3,3,0,0]},data:n.map(a=>a.avg)},{name:"绩点",type:"line",yAxisIndex:1,smooth:!0,symbolSize:6,itemStyle:{color:"#d97706"},lineStyle:{width:2},data:n.map(a=>a.gpa)}]}},[r,l]);if(s.isLoading)return e.jsx("div",{className:"py-16 text-center text-[13px] text-ink-3",children:"加载中…"});const m=[...(r==null?void 0:r.semesters)??[]].sort((n,a)=>a.term.localeCompare(n.term));return e.jsxs("div",{className:"mx-auto max-w-[1080px] px-3 py-4 sm:px-6 sm:py-5",children:[e.jsxs("div",{className:"mb-4 flex flex-wrap gap-3",children:[e.jsx(_,{label:"总学分",value:(r==null?void 0:r.overall.credits)??0}),e.jsx(_,{label:"加权平均分",value:(r==null?void 0:r.overall.avg)!=null?r.overall.avg:"—"}),e.jsx(_,{label:"已录课程",value:(r==null?void 0:r.overall.courses)??0}),e.jsx(_,{label:"学期数",value:(r==null?void 0:r.semesters.length)??0})]}),e.jsxs("div",{className:"mb-4 grid grid-cols-1 lg:grid-cols-2 gap-4",children:[e.jsxs(w,{children:[e.jsx(G,{title:"单科成绩等级分布"}),e.jsx(F,{children:e.jsx("div",{ref:x,className:"h-[220px]"})})]}),e.jsxs(w,{children:[e.jsx(G,{title:"学期趋势(加权平均分 / 绩点)"}),e.jsx(F,{children:e.jsx("div",{ref:p,className:"h-[220px]"})})]})]}),e.jsx(me,{bands:(r==null?void 0:r.bands)??[],weights:r==null?void 0:r.weights}),e.jsxs("div",{className:"mb-3 mt-5 flex items-center justify-between",children:[e.jsx("h2",{className:"text-[14px] font-semibold text-ink-1",children:"学年学科成绩"}),e.jsx(ve,{})]}),m.length?e.jsx("div",{className:"flex flex-col gap-5",children:ue(m).map(([n,a])=>e.jsxs("section",{children:[e.jsx("div",{className:"mb-2 text-[12px] font-medium text-ink-3",children:n}),e.jsx("div",{className:"flex flex-col gap-3",children:a.map(i=>e.jsx(pe,{sem:i},i.id))})]},n))}):e.jsx(w,{children:e.jsx(H,{icon:e.jsx(U,{size:36,strokeWidth:1.5}),title:"暂无学期成绩",description:"新增一个学期(如 2024-2025-1),再录入各科成绩。"})})]})}function ue(l){const s=new Map;for(const r of l){const o=ce(r.term);s.has(o)||s.set(o,[]),s.get(o).push(r)}return[...s.entries()]}function _({label:l,value:s}){return e.jsxs("div",{className:"min-w-[128px] flex-1 max-w-[220px] rounded-lg border border-line bg-surface px-4 py-3 shadow-card",children:[e.jsx("div",{className:"text-[12px] text-ink-3",children:l}),e.jsx("div",{className:"num mt-0.5 text-[22px] font-semibold leading-tight text-ink-1",children:s})]})}function me({bands:l,weights:s}){const r=k(),o=C(),[h,x]=u.useState(null),[p,m]=u.useState(null),n=y({mutationFn:W,onSuccess:()=>{o("success","梯度已保存"),r.invalidateQueries({queryKey:["grades"]})},onError:i=>o("error",i.message)}),a=y({mutationFn:J,onSuccess:()=>{r.invalidateQueries({queryKey:["grades"]}),m(null)}});return e.jsxs(w,{children:[e.jsx(G,{title:"成绩梯度",extra:e.jsx("span",{className:"text-[11px] text-ink-3",children:"绩点按档内线性折算(起~顶),各校规则不同可修改"})}),e.jsxs(F,{className:"p-0",children:[e.jsx("div",{className:"divide-y divide-line",children:l.map(i=>e.jsx(L,{band:i,onSave:d=>n.mutate(d),onDelete:()=>m(i)},i.id))}),e.jsx("div",{className:"border-t border-line px-4 py-2.5",children:h?e.jsx(L,{band:h,isNew:!0,onChange:x,onSave:()=>{n.mutate(h),x(null)},onCancel:()=>x(null)}):e.jsxs(j,{size:"sm",variant:"secondary",onClick:()=>{var i;return x({id:0,label:"",color:"#3056d3",min:0,max:60,gp:null,gpTop:null,sort:(((i=l.at(-1))==null?void 0:i.sort)??0)+10})},children:[e.jsx(E,{size:13})," 添加等级"]})})]}),e.jsxs("div",{className:"border-t border-line px-4 py-3",children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between",children:[e.jsx("span",{className:"text-[12px] font-semibold text-ink-2",children:"课程权重系数"}),e.jsx("span",{className:"text-[11px] text-ink-3",children:"课程学分绩点 = 绩点 × 权重 × 学分"})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:Object.entries(s??{}).map(([i,d])=>e.jsxs("div",{className:"flex items-center gap-1.5 rounded-md border border-line bg-surface-2 px-2.5 py-1",children:[e.jsx("span",{className:"text-[11.5px] text-ink-2",children:i}),e.jsx(g,{type:"number",step:"0.1",className:"num h-6 w-[56px] border-0 bg-transparent p-0",value:String(d),onChange:b=>{const v={...s??{},[i]:Number(b.target.value)||1};Y(v).then(()=>r.invalidateQueries({queryKey:["grades"]})).catch(t=>o("error",t.message))}})]},i))}),e.jsx("div",{className:"mt-2 text-[11px] text-ink-3",children:"公式:平均学分绩点 = Σ(课程绩点 × 权重系数 × 学分) ÷ Σ(学分) · 各校规则不同,可直接修改"})]}),e.jsx(A,{open:!!p,title:"删除等级",content:p?"确定删除「"+p.label+"」吗?已录成绩将不再显示该等级。":"",onCancel:()=>m(null),onOk:()=>p&&a.mutate(p.id)})]})}function L({band:l,onSave:s,onDelete:r,onChange:o,onCancel:h,isNew:x}){const[p,m]=u.useState(l),n=x&&o?p:l,a=d=>{const b={...n,...d};o?o(b):m(b)},i=x||JSON.stringify({...n,id:0})!==JSON.stringify({...l,id:0});return e.jsx("div",{className:"px-4 py-3",children:e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-2.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:n.color,onChange:d=>a({color:d.target.value}),className:"size-6 shrink-0 cursor-pointer rounded border border-line bg-surface","aria-label":"颜色"}),e.jsx(g,{className:"min-w-0 flex-1 sm:w-[96px] sm:flex-none",value:n.label,onChange:d=>a({label:d.target.value}),placeholder:"等级名"})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-1.5 rounded-md border border-line bg-surface-2 px-2.5 py-1",children:[e.jsx("span",{className:"text-[11px] text-ink-3",children:"分数"}),e.jsx(g,{type:"number",className:"num h-6 w-[64px] border-0 bg-transparent p-0 text-right",value:String(n.min),onChange:d=>a({min:Number(d.target.value)})}),e.jsx("span",{className:"text-[11.5px] text-ink-3",children:"—"}),e.jsx(g,{type:"number",className:"num h-6 w-[64px] border-0 bg-transparent p-0",value:String(n.max),onChange:d=>a({max:Number(d.target.value)})}),e.jsx("span",{className:"ml-1 text-[11px] text-ink-3",children:"绩点"}),e.jsx(g,{type:"number",step:"0.1",className:"num h-6 w-[52px] border-0 bg-transparent p-0 text-right",value:n.gp!=null?String(n.gp):"",placeholder:"起",onChange:d=>a({gp:d.target.value===""?null:Number(d.target.value)})}),e.jsx("span",{className:"text-[11.5px] text-ink-3",children:"~"}),e.jsx(g,{type:"number",step:"0.1",className:"num h-6 w-[52px] border-0 bg-transparent p-0",value:n.gpTop!=null?String(n.gpTop):"",placeholder:"顶",onChange:d=>a({gpTop:d.target.value===""?null:Number(d.target.value)})})]}),e.jsx("div",{className:"flex items-center gap-1.5 sm:ml-auto",children:x?e.jsxs(e.Fragment,{children:[e.jsx(j,{size:"sm",variant:"primary",onClick:()=>s==null?void 0:s(n),children:"添加"}),e.jsx(j,{size:"sm",variant:"ghost",onClick:()=>h==null?void 0:h(),children:"取消"})]}):e.jsxs(e.Fragment,{children:[e.jsx(j,{size:"sm",variant:i?"primary":"secondary",disabled:!i,onClick:()=>s==null?void 0:s(n),children:"保存"}),e.jsx(j,{size:"icon-sm",variant:"ghost","aria-label":"删除等级",onClick:()=>r==null?void 0:r(),children:e.jsx(q,{size:13})})]})})]})})}function pe({sem:l}){const s=k(),r=C(),o=O({queryKey:["grades"],queryFn:D}),[h,x]=u.useState(null),[p,m]=u.useState(null),[n,a]=u.useState(!1),i=()=>void s.invalidateQueries({queryKey:["grades"]}),d=y({mutationFn:V,onSuccess:()=>{i(),m(null)}}),b=y({mutationFn:()=>{var N,c;const t=xe(l.courses,(N=o.data)==null?void 0:N.bands,(c=o.data)==null?void 0:c.weights);if(t==null)throw new Error("请先为课程填写绩点");return B({id:l.id,term:l.term,gpa:t,rank:l.rank??null,total_students:l.total_students??null})},onSuccess:()=>{r("success","绩点已按课程自动计算"),i()},onError:t=>r("error",t.message)}),v=y({mutationFn:()=>X(l.id),onSuccess:()=>{i(),a(!1),r("success","学期已删除")}});return e.jsxs(w,{children:[e.jsxs("div",{className:"flex min-h-11 flex-col items-start justify-center gap-1.5 border-b border-line px-4 py-2 sm:flex-row sm:items-center sm:justify-between sm:gap-2",children:[e.jsx("h3",{className:"text-[13px] font-semibold text-ink-1",children:l.term}),e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsxs(S,{color:"var(--brand-text)",children:["绩点 ",l.gpa??"—"]}),l.rank!=null&&e.jsxs(S,{color:"var(--success)",children:["排名 ",l.rank,"/",l.total_students??"—"]}),e.jsxs(S,{color:"var(--text-3)",children:["均分 ",l.stats.avg??"—"]}),e.jsxs(S,{color:"var(--text-3)",children:[l.stats.credits," 学分"]}),e.jsxs(j,{size:"sm",variant:"ghost",onClick:()=>b.mutate(),disabled:b.isPending,children:[e.jsx(R,{size:13})," 自动绩点"]}),e.jsx(j,{size:"icon-sm",variant:"ghost","aria-label":"编辑学期",onClick:()=>a(!0),children:e.jsx(Q,{size:13})})]})]}),e.jsx(F,{className:"p-0",children:e.jsx("div",{className:"hidden overflow-x-auto md:block",children:e.jsx("div",{className:"-mx-1 overflow-x-auto px-1",children:e.jsxs("table",{className:"w-full border-collapse text-[13px]",children:[e.jsx("thead",{children:e.jsx("tr",{children:["课程","学分","分数","类别","等级","绩点",""].map(t=>e.jsx("th",{className:"border-b border-line bg-surface-2 px-3 py-2 text-left text-[12px] font-semibold text-ink-3",children:t},t))})}),e.jsxs("tbody",{children:[l.courses.map(t=>h===t.id?e.jsx(ge,{sem:l,course:t,onDone:()=>x(null)},t.id):e.jsxs("tr",{className:"transition-colors hover:bg-surface-2",children:[e.jsx("td",{className:"border-b border-line px-3 py-2 font-medium text-ink-1",children:t.course_name}),e.jsx("td",{className:"num border-b border-line px-3 py-2 text-ink-2",children:t.credit}),e.jsx("td",{className:"num border-b border-line px-3 py-2",children:t.score!=null?e.jsx("span",{className:"font-medium",children:t.score}):e.jsx("span",{className:"text-ink-3",children:"未录入"})}),e.jsx("td",{className:"border-b border-line px-3 py-2 text-[12px] text-ink-3",children:t.category??"—"}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:t.band?e.jsx(S,{color:t.band.color,children:t.band.label}):e.jsx("span",{className:"text-ink-3",children:"—"})}),e.jsx("td",{className:"num border-b border-line px-3 py-2 text-ink-2",children:t.grade_point??"—"}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsxs("div",{className:"flex justify-end gap-1",children:[e.jsx(j,{size:"icon-sm",variant:"ghost","aria-label":"编辑课程",onClick:()=>x(t.id),children:e.jsx(Q,{size:13})}),e.jsx(j,{size:"icon-sm",variant:"ghost","aria-label":"删除课程",className:"text-ink-3 hover:text-danger",onClick:()=>m(t),children:e.jsx(q,{size:13})})]})})]},t.id)),e.jsx(he,{sem:l})]})]})})})}),e.jsxs("div",{className:"divide-y divide-line border-t border-line md:hidden",children:[l.courses.map(t=>h===t.id?e.jsx(be,{sem:l,course:t,onDone:()=>x(null)},"e"+t.id):e.jsxs("div",{className:"p-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"min-w-0 flex-1 truncate text-[13px] font-medium text-ink-1",children:t.course_name}),t.band&&e.jsx(S,{color:t.band.color,children:t.band.label})]}),e.jsxs("div",{className:"num mt-1 flex flex-wrap gap-x-3 text-[11.5px] text-ink-3",children:[e.jsxs("span",{children:["学分 ",t.credit]}),e.jsxs("span",{children:["分数 ",t.score??"—"]}),e.jsxs("span",{children:["绩点 ",t.grade_point??"—"]})]}),e.jsxs("div",{className:"mt-2 flex gap-1.5",children:[e.jsxs(j,{size:"sm",variant:"secondary",onClick:()=>x(t.id),children:[e.jsx(Q,{size:12})," 编辑"]}),e.jsxs(j,{size:"sm",variant:"ghost",className:"text-ink-3 hover:text-danger",onClick:()=>m(t),children:[e.jsx(q,{size:12})," 删除"]})]})]},t.id)),e.jsx(je,{sem:l})]}),e.jsx(A,{open:!!p,title:"删除课程",content:p?"确定删除「"+p.course_name+"」吗?":"",onCancel:()=>m(null),onOk:()=>p&&d.mutate(p.id)}),e.jsx(I,{open:n,sem:l,onClose:()=>a(!1),deleteMut:v})]})}function he({sem:l}){const s=k(),r=C(),[o,h]=u.useState(""),[x,p]=u.useState(""),[m,n]=u.useState(""),[a,i]=u.useState(""),[d,b]=u.useState("必修课"),v=y({mutationFn:()=>M({semester_id:l.id,course_name:o,credit:Number(x)||0,score:m===""?null:Number(m),grade_point:a===""?null:Number(a)}),onSuccess:()=>{h(""),p(""),n(""),i(""),s.invalidateQueries({queryKey:["grades"]})},onError:t=>r("error",t.message)});return e.jsxs("tr",{className:"bg-surface-2",children:[e.jsx("td",{className:"px-3 py-2",children:e.jsx(g,{className:"h-7 w-[160px]",placeholder:"课程名称",value:o,onChange:t=>h(t.target.value)})}),e.jsx("td",{className:"px-3 py-2",children:e.jsx(g,{type:"number",step:"0.5",className:"num h-7 w-[64px]",placeholder:"0",value:x,onChange:t=>p(t.target.value)})}),e.jsx("td",{className:"px-3 py-2",children:e.jsx(g,{type:"number",className:"num h-7 w-[72px]",placeholder:"0-100",value:m,onChange:t=>n(t.target.value)})}),e.jsx("td",{className:"px-3 py-2",children:e.jsx(T,{className:"h-7 w-[110px]",value:d,onChange:t=>b(t.target.value),options:["必修课","专业选修课","人文素质选修课","其他"].map(t=>({value:t,label:t}))})}),e.jsx("td",{className:"px-3 py-2 text-ink-3",children:"—"}),e.jsx("td",{className:"px-3 py-2",children:e.jsx(g,{type:"number",step:"0.1",className:"num h-7 w-[64px]",placeholder:"选填",value:a,onChange:t=>i(t.target.value)})}),e.jsx("td",{className:"px-3 py-2",children:e.jsxs(j,{size:"sm",variant:"secondary",disabled:!o.trim()||v.isPending,onClick:()=>v.mutate(),children:[e.jsx(E,{size:13})," 添加"]})})]})}function ge({sem:l,course:s,onDone:r}){const o=k(),h=C(),[x,p]=u.useState(s.course_name),[m,n]=u.useState(String(s.credit)),[a,i]=u.useState(s.score!=null?String(s.score):""),[d,b]=u.useState(s.grade_point!=null?String(s.grade_point):""),[v,t]=u.useState(s.category??"必修课"),N=y({mutationFn:()=>M({id:s.id,semester_id:l.id,course_name:x,credit:Number(m)||0,score:a===""?null:Number(a),grade_point:d===""?null:Number(d),category:v}),onSuccess:()=>{o.invalidateQueries({queryKey:["grades"]}),r()},onError:c=>h("error",c.message)});return e.jsxs("tr",{className:"bg-brand-subtle/40",children:[e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsx(g,{className:"h-7 w-[160px]",value:x,onChange:c=>p(c.target.value)})}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsx(g,{type:"number",step:"0.5",className:"num h-7 w-[64px]",value:m,onChange:c=>n(c.target.value)})}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsx(g,{type:"number",className:"num h-7 w-[72px]",value:a,onChange:c=>i(c.target.value)})}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsx(T,{className:"h-7 w-[110px]",value:v,onChange:c=>t(c.target.value),options:["必修课","专业选修课","人文素质选修课","其他"].map(c=>({value:c,label:c}))})}),e.jsx("td",{className:"border-b border-line px-3 py-2 text-[12px] text-ink-3",children:"保存后按梯度定级"}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsx(g,{type:"number",step:"0.1",className:"num h-7 w-[64px]",value:d,onChange:c=>b(c.target.value)})}),e.jsx("td",{className:"border-b border-line px-3 py-2",children:e.jsxs("div",{className:"flex justify-end gap-1.5",children:[e.jsx(j,{size:"sm",variant:"primary",onClick:()=>N.mutate(),disabled:N.isPending,children:"保存"}),e.jsx(j,{size:"sm",variant:"ghost",onClick:r,children:"取消"})]})})]})}function je({sem:l}){const s=k(),r=C(),[o,h]=u.useState(""),[x,p]=u.useState(""),[m,n]=u.useState(""),[a,i]=u.useState(""),[d,b]=u.useState("必修课"),v=y({mutationFn:()=>M({semester_id:l.id,course_name:o,credit:Number(x)||0,score:m===""?null:Number(m),grade_point:a===""?null:Number(a),category:d}),onSuccess:()=>{h(""),p(""),n(""),i(""),s.invalidateQueries({queryKey:["grades"]}),r("success","课程已添加")},onError:t=>r("error",t.message)});return e.jsxs("div",{className:"p-3",children:[e.jsx(g,{className:"mb-2",placeholder:"课程名称",value:o,onChange:t=>h(t.target.value)}),e.jsxs("div",{className:"mb-2 grid grid-cols-3 gap-2",children:[e.jsx(g,{type:"number",step:"0.5",placeholder:"学分",value:x,onChange:t=>p(t.target.value)}),e.jsx(g,{type:"number",placeholder:"分数",value:m,onChange:t=>n(t.target.value)}),e.jsx(g,{type:"number",step:"0.1",placeholder:"绩点",value:a,onChange:t=>i(t.target.value)})]}),e.jsx(T,{className:"mb-2",value:d,onChange:t=>b(t.target.value),options:["必修课","专业选修课","人文素质选修课","其他"].map(t=>({value:t,label:t}))}),e.jsxs(j,{size:"sm",variant:"primary",disabled:!o.trim()||v.isPending,onClick:()=>v.mutate(),children:[e.jsx(E,{size:13})," 添加课程"]})]})}function be({sem:l,course:s,onDone:r}){const o=k(),h=C(),[x,p]=u.useState(s.course_name),[m,n]=u.useState(String(s.credit)),[a,i]=u.useState(s.score!=null?String(s.score):""),[d,b]=u.useState(s.grade_point!=null?String(s.grade_point):""),[v,t]=u.useState(s.category??"必修课"),N=y({mutationFn:()=>M({id:s.id,semester_id:l.id,course_name:x,credit:Number(m)||0,score:a===""?null:Number(a),grade_point:d===""?null:Number(d),category:v}),onSuccess:()=>{o.invalidateQueries({queryKey:["grades"]}),r()},onError:c=>h("error",c.message)});return e.jsxs("div",{className:"bg-brand-subtle/40 p-3",children:[e.jsx(g,{className:"mb-2",placeholder:"课程名称",value:x,onChange:c=>p(c.target.value)}),e.jsxs("div",{className:"mb-2 grid grid-cols-3 gap-2",children:[e.jsx(g,{type:"number",step:"0.5",placeholder:"学分",value:m,onChange:c=>n(c.target.value)}),e.jsx(g,{type:"number",placeholder:"分数",value:a,onChange:c=>i(c.target.value)}),e.jsx(g,{type:"number",step:"0.1",placeholder:"绩点",value:d,onChange:c=>b(c.target.value)})]}),e.jsx(T,{className:"mb-2",value:v,onChange:c=>t(c.target.value),options:["必修课","专业选修课","人文素质选修课","其他"].map(c=>({value:c,label:c}))}),e.jsxs("div",{className:"flex gap-1.5",children:[e.jsx(j,{size:"sm",variant:"primary",onClick:()=>N.mutate(),children:"保存"}),e.jsx(j,{size:"sm",variant:"ghost",onClick:r,children:"取消"})]})]})}function ve(){const[l,s]=u.useState(!1);return e.jsxs(e.Fragment,{children:[e.jsxs(j,{variant:"primary",size:"md",onClick:()=>s(!0),children:[e.jsx(E,{size:14})," 新增学期"]}),e.jsx(I,{open:l,sem:null,onClose:()=>s(!1)})]})}function I({open:l,sem:s,onClose:r,deleteMut:o}){const h=k(),x=C(),[p,m]=u.useState((s==null?void 0:s.term)??""),[n,a]=u.useState((s==null?void 0:s.gpa)!=null?String(s.gpa):""),[i,d]=u.useState((s==null?void 0:s.rank)!=null?String(s.rank):""),[b,v]=u.useState((s==null?void 0:s.total_students)!=null?String(s.total_students):""),[t,N]=u.useState(""),c=y({mutationFn:()=>B({id:s==null?void 0:s.id,term:p,gpa:n===""?null:Number(n),rank:i===""?null:Number(i),total_students:b===""?null:Number(b)}),onSuccess:()=>{x("success",s?"学期已更新":"学期已新增"),h.invalidateQueries({queryKey:["grades"]}),r()},onError:f=>N(f.message)});return e.jsx(Z,{open:l,onClose:r,width:480,title:s?"编辑学期 · "+s.term:"新增学期",footer:e.jsxs(e.Fragment,{children:[t&&e.jsx("span",{className:"mr-auto text-[12px] text-danger",children:t}),s&&e.jsxs(j,{variant:"danger-ghost",className:"mr-auto",onClick:()=>o==null?void 0:o.mutate(),disabled:o==null?void 0:o.isPending,children:[e.jsx(q,{size:13})," 删除学期"]}),e.jsx(j,{variant:"secondary",onClick:r,children:"取消"}),e.jsx(j,{variant:"primary",onClick:()=>c.mutate(),disabled:c.isPending,children:"保存"})]}),children:e.jsxs("div",{className:"flex flex-col gap-3.5",children:[e.jsx(z,{label:"学期名称",required:!0,hint:"如 2024-2025-1",children:e.jsx(g,{value:p,onChange:f=>m(f.target.value),placeholder:"2024-2025-1"})}),e.jsxs("div",{className:"grid grid-cols-3 gap-3",children:[e.jsx(z,{label:"绩点",children:e.jsx(g,{type:"number",step:"0.01",className:"num",value:n,onChange:f=>a(f.target.value),placeholder:"选填"})}),e.jsx(z,{label:"排名",children:e.jsx(g,{type:"number",className:"num",value:i,onChange:f=>d(f.target.value),placeholder:"选填"})}),e.jsx(z,{label:"年级人数",children:e.jsx(g,{type:"number",className:"num",value:b,onChange:f=>v(f.target.value),placeholder:"选填"})})]}),e.jsxs("p",{className:"flex items-start gap-1.5 rounded-md bg-surface-2 px-3 py-2 text-[12px] text-ink-3",children:[e.jsx(R,{size:13,className:"mt-0.5 shrink-0"}),"绩点可手动填写,也可在卡片上点「自动绩点」按课程学分加权计算。"]})]})})}export{Ce as GradesPage};
|