From 155db7a1e439d4db0005c7dd23662c14696ff560 Mon Sep 17 00:00:00 2001 From: yuk255 Date: Fri, 12 Sep 2025 22:59:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=AF=B9=E6=8E=A5=E9=83=A8=E5=88=86?= =?UTF-8?q?=E7=8F=AD=E7=BA=A7=E9=A1=B5=E9=9D=A2=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E9=83=A8=E5=88=86=E8=AF=BE=E7=A8=8B?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=8C=E5=AF=B9=E6=8E=A5=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E9=83=A8=E5=88=86=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/images/profile/folder.png | Bin 24317 -> 24047 bytes src/api/modules/teachCourse.ts | 155 +- src/api/modules/upload.ts | 4 +- .../admin/CourseComponents/CourseCategory.vue | 140 +- .../admin/CourseComponents/CourseCreate.vue | 428 +++-- src/components/admin/MyResources.vue | 371 +--- src/components/teacher/ClassManagement.vue | 400 +++-- src/stores/course.ts | 333 ++-- .../teacher/course/AddCoursewareModal.vue | 344 ++-- .../teacher/course/ChapterManagement.vue | 613 ++----- .../teacher/course/CoursewareManagement.vue | 1559 +---------------- .../course/CoursewareManagementBackup.vue | 1543 ++++++++++++++++ src/views/teacher/student/ClassManagement.vue | 79 +- 13 files changed, 2959 insertions(+), 3010 deletions(-) create mode 100644 src/views/teacher/course/CoursewareManagementBackup.vue diff --git a/public/images/profile/folder.png b/public/images/profile/folder.png index 7d7298434bc90250400fedfc2e9eabb670b4b96a..90b3fdd7f811e5bc5e0e8a0eca990658556f8555 100644 GIT binary patch literal 24047 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 Ci~kw` literal 24317 zcmXt91yEaE({9lgZ-JtPQi@A(309y*UW!9;w^H0K2?dH2E$*Zg_fjZMa3{FCyCuPr zB0v3R{<(8AnK{|B=k7iG?C!HC-!#+|i3w;49zA+QtgQ4->(Qgfc>nGv51)_1g(V~( zJtBLg{7zQK_wiAyU#-nNc=k%-s`a4s!1?0G$1)a!&&oUoBHjV*FGNT#I}v2PWUt76 zzm2je@aF5+jdJlcBdWv`1-uX_7%wX5NN91rxz z{dakDj**6C2YXiQ{m^^$laZ*E&>wfi0M|5f|1xB~pxB);Pj4+t_Xi`XCWk!^ze*E?4%NL;SAXr2$y1X;8C%5QJ~3$MRCA6)Rlp z;XD0c_R--UWkb|IaT9J^b+16ZAEPIiTo39Ot8}l9C>!|x4TUyNgL7N4>dpSiLn@l= zs@g+K9<=ZdSHRk+7VLZi|1IWf_I9skpRxh)Z}opSM9!7Z36{+M$=`a(U>yB%PofCU zL)Kvp#8+2uFh{(mxR?%C#EGAoTU9&HKb1x)#S-TP#x4JTwXuwXZI}ibeSDa>o_qZE zc+75=%k_U#2WU>`)I1nK@1Fr~@GkeS2$udgv#HLX-6Kk|-G3^jT7sm!s@nZ3{u$#i z`w(?P*%1D}0d8mYWiD6Ke+p6lyO@>$+!G62-lGmzQilcYD}t=Q|I{z7cEY|qSnPjK ze4B9@-HNpf!@4yWyQ=>M_@TFUqPGT$+?5bb2sr3Gkx}|Si#o#Ziefh;-KP{g|0ghZ>S|_I)gD#c9txx;z%`6}COX67{I*Kog^rD- zlF%wYz?FCz?h1bC*4dCpZozwdK-pl%<;p~YceP$rm3lo6Kkp!OA#)&FgiqPhZ$xiku2~T zhU#uyIYQ=MiVd;LdNaEUejfPZ#^xv%O&SP_CIxW@3+_OUqok`+OR=u@#qb09u1Rjm z8R<49R+?k)ue#(x--*#TF;7++P$@*~_pig4I;oUD$l&JU0Qwhj9ffG^2dSpN@no`6 zYL$8;(Bw#zaSL9DNHNn;VqG6oxyY<+IG zp>+JQ^iPj^uv#c_!?;TI6P&l69CtkZ4$NxM(z9Pigu>Nl^zS~2&iC))S#AHJ>Xm7P zgcOA`!LID$HcnwK(Q#5$1rPppSJK|WK;%4pb!XfybKj`jKr?$t=jCF#HYo9(?nULG zJUbg}wj{US#o2VoPpzBkU#ET-kCe4M`Zu~+Qop;PIY)h7(Cf%tmgHSuUR7+0=deyx zw>>xnKBd@P$hw`h<_10l^Jaz(Xf=9N95Ge_+OK}I;2R8<^iuweNPlx?l%a2)$>!|$lH37AI7wdK?JX@eHzqsLhFtIAV@w$eF9!Qn}@BA!w-m{ok zNq`8nq!gg*$NnmT)F6z1R#a^RKhQgx@gA*XZ5+5ydF}Y|$4S=c4$(=+93z-_!wPDf zn9RRAzmDW{Ek+B<$Q|V7W$F!j>*8mowx|m};&>$x;mu@e}5B6qo&P#U%lB?{O?T3~sls$>M}&{!OB-xd-H&Cg z8t>VADps}I6=D53l##GntVvzBMg?C0O(^XXojWi-K}0W@`=T*+Li^C>#WAwq4P5&_+0 zcVw|p`o>ob+$_oQ{`1i)R|g@Bj+2$jwCPk_!5%kL7ZEN2F5hHOQis=z_dg-`XLoTa z*NC_tjvMMGu&)dz>vcSdkc*V1ZEF8eCJ&LEfFwK^YA;x}M4W#+Qjc zfreZykw{Y@7!b1T*G$*cP&l|*^FECbO|8FyF0AYmJMgneGqQ|7>fx|zy7g=9N* z=Fbi`!LwgJCam>Hey1MbqI`mye0*Zu?H=R0K;Gh-yKWrOJ5a=#?goC2#@C#6>5jpj znRV`d`U!{@_6Ap}dxCG@SWUqpbLZM01Kl?j%5h*jL3c_HnL#vCy0wXmMMmZuDx^N~)apVgp*N6DhgSB@5We7eThSFi3Eo}SH} z6GHxrFZ&MYE;hsxwPe1z*7|v;^gcgu{qNTVBbm)${H^Y?{XCi2`Ty( z>Q(H|9T_^wqj-vC*PgO&8$zdwGn2?Fr#=qa6Lf`&LeK>7JKm4T@tj$VusmA|kH63*kthi_-gSuZ06s}lD`*W|NKcgT5@$4uhZZ*Ek+uh`!>eR z`Y59Ow3rkWl#(w?uJ)GUv0krmGl>mSU4rDjYyE?12WI^!L5dnt%>|{DyPLZ=*X|S}>I3 z$F^vyWG+)}Nn&hl9Kt|tyTukS|G%Qr|Nf0aS!;ygH) zhbfd|54f$nXk90(mFD<{_?6ehQ?h_ayqa-`u98Ur2LPELG-q7kul*;?(nNv!VZvU4{{qoYW zcYkmG!|>3m;lhd=!?aQK+ccuLxL`=0@Si16SdVKuKXfuorgz|0kZ@*`|Dy@viath39f!k0@*jTm+ z&?Aw6ey77+@R2`L=6|1w^NVZrcI1QbxUs^2YBrHx|EMI6%d14sFT~Y*`X@8@O{zCM z6T+t(MszZwo_I3geSN;^5W{0nSpH0Hie5`9GUQdiRcI7i0@tZV`u1G^QML!o4~*;t zyQ)E$CdaUp8mW?kg>nJk$quSe8Y>csvQqb}tr6 zRs1UCn-Ez`1HFjASS>x_8n)vdzsZo^Z-^xY`BTaqK?lhvt1|T-z&b35wN~>tlePC} zb5tqsBQv&OV{}=du1yiE%J0gaa;@L44;|G4`jprV!{za$a9e9 zSE){;KAE58F%bm9t+=dnp0IKDN^2N~FmG`T`>srn7yraIP)|plbt? zR8^*l6Ctn}+1D9k)@Q0Rb$)nnsM3$*+2>z;#-4xfg)0(!Iu^RTM60HPa%fUOt0i#z zznc)C$^ZQ{IB~+eL~(8KM@&na{KGC0{}ZE)qyv*YRS-}UHQA!m3jb|06cd!?Z)&|v z_KO}Et0|>O@sqFbKkQ~BJpzpvAnJwLH?cJ0MLGq%znzDl8UE=|D05wkzbRp(p|Z*s zYFmuscn+<{CE=woEQwi*6mwF@ z)`%uo?Hp1Xam$U1CYem|cw5@XQ&}Qp8YuTm{56{2eZ8tqj&WVG?jU-eo@@hL;VPfW zoTh%3H`-3?p<#`BTi2`MY$YV)H8O~ono;u|6?!otUlj|c{N?=jeAiHP?9rd6;f_B# zKc`UJ3(-CGG8M^uvJuP(W|}Naqh(;3&ChEjYp|UMF-K%@DWXs2;1uvrv#0lp+OI!l1_^SO z&#l=c+1N4QroOf^*EG-Kmo>Gn{Gc(m9uLz>$4Ye7@ZC(%{bn4^5ub@Y{{3r9rUr*6 z$;AJ20g(m?(lio1I?@x+^f!4`{-P-@3ib#66W9M$(EL})si&~g@Gzy43ZGtO;Jdy| z4`dqhv(9sySs_$4%7glR>;jkT=16euOWPVp3(jZxywN8gN=c0d5 zNkQ@`^OuOWMP3BcYRpuC(w5H?&&c2Gf5r~;F?y97IQ7&v2oYmEmRy3{YyFR&I1*N&`C|o$ zBM?nhIhD9SJOs?LKMK>P6dMZ(3RiCq-Cp?6(aZa--!y8!NC{PNK>Vzft~7nN<)GJI zx_Ae4kR<4AoAe)MYe#nKjkz|!ERZgOQErHNo7)|_#dvakvS=xw@pw;B|D80DJYH@q zE;Dytm(WUusBxaa6f3wXma);T!p!xNeaYA;=)ZJwTs<6saVa^xkckwxc44}vUOPdr zh})#oi*qwg4+;Avt!#1f*f92aQD8-L<8n6J~eaqQqsW-)f6ovV?lV!|P*3ZsL&T^X%L4M3z z>m};txG^dXv;PJ+w!=HN6GS{dRqU4(Ld83yAz)TBIwfguf{1KSuGtFN6NSFf^Xj(X5slK3X(Ap8c;2X)R z1e~{HXpA)zzMy1Dm9!UU|6KVK3q1YaS-{l6165gMVstiH4D3o;mh_S*-XbdOelZr& z1|dt{+YTFc$!e~d~a zzUFAEt$IDt+i)9T9fGeWbP zNI-HhAmko7Y7pwnbzV_r5_-;MD$%Xi;v7*0TIPiCUvnbPIbjF;dDp4!fS~(>*{Y4y z77I!3%|^M-4~BX=z|#OyHyZ4|qq2eYAU zJ3!^Hq2f05*ghhv?t=5WtAZlU2yea2Tq)WZFo$ht>=5P~m+#Wek*n87nm2T2o)m4$ z?f15OE_VrepM2?VT+kDFz7oEDsg)bqYkJ@nPScBijZ>DYP;8O}{L0!6h20sKlK?@_ zrh2RyhpKgBj;jwds=T&|CLI#>?}|s`Ncqr0kHKH+kNPTcPEGlxHWZ{;`_2XXI(+w@ z%ncZR`@K2xHXB&1cVHp#0-I{WwuPcFRj#e*e(Q})y6sQ3nzUrT113LRQ_^Q39O~kC z8NLQAks;OD`O}0l+(!%gl#Xp$dmVeRg6?Q0-;oRAB2)!Jfo;7Lw ze0W&Kz_8&U_JpyK9xVk&2813w(-h;zA!Uj35_Ks0%W1B6GzksJj#+qNVKpD&_o$tH zw~E>Ad-#}+JUF^A;Kq?|GS2TSow=41IZBmQzlpC(-`o5k1ls#{neP*p2q_bKD%Vww z_`oM#B&h)jG)WwrDgHPuf+w=}gQJfJ7j}kF{_&EBV2aS`V%^I+j1rfGOL@^)FDmrs zNDo^Nd}u+LCb)W=^L*U^D^lE9QaM^1#2=s&V);UpfjH-cuaoBnmkNlwD<#V zRvHKAqExx>Ey}qDr;4D4MJNe0c(q><|1hnI^(s(!FVG>YPoo>E#7{I8`FM-#HIF|@ zI`(O8o*nfY5kL-KG2(rkpykZRmm4#G)Mx2WxS3bO8OE z9 zy&Im}Hkf3VLs#03H_UmnA5X^=1-?V)#=ei~EUNRF$hF<;`tw5z6 zXHa6n-!Y^;SAiODiDah454a-dIVDO~1J`VRn~t!@lh#yKpB?1mi3k? zG|MotiRH`#+Cns*(mtDU(#&?R&lR2FBqHD!h;!3jo_>0aGZShvsMy&G}(ojHU@S+e{7`d;lf2kW2)dAv#khiE=;vYg|R00*p2Y^UDP;W!FTJAe^ID07{ zYvzP?2W9^|eLrZSp3nFsHHi>@%D}~~`gVd<*qJ))K$Onme)M(rbjD=bVBQBN_nMMP zvr_+WVBj%ErRT+{HKE5x00Dsb7plNnX?4wH1szfB@QpYW9%aLtZT8`dPbL&!W%D9l zQ~{iri204J&EmWM`p_1H67q3EYB2#)TC7SJ!+B)rjjON7ykS!u#b%hYL$NZf4nXB- zUAEECTl~2%Pd|>cyCev4oaT5w<<H^?dg|6o=$cKwu>ebw2Ao=&ZlAbHDbv0xBNl z-+ivmVDd6Vo-7muH`y(S_Rra^`#^*+x>O#aCx>nlZ*|2xj1;V_M*jDHr#Fb}Fs&}d ziuAqkt|4+q%lXuEq$lfOE1h6k=b#~*pcc3id)kPoW-`oE()PaeR7#}WF6h%)UssWr z^ySz%aO+Oq6bmhE1ESf@q+`jDq@5};$tQBHbJJ$qSEnA_9t~KP1m}8-`lkymRjgJu?C@l4R+t zX(p0l^XH5Bx9a4>m zi{^F;hUO5)`<1)>zOWm??a_c9&K%PlG>VSFtcUKq8EN)Iwdi?gQ0v<@gvk7{bfy5J zMUECC<_lc>E&F9kAXW=o;l7hY;l8XF@-5oqwOPAJ6{r=Tt zkel8QEi10DYvY}o?o6Mp`d4KEgeY~HPst9j(f2Q0a*9F04bhsU&}t2HVkWyCu^T$JVKc!c6A?;mg^F!sfyChyFYxaADGVmt&7gmjC&v=d)i= zh`gkCa-Y>Z8MSM`6SnW*a^2m{ljjGvXB0nIrT=RAya)_l@2*aHRfOgbt;-?>`sG3h z=g!sJ51F-CU3yh;FAb`0o_BabST~ziY#wl;a+)m$;6F_!&Er>OkYXM7TkKw)2$gWc z;qjpVWqXg^XOhR%nc=tJp%#P!ddQELx%grFsBQUmr}yBHqVN`JIY^jt#`6q+QyuxS zCCq0SwmM&hK|v?IvPFYHx=wbm(5B{pCYd^)%&@3Z6Ev#0TWJh)E?YzS?K--f>kNuI zf)Yror|S8IR!IbUIuS|Ho%aN&_#tdcc&_bfCtdfKH<5s|+a|w%RJ!ZHkrzqW!mIOW zsgfowN+lTfK%Hs4BKTloniTt4qWkM2OK(bN956X-Z;Tz}>|I=n*WD7GeN5e`6*v=h zi3eUpA~Hd{GMDf8X|D6Du*DD0`_E zE8LH7jQH{q;~RHG1>3<67n=X)0{&>+`BMh|!6}mkt@*TXYHw8Q{m1o=L=FVh{<`-i z>ENKa(6u$^FT?CLRajb>h$BQ>hoNIbuZrKjJeo-chLsCPW$hesg1@0CKs{K(~mI8}sZ9SB*XAXCc)-IFOe^`ExYtFG_ zr8rk+iPTx@qDu|?)#sjRH(#8jWMF<)%}G&Yl&i7_ybxYdT-hoTpLM+O5>JsPp7y_V zs3f-AKMHNx($4=dfp^@yMQ@|C#G-#_Vcsr+)(15~Bvdx}s0&jqYF zsK?`27@FPi%FyHeSeF)Z$8C z;=9%GZX)l$Z65?RYH^xFM#0%W1o?v6LuCev@b&_P-t4(AW&6QVcG)8Z16no+c797g z8B=cx#4xiW!Y_`oXBOs6*@jHly*aRp-8jrK?Kw298^rDm0Mt1{s7A`$4?YZui=2hU z*IdmeF%WRnQZ>n&d`ouufZz-7G-5F5*&Wx1qSnZ&)_hE>-d;sMV7yB=TEd6ZGv4{Lo^bhmR z&X1oGp6mJ6k6-QB9L%8fgF5qjv?ZTnsN#{ej}{=yrC9j>d}CM_rH8vhXU#ZJCJlLC z!}iywsfoXCfm;N=_qWItVgFI4el zJvqL%x*o5F2`??ild%1LXdT_+g`4uDI73>3K}o zP2vd(_l-9HCVn7mi-MXiJNI8DnKP4ySeE^e9hdn}BRtA=o}9`e+s8iU!5Q`GEXbA8+_9t5n(=N@}v>7@*H zS!iun^>NCaWquR7N_~hy)Ob+ZTitC}>Y>KnGO^+iCeda*m6K!MxtpZj@FDIwgr3Slfo=z;jZ0->bv>AUm|FEBNY&t1Y zrz5tKu&|{U8`eP7fQ+$_Qs7>fsk2&=T6NpC{xU6|zMDQ-`&inoqI(qbvpX)(6X&qO zU8whgBS2vKI9K>4pS$>ScLow15yw#-JsVA2>jIQ-cFmqV_jbQsS{@AG935EBM3pSn z7x#?NRxGy~>}FTEtCtDnmts=aQ~uGw|^AF_lwCB}+P zazK)#Xcn;&M~cuMt=K4nN<@Y;h(*pyy%5X^tHSU6 z9^OgE80Wi#=$C&uabN{HLuYPc2OKd1<*#z7oO2F8S}hO5To~Z@+(wypdGLGhedjD> zt8pF*=)hw)pOq+5y_Fo8!Qgk)!4Jb+Sb<*RcL}N!EuH3F(_pNh{_VX(k3(f51OJn` zT^lXmWFAGZ`#mNJ0;@>Y<9Ff9i1(5PifwF)#%}gDMD9XmzU|6@nRBpb)zmhuUs6g6 zh}_{d;WW{agFxq(QQY5&)=JyvmGGiGNi!nVxohq#D+gi@xByQ2gLa5vO9tjaGM2Hm zVc|ochpHsv$u=lxJ;N$ft*K1!#lpKyIwzn_b<#FnN?k$azV<9@qkbNyKz*}-7_Qh@ zur_IZZKiK3@r?{%Y&OXyx`EzpM^OUW2?KWhJTE6lSH&V3@792j9deRPw%zvP)H``ECSexrGB|KO!sRG;2Z}zvz zRTYAb7i#D14(BKR5f<{hw1_$I-ZlvYKfiWJbkQ;8-rffO;ZHVXR3k-q>rnl*jg4XY zyYGiNXuNQ{*&9tJL~psCkl+Pwo^>&DJ^*=}TgYMyDy$D)=(E%2In0LTDcB>1QjwA@ zq{Rn{$`7?Q0|Gpu9=9vSU@h!teZgj_?`d^^~s# z2`-iY2}v0Ab_+No{g*$$#de*hR*UZQa3*ZWN1ZwD>w9x<;@)C%Rs88$R;5Uu5`Xg} zh1h-O|AI(_)Gb;Pgf?&>y_(klB2Jo)R?|<&|AAtom_6S4?=L90I$Hzj^BNmd%Zx5iO*=v2l~t9I{S6 z`?~D|QXzJ!KYvNkz7-*#)Iknql{En4iO?vug-UPY)8@Vl8ue}JxSx4#;}tB)K}Bni zb8yCm-lj$j5@R9^dQJORL3Gn# z2{}2&$n5qt^wiTg`)`Bmz(6qDTeUcc57;E)F!#-ZM55+zP|u>zUlW1-cC{nXyFJF@ zY<}at%iGCp!&kK8ewLq4=hz-KZg+=5xXH-R&c8n7 z#eb!<9V46PV(i^B?GlZaxF?OyE;H`K`npJ6`CgeN{ezP@)0e*8bo0izhGI|Vtd}Yp z$M+H@oc%kz>CUpdefOP1gbhkf+E~23Fv87stfHk(C3-WgTdDd7DJ>5>{?2mU{xQ7#3YXtHB8P(x~^ieDcO_dz^KcA$_ zn@-KVp>Snxm2FxLFizFQ_i&V~pYm^PsOk4ZX-R5lQ*>Tl1Q%!p^-^{!Q|4<+5vU+u z{W+2Wk9g&**MVG>O?QSD&`LRiTuilto*F>@f?R}C3&1o`tFg6(>7ozcGPzqRqZcp4 zxkllj)H;^7%m8Q$ebu}XiPO&kt?ixqd~T_L0`y)zFE;SmSY&*Cny?q@yWiTU2z&sI zpWDB1;sPJ4x;E@+EgPOW)L4BsHvg#kjL+UpM73r!$4$kgX8Ea;pIV<|n|$^$m3Z7F z!l!bS-`Bp;e0K>t08I5WJgM2szJ{gI?@$e0u%C|VuA(odi#naj7B8mjU=U{Bg~{MU z>C^|$ASGGfd9ebzf9i~_J_ver9pCALb8M7ES;U>aVc1eD1+=C2 zW@M(TlJc{hK3w!fsu&@=RWjpRAV2q0Y7rRWy+z*=>3q1?VErE>N3_P-b__(pML9na?pXvnvGkRK=LcqMWz7Oq<5^@N>9Sz^4ZBxlMoD2AR)!=c`U_i`&Z#1q81UH2*wJ9jYC*HecI#Y? z!tKalk?JQiEx+nAm)|0}pcl2G+~6smZI(6%?Ug90L*s`)P>l>IZWUa$JGzWUa?q9) zs}sFxGM{afq~>LO-x6IE7EdmtjOHZfAXPe^T=SkwMZ@+!WS(cN~# z{*eAcBGmm*;;+3r*dz~PugC^S5)6mE&DL;X*f;$EdpM=R?U|nFrf^bS=k|NxG{oEE zxbrq!WWz-P?&tnHHWlG8sIu#x+Au*C=h0{l389EHGkH(*NVFm6oP|-Ubv{LYnI~wI z2V8hle=52q>AWg4a%nc=GO)UzC7n3eYPFmv44jF|K6L7xXSDPSOro0_5~N)Hys=H1 zGsGh&EM0TBREZfMT4|z$KE;=Q{-_(nV*MlPZHut$hH6BNLB!)JEpe0(LnNJ5_Y2#X z*-8A@#|3bh%7q@=)>RNm_HO5wfg%|X)h4MT`nG*KVSwMkrl8v(u?nd@slLw--4d@L*=X zXx)UKHreI>=K^w058uP@j2Vb-4AT>{G6!68dIfs>Q5*XIIlG=5dQPh7WQQwks$8Ul z{ul{ovTRN<54Q-6jfNRn&cvIS$n=Q*<$cIhC(j3)$5=B=P09NI{7La!s;wDOhzYeb zFi4#z?MWApPCxrOGvJF7+tGZ1Y}QyEb5u>?^@>U5bs|i+$u_hz>H2;_JAXTPSUqTy zP`{%Bi|6i>|Hg(P$4-`3oE^GNW-;O0!Cq}2km;tqvySc`{e5=lZ3!pl&AQ7&Vr}M^ z-C>6-^<>bNR|``wUXOm|MRB83JW7m^@RdD-x|(yI%JF%Z>XGsuOE~;WZC_wiazt&V z&mg_qwHh;@Y$r1#j%2Z9z+1ZCN=!LQr6=@j#lGkRq4s=;@*7-d8$p(5ye1pf z>&U@Cl-pYNE89<81%tBk{Q>M0w6!1n_apKs5@w5e8fnW^%g4)7?mw94ylC6H+Fw}8 za8gdK9`fV4_?MxsrZf*Mm^6QP(O<|s`8Y){*H*J5cu4aDebDyRKbNE)y}~()SfbiC z5xQUY5^0pC@r`p>bv!>vVMknt*fyt$)#GC`-ftj=ZLAPK3E?TiHF?ASXPTWgJ<#iclpy3)L#TWbR|1YjCN!8qqQ!q{oQi<4le2kHk3w#$4G4N2NVsChU%vz zD$~5S1Xyi6j{9q1^ZCTrpX~ z-4-Hywt0-liO0Jz(agvWqXzWYuP^Y3#=EHT`pCIMS?7Ra|c*K%W&FWU7fLgtZQ~BZrxa9U^XX(VYve_hD zB7^SA?=pO}@okN0%jp>?TXfrR^~`Kgsq>0$M!CICeMgh&yWHR!o@1ok;&b^aaguV) zhbRD{QdtbE688qXu)0_t8v1N!_V7COKK0UK3Z!Lj3o4E?+U2VuTR zaV2_jqw|FgQIk^j>O?c`ZC_f3@xQKBTUe9FqKHW{q<%kjgcZ6#g+<*jGW*RP%YGYDUY&!LQ{`iArL%a=Ed-nzhKhUemK+ z@x`|MuqROO_OnO%{p0{!SU*UmwM8i)Gs+YBJ}#Yq+KI2qL!1<(IGa?9P6)@bnyj9$ zKWM5|m3Dy4Lhp8799)niH@G3|fA z*B<;1pF>iBSxx@TR&&JxBy2aMq67cvw%Ka?(AqFG$JTrkXF>U;<+?lXhzkO|N~^ti z|IQe^IJEa8K=CHR+9ed^b6t^i50EnAW1qOHU}81IL5WFo87MPaQLzE%6T_h#HphcP zcE{V%0VQzBP_JaI-O3YTK%PF;g^v01!+IlpH#p1I27>+?u39|XrbBAFP55<{LCm?{ zcM=zd%TC$-8uuT;(8_POY!JvrRWbXefS zv*@xM``v}X5#t3~#c~^@>VIF{aPQ%?*$(r~YPST4X1+e>lZSfAB*v{gt?#q9Q%ou_ zuw<;a)?i@%>NlL_)@>v$>#Chjkx7I#$?r(`5})_|wM$f|>D-|)BT>uKZYz2sW*28PVQt<LBGg^r&O8HpybqND$Q;(II)&8kFxuB`J*`yL4)(D5y!1Pl`l9DJ z3H+|{+qY;ouXS1+owLTrFI6P!^&sRCm znc(7;=zY0eD-IQiuBi<83IJ9_1W|5orjdkV2iPfHI=(*?lC zEvNK|YCmm(O6j|2j0bnfiT)J0h+Ggw!5fIDXl8!|h5$FU3Zc8$39r2Dp}yN9yQMB3 zbT6zv!WItc4WkixblD)|fLZ%2YPVw4XR9gWk|95}-w^Uw=^n9)9myUlCQ*q5(c&aR z$78G#yQO8Dda%k047XpxxMG!`_1c3IzP>LX`MYsTmB-lD$=Q&*a&Bammgx)yq>ubc z6+Bnyjy-l<1zS0LHhUNisz7{Nz)1LQ_J!@zi?%GEbWuyxVl0P*gR^+bdAT_E1@dPP z54tb_;TbT(GwOb#B5es*Ms9_4(5V{lK~aHx^rQ#^=luJ=U>NpXw-%$D9RxvQDeACl z=YXk2q}Y;p3Br8_f+#3e8TV8Sa_bSa*&u3(FL5L3RInb(4bIW#M2uFZ=htu+v!};M zG|m^(%wk}#M-E}Dh^(tpCKMz;Qq)5Y$jF*%tO2A!VIvk_0pwV~4ZY{`v4TTZI(~!V zfAb~9c#dp-#%gx9#k&%LQxD7C&Ew`*-JGd9ZYE}{L*4U`jU>B5ThvzN8@ZeO4E|sI zOwJCM9{yeS;+$?Pkxoee+plMiPv*9gQ_pHj-5r47;*B!-b{D@`f1_Ri?{N0kH`fQ zLZ=7WTK+ka0I!5~n9U2DLQNXy^A{8u@D+d#Z+82At&l9cTF1!D#%O-N!pyv{_YB=> zh=X&kIXp|Ng)cURJD;gNvINk${4BYqP=(oHWdosXovc5V2`G*&hM-!xKopHpKi5kH zPr=p$9QkAqQBPPzGS<(CZ@9z^X65BW(SQDckaSbVcJot*0WX~DL==+iXQ__D^xC+C z!!>LJtE;A&xbHdJd|>V+?*>AG@HR*$^X47@pe6an?3h0q(pj5N>Na9Jw7XMX2?N#)#=%R99%Lqy$n=RfW|Ju7?~*kt8K9)m|pLqW6PAiyt*fwWpFPd z4ydW!n$fQwNf|5moJQVb?6!UVg1Alby9T@LnYy0;2pzshCbqC`rF$;CdnKXncZ<{2 zt4&Jk=1JE4S~?FJ!rn3DYv~(dW<=7}&Pq&M(Je+Iq+6j1i)xSkF*YB=i=MKG<8aPb zQLuhI(2`e;!xE$AMU9#b*O1||Qj@B*aAZ=STu<=e;#+Y1B>E}wB5J^FVdjU_bqRXe zGTy43e-B%h*Gm$|BeP7?k6%HD(Y@`ktAmH>Aae5rsF|UH<3S9eXIq>8w$v?K z`E+N|qzED#jS@BOJ{NpVA2xt zwhLXRTHuw=G^;c7?m{wP>L!L4(H2=_D{J(Vq>AYISV!q?mQoj!aPjDP5yoSO&y~(j zvG&F`;LH6f2cMXj)X11Xi4yX+jtujdE-=EzE-`@qdZClO}2EOd>Sflz*>M>EZ z|24iB85Xy6jAh0F|L#6Uj~$^Q4bG^n zNJQG0L~}*!MgRmW_;It{nl(;yOHECI&n49E4mg+cJH(uFkaXO$_T~J^B;DPTr}0Y* z-Tl;+)rgqV)GBuE8?wJM;zaV27r%9lr3*PQJ>dh`9KrX)SFY}Io7{B8A|Wy69!lV0 zCt|?~V`kOqUx;sxuWx%k>u!{p1yZacllu^KIZ}~<$Aljd4lY4vSD}ja=LS316)sY- zW*2B7*45;!=*^{;5x5_5$RVeARb7~EB2fKyX$uKgTyD^}ODr3;%|3pqv--KrYP%Wp zQ(;8>d5lg*G@aB!FS6N6bD{ zn%Qb!<~cM;yfMegC_At11ah#xhmS3c+yHC1->t6-_%6iF>;DmVjELX)wXc|ARfzny zK*3CUZLg=up@tZ(H_3PC?NR!~oHDa-Cg=xTgs=w-tB0DOx!SPH_QmngxxzsBTP)Iu} z*|D^5N;e~3+nAMr80SSUdvXALk1ZQ}ITeQ+5iXz_fta-Luu?l{BA ztOvVo;nj3}z2Pl|q^*d*E~QU2zBq8qp%Xe&%*pdGi!=hh1FijE3FjWq^!GpTKKhh$ zEfOJ;ic-z}eknwKgpej-v|MT~F^jQL$)&O(G|VL_xsTkLjhZ1w?)UqBF0;9AZolpO z`|tI5zu&Ldd7anmyti}C`*oheMg#>~`{O~AS599OWaghRwYSMW-Bh66+kt^Rr$N|@ zVdosR7QpAls*rc zNIX>N^8Rp@k)s^kznSl1N$B zwTU!LiRHFX0Z()bQtdZ7uYjC4;vx&DixpwyQ$m}E->-hU3Hd}L>|_f9<|tL~HQX~_ zT6-lEW4YyH227^zuvGVr=V3xQG1V@W^ErT*PVGQxsG32p-@&zW2Jq&GwMjX)QC|uW zbj=Nea5SZZo${NDi3pR84wwJVEq`QX40Q1is%k!qziq~612$&$ggv_(;#qR}Yu%Dw zs1UvKfO&84JMH}R@HlX)cB~RjoBDEUyn150g)06Ei9M(tGa!TZ8buum6#+_Vbcmm+UP`|F-5(4foSqXuYTpBi(I0;iETV=amM2A8pBllYUpj7p-+m zR(ib`fc)f+_f<--nUgDof9*?a^bm!BqZ?h`J>@aj@{mZA4Jwihes?;S{aT|;U6#ck zN0aW|c_UrY0U?<_KKwRd@~VMT9Q_6yz5j=&fU$YYX-{XnwaG}`cQV4~wYM31U|^=a zpMMc!{XA>(x*3BM!ZIOkA1;d>HU(Qu;p*I@iCabw*81H;(rQo+D-=t6uU<=d7;JAp z!>-8`P zipJP9g#dzC8AL!K4CR;rs8DE=!EeWm@m-7D3Z0WqglbD_TG1VExI_C;+Kv z{AVFC!1t&DGQ|l5C$@S_PbvF6g#8h@yw?}%uia+q_=ei8PurFFmwn_SkD`{K^+Rds zd+kyW2n){}9hf*D)V%W|BXCa1dWkCC>5+Fv>53g#g*!7DKM)^KniqXFk z3XR(E0Sr{niKm$W?>Njk)Hel@8}2Mp82W;jP4ZPVx?DoM)S`v|NFsRiSNmM zbq;i$g~*$t0>@QemGMaaYWUmtiD-?OdGjTgoJ1TXr%-NVUf!AhZkz4mY$7Nu-@hDB zYnL~vPejSHxA0tZV{wW!#rdCB`TBp=kXa3>;4WYqxZll`SRV001Bf=A`i9RDE}pq4 z;PzzfecCd*chB$src_eb$=J5RoC6W}La0igX78&@Ngs84=c>>c?Y^W03>Anx1s<;} z(65E~-=w}+?rJJY2-iB#p7Y*r0ND@<43u7StM}hN&v&zx=pN;pM&p4`FTSllIg#(( zt!Z14Y;V&7Oh}`2A|UbQlBm8UstRdum(`e^Q*lDNT!E;Q{WEIu%j?heq3>Vd=nId_ z_7>Hi>Zom5EGN`1JG#5@w@TJ76)*;u9MI)6l*hBmlu>4e$>zQNU$hPFCEc!=cZoNj z$~g{}k`0l4a$xpcs`v2Ye=qQOfmP=~R;LgqP;tHlD9LEMi zPe2ot)dGgDNHdR1@|a_)|2*pun{vy@&6FE#dJff?v74*6_zwSQrx-PV)b_?68lyzTPEKF_pp|5#wdv*kU_Rq@|MAaDZ6#${+gjs@lQYST z&#MkX(eX+{a?6ggAryo4Z@LueG0Br;0;wJs>|cFZ+vga^ResPd7GUkK#)zNzCzII7 z9uU0b1v4&t01wq5=C;t!`6}OBBn|iUKVZ3L2EGA^fA7D-`lW5?V5Ut{wx~;juHRUIE#HSY$;xbA4XbVi7co|~F|^d3Io6dI`Yy|SXTTrh zs0uy2Fe#pvN^L`TY4vBNYH4QzXZ2pUXf4Ub4&zTPiOZ#hm}{)pLP##@rTC;N%11kh zO2O1^{UH5KWqnI$T7NdzHp_V+dPB(ffR|{R|3<=~C*W~Sy_<84$$?AzC3mBCT~z8` z4~e}u)SLZKN;VzwG77|sutoe@kSK*{QHa!>lYoWhPqGHE>p?z*_EELfg6{G; zgNUz$%tqCrjV`42=C9ye{3<{ENN(vvq>9mU&#=87!lF8TCS`NyIyr|>t4+@2&cE^V z(e3>`71qatL+v|{EgZSoU*1c<$`y5;(KQ<~7BP}Kvtgm`*4yZ{24?*=pqG1+$G2go z^mb6-8RD!Nkd6%~?y2L?_+B?C?l|O4K0M1ff&5%DcenzANgi$i`Iw>TUrjTq^J4km z!iN#NkTL;S8aB!CvGncp@PM(MTpix_M%||wg4;yi?Jp*@H!THdZL zC>TKzJ00VAj=jUj_ZL^lQ;e#Z2|MM4%{ccw$8$<%{QQDJ&fYCyu1DH0BF|nhP|uV4 zCNQl4w+@uxZkPr}u1SZ}fnU2iuCU9!>9aV;M%)fwrcc*K2YC1{c`?1tqVJtT?|K3l?{B+sj?^`0&X?xgz2F(a0tqKDCIVtHLG(kwemEl}~6o z(drjKVbGwh?noc-TS55a-xk`>2s$r~5}$hw_h@F0v&YDfLYGAwrQ;qz}b`u}vhmY#QOJDxT8H|B^f>tMmu>>xnMH)DTqZ~gT6zRl(I+S8Kn z8g?%^cR8%V(u$0}p)ql4=@i-`i zWx}i8bc4j+t`igPPSsTx7fbAa^ENzZ7t^HbeM48$!jT|F#H znSo9?%mw(|$s!2PX$l?8un8>J5!!q$~ca-l6lElWq!Tm$ztN?2xU?}4e;$Bf$VVlH`b&HAk=!R;$=08HH%6r!=p-*#kQI#{* z{8S|9T+Zi1=B8ZHot?U{jcGtVNP+I_pMlqZS94jvy_?*GTPkgkv$>f(9Zy0|4V_{= z)PI4#iea^(G7#(4?G_urQbIoZ38Vnxa&leU^xdqE`V<AXx8+idtRGWK7Wew zBx(6cjq+?VRIs{41BT;1X*QVBL3Zl@nH;={1FJrHw!E0MR&e*prXZRt7AiiqBR{nn z<7<@sglGYra8_8~m_{_!2YFqShza>(^%)gja;+4e(qXU0O2{OrvR^S&xi+ESNM zU+wYB_Uio8=)2<%HZ8CPU`cfbnHP!byy-(ouu`lO7o=sfSWPZ|Wd}c>{Ilx~3^>K; zX8-%Seld4}&gk%@S-XmVu+3{VckVX-xz*FD!XRIXHQnQ>g^?;Rd{ly+X5K}G{7b#V zz@I@}7)&s$ndA=nF4`#$tXsR`ZCmbw+-Dj65k~#tjq+J;Y2a`!zEGM5vX%Tq0GicZYGaO8-RdN?Y+c=Bl$NY#H+K|%thJFhug*<1qf zp{59eyR_6oyKgM|wPnkZ>6HwRZea5`AK7xN4hot}LTt0lwfv;wK@2nGw2vzY{rvvA z&qK%GMLyktMT-&h`53_dEr0wX`_IGsE^+J8gtK4-SU-t47WT%64;~*S{FydAFCO%3 z)uH>AEW7yE!qIr>`Ht_KjmGf+RcXh5GW!?gy?Q8ecG!-wB-zx_b&(;RM#v3^hWbZ*z<=>xC#w^&4Qj zi{>#l5-NMUw}T+CZz-Y%ceUR`~Z0>)EuGibOuk zL_L*tx}$Gks7LLLdL%-^Y%BtoFmgEx{XA8sNf`sR7siG@(q+!1rv3i6XYXYN{I=skSaT0=s9Xxe6nBOTu&QZ=F=qllo$M=xf%eiNNT(N1;o%_*KA?I+>Q;X zyAQS3O~PWjctR9TWcr9o3wlV6y|-Ajqg$H__9mT2%2W(RyvSI`u;*W?)Qq$zuaNhq zG!4&A{A@N|_QXDwt7axw(k1>IQSP^h4uRchhlv_Voekgo%q|7mx?Y*&qST)!abjwy zQ&^KS*~Wa@f29kHaZT^>S+s~jCEt75Af|(h8?n?Y`*09Lw2s0$a3dA*%WtCOilXuH zYkEi18n%687!v+9cgETy`C;m*4{+WWvIlJ{W6Kw_oEGF}Dm&G?>IaUI`1Tu>EvIcd z0_UvfF`?~+RrfkIg0mJQ3B{*p!Xe5QDJAiG%ofYg{-;vlcX$u=Tvi)cAeNC}G!}D# zB{Bz`jna*$D`DiBHNA?~d5NxV014%|S^f zysl?hxxXJaC2tIwq>Myh05iS?r>S<31-q~0yT?i(it~m)Vh%R5{=o_aQ@ zI8J9d>NkA+xxOy@?p0SWEpn|f6=sdgU_?2E?x#4Vz1pRgi^DkxBWg}Syhegujoly!b8pnM{qo{7 zi9ua-?_2`2I5%IZ031DHca;`B8)R+C=Ph9{dxH-f(Mg5W8ALG=`_)7-EM?D}{suE|+MTWG@)VN@g=o)Q8KG5r$*xF^&)IZUjQ@~2 zaUX!(im^p*6_$DymY{9!K0-oL8OOaW%!c(HOMN`uJBZAL+*P$#DszVDV;#D!eS7&{ zS^-UGhC?nx)OH)K5QF&TA`X@eN^;z%8{s9WZK8x(ziV;a62QM*4@=g2vNWLx$3DsygAPx`T^ZQd25bJW)ga4Un4LfA_Cu z3)NX=3{SWiiw%73>iEH`Xzjn8Z!Eoi;eHBI_TH0`7pkz zW=da4C_*n)4WOGO%ftiKW2)k+M(Yw7r(#YNENuG1}B($sn z=1+{t4f&P^Q&04v85e*V&LDoRY(Jy-wj)Uh?`XAg5B&yBi09mm2TfIPEUu;6P)ksk zl`9V}uH;HzWV%WQ%_oMe-LQ<~mL&}JwNVD*4ZZ#42KpBA3g`5!0A;s%{WqlQGbZxu z=H>~`HfPZ?dRMLHBh5!o=qXjqz6OGNjxv?daFwbvmTR4pUL9yUHXRi>(TrZGvORW_ z)Zl!2&(ia7K|`u>n3zKu1opy5LOWFP|4h zZug7(J}8*!ocC3;YCe~_qRdD<+5Vg9d8)v@&4JZdW2|X9Y2UW}1#&S`b+c!J(J7|Y z^j`mU$590s>9@rEz`5U9k6sgDg1Mc+b`8O9F!d61xU+gs%TiD?B8Qi!+>xky-S zjrr-cW!O}xP+wS6-klk^bI41-0rEX_$OPzo7~k(Tr4NqM05 z5FiVI1Oizq+zT3EK0{nV&>4rAp91WS9zVQ-Z<{!Js`AhDd}?FuWMi$eceo&I_l`}` zMxk%-ygcFLp|J$EDs*1q5j~i=C4aC3FhJuFj)y<#7TarV7_Pl<`b;MSqmPt5pt$>x zhKV~tQ(ho{)Q^*IQuj7@@oC4bk)`NBRJlNNBaco5Db|si-(4qMSfgqenU~A65u*i^*4TI z+O1uk=J+H}pC;OQUU@)CS>1ZVc)3FpdH&d(zurONAWeKLV(EGJ_Db7iS{v}0*Ti^3 z&G_w9u&QQEKwjup&>pLUC&N>#QC&4cV5% zEXG|MUf<$Lo#s%7rAG1T6~GDI{{feotDDtq;BwagZirO;SP{|e;8=naf|09rT-!NZ zq73IM)AHr#!N&x$ImqOsCxfD03NN=gSm;_{YkDqw^~90GsuPhibzA{BuI1pI#Ag;>4Edqr_wDE! zVZ`apaBe-5t>K_X)TkHYW!SVQo>VNSFC!y)`klMAT#;(E>`e6SFXyx0C&NxNX~x(W7`BlqrD7#A5jzx_W&xN`jf diff --git a/src/api/modules/teachCourse.ts b/src/api/modules/teachCourse.ts index 17d63b3..3de2d28 100644 --- a/src/api/modules/teachCourse.ts +++ b/src/api/modules/teachCourse.ts @@ -50,9 +50,10 @@ export interface CreateCourseRequest { max_enroll?: number | null status?: number | null question?: string | null - pause_exit: string - allow_speed: string - show_subtitle: string + pauseExit: string + allowSpeed: string + showSubtitle: string + categoryId?: number | string | null // 支持单个ID(number)或多个ID的逗号分隔字符串 } // 编辑课程请求参数 @@ -89,6 +90,37 @@ export interface CourseStudent { enrollTime?: string } +// 课程章节类型定义 +export interface CourseSection { + id?: string + course_id?: string | null + name?: string | null + type?: number | null + sort_order?: number | null + parent_id?: string | null + level?: number | null +} + +// 新建课程章节请求参数 +export interface CreateCourseSectionRequest { + course_id?: string | null + name?: string | null + type?: number | null + sort_order?: number | null + parent_id?: string | null + level?: number | null +} + +// 编辑课程章节请求参数 +export interface EditCourseSectionRequest extends CreateCourseSectionRequest { + id: string +} + +// 查询课程章节参数 +export interface QueryCourseSectionParams { + keyword?: string // 关键词模糊查询 +} + /** * 教师端课程API模块 */ @@ -124,6 +156,19 @@ export class TeachCourseApi { } } + /** + * 查询教师列表 + */ + static async getTeacherList(): Promise> { + try { + const response = await ApiRequest.get<{ result: any[] }>('/aiol/aiolUser/teachers') + return response + } catch (error) { + console.error('❌ 查询教师列表失败:', error) + throw error + } + } + /** * 编辑课程信息 */ @@ -160,6 +205,14 @@ export class TeachCourseApi { } } + /** + * 课程视频上架 + */ + // static async deleteCourse(id: string): Promise> { + + // } + + /** * 课程视频上传 */ @@ -224,6 +277,80 @@ export class TeachCourseApi { throw error } } + + /** + * 新建课程章节 + */ + static async createCourseSection(data: CreateCourseSectionRequest): Promise> { + try { + console.log('🚀 发送新建课程章节请求:', { url: '/aiol/aiolCourseSection/add', data }) + + const response = await ApiRequest.post('/aiol/aiolCourseSection/add', data) + + console.log('📚 新建课程章节响应:', response) + return response + } catch (error) { + console.error('❌ 新建课程章节失败:', error) + throw error + } + } + + /** + * 编辑课程章节信息 + */ + static async editCourseSection(data: EditCourseSectionRequest): Promise> { + try { + console.log('🚀 发送编辑课程章节请求:', { url: '/aiol/aiolCourseSection/edit', data }) + + const response = await ApiRequest.put('/aiol/aiolCourseSection/edit', data) + + console.log('✏️ 编辑课程章节响应:', response) + return response + } catch (error) { + console.error('❌ 编辑课程章节失败:', error) + throw error + } + } + + /** + * 删除课程章节 + */ + static async deleteCourseSection(id: string): Promise> { + try { + console.log('🚀 发送删除课程章节请求:', { url: '/aiol/aiolCourseSection/delete', id }) + + const response = await ApiRequest.delete('/aiol/aiolCourseSection/delete', { + params: { id } + }) + + console.log('🗑️ 删除课程章节响应:', response) + return response + } catch (error) { + console.error('❌ 删除课程章节失败:', error) + throw error + } + } + + /** + * 查询课程章节列表 + */ + static async getCourseSections(courseId: string, params?: QueryCourseSectionParams): Promise> { + try { + console.log('🚀 发送查询课程章节请求:', { + url: `/aiol/aiolCourse/${courseId}/section`, + courseId, + params + }) + + const response = await ApiRequest.get<{ result: CourseSection[] }>(`/aiol/aiolCourse/${courseId}/section`, params) + + console.log('📑 课程章节列表响应:', response) + return response + } catch (error) { + console.error('❌ 查询课程章节列表失败:', error) + throw error + } + } } // 默认导出 @@ -246,6 +373,14 @@ export interface ImportStudentsRequest { ids: string; // 逗号分隔的学生id } +export interface CreatedStudentsRequest { + realName: string; + studentNumber: string; + password: string; + school: string; + classId: string; +} + export class ClassApi { /** * 创建班级 @@ -254,6 +389,10 @@ export class ClassApi { return ApiRequest.post('/aiol/aiolClass/add', data); } + static async queryClassList(params: { course_id: string|null }): Promise> { + return ApiRequest.get('/aiol/aiolClass/query_list', params); + } + /** * 编辑班级 */ @@ -265,9 +404,17 @@ export class ClassApi { * 删除班级 */ static async deleteClass(id: string): Promise> { - return ApiRequest.delete('/aiol/aiolClass/delete', { params: { id } }); + return ApiRequest.delete('/aiol/aiolClass/delete', { id }); } + /** + * 添加学生 + */ + static async createdStudents(data: CreatedStudentsRequest): Promise> { + return ApiRequest.post(`/aiol/aiolClass/create_and_add_student`, data); + } + + /** * 班级通过搜索导入学生 */ diff --git a/src/api/modules/upload.ts b/src/api/modules/upload.ts index 7c99cda..c53affc 100644 --- a/src/api/modules/upload.ts +++ b/src/api/modules/upload.ts @@ -40,6 +40,8 @@ export class UploadApi { onProgress?: (progress: number) => void ): Promise> { @@ -49,7 +51,7 @@ export class UploadApi { formData.append('courseId', courseId.toString()) } - return ApiRequest.post('/upload/course-thumbnail', formData, { + return ApiRequest.post('/sys/common/upload', formData, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/src/components/admin/CourseComponents/CourseCategory.vue b/src/components/admin/CourseComponents/CourseCategory.vue index b26ea01..e377b8b 100644 --- a/src/components/admin/CourseComponents/CourseCategory.vue +++ b/src/components/admin/CourseComponents/CourseCategory.vue @@ -65,7 +65,7 @@ -
+
{{ course.statusText }} @@ -123,6 +123,7 @@ import { useRouter } from 'vue-router'; import { EllipsisVerticalSharp, Refresh } from '@vicons/ionicons5'; import { useMessage, useDialog } from 'naive-ui'; import TeachCourseApi, { type TeachCourse } from '@/api/modules/teachCourse'; +import { useCourseStore } from '@/stores/course'; // 扩展课程接口,添加前端显示需要的字段 interface CourseDisplayItem extends TeachCourse { @@ -133,6 +134,7 @@ interface CourseDisplayItem extends TeachCourse { const router = useRouter(); const message = useMessage(); const dialog = useDialog(); +const courseStore = useCourseStore(); // 原始课程数据 const originalCourseList = ref([]); @@ -144,9 +146,11 @@ const loading = ref(false); const error = ref(''); // 获取课程列表 -const getCourseList = async (forceRefresh: boolean = false) => { +const getCourseList = async (forceRefresh: boolean = false, showLoading: boolean = true) => { try { - loading.value = true; + if (showLoading) { + loading.value = true; + } error.value = ''; // 清除之前的错误状态 const params = { @@ -202,7 +206,9 @@ const getCourseList = async (forceRefresh: boolean = false) => { // 显示错误提示 message.error(error.value); } finally { - loading.value = false; + if (showLoading) { + loading.value = false; + } } }; @@ -249,8 +255,13 @@ const activeTab = ref('ongoing') // 监听标签页变化,重新调用接口获取数据 watch(activeTab, async (newTab, oldTab) => { console.log('📋 Tab切换:', oldTab, '->', newTab); - // 当tab切换时,重新调用接口获取对应状态的数据 - await getCourseList(true); + + // 立即清空当前列表,避免显示错误的数据 + courseList.value = []; + originalCourseList.value = []; + + // 当tab切换时,重新调用接口获取对应状态的数据,但不显示加载状态 + await getCourseList(true, false); }); // 监听搜索值变化,进行本地过滤 @@ -278,14 +289,14 @@ const getOptionsForCourse = (course: CourseDisplayItem) => { return [ { label: '下架', value: 'offline', icon: '/images/teacher/下架.png' }, { label: '编辑', value: 'edit', icon: '/images/teacher/小编辑.png' }, - { label: '移动', value: 'move', icon: '/images/teacher/移动.png' }, + // { label: '移动', value: 'move', icon: '/images/teacher/移动.png' }, { label: '删除', value: 'delete', icon: '/images/teacher/删除.png' } ]; } else if (course.status === 0) { // 未开始/草稿 return [ { label: '发布', value: 'publish', icon: '/images/teacher/加号.png' }, { label: '编辑', value: 'edit', icon: '/images/teacher/小编辑.png' }, - { label: '移动', value: 'move', icon: '/images/teacher/移动.png' }, + // { label: '移动', value: 'move', icon: '/images/teacher/移动.png' }, { label: '删除', value: 'delete', icon: '/images/teacher/删除.png' } ]; } else if (course.status === 2) { // 已结束 @@ -324,7 +335,13 @@ const handleOptionSelect = (value: string, course: any) => { // 根据不同的 value 执行对应的操作 switch (value) { case 'edit': - // 编辑逻辑 - 跳转到课程编辑页面 + // 编辑逻辑 - 将课程数据保存到store并跳转到编辑页面 + console.log('✏️ 编辑课程,准备数据:', course); + + // 保存到store + courseStore.setCourseEditData(course); + + // 跳转到课程编辑页面,只传递课程ID router.push(`/teacher/course-create/${course.id}`); break; case 'delete': @@ -339,10 +356,10 @@ const handleOptionSelect = (value: string, course: any) => { // 发布逻辑 handlePublishCourse(course); break; - case 'move': - // 移动逻辑 - handleMoveCourse(course); - break; + // case 'move': + // // 移动逻辑 + // handleMoveCourse(course); + // break; default: break; } @@ -416,9 +433,10 @@ const handleOfflineCourse = (course: CourseDisplayItem) => { name: course.name, description: course.description, status: 2, // 2=已结束状态 - pause_exit: '1', - allow_speed: '1', - show_subtitle: '1' + // 添加必需的字段 + pauseExit: '1', + allowSpeed: '1', + showSubtitle: '1' }; await TeachCourseApi.editCourse(updatedData); @@ -456,56 +474,56 @@ const handlePublishCourse = (course: CourseDisplayItem) => { }; // 移动课程 -const handleMoveCourse = (course: any) => { - const currentIndex = courseList.value.findIndex(c => c.id === course.id); - const totalCourses = courseList.value.length; +// const handleMoveCourse = (course: any) => { +// const currentIndex = courseList.value.findIndex(c => c.id === course.id); +// const totalCourses = courseList.value.length; - dialog.create({ - title: '移动课程位置', - content: () => h('div', [ - h('p', `课程"${course.name}"当前位置:第 ${currentIndex + 1} 位`), - h('p', { style: 'margin-top: 10px; margin-bottom: 10px;' }, '移动到位置:'), - h('input', { - type: 'number', - min: 1, - max: totalCourses, - value: currentIndex + 1, - style: 'width: 100%; padding: 8px; border: 1px solid #d9d9d9; border-radius: 4px;', - placeholder: `请输入位置 (1-${totalCourses})`, - id: 'movePositionInput' - }), - h('p', { - style: 'margin-top: 8px; font-size: 12px; color: #666;' - }, `提示:输入 1-${totalCourses} 之间的数字`) - ]), - positiveText: '确定移动', - negativeText: '取消', - onPositiveClick: () => { - const input = document.getElementById('movePositionInput') as HTMLInputElement; - const newPosition = parseInt(input.value); +// dialog.create({ +// title: '移动课程位置', +// content: () => h('div', [ +// h('p', `课程"${course.name}"当前位置:第 ${currentIndex + 1} 位`), +// h('p', { style: 'margin-top: 10px; margin-bottom: 10px;' }, '移动到位置:'), +// h('input', { +// type: 'number', +// min: 1, +// max: totalCourses, +// value: currentIndex + 1, +// style: 'width: 100%; padding: 8px; border: 1px solid #d9d9d9; border-radius: 4px;', +// placeholder: `请输入位置 (1-${totalCourses})`, +// id: 'movePositionInput' +// }), +// h('p', { +// style: 'margin-top: 8px; font-size: 12px; color: #666;' +// }, `提示:输入 1-${totalCourses} 之间的数字`) +// ]), +// positiveText: '确定移动', +// negativeText: '取消', +// onPositiveClick: () => { +// const input = document.getElementById('movePositionInput') as HTMLInputElement; +// const newPosition = parseInt(input.value); - if (isNaN(newPosition) || newPosition < 1 || newPosition > totalCourses) { - message.error(`请输入有效的位置 (1-${totalCourses})`); - return false; // 阻止对话框关闭 - } +// if (isNaN(newPosition) || newPosition < 1 || newPosition > totalCourses) { +// message.error(`请输入有效的位置 (1-${totalCourses})`); +// return false; // 阻止对话框关闭 +// } - // 执行移动操作 - const targetIndex = newPosition - 1; - if (targetIndex !== currentIndex) { - // 移除课程从当前位置 - const [movedCourse] = courseList.value.splice(currentIndex, 1); - // 插入到新位置 - courseList.value.splice(targetIndex, 0, movedCourse); +// // 执行移动操作 +// const targetIndex = newPosition - 1; +// if (targetIndex !== currentIndex) { +// // 移除课程从当前位置 +// const [movedCourse] = courseList.value.splice(currentIndex, 1); +// // 插入到新位置 +// courseList.value.splice(targetIndex, 0, movedCourse); - message.success(`课程"${course.name}"已移动到第 ${newPosition} 位`); - } else { - message.info('位置未发生变化'); - } +// message.success(`课程"${course.name}"已移动到第 ${newPosition} 位`); +// } else { +// message.info('位置未发生变化'); +// } - return true; // 允许对话框关闭 - } - }); -}; +// return true; // 允许对话框关闭 +// } +// }); +// }; onMounted(() => { diff --git a/src/components/admin/CourseComponents/CourseCreate.vue b/src/components/admin/CourseComponents/CourseCreate.vue index 74da6d1..f82dd1a 100644 --- a/src/components/admin/CourseComponents/CourseCreate.vue +++ b/src/components/admin/CourseComponents/CourseCreate.vue @@ -24,6 +24,12 @@
+ +
+ + +
+
@@ -31,14 +37,6 @@ class="form-input" />
- - - -
- - -
-
@@ -57,7 +55,8 @@
-
+
+
@@ -68,15 +67,15 @@
-
-
+
@@ -173,7 +172,7 @@ \ No newline at end of file diff --git a/src/stores/course.ts b/src/stores/course.ts index 852a837..abbc1c4 100644 --- a/src/stores/course.ts +++ b/src/stores/course.ts @@ -17,7 +17,39 @@ export interface Lesson { isFree?: boolean } +// 课程编辑数据接口 - 保存完整的后端数据,不做字段限制 +export interface CourseEditData { + [key: string]: any // 允许任意字段,直接保存后端返回的所有数据 +} + export const useCourseStore = defineStore('course', () => { + // 持久化存储的key + const COURSE_EDIT_DATA_KEY = 'courseEditData' + + // 从localStorage加载课程编辑数据 + const loadCourseEditDataFromStorage = (): CourseEditData | null => { + try { + const stored = localStorage.getItem(COURSE_EDIT_DATA_KEY) + return stored ? JSON.parse(stored) : null + } catch (error) { + console.error('从localStorage加载课程编辑数据失败:', error) + return null + } + } + + // 保存课程编辑数据到localStorage + const saveCourseEditDataToStorage = (data: CourseEditData | null) => { + try { + if (data) { + localStorage.setItem(COURSE_EDIT_DATA_KEY, JSON.stringify(data)) + } else { + localStorage.removeItem(COURSE_EDIT_DATA_KEY) + } + } catch (error) { + console.error('保存课程编辑数据到localStorage失败:', error) + } + } + // 状态 const courses = ref([]) const currentCourse = ref(null) @@ -27,6 +59,9 @@ export const useCourseStore = defineStore('course', () => { const searchQuery = ref('') const selectedCategory = ref('') const selectedLevel = ref('') + + // 课程编辑数据 - 初始化时从localStorage加载 + const courseEditData = ref(loadCourseEditDataFromStorage()) // 计算属性 const filteredCourses = computed(() => { @@ -60,151 +95,149 @@ export const useCourseStore = defineStore('course', () => { const fetchCourses = async () => { isLoading.value = true try { - console.log('尝试从API获取课程数据...') const response = await CourseApi.getCourses() - console.log('API响应:', response) courses.value = response.data } catch (error) { console.error('API调用失败,使用模拟数据:', error) // 如果API调用失败,使用模拟数据作为后备 - const mockCourses: Course[] = [ - { - id: "1", - title: 'Vue.js 3 完整教程', - description: '从零开始学习Vue.js 3,包括Composition API、TypeScript集成等现代开发技术', - content: '详细的Vue.js 3课程内容', - instructor: { - id: 1, - name: '李老师', - title: '前端开发专家', - bio: '资深前端开发工程师', - avatar: 'https://via.placeholder.com/50', - rating: 4.8, - studentsCount: 1234, - coursesCount: 5, - experience: '5年前端开发经验', - education: ['计算机科学学士'], - certifications: ['Vue.js认证'] - }, - thumbnail: 'https://via.placeholder.com/300x200', - coverImage: 'https://via.placeholder.com/300x200', - price: 299, - originalPrice: 399, - currency: 'CNY', - rating: 4.8, - ratingCount: 100, - studentsCount: 1234, - duration: '12小时', - level: 'intermediate', - category: { - id: 1, - name: '前端开发', - slug: 'frontend', - description: '前端开发相关课程' - }, - tags: ['Vue.js', 'JavaScript', 'TypeScript'], - totalLessons: 20, - language: 'zh-CN', - skills: ['Vue.js', 'TypeScript', 'Composition API'], - requirements: ['JavaScript基础', 'HTML/CSS基础'], - objectives: ['掌握Vue.js 3核心概念', '学会使用Composition API', '理解TypeScript集成'], - status: 'published', - createdAt: '2024-01-01', - updatedAt: '2024-01-15', - publishedAt: '2024-01-01' - }, - { - id: "2", - title: 'React 18 实战开发', - description: '掌握React 18的新特性,包括并发渲染、Suspense等高级功能', - content: '详细的React 18课程内容', - instructor: { - id: 2, - name: '王老师', - title: 'React专家', - bio: '资深React开发工程师', - avatar: 'https://via.placeholder.com/50', - rating: 4.9, - studentsCount: 2156, - coursesCount: 8, - experience: '6年React开发经验', - education: ['软件工程硕士'], - certifications: ['React认证'] - }, - thumbnail: 'https://via.placeholder.com/300x200', - coverImage: 'https://via.placeholder.com/300x200', - price: 399, - originalPrice: 499, - currency: 'CNY', - rating: 4.9, - ratingCount: 200, - studentsCount: 2156, - duration: '15小时', - level: 'advanced', - category: { - id: 1, - name: '前端开发', - slug: 'frontend', - description: '前端开发相关课程' - }, - tags: ['React', 'JavaScript', 'Hooks'], - totalLessons: 25, - language: 'zh-CN', - skills: ['React 18', 'Hooks', '并发渲染'], - requirements: ['JavaScript基础', 'React基础'], - objectives: ['掌握React 18新特性', '学会并发渲染', '理解Suspense'], - status: 'published', - createdAt: '2024-01-05', - updatedAt: '2024-01-20', - publishedAt: '2024-01-05' - }, - { - id: "3", - title: 'Node.js 后端开发', - description: '学习Node.js后端开发,包括Express、数据库操作、API设计等', - content: '详细的Node.js课程内容', - instructor: { - id: 3, - name: '张老师', - title: 'Node.js专家', - bio: '资深后端开发工程师', - avatar: 'https://via.placeholder.com/50', - rating: 4.7, - studentsCount: 987, - coursesCount: 6, - experience: '7年后端开发经验', - education: ['计算机科学硕士'], - certifications: ['Node.js认证'] - }, - thumbnail: 'https://via.placeholder.com/300x200', - coverImage: 'https://via.placeholder.com/300x200', - price: 349, - originalPrice: 449, - currency: 'CNY', - rating: 4.7, - ratingCount: 150, - studentsCount: 987, - duration: '18小时', - level: 'intermediate', - category: { - id: 2, - name: '后端开发', - slug: 'backend', - description: '后端开发相关课程' - }, - tags: ['Node.js', 'Express', 'MongoDB'], - totalLessons: 30, - language: 'zh-CN', - skills: ['Node.js', 'Express', 'MongoDB', 'API设计'], - requirements: ['JavaScript基础', '编程基础'], - objectives: ['掌握Node.js后端开发', '学会Express框架', '理解数据库操作'], - status: 'published', - createdAt: '2024-01-10', - updatedAt: '2024-01-25', - publishedAt: '2024-01-10' - } - ] - courses.value = mockCourses + // const mockCourses: Course[] = [ + // { + // id: "1", + // title: 'Vue.js 3 完整教程', + // description: '从零开始学习Vue.js 3,包括Composition API、TypeScript集成等现代开发技术', + // content: '详细的Vue.js 3课程内容', + // instructor: { + // id: 1, + // name: '李老师', + // title: '前端开发专家', + // bio: '资深前端开发工程师', + // avatar: 'https://via.placeholder.com/50', + // rating: 4.8, + // studentsCount: 1234, + // coursesCount: 5, + // experience: '5年前端开发经验', + // education: ['计算机科学学士'], + // certifications: ['Vue.js认证'] + // }, + // thumbnail: 'https://via.placeholder.com/300x200', + // coverImage: 'https://via.placeholder.com/300x200', + // price: 299, + // originalPrice: 399, + // currency: 'CNY', + // rating: 4.8, + // ratingCount: 100, + // studentsCount: 1234, + // duration: '12小时', + // level: 'intermediate', + // category: { + // id: 1, + // name: '前端开发', + // slug: 'frontend', + // description: '前端开发相关课程' + // }, + // tags: ['Vue.js', 'JavaScript', 'TypeScript'], + // totalLessons: 20, + // language: 'zh-CN', + // skills: ['Vue.js', 'TypeScript', 'Composition API'], + // requirements: ['JavaScript基础', 'HTML/CSS基础'], + // objectives: ['掌握Vue.js 3核心概念', '学会使用Composition API', '理解TypeScript集成'], + // status: 'published', + // createdAt: '2024-01-01', + // updatedAt: '2024-01-15', + // publishedAt: '2024-01-01' + // }, + // { + // id: "2", + // title: 'React 18 实战开发', + // description: '掌握React 18的新特性,包括并发渲染、Suspense等高级功能', + // content: '详细的React 18课程内容', + // instructor: { + // id: 2, + // name: '王老师', + // title: 'React专家', + // bio: '资深React开发工程师', + // avatar: 'https://via.placeholder.com/50', + // rating: 4.9, + // studentsCount: 2156, + // coursesCount: 8, + // experience: '6年React开发经验', + // education: ['软件工程硕士'], + // certifications: ['React认证'] + // }, + // thumbnail: 'https://via.placeholder.com/300x200', + // coverImage: 'https://via.placeholder.com/300x200', + // price: 399, + // originalPrice: 499, + // currency: 'CNY', + // rating: 4.9, + // ratingCount: 200, + // studentsCount: 2156, + // duration: '15小时', + // level: 'advanced', + // category: { + // id: 1, + // name: '前端开发', + // slug: 'frontend', + // description: '前端开发相关课程' + // }, + // tags: ['React', 'JavaScript', 'Hooks'], + // totalLessons: 25, + // language: 'zh-CN', + // skills: ['React 18', 'Hooks', '并发渲染'], + // requirements: ['JavaScript基础', 'React基础'], + // objectives: ['掌握React 18新特性', '学会并发渲染', '理解Suspense'], + // status: 'published', + // createdAt: '2024-01-05', + // updatedAt: '2024-01-20', + // publishedAt: '2024-01-05' + // }, + // { + // id: "3", + // title: 'Node.js 后端开发', + // description: '学习Node.js后端开发,包括Express、数据库操作、API设计等', + // content: '详细的Node.js课程内容', + // instructor: { + // id: 3, + // name: '张老师', + // title: 'Node.js专家', + // bio: '资深后端开发工程师', + // avatar: 'https://via.placeholder.com/50', + // rating: 4.7, + // studentsCount: 987, + // coursesCount: 6, + // experience: '7年后端开发经验', + // education: ['计算机科学硕士'], + // certifications: ['Node.js认证'] + // }, + // thumbnail: 'https://via.placeholder.com/300x200', + // coverImage: 'https://via.placeholder.com/300x200', + // price: 349, + // originalPrice: 449, + // currency: 'CNY', + // rating: 4.7, + // ratingCount: 150, + // studentsCount: 987, + // duration: '18小时', + // level: 'intermediate', + // category: { + // id: 2, + // name: '后端开发', + // slug: 'backend', + // description: '后端开发相关课程' + // }, + // tags: ['Node.js', 'Express', 'MongoDB'], + // totalLessons: 30, + // language: 'zh-CN', + // skills: ['Node.js', 'Express', 'MongoDB', 'API设计'], + // requirements: ['JavaScript基础', '编程基础'], + // objectives: ['掌握Node.js后端开发', '学会Express框架', '理解数据库操作'], + // status: 'published', + // createdAt: '2024-01-10', + // updatedAt: '2024-01-25', + // publishedAt: '2024-01-10' + // } + // ] + courses.value = [] } finally { isLoading.value = false } @@ -299,6 +332,21 @@ export const useCourseStore = defineStore('course', () => { } } + // 课程编辑数据管理方法 + const setCourseEditData = (data: CourseEditData) => { + // 清空旧数据再保存新数据 + courseEditData.value = null + courseEditData.value = data + // 持久化到localStorage + saveCourseEditDataToStorage(data) + } + + const clearCourseEditData = () => { + courseEditData.value = null + // 从localStorage清除 + saveCourseEditDataToStorage(null) + } + return { // 状态 courses, @@ -309,6 +357,7 @@ export const useCourseStore = defineStore('course', () => { searchQuery, selectedCategory, selectedLevel, + courseEditData, // 计算属性 filteredCourses, categories, @@ -317,6 +366,8 @@ export const useCourseStore = defineStore('course', () => { fetchCourseById, fetchLessons, enrollCourse, - updateProgress + updateProgress, + setCourseEditData, + clearCourseEditData } }) diff --git a/src/views/teacher/course/AddCoursewareModal.vue b/src/views/teacher/course/AddCoursewareModal.vue index 9dd0c98..81bf761 100644 --- a/src/views/teacher/course/AddCoursewareModal.vue +++ b/src/views/teacher/course/AddCoursewareModal.vue @@ -2,53 +2,62 @@