- /auth/register: strip client-supplied seed flag (PoC confirmed it bypassed invite code, MAX_USERS quota AND first-user auto-admin, granting admin without any credential); demo-rebuild internal path unaffected - /auth/login: per-IP+username of 5 consecutive failures gets a 10-minute cooldown against in-memory counter (brute-force guard) - /auth/logout: new endpoint revokes the current Bearer token server-side; frontend calls it (best-effort) before local clearToken on sidebar logout - attachment docx/xlsx preview: sanitize generated HTML (strip scripts, event handlers, dangerous protocols) before dangerouslySetInnerHTML render, preventing token theft via malicious previewed documents PoC suite: seed smuggling rejected, 429 on 6th login attempt, token dead after logout, per-user isolation intact (403/401/404 as before); integration 61/61 green
28 lines
35 KiB
JavaScript
28 lines
35 KiB
JavaScript
import{c as ve,d as Ce,f as pe,r as S,ai as ke,aj as Se,j as e,S as _e,B as A,ak as xe,ah as ze,m as me,H as fe,af as Oe,ag as Ie,v as Me,M as Re}from"./index-DuP8O2p4.js";import{R as he,P as Fe,C as Ke}from"./rotate-ccw-xltE5Sb1.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 Ee=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],Te=ve("ChevronLeft",Ee);/**
|
||
* @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 Le=[["path",{d:"M18 22H4a2 2 0 0 1-2-2V6",key:"pblm9e"}],["path",{d:"m22 13-1.296-1.296a2.41 2.41 0 0 0-3.408 0L11 18",key:"nf6bnh"}],["circle",{cx:"12",cy:"8",r:"2",key:"1822b1"}],["rect",{width:"16",height:"16",x:"6",y:"2",rx:"2",key:"12espp"}]],De=ve("Images",Le),be={politics:{中共党员:3,中共预备党员:2.5,入党积极分子:2,共青团员:1.5,群众:1},conductDefault:8,integrityDefault:2,sportsFactor:.025,gpaFactor:10,table2:{国家级:{一等奖:3,二等奖:2,三等奖:1,优秀奖:.5},省市级:{一等奖:2,二等奖:1,三等奖:.5,优秀奖:.2},区县级:{一等奖:1,二等奖:.5,三等奖:.2,优秀奖:.1},校级:{一等奖:.5,二等奖:.2,三等奖:.1,优秀奖:.05},二级学院:{一等奖:.2,二等奖:.1,三等奖:.05,优秀奖:0}},table4:{校级:{干部:4,干事:2,社团干部:1,学工助理:2},院级:{干部:3,干事:1.5,支部委员:1.5,支部组长:1,班长:1,团支书:1,班委:.5,社团干部:1,学工助理:2}},publicGood:{无偿献血:.5,捐献骨髓:3,国家级:1.5,省市级:1,区县级:.5,校级:.2,二级学院:.1},rewards:{荣誉称号:{院级:.3,校级:.5,区级:1,市级:1.5,国家级:2},英语等级:{三级:.5,四级:1,六级:2},计算机等级:{一级:.5,二级:1,三级:2},职业资格:{从业资格:.5,初级:1,中级:2,高级:3}},penalties:{留校察看:5,记过:4,严重警告:3,警告:2,通报批评:1}};function ie(i){const l=/^(\d{4})-(\d{4})/.exec(String(i??"").trim());return l?l[1]+"-"+l[2]:null}function we(i){const l=/^(\d{4})-(\d{4})$/.exec(i);return l?[l[1]+"-09-01",l[2]+"-09-01"]:null}function ue(i,l){const m=ie(i)??i,b=/^(\d{4})/.exec(m),y=/^(\d{4})/.exec(l??"");if(!b||!y)return m+" 学年";const a=Number(b[1])-Number(y[1])+1,h=["大一","大二","大三","大四","大五","大六","大七"];return a<1?m+" 学年":(h[a-1]??a+"年级")+"("+m+" 学年)"}function We(i,l){if(!l)return!0;const m=(i??"").slice(0,10);return m>=l[0]&&m<l[1]}function ne(i){const l=(i??"").trim();return l?l.includes("国家")?"国家级":l.includes("省")||l.includes("市")?"省市级":l.includes("区")?"区县级":l.includes("院")||l.includes("二级")?"二级学院":l.includes("校")?"校级":null:null}function ge(i){const l=(i??"").trim();return l?/特等|一等|金(色)?奖|冠军|第1名|第一名/.test(l)?"一等奖":/二等|银(色)?奖|亚军|第2名|第3名|第二名|第三名/.test(l)?"二等奖":/三等|铜(色)?奖|第[4-6]名|第四名|第五名|第六名/.test(l)?"三等奖":/优秀|优胜|第[7-9]名|第七名/.test(l)?"优秀奖":null:null}const K=i=>Math.round(i*100)/100;function ye(i,l,m){var y;return!l||!m?null:((y=i.table2[l])==null?void 0:y[m])??null}function Ge(i){var x,I,G,ee;const{year:l,records:m,semesters:b,bands:y,weights:a,profile:h,rules:o,ov:w}=i,C=l==="all"?null:we(l),f=m.filter(t=>t.status!=="draft"&&We(t.start_date??t.created_at,C)),j=t=>{var n;return(n=w.itemOverrides)==null?void 0:n[t]},v=(t,n,d,p,N,U)=>{const F=j(t),Ne=(F==null?void 0:F.score)??p??0;return{itemKey:t,title:n,source:d,score:Ne,overridden:(F==null?void 0:F.score)!=null,note:N,fromRecord:U}},R=(t,n,d,p)=>({key:t,label:n,cap:d,items:p,subtotal:K(p.reduce((N,U)=>N+U.score,0))}),_=[],te=h.political??"",J=Object.keys(o.politics).find(t=>te.includes(t)),u=J?o.politics[J]:1,E=w.conduct??o.conductDefault,z=w.integrity??o.integrityDefault;_.push(R("conduct","品行素质",13,[{itemKey:"politics",title:"思想政治基础分("+(te||"群众")+")",source:"个人信息 · 政治面貌",score:u},{itemKey:"conduct",title:"操行考评成绩",source:"辅导员考评(可修改)",score:E,overridden:w.conduct!=null},{itemKey:"integrity",title:"诚信分",source:"默认满分(可修改)",score:z,overridden:w.integrity!=null}]));const O=t=>{if(t.grade_point!=null)return t.grade_point;if(y&&t.score!=null){const n=y.find(d=>t.score>=d.min&&(t.score<d.max||d.max>=100&&t.score<=d.max));if(n&&n.gp!=null){if(n.gpTop!=null){const d=n.max>=100?n.max:n.max-1,p=(n.gpTop-n.gp)/Math.max(1,d-n.min);return K(n.gp+(t.score-n.min)*p)}return n.gp}}return null},Q=t=>a?a[t.category??"其他"]??a.其他??1:1,P=ie(l),H=b.filter(t=>!P||ie(t.term)===P),q=[],D=[];for(const t of H){if(q.push(...t.courses??[]),t.gpa!=null){D.push({term:t.term,gpa:t.gpa,fallback:!1});continue}const n=(t.courses??[]).map(p=>({...p,grade_point:O(p)})).filter(p=>p.grade_point!=null&&p.credit>0);if(!n.length)continue;const d=n.reduce((p,N)=>p+N.credit,0);D.push({term:t.term,gpa:K(n.reduce((p,N)=>p+N.grade_point*Q(N)*N.credit,0)/d),fallback:!0})}const T=D.length?K(D.reduce((t,n)=>t+n.gpa,0)/D.length):null,ae=T==null?"该学年暂无学期绩点数据(先在「成绩」页录入学期或课程)":D.some(t=>t.fallback)?"部分学期绩点未录入,按课程推算":void 0,ce=T!=null?K(T*o.gpaFactor):0;_.push(R("academic","学业成绩",60,[{itemKey:"gpa",title:"学年平均学分绩点 "+(T!=null?T.toFixed(2):"—")+" × "+o.gpaFactor,source:"成绩模块 · "+H.length+" 学期"+(D.length?"(绩点均值)":""),score:ce,note:ae||(T==null?void 0:q.length+" 门课程")}]));const W=q.filter(t=>/体育/.test(t.course_name)),se=K(W.reduce((t,n)=>t+(n.score??0),0)*o.sportsFactor),re=[];W.length&&re.push({itemKey:"sports",title:"体育成绩("+W.length+" 学期体育课)",source:"体育课成绩之和 × "+o.sportsFactor,score:Math.min(se,5)});const k=[];for(const t of f.filter(n=>n.type_name==="文体活动")){const n=ye(o,ne(t.level),ge(t.award_grade));n==null&&!((x=j("w"+t.id))!=null&&x.score)||k.push(v("w"+t.id,t.title,t.type_name+" · "+(t.level??"")+" "+(t.award_grade??""),n,void 0,t.id))}const de=K(Math.min(k.reduce((t,n)=>t+n.score,0),5));_.push(R("sports","文体素质",10,[...re,{itemKey:"wcap",title:"文体类加分(上限 5 分)",source:k.length+" 条记录",score:de,note:k.map(t=>t.title+" "+t.score+"分").join(";")||"无匹配记录",recordIds:k.map(t=>t.fromRecord).filter(Boolean)}]));const Y=[];for(const t of f.filter(n=>n.type_name==="竞赛"||n.type_name==="科研")){const n=ye(o,ne(t.level),ge(t.award_grade));n==null&&!((I=j("c"+t.id))!=null&&I.score)||Y.push(v("c"+t.id,t.title,t.type_name+" · "+(t.level??"")+" "+(t.award_grade??""),n,void 0,t.id))}const $=K(Math.min(Y.reduce((t,n)=>t+n.score,0),10)),Z=[];for(const t of f.filter(n=>n.type_name==="学生工作")){const n=ne(t.level)??"院级",d=(t.role??"")+" "+t.title,p=o.table4[n==="国家级"||n==="省市级"||n==="区县级"?"校级":n]??o.table4.院级;let N=null;for(const[U,F]of Object.entries(p))if(d.includes(U)){N=F;break}N==null&&!((G=j("k"+t.id))!=null&&G.score)||Z.push(v("k"+t.id,t.title,"学生工作 · "+(t.level??"院级")+" "+(t.role??""),N,N==null?"请手动填写分值":void 0,t.id))}const X=K(Math.min(Z.reduce((t,n)=>t+n.score,0),4)),V=[];for(const t of f.filter(n=>n.type_name==="志愿公益")){const n=ne(t.level),d=/献血/.test(t.title);let p=d?o.publicGood.无偿献血:n?o.publicGood[n]??null:null;p==null&&!((ee=j("g"+t.id))!=null&&ee.score)||V.push(v("g"+t.id,t.title,"公益 · "+(d?"无偿献血":t.level??"校级"),p,void 0,t.id))}const oe=K(Math.min(V.reduce((t,n)=>t+n.score,0),3));_.push(R("expand","拓展性素质",17,[{itemKey:"ccap",title:"竞赛获奖(上限 10 分)",source:Y.length+" 条记录",score:$,note:Y.map(t=>t.title+" "+t.score+"分").join(";")||"无匹配记录",recordIds:Y.map(t=>t.fromRecord).filter(Boolean)},{itemKey:"kcap",title:"担任学生工作(上限 4 分)",source:Z.length+" 条记录",score:X,note:Z.map(t=>t.title+" "+t.score+"分").join(";")||"无匹配记录",recordIds:Z.map(t=>t.fromRecord).filter(Boolean)},{itemKey:"gcap",title:"公益活动(上限 3 分)",source:V.length+" 条记录",score:oe,note:V.map(t=>t.title+" "+t.score+"分").join(";")||"无匹配记录",recordIds:V.map(t=>t.fromRecord).filter(Boolean)}]));const s=[];for(const t of f.filter(n=>n.type_name==="荣誉惩处"||n.type_name==="证书技能")){const n=j("h"+t.id),d=t.title+" "+(t.award_grade??"");if(/综合测评奖学金/.test(d))continue;let p=null,N=t.type_name;if(/留校察看/.test(d))p=-o.penalties.留校察看;else if(/记过/.test(d))p=-o.penalties.记过;else if(/严重警告/.test(d))p=-o.penalties.严重警告;else if(/警告/.test(d))p=-o.penalties.警告;else if(/通报批评/.test(d))p=-o.penalties.通报批评;else if(/六级|专八/.test(d))p=o.rewards.英语等级.六级;else if(/四级|专四/.test(d))p=o.rewards.英语等级.四级;else if(/三级/.test(d)&&/英语/.test(d))p=o.rewards.英语等级.三级;else if(/计算机/.test(d)&&/三级/.test(d))p=o.rewards.计算机等级.三级;else if(/计算机/.test(d)&&/二级/.test(d))p=o.rewards.计算机等级.二级;else if(/计算机/.test(d)&&/一级/.test(d))p=o.rewards.计算机等级.一级;else if(/高级/.test(d))p=o.rewards.职业资格.高级;else if(/中级/.test(d))p=o.rewards.职业资格.中级;else if(/初级/.test(d))p=o.rewards.职业资格.初级;else if(/从业|资格证|教师资格|普通话|驾驶证|软考/.test(d))p=o.rewards.职业资格.从业资格;else{const U=ne(t.level),F=U==="省市级"?"市级":U==="区县级"?"区级":U==="二级学院"?"院级":U;F&&o.rewards.荣誉称号[F]!=null&&(p=o.rewards.荣誉称号[F],N="荣誉 · "+F)}p==null&&!(n!=null&&n.score)||s.push(v("h"+t.id,t.title,N,p,void 0,t.id))}const r=K(Math.max(Math.min(s.reduce((t,n)=>t+n.score,0),5),-5));_.push(R("rewards","奖惩分",5,[{itemKey:"hcap",title:"奖惩合计(±5 分)",source:s.length+" 条记录",score:r,note:s.map(t=>t.title+" "+t.score+"分").join(";")||"无匹配记录",recordIds:s.map(t=>t.fromRecord).filter(Boolean)}]));for(const t of w.manual??[]){const n=_.find(d=>d.label===t.section)??_[_.length-1];n.items.push({itemKey:"m"+t.title+t.score,title:t.title,source:"手动添加",score:t.score}),n.subtotal=K(n.items.reduce((d,p)=>d+p.score,0))}const c=K(_.reduce((t,n)=>{const d=n.key==="rewards"?n.subtotal:Math.min(n.subtotal,n.cap);return t+d},0));return{sections:_,total:c,gpa:T}}function M(i){return String(i??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Ue(i,l){var y;const m="----=_fp_zongce",b=[];b.push(`MIME-Version: 1.0\r
|
||
Content-Type: multipart/related; type="text/html"; boundary="`+m+`"\r
|
||
\r
|
||
--`+m+`\r
|
||
Content-Location: document.html\r
|
||
Content-Type: text/html; charset="utf-8"\r
|
||
Content-Transfer-Encoding: 8bit\r
|
||
\r
|
||
`+i+`\r
|
||
`);for(const a of l){const h=a.dataUri.indexOf(","),o=a.dataUri.slice(0,h),w=a.dataUri.slice(h+1),C=((y=/data:([^;]+)/.exec(o))==null?void 0:y[1])??"image/png";b.push("--"+m+`\r
|
||
Content-Location: `+a.name+`\r
|
||
Content-Type: `+C+`\r
|
||
Content-Transfer-Encoding: base64\r
|
||
\r
|
||
`+w+`\r
|
||
`)}return b.push("--"+m+`--\r
|
||
`),new Blob([b.join("")],{type:'multipart/related; type="text/html"; boundary="'+m+'"'})}const g="border:0.75pt solid #3a3a3a;padding:5pt 8pt;font-size:10.5pt;vertical-align:middle",L='border:0.75pt solid #3a3a3a;padding:5pt 8pt;font-size:10.5pt;font-family:"黑体",SimHei;letter-spacing:1pt;vertical-align:middle;background:#eef1f6',Be='border:0.75pt solid #3a3a3a;padding:5pt 8pt;font-size:11pt;font-family:"黑体",SimHei;letter-spacing:1.5pt;background:#f5f6f9;text-align:left',je=(i,l)=>'<!--[if supportFields]><span style="mso-element:field-begin"></span>'+i+'<span style="mso-element:field-separator"></span><![endif]-->'+l+'<!--[if supportFields]><span style="mso-element:field-end"></span><![endif]-->';function He(i){const l='<table style="border-collapse:collapse;width:100%;margin:4pt 0" border="1"><tr><td style="'+L+';width:30%">基础项</td><td style="'+L+'">分值 / 规则</td></tr><tr><td style="'+g+'">政治面貌分</td><td style="'+g+'">'+M(Object.entries(i.politics).map(([f,j])=>f+" "+j+" 分").join(";"))+'</td></tr><tr><td style="'+g+'">操行考评 / 诚信分默认</td><td style="'+g+'">'+M(i.conductDefault)+" 分 / "+M(i.integrityDefault)+' 分</td></tr><tr><td style="'+g+'">学业成绩</td><td style="'+g+'">学年平均学分绩点 × '+M(i.gpaFactor)+'(上限 60 分)</td></tr><tr><td style="'+g+'">体育加分</td><td style="'+g+'">体育课成绩之和 × '+M(i.sportsFactor)+'(上限 5 分)</td></tr><tr><td style="'+g+'">公益服务</td><td style="'+g+'">'+M(Object.entries(i.publicGood).map(([f,j])=>f+" "+j).join(";"))+"</td></tr></table>",m=i.table2,b=i.table4,y=i.rewards,a=Object.keys(m),h=["一等奖","二等奖","三等奖","优秀奖"],o='<table style="border-collapse:collapse;width:100%;margin:4pt 0" border="1"><tr><td style="'+L+';width:20%">获奖级别</td>'+h.map(f=>'<td style="'+L+'">'+f+"</td>").join("")+"</tr>"+a.map(f=>'<tr><td style="'+g+'">'+M(f)+"</td>"+h.map(j=>{var v;return'<td style="'+g+';text-align:right" class="num">'+M(((v=m[f])==null?void 0:v[j])??"—")+"</td>"}).join("")+"</tr>").join("")+"</table>",w='<table style="border-collapse:collapse;width:100%;margin:4pt 0" border="1"><tr><td style="'+L+';width:20%">学生工作级别</td><td style="'+L+'">岗位分值</td></tr>'+Object.keys(b).map(f=>'<tr><td style="'+g+'">'+M(f)+'</td><td style="'+g+'">'+M(Object.entries(b[f]).map(([j,v])=>j+" "+v).join(";"))+"</td></tr>").join("")+"</table>",C='<table style="border-collapse:collapse;width:100%;margin:4pt 0" border="1"><tr><td style="'+L+';width:20%">类别</td><td style="'+L+'">分值</td></tr>'+["荣誉称号","英语等级","计算机等级","职业资格"].map(f=>'<tr><td style="'+g+'">'+M(f)+'</td><td style="'+g+'">'+M(Object.entries(y[f]??{}).map(([j,v])=>j+" "+v).join(";"))+"</td></tr>").join("")+'<tr><td style="'+g+'">违纪扣分</td><td style="'+g+'">'+M(Object.entries(i.penalties).map(([f,j])=>f+" -"+j).join(";"))+"</td></tr></table>";return'<div style="font-family:SimHei;font-size:12pt;margin:14pt 0 4pt">附 2:评分细则参考(默认值,可自行调整)</div>'+l+o+w+C}function qe(i,l,m,b,y){const a=u=>M(u),h=m.school?'<div style="text-align:center;font-size:10.5pt;letter-spacing:2pt;color:#222">'+a(m.school)+"</div>":"",o=(u,E)=>'<td style="'+L+';width:16%;text-align:center">'+E+'</td><td style="'+g+';text-align:center">'+a(u||"")+"</td>",w=["一","二","三","四","五","六","七","八"],C=[];l.sections.forEach((u,E)=>{const z=u.key==="rewards"?u.subtotal:Math.min(u.subtotal,u.cap);C.push('<tr><td colspan="3" style="'+Be+'">'+a(w[E]??E+1)+"、"+a(u.label)+"(上限 "+a(u.cap)+" 分)</td></tr>");for(const O of u.items)C.push('<tr><td style="'+g+'">'+a(O.title)+(O.overridden?'<span style="color:#8a6d3b">(已手动修正)</span>':"")+'</td><td style="'+g+';color:#444;font-size:9.5pt;border-left-width:0.75pt">'+a(O.note||O.source)+'</td><td style="'+g+';text-align:right;width:64pt" class="num">'+a(O.score)+"</td></tr>");C.push('<tr><td colspan="2" style="'+g+';text-align:right;background:#fafbfc">'+a(u.label)+'小计</td><td style="'+g+';text-align:right;background:#fafbfc" class="num"><b>'+a(z)+"</b></td></tr>")}),C.push('<tr><td colspan="2" style="'+g+';text-align:center;font-family:"黑体",SimHei;font-size:12pt;letter-spacing:2pt;background:#eef1f6">综合素质测评总分</td><td style="'+g+';text-align:right;background:#eef1f6" class="num"><b style="font-size:12pt">'+a(l.total)+"</b></td></tr>");const f='<table style="border-collapse:collapse;width:100%;margin-top:10pt" border="1"><tr><td style="'+L+';width:34%;text-align:center">考评项目</td><td style="'+L+';text-align:center">评分依据</td><td style="'+L+';width:64pt;text-align:center">分值</td></tr>'+C.join("")+"</table>",j=[];let v=0;const R=b.map(u=>{const E=u.images.map(z=>{v++;const O="ev"+u.recordId+"_"+j.length;return j.push({name:O,dataUri:z}),'<div style="text-align:center;margin:3pt 0"><img src="'+O+'" style="width:200pt;border:0.75pt solid #5a5a5a" alt="附图"><br><span style="font-size:9pt;color:#333;font-family:"宋体",SimSun">图 '+v+" "+a(u.title)+"</span></div>"}).join("");return'<tr><td style="'+g+';width:26%;vertical-align:top;background:#fafafa"><b style="font-size:10pt">'+a(u.title)+'</b><br><span style="font-size:9pt;color:#555">'+a(u.meta)+'</span></td><td style="'+g+'">'+E+"</td></tr>"}).join(""),_=R?'<div style="font-family:"黑体",SimHei;font-size:12pt;margin:16pt 0 4pt;letter-spacing:1pt">附 1:加分证明材料</div><div style="font-size:9.5pt;color:#555;margin:0 0 4pt">('+a(b.length)+" 项记录 · "+a(v)+' 张材料图)</div><table style="border-collapse:collapse;width:100%" border="1">'+R+"</table>":"",te='<table style="border-collapse:collapse;width:100%;margin-top:12pt" border="1"><tr>'+o(m.studentId,"学 号")+o(m.name,"姓 名")+o(m.gender,"性 别")+"</tr><tr>"+o(m.college,"学 院")+o(m.major,"专 业")+o(m.className,"班 级")+"</tr><tr>"+o(m.political,"政治面貌")+o(i,"统计周期")+o(m.phone,"电话号码")+"</tr></table>",J='<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word"><head><meta charset="utf-8"><title>学生综合素质测评表</title><!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:Zoom>100</w:Zoom><w:TrackChanges>0</w:TrackChanges></w:WordDocument></xml><![endif]--><style>@page WordSection1 { size:595.3pt 841.9pt; margin:72pt 78pt 66pt; mso-footer: f1; }div.WordSection1 { page:WordSection1; }body { font-family:"宋体",SimSun,serif; font-size:10.5pt; color:#1a1a1a; line-height:1.5; }h1.title { font-family:"黑体",SimHei; font-size:18pt; text-align:center; letter-spacing:4pt; margin:2pt 0 6pt; font-weight:bold; }p.sub { text-align:center; font-size:10pt; color:#333; margin:0 0 2pt; }table { border-collapse:collapse; }.num { font-family:"Times New Roman",SimSun; }</style></head><body><div class="WordSection1">'+h+'<h1 class="title">学生综合素质测评表</h1><p class="sub">测评学年:'+a(i)+"</p>"+te+f+_+He(y)+'<table style="width:100%;border-collapse:collapse;margin-top:26pt;font-size:10.5pt"><tr><td style="width:25%">学生签名:_____</td><td style="width:25%">班长签名:_____</td><td style="width:25%">辅导员签名:_____</td><td>日期:______</td></tr></table><p style="font-size:9pt;color:#555;margin-top:12pt">说明:本表依据《学生综合素质测评评分细则》自动生成(细则默认值见附 2,可自行调整);带「已手动修正」标记的分值为手动核定结果。导出前请核对加分记录与证明材料一致。</p><div style="mso-element:footer" id="f1"><p style="text-align:center;font-size:9pt;font-family:"宋体",SimSun;margin:0">第 '+je("PAGE","1")+" 页(共 "+je("NUMPAGES","1")+" 页)</p></div></div></body></html>";return Ue(J,j)}const B=({value:i,onChange:l,wide:m})=>e.jsx("input",{type:"number",step:"0.05",className:"num rounded-md border border-neutral-200 bg-white px-1 py-0.5 text-right text-[11.5px] focus:border-brand focus:outline-none "+(m?"w-[76px]":"w-[58px]"),value:i,onChange:b=>l(b.target.value===""?0:Number(b.target.value))}),le=({head:i,children:l})=>e.jsxs("table",{className:"w-full border border-neutral-200 text-[11.5px]",children:[e.jsx("thead",{children:e.jsx("tr",{children:i.map((m,b)=>e.jsx("th",{className:"border-b border-neutral-200 bg-neutral-50 px-2 py-1 text-left font-medium text-neutral-500",children:m},b))})}),e.jsx("tbody",{children:l})]});function Ze(){var V,oe;const i=Ce(),l=pe({queryKey:["profile"],queryFn:Ie}),m=pe({queryKey:["zc-records"],queryFn:()=>Me({page:1,page_size:500})}),b=pe({queryKey:["grades"],queryFn:Re}),y=(V=l.data)==null?void 0:V.content,a={...(y==null?void 0:y.info)??{}},[h,o]=S.useState(""),[w,C]=S.useState({}),[f,j]=S.useState([]),[v,R]=S.useState(!1),[_,te]=S.useState(!1),J=S.useRef(null),[u,E]=S.useState(be),[z,O]=S.useState(null);S.useEffect(()=>{var s,r;y&&(C(((s=y.zongce)==null?void 0:s.overrides)??{}),(r=y.zongce)!=null&&r.rules&&E(y.zongce.rules))},[y]);const Q=((oe=m.data)==null?void 0:oe.items)??[],P=S.useMemo(()=>{var s;return Array.from(new Set((((s=b.data)==null?void 0:s.semesters)??[]).map(r=>ie(r.term)).filter(Boolean))).sort()},[b.data]);S.useEffect(()=>{var s;y&&(C(((s=y.zongce)==null?void 0:s.overrides)??{}),!h&&P.length&&o(P[0]))},[y,b.data]);const H=w[h]??{},q=S.useMemo(()=>{var s,r,c;return Ge({year:h||"all",records:Q,semesters:((s=b.data)==null?void 0:s.semesters)??[],bands:(r=b.data)==null?void 0:r.bands,weights:(c=b.data)==null?void 0:c.weights,profile:a,rules:u,ov:H})},[Q,b.data,a,u,H,h]),D=a.eduStart||(P.length?P[0]+"-09":""),T=h==="all"||!h?"全部学年":ue(h,D),ae=S.useMemo(()=>{const s=h&&h!=="all"?we(h):null;return Q.filter(r=>{if(r.status==="draft")return!1;if(!s)return!0;const c=(r.start_date??r.created_at??"").slice(0,10);return c>=s[0]&&c<s[1]}).map(r=>r.id)},[Q,h]),ce=S.useMemo(()=>{const s=new Set;return q.sections.forEach(r=>r.items.forEach(c=>{c.fromRecord&&s.add(c.fromRecord);for(const x of c.recordIds??[])s.add(x)})),s},[q]);S.useEffect(()=>{let s=!0;return(async()=>{const r=[];for(const c of ae){const x=Q.find(I=>I.id===c);try{const I=await ke(c),G=[];for(const ee of I.items.filter(t=>t.id&&(t.mime??"").startsWith("image/"))){const t=await Se(ee.id);t.data_b64&&G.push("data:"+(ee.mime==="image/jpeg"?"image/jpeg":"image/webp")+";base64,"+t.data_b64)}if(G.length){const ee=[x==null?void 0:x.type_name,x==null?void 0:x.level,x==null?void 0:x.award_grade].filter(Boolean).join(" · ");r.push({recordId:c,title:(x==null?void 0:x.title)??"记录 "+c,meta:ee,images:G})}}catch{}}s&&j(r)})(),()=>{s=!1}},[ae.join(",")]);const W=S.useMemo(()=>{const s=[];for(const r of f)for(const c of r.images)s.push({src:c,title:r.title});return s},[f]),se=s=>void Oe({info:a,zongce:{rules:s.rules??u,overrides:s.overrides??w}}).catch(r=>i("error",r.message)),re=s=>{C(r=>({...r,[h]:s})),se({overrides:{...w,[h]:s}})},k=s=>{const r=JSON.parse(JSON.stringify(u));s(r),E(r),se({rules:r})},de=()=>{const s=JSON.parse(JSON.stringify(be));E(s),se({rules:s}),i("success","评分细则已恢复默认")},Y=()=>{const s=qe(T,q,a,f,u),r=URL.createObjectURL(s),c=document.createElement("a");c.href=r,c.download="综合素质测评_"+T+".doc",c.click(),setTimeout(()=>URL.revokeObjectURL(r),6e4),i("success","综测表已导出(.doc,附证明材料图 "+W.length+" 张 + 细则参考)")},$=z?W.findIndex(s=>s.src===z.src):-1,Z=s=>{const r=$+s;r>=0&&r<W.length&&O({src:W[r].src,title:W[r].title,index:r})},X=W.length;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:"no-print mb-4 flex flex-wrap items-center justify-between gap-2",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-[15px] font-semibold text-ink-1",children:"综合测评"}),e.jsx("p",{className:"mt-0.5 text-[11.5px] text-ink-3",children:"按学年依据评分细则自动计算,可手动修正分值,支持导出 Word 测评表"})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(_e,{className:"w-[190px]",value:h,onChange:s=>o(s.target.value),options:[...P.map(s=>({value:s,label:ue(s,D)})),{value:"all",label:"全部学年"}]}),e.jsxs(A,{variant:"secondary",onClick:()=>{const s=!_;te(s),s&&setTimeout(()=>{var r;return(r=J.current)==null?void 0:r.scrollIntoView({behavior:"smooth",block:"start"})},80)},children:[e.jsx(xe,{size:13})," 评分细则参考"]}),e.jsxs(A,{variant:"secondary",onClick:Y,children:[e.jsx(ze,{size:13})," 导出 Word"]}),e.jsxs(A,{variant:"secondary",onClick:()=>R(!0),children:[e.jsx(he,{size:13})," 初始化"]}),e.jsxs(A,{variant:"primary",onClick:()=>window.print(),children:[e.jsx(Fe,{size:13})," 打印"]})]})]}),_&&e.jsxs("div",{ref:J,className:"no-print mb-4 scroll-mt-16 rounded-xl border border-line bg-white p-4 shadow-card",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(xe,{size:15,className:"text-neutral-500"}),e.jsx("span",{className:"text-[13.5px] font-bold text-neutral-900",children:"评分细则参考"}),e.jsx("span",{className:"text-[11.5px] text-neutral-400",children:"默认值可自行调整,调整后即时生效并随档案保存"})]}),e.jsxs(A,{variant:"ghost",onClick:de,children:[e.jsx(he,{size:13})," 恢复默认"]})]}),e.jsxs("div",{className:"mt-3 grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"mb-1.5 text-[12px] font-semibold text-neutral-600",children:"基础分值"}),e.jsxs(le,{head:["项目","分值"],children:[Object.entries(u.politics).map(([s,r])=>e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:s}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:r,onChange:c=>k(x=>{x.politics[s]=c})})})]},s)),e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:"操行考评默认分"}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:u.conductDefault,onChange:s=>k(r=>{r.conductDefault=s})})})]}),e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:"诚信分默认"}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:u.integrityDefault,onChange:s=>k(r=>{r.integrityDefault=s})})})]}),e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:"学业成绩(绩点 ×)"}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:u.gpaFactor,onChange:s=>k(r=>{r.gpaFactor=s})})})]}),e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:"体育加分(成绩 ×)"}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:u.sportsFactor,onChange:s=>k(r=>{r.sportsFactor=s})})})]})]}),e.jsx("div",{className:"mb-1.5 mt-3 text-[12px] font-semibold text-neutral-600",children:"公益服务"}),e.jsx(le,{head:["项目","分值"],children:Object.entries(u.publicGood).map(([s,r])=>e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:s}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:r,onChange:c=>k(x=>{x.publicGood[s]=c})})})]},s))}),e.jsx("div",{className:"mb-1.5 mt-3 text-[12px] font-semibold text-neutral-600",children:"违纪扣分"}),e.jsx(le,{head:["项目","扣分"],children:Object.entries(u.penalties).map(([s,r])=>e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:s}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:r,onChange:c=>k(x=>{x.penalties[s]=c})})})]},s))})]}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-1.5 text-[12px] font-semibold text-neutral-600",children:"竞赛 / 文体奖项加分(级别 × 奖项)"}),e.jsxs("table",{className:"w-full border border-neutral-200 text-[11.5px]",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:"border-b border-neutral-200 bg-neutral-50 px-2 py-1 text-left font-medium text-neutral-500",children:"级别"}),["一等奖","二等奖","三等奖","优秀奖"].map(s=>e.jsx("th",{className:"border-b border-neutral-200 bg-neutral-50 px-2 py-1 text-left font-medium text-neutral-500",children:s},s))]})}),e.jsx("tbody",{children:Object.entries(u.table2).map(([s,r])=>e.jsxs("tr",{children:[e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1 font-medium text-neutral-700",children:s}),["一等奖","二等奖","三等奖","优秀奖"].map(c=>e.jsx("td",{className:"border-b border-neutral-100 px-1 py-1",children:e.jsx(B,{value:r[c]??0,onChange:x=>k(I=>{I.table2[s][c]=x})})},c))]},s))})]}),e.jsx("div",{className:"mb-1.5 mt-3 text-[12px] font-semibold text-neutral-600",children:"学生工作"}),e.jsx(le,{head:["级别 / 岗位","分值"],children:Object.entries(u.table4).flatMap(([s,r])=>Object.entries(r).map(([c,x])=>e.jsxs("tr",{children:[e.jsxs("td",{className:"border-b border-neutral-100 px-2 py-1",children:[s," · ",c]}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:x,onChange:I=>k(G=>{G.table4[s][c]=I})})})]},s+c)))}),e.jsx("div",{className:"mb-1.5 mt-3 text-[12px] font-semibold text-neutral-600",children:"荣誉与证照加分"}),e.jsx(le,{head:["类别 / 等级","分值"],children:Object.entries(u.rewards).flatMap(([s,r])=>Object.entries(r).map(([c,x])=>e.jsxs("tr",{children:[e.jsxs("td",{className:"border-b border-neutral-100 px-2 py-1",children:[s," · ",c]}),e.jsx("td",{className:"border-b border-neutral-100 px-2 py-1",children:e.jsx(B,{value:x,onChange:I=>k(G=>{G.rewards[s][c]=I})})})]},s+c)))})]})]})]}),e.jsxs("div",{className:"print-sheet mx-auto w-full max-w-[820px] rounded-xl border border-line bg-white shadow-card sm:p-8",children:[a.school&&e.jsx("div",{className:"text-center text-[11px] tracking-widest text-neutral-500",children:a.school}),e.jsx("h1",{className:"mt-0.5 text-center text-[19px] font-bold tracking-wide text-neutral-900",children:"学生综合素质测评表"}),e.jsxs("div",{className:"mt-1 text-center text-[12px] text-neutral-500",children:["测评学年:",T]}),e.jsx("div",{className:"mt-4 grid grid-cols-2 gap-px overflow-hidden rounded-lg border border-neutral-300 bg-neutral-300 text-[12.5px] sm:grid-cols-3",children:[["学 号",a.studentId],["姓 名",a.name],["性 别",a.gender],["学 院",a.college],["专 业",a.major],["班 级",a.className],["政治面貌",a.political],["统计周期",T],["电话号码",a.phone]].map(([s,r])=>e.jsxs("div",{className:"flex bg-white",children:[e.jsx("span",{className:"w-[62px] shrink-0 bg-neutral-50 px-2 py-1.5 font-medium text-neutral-500",children:s}),e.jsx("span",{className:"min-w-0 flex-1 truncate px-2 py-1.5 text-neutral-900",children:r||"—"})]},s))}),e.jsxs("div",{className:"mt-4 flex items-center justify-center rounded-lg bg-gradient-to-r from-neutral-900 to-neutral-700 px-4 py-2.5 text-white",children:[e.jsx("span",{className:"text-[12px] opacity-80",children:"综合素质测评总分"}),e.jsx("span",{className:"num ml-3 text-[26px] font-bold leading-none",children:q.total}),e.jsx("span",{className:"ml-1.5 text-[12px] opacity-80",children:"/ 100 分"})]}),q.sections.map(s=>e.jsxs("div",{className:"mt-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"h-4 w-1 rounded-full bg-brand"}),e.jsx("span",{className:"text-[13.5px] font-bold text-neutral-900",children:s.label}),e.jsxs(me,{className:"no-print",color:"var(--text-3)",children:["上限 ",s.cap," 分"]})]}),e.jsxs("span",{className:"num rounded-md bg-neutral-100 px-2 py-0.5 text-[12px] font-semibold text-neutral-700",children:["小计 ",s.key==="rewards"?s.subtotal:Math.min(s.subtotal,s.cap)]})]}),e.jsxs("div",{className:"mt-2 flex flex-col gap-1.5 rounded-lg border border-neutral-200 bg-neutral-50/60 p-3",children:[s.items.map(r=>e.jsxs("div",{className:"flex items-center gap-2 text-[12.5px]",children:[e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:"text-neutral-900",children:r.title}),e.jsx("span",{className:"ml-2 text-[11px] text-neutral-400",children:r.source}),r.note&&e.jsx("div",{className:"text-[11px] leading-relaxed text-neutral-400",children:r.note})]}),e.jsx("input",{type:"number",step:"0.1",className:"num w-[72px] rounded-md border border-neutral-200 bg-white px-1.5 py-0.5 text-right text-[12px] focus:border-brand focus:outline-none",value:r.score,onChange:c=>{var x;if(r.itemKey==="conduct"||r.itemKey==="integrity")re({...H,[r.itemKey]:Number(c.target.value)});else{const I={...H.itemOverrides??{},[r.itemKey]:{...((x=H.itemOverrides)==null?void 0:x[r.itemKey])??{},score:Number(c.target.value)}};re({...H,itemOverrides:I})}}})]},r.itemKey)),!s.items.length&&e.jsx("div",{className:"text-[12px] text-neutral-400",children:"暂无数据"})]})]},s.key)),(f.length>0||X>0)&&e.jsxs("div",{className:"mt-7",children:[e.jsx("div",{className:"flex items-center justify-between border-t border-neutral-200 pt-4",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(De,{size:15,className:"text-neutral-500"}),e.jsx("span",{className:"text-[13.5px] font-bold text-neutral-900",children:"附:加分证明材料"}),e.jsxs("span",{className:"text-[11.5px] text-neutral-400",children:["共 ",f.length," 项记录 · ",X," 张图片(点击可放大)"]})]})}),e.jsx("div",{className:"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2",children:f.map(s=>e.jsxs("div",{className:"rounded-lg border border-neutral-200 bg-white p-2.5 transition-shadow hover:shadow-md",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-2",children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-1.5",children:[ce.has(s.recordId)?e.jsx(me,{color:"var(--brand-text)",children:"计分"}):e.jsx(me,{className:"no-print",color:"var(--text-3)",children:"未计分"}),e.jsx("div",{className:"min-w-0 truncate text-[12.5px] font-semibold text-neutral-800",children:s.title})]}),e.jsx("div",{className:"shrink-0 text-[10.5px] text-neutral-400",children:s.meta})]}),e.jsx("div",{className:"mt-2 gap-2 "+(s.images.length>1?"grid grid-cols-2":"flex"),children:s.images.map((r,c)=>e.jsx("button",{onClick:()=>O({src:r,title:s.title,index:W.findIndex(x=>x.src===r)}),className:"group overflow-hidden rounded-md border border-neutral-200 bg-neutral-50",children:e.jsx("img",{src:r,alt:"证明 "+(c+1),className:"aspect-[4/3] w-full object-cover transition-transform group-hover:scale-[1.03]"})},c))})]},s.recordId))})]}),e.jsx("div",{className:"mt-6 border-t border-neutral-200 pt-3 text-[11px] leading-relaxed text-neutral-400",children:"计分依据:《学生综合素质测评评分细则》(默认值可在上方「评分细则参考」查看与修改)。 自动匹配条目均可手动修正分值;「初始化」清除本学年全部手动修正。导出 Word / 打印前请核对加分记录与证明材料一致。"})]}),e.jsx(fe,{open:!!z,onClose:()=>O(null),width:920,title:z?z.title+"("+($+1)+"/"+X+")":"",footer:e.jsxs("div",{className:"flex w-full items-center justify-between",children:[e.jsxs(A,{variant:"secondary",disabled:$<=0,onClick:()=>Z(-1),children:[e.jsx(Te,{size:13})," 上一张"]}),e.jsx("span",{className:"num text-[12px] text-ink-3",children:z?$+1+" / "+X:""}),e.jsxs(A,{variant:"primary",disabled:$>=X-1,onClick:()=>Z(1),children:["下一张 ",e.jsx(Ke,{size:13})]})]}),children:z&&e.jsx("img",{src:z.src,alt:z.title,className:"mx-auto max-h-[74vh] rounded-md"})}),e.jsx(fe,{open:v,onClose:()=>R(!1),width:440,title:"初始化综测",footer:e.jsxs(e.Fragment,{children:[e.jsx(A,{variant:"ghost",onClick:()=>R(!1),children:"取消"}),e.jsx(A,{variant:"primary",onClick:()=>{const s={...w};delete s[h],C(s),se({overrides:s}),R(!1),i("success","已恢复自动计算")},children:"恢复自动计算"})]}),children:e.jsxs("div",{className:"text-[12.5px] leading-relaxed text-ink-2",children:["将清除 ",e.jsx("b",{children:h==="all"||!h?"全部学年":ue(h,D)})," 的全部手动修正 (分值覆盖、操行/诚信分修改),恢复为按细则规则的自动计算结果。",e.jsx("div",{className:"mt-2 text-ink-3",children:"记录数据、个人信息与评分细则不受影响。"})]})})]})}export{Ze as AssessmentPage};
|