From 24d63e6702ade4bdad1487bd4bdb166789aec924 Mon Sep 17 00:00:00 2001 From: lzcode Date: Fri, 16 Oct 2026 14:01:02 +0800 Subject: [PATCH] up --- admin/src/views/SeriesManage.vue | 64 +++++++++++++++++- .../api/v1/__pycache__/admin.cpython-311.pyc | Bin 40403 -> 43197 bytes server/app/api/v1/admin.py | 42 ++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/admin/src/views/SeriesManage.vue b/admin/src/views/SeriesManage.vue index f9c3783..2d221ca 100644 --- a/admin/src/views/SeriesManage.vue +++ b/admin/src/views/SeriesManage.vue @@ -58,8 +58,30 @@ - - + +
+ +
+ + 上传中… +
+ 选择图片 +
+ 移除 +
+
+ + @@ -93,11 +115,38 @@ const categories = ref([]) const dialogVisible = ref(false) const editing = ref(null) const submitting = ref(false) +const coverUploading = ref(false) const form = reactive({ title: '', cover_url: '', description: '', category_id: 0, }) +async function uploadCover(file) { + if (!file || !file.raw) return + const allowed = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'] + if (!allowed.includes(file.raw.type)) { + return ElMessage.error('仅支持 jpg/png/webp/gif') + } + if (file.raw.size > 5 * 1024 * 1024) { + return ElMessage.error('图片不能超过 5MB') + } + coverUploading.value = true + try { + const fd = new FormData() + fd.append('file', file.raw) + const r = await request({ + url: '/admin/upload/image', method: 'post', data: fd, + headers: { 'Content-Type': 'multipart/form-data' }, + }) + form.cover_url = r.data.url + ElMessage.success('封面上传成功') + } catch (e) { + ElMessage.error(e?.message || '上传失败') + } finally { + coverUploading.value = false + } +} + onMounted(async () => { load() try { @@ -181,4 +230,15 @@ async function del(row) { .header { display: flex; justify-content: space-between; align-items: center; } .title-col { display: flex; align-items: center; gap: 8px; } .cover { width: 40px; height: 40px; border-radius: 4px; object-fit: cover; } +.cover-upload { display: flex; align-items: center; } +.cover-preview { + width: 120px; height: 70px; border-radius: 6px; overflow: hidden; + border: 1px dashed #dcdfe6; cursor: pointer; position: relative; + display: flex; align-items: center; justify-content: center; +} +.cover-preview img { width: 100%; height: 100%; object-fit: cover; } +.cover-preview .mask { + position: absolute; inset: 0; background: rgba(0,0,0,.6); + color: #fff; font-size: 12px; display: flex; align-items: center; justify-content: center; +} diff --git a/server/app/api/v1/__pycache__/admin.cpython-311.pyc b/server/app/api/v1/__pycache__/admin.cpython-311.pyc index e52569812d9435f78b9c20b93cb4e6e84d076da3..793f291f7e6fa77303c85aab6212bcf4063b196b 100644 GIT binary patch delta 5949 zcmZ`-3s_Xwoxf+^bBB4rzzh#ZVS~y9Wqj~3h$5gEi9CHoNfbuz1qKFYJTqX_85q$h zx+?0i)vBq~c2nJcNocO!O&hEBYm=|dx9u_s?b7LH<2DlG=1W7rG~2HI((L&kV0erj z@BHT6|M{K&`<`?0y*Fh)4$BPR)$4hVe%9OyxAixkH6+UlZQsw5tI6j&3o0N(=m{MX zOrl0e7ER3x@ir%l zXP^2!GMJV^%CuSJHRU2LuoFc~TRu6hSZFSeVHc2bT?%Qj7+l}V7}zBCNx5A%<5985~`cBQLtsQPGyhP zzzbVrG^`g>1~-tiDzlsuqI%?157}(YK;#8RB39>JF}_r=T=y&2%zlSkiq>Q8D+_|QxDf6*dQ!J1kwr3`a&KY}Ve+*Y( z6+aGK`w5o8JyE_!_{SK&I3s+vN)M~1_DK~PpO?t2p8}2KgL$fjP0?A6a5_d`iy+&= z*#{)v=CY>UKoO1L^oxF1he*eY8mGUt3U8wMct}p?p0vSyv&$`ZI_bPDqHcBioPIyX z0%hDF1$l?j7v#;nRpu|?#JT_GiyxhT?W2>2(jTEEkBBONCAvWh^KIxM*^!Tp&r?c7 z?WGpnu041+`E9=4+)QP-5hhgKPIs5+!vaYvxSa}Iyc?hgpcfeOc5y%MBcB$`Lq`a| z>JYjnom`ctFzFp#Ubn|7I9wgh7O_c2?o}q1-lbK2hC|#1j&^~}&2^xltV0%*Be<8l z><$~H)PT;?df;{Cb1KKurP{Xtr z3A&dNT}!_cpEljphzuRfGzWD7U4ZXK*fD7;P9Vr(HTZ2)G>!}KB&Ts6XmOVfMU=%<-2Uq1jCh_V4OqK2jT?N0cu`|XP5vO&;tey0mEQCQ}Nej*5|1e)$CV- zwuC8nE^`6hW$q=`=EvsWC@Q@7&-34<2UXyXEN<`H+YTuZgWKl17dyIebHWdYLK z_eO2e{;&r0mpLIhV5Ctgf{Fg+Gi)XX;)Rqeve}mDW0u-=k+PgZhpRLFVd&C>^Vi2N z-+plX*!?$7+`l#W*{w@sLx&!|bj>mLottBa2OJNiH^=%f0OghAABOtIdSAIX)<2Yv zyE@?ko$PbpM5Fs02Y1p>W##(yLC0sePV(vW^YNYYW0${~-kO&_cJ=DmnNwo}uRXYY z^P|)M^zo~A9$t9$!KEW(ub%wqYd6!k)orE*Fm$S2hIh~(To3RZz%GDt3aEyEv{yYZQd4& z-p-asN;($dXP>yoi!DI+0_>%5!0f;tkKf_No;I<`@91_3q6cF-6H!m5H=>@1!WU7o z2z*`B-RWBMS(IKk{so4x>)uLD5eGW(IZ;+neZiVbC38|td7x8iTW#3c$5Eu0Jua5Ug6 zAp9o4Re(W&S19B>Aw&+&U4BY!;0mx7rDJ^ktuap zG3z4ErxrXt%6jRd;;QbF?i>0mdfGVQxayI(>d=N!ooSpy%7RftT7SpIvf+%pupxiM zkUy-+A5EEmaqpGnQ29N>s$q7WD{LseXSSZn9Zp^vHs_3(b3&U(`GkQbCzc$~Ihpex ze8#(c#$Z;M&mQ5kLuI3e)QdaAhDFy?!iE(?JHm!FcjaM285t-{Szt~+lXte@e8KtE z!=|i36$N^QHjSFB7wuuw6U4ImLFqldbjUo+m(pu!|HN;o?0ud7Ow)D6uwf~^!n&Lh zUCyu~#|QO$E3QOSo*{obLs7m^{dN{AUr6p0{gQv3PGNxe$=BEX1xaLJZ5sar5CV)z zH`iJbl`h|4CLa{1>i!jG06yW!K)ppuUAGYNKLjDb=hCJUCD3at^U)*eXsHdQ-iApD z;0{1Oz+Hf!kWf`J`E^;M?x%1Ipg_`}%8C%WP3m zpTiV@6{h~8dk5|T<|A@#@@!d6o5=5-F!L=pneoT!3&Cga8%N z>s9#({dOv${O@1}piWA!NkqE;gnO2x_gQ|fE{x|t02#pZ60Xff=pOU@_aFrjiJ`(u zKCAn0{yvBRI;F^#9E8TAW*)!{fL~g-4Iu>-gq(dYm4N>Lfk}WK>A-fH{!gOIK7|>8 zW6~d<)gkl;7R@+F0nSKEc0P&FAEW%wVFuu$bh>^C;=h10$$Pa65Z!Ysh+QsZu-D5S4g9H#G99999S0a$7@FoHeoh77mTp9u2J zK2=DSClmdO)HR*T{2R>kzP)azyQx*|*pKOJ9fuKxh;m=6h(&6F$c1$>1tJ@S@&&-3 z!BP199e!*8x&nLl`G}{-LhcHBWjYnzlHL`L%i@@e7Fef3q@|^H0~2fk!^VaNXJ@C! z@ASJooxX;KiAb`*1v}`JyE^?hxQP>r9f+AQ1@J!kvc-ckNk{8Dy$eA&od~v^?s*(` z06QER7D3Edxjc3bVfgZUOGoukQ$zhdA;tu70$F z6t|r#nq!1%V5*t9d{{h3VJ^r3J|X({GL$RTw&%;WUxLA}C=j&gTQ*EztU0U&;3>q` zvR6*S#c@DjuIlN?o`_8#U0<-C zfSrDEIFEYSC0G{C?hHJiQX+hlhrV4kM4JRJAWOZeJTwOe7?*0j|0^qJ;XX;jwJYb= z5!zs)tMllH)^R$hITg2)Q@#Z@aG7eE2MM$RuydLDrbFZxz6{k`%FxNkxbIgePrBnj zfY6tuuzQJaT5%)U+g-A}2rRQ0wHR#w9i22vBt%dJGessD_kD$GSy=0+ zz^@*|b6Bguz(<8}?_YHq!-*Wzy08Mnx~g6;W6#$t!ojVPPlUB1?dCSg63 z${K`q6MJG<=dgXKh~)GvNMmVdb~rEwy9#!J30jKQo@L59Dp)DK)blz*t)wQj1O=pE z=qaRQZe#(`L4I;*XZtl6!ut$6irLW{(QosKcnjS*x_ouwUUuk4j5Qv*Vfadfwl1F^ zr0nSZF)W1hGoq^#eWKs*7GVyK&WN^7Z0_n5;Qr@8dxwPjEQN3mMocx%rgr)_?=~;| z4G#=<7#;!|oP81XMprYl@*aqO129U4`>d+p!SDm}X`eOw_b`MbCt@t~bT+$MrnRv% zhn+3#7#Syy!%6LMIIt5TV%{Ql`dofjxA?3F3nc>cksT0l1hA(kqVet*ob<1kCY%AO z{RaTH(`3R3wkfu?U}$*^or$4&Fr*zXBd;A!*1bT7^x}M*Ql)nf?@`qT=>Ozsj-~ab z^*4l(Z3Nlw<*pvu_(o+ow_+r>VqCrmImS5(gDvc5G;{g1j7k0|=VbHgx^Wp$w<9V4 I#7pM?2R#Se!~g&Q delta 4277 zcmZuz3vg7`8Q!zWZuXIokWF@3laMe4l87&=;TaH&g1kZ=JVIniHhb@qC7WGx?%hC8 z31CoAaEgCB6pIBd3RWD%%Qy}UR@;uPZKoq`t##X?b`U{|)>ehmVtc-m%`WD$GyCm5 z|Ns5Z^PhY6RnSq zk7tkb%rJ2$(dcYHU2;@WxuYP*D!G%XVua6gr-?h|39Fy>ISc7X&K5TuTQ}rbEXr(p z-BrTwqOY72Se-~XME!*uYh23RYFUbr;og(Bs!Tu4N%Q8?=-d*|y{5p^kR+Q&`<+vr z@QQ+_izJJSUCMkDyH=K@=1xmG?{GbRR8|Fsc~kJRY@CG4jLAyj`YSllxCCZ zJ+co=hQg(in}g)2Cclu)71gn2Lo?%Eo^ElAXskagS6M-?=1*X)LktRxbg^mJK6 zJF28wwg@c~JF1%4^#~RQnO?|qc~+YUi?I*%p{I(D*v2~}soWc6?rTi!M!4%5%ANKV z=ZYpAE*|HLny5`fn?;w4JZKDy(Ji){J#iDW8BW)Jqq9BetcRPZOJwnyJfC{1_@y$} zgo(QhZhL7{;e&K^)M(E-6Jfb@)(dAgoQoE!_mA_fH}O^sRbo~8KxP~0Q-8VVeiN}3 z5g(w6lBEkCG%4>>n6fdtvOCZk=w8*@#w=FLT#M2_U{N-yf#>}N2|cPQIUd?nKg zX*32#nHTD#CIeNb@)!b4m>>gmr1=hIhlw9ntj(6{okqAU;w!0UNrw{DRXx(Jis$Tx zpx#-}=ZPjo=#x8kltCYkMAcYO=&i||&Y%|5bRu8A`zwx0d& zk+VBCS6pE?ZJ>@xx0l0aZIG)mT}wLD^$|^Pi+Axkf}FIj>xj^?Nj(2PtOQH%j7B>6 zN~)P$?FkAQ4?tn>4Mr2H#@nf9@@qGM%U1$4fDT4hm)ghI(Yz_8tdGJ|HnZKvxhXZ- zIrduhAq;{F9KC0rCWBn2(Bz3hsww?+~0Y=Fjsn z_9XSU-t77zq<}YQW2Mh{Y5q9o+7B7vE#v(KHfEPzpP}!Bs$2)40=#XME-GU;Jd3r| z<6h*G00#kw1bq~B)fc&cj3ppxF&?e2W$am+5va^R3^CxW_-eDMzIl{U+`t%nks1RY z_YtT87cErNc-egvYrq#4>RIKb`li!mPm86NEkM+mD$)QAaE0Dq;4|8r3mH3xc&=BV z0WgXMeAM1-r#F_Iw;zMpLobajb-jv5fP+3?=A(;CKfYds<6r>_1nUYrA=`2iLV%Y> zw_FmfMX!DWA)rDCeMZ}ga>iblP5&u0fGXpa)*|Nq8P>9QKbLL0c;86Zn~(v%O$9-p zQNFT_v0una-hu`&T~u<}^=m8vcN=S0-NM*!WQgBF3Yc&Fv5lqnuqN&O6x4tvMnO>Q z$?v4mA0Pz;jDZd}WADg1-h~tpmUX-r@-X%%@ZCvh05L}Wm0r5o<}m8iJm&ff6oB)tu`Bj{aPPc#?}b*kNc{9_^D=ODGM>r}ZaBG8`L zEb9de{W&(r2mUpjY)$Xh`Ii=&5}#npVHV31MrVAxHCLwP1y@Yw)t*MH@Y2BjH_A-& z1&qQYk zM8BAlWL-Q&eVfO-CJN?f;;a3VDhApO=awI^M%ju=A*^;@Q)&Q7SHtm*fC+$J$TERN zWsrWeG8FdZLu2f>3)NL-ln&%)_ser{TNY8&xE#RxM85EJ?%>1cpV@Wh)tw)``2COe z9^y#hJdRqm_nJIv5MtPY= z*V!sAGsw(&2s}~b*V}HhO%?H+#_ii*W^6T`ee@>QV|X5$%G@%+DiFQ2e8-CZ-FVys z*ef8Jw^aOXXx4*zLTgfc