From be7675954ada28f463426de63f7561f72d2493d6 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 31 Jul 2026 15:34:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- index.html | 6 +- src/api/merchantIam.test.mjs | 9 +- src/assets/brand/baiyue-favicon.png | Bin 0 -> 19511 bytes src/assets/brand/baiyue-logo-dark.png | Bin 0 -> 28809 bytes src/data/firstLegParties.ts | 9 -- src/data/firstLegPartySource.ts | 3 +- src/layouts/AppLayout.vue | 5 +- src/router/index.ts | 2 +- src/stores/firstLegOrders.ts | 12 +-- src/stores/tenantAdministration.ts | 89 ++++--------------- src/styles/index.css | 19 ++-- src/utils/firstLegOrder.test.mjs | 21 +++-- src/views/AuthViews.test.mjs | 5 +- src/views/CompanyProfileView.vue | 48 +++++----- src/views/DashboardView.vue | 20 +++-- src/views/FirstLegOrdersView.test.mjs | 6 +- src/views/FirstLegOrdersView.vue | 61 ++++++++++--- src/views/LoginView.vue | 13 +-- src/views/MembersView.vue | 21 +++-- src/views/ModuleView.vue | 16 ---- src/views/PermissionsView.vue | 28 +++++- src/views/RegisterView.vue | 3 +- src/views/RolesView.vue | 21 +++-- src/views/TenantAdministrationViews.test.mjs | 9 ++ 25 files changed, 224 insertions(+), 204 deletions(-) create mode 100644 src/assets/brand/baiyue-favicon.png create mode 100644 src/assets/brand/baiyue-logo-dark.png delete mode 100644 src/views/ModuleView.vue diff --git a/README.md b/README.md index a58b4f1..01b392e 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ pnpm test 认证会话保存 Access Token 和轮换后的 Refresh Token,并对并发 401 请求执行单次刷新。刷新或会话上下文加载遇到临时网络故障、超时等非认证错误时保留当前有效 Token,只有服务端明确返回 401/会话失效才清理登录状态。客户端只接受 `app_code` 为 `MERCHANT` 的 JWT;页面权限取 JWT 声明与后端启用权限资源的交集。前端权限仅用于导航和交互控制,服务端仍须按用户、租户和权限编码完成最终授权。 -本地联调账号提示和默认用户名只在 Vite 开发模式下启用,URL 显式传入的登录用户名仍优先。生产登录表单默认留空,生产构建产物不得包含本地联调账号或开发提示文案。 +登录表单在开发和生产环境均默认留空;URL 显式传入的登录用户名仍优先。源码和构建产物不得包含联调账号、默认密码或开发提示文案。 “我的信息”使用真实个人资料和修改密码接口,姓名、电话、邮箱按服务端约束维护;修改密码成功后清理旧会话并返回登录页。成员列表返回姓名、联系方式和 `roleIds`,新增、编辑、角色全量保存、启停和管理员重置密码均使用真实接口,不回退静态成功。角色页同时加载成员关系,直接打开或刷新后成员数仍按真实 `roleIds` 统计。角色列表返回 `permissionIds`,页面可回显并全量保存角色权限;角色编辑、启停、删除分别调用 `PUT /merchant/v1/iam/roles/{roleId}`、`PUT /merchant/v1/iam/roles/{roleId}/status` 和 `DELETE /merchant/v1/iam/roles/{roleId}`,内置角色及仍有关联成员的角色继续受保护。 diff --git a/index.html b/index.html index be4f977..462b6e4 100644 --- a/index.html +++ b/index.html @@ -3,12 +3,12 @@ - - 虫虫出海客户工作台 + + + 柏悦物流客户工作台
- diff --git a/src/api/merchantIam.test.mjs b/src/api/merchantIam.test.mjs index 071c428..a129319 100644 --- a/src/api/merchantIam.test.mjs +++ b/src/api/merchantIam.test.mjs @@ -33,9 +33,12 @@ test('uses membershipId and full replacement arrays in authorization writes', () assert.doesNotMatch(source, /data: \{ userId, roleIds \}/) }) -test('clears mock records before loading server role and member lists', () => { - assert.match(storeSource, /rolesLoadedFromApi\.value = true\s+roles\.value = \[\]/) - assert.match(storeSource, /membersLoadedFromApi\.value = true\s+members\.value = \[\]/) +test('starts empty and only loads server role and member records', () => { + assert.match(storeSource, /const members = ref\(\[\]\)/) + assert.match(storeSource, /const roles = ref\(\[\]\)/) + assert.match(storeSource, /async function loadRoles\(\) \{\s+roles\.value = \[\]/) + assert.match(storeSource, /async function loadMembers\(\) \{\s+members\.value = \[\]/) + assert.doesNotMatch(storeSource, /initialRoles|initialMembers|示例贸易|演示大道/) assert.match(storeSource, /await createMerchantRole/) assert.match(storeSource, /await updateMerchantRole/) assert.match(storeSource, /await changeMerchantRoleStatus/) diff --git a/src/assets/brand/baiyue-favicon.png b/src/assets/brand/baiyue-favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..e6151c8896bb003eaa0e17fd1db7eb26c8eabb79 GIT binary patch literal 19511 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

Rw~D;IXvND(}Q>0rzFFk9pXXpj7Zy zf5*(*O;;Eu|fMETacqWo+1%#rSYm_&tX@fvU)EU!nj~V5`!x8mS*l5Kqp$kY+Oo!ka*MCA9{W$|k0&2# zO_Lp)-lUQqd1^S&qfE|h99?W=`-~Jl5{6m`$Jow3PrV{Z7t%&nut13q-i62C%pZ}; zdT#fklBqIUl?h)-@di$Pq@)V^ghWHPIzZB@o#}WD;|EA8u{0uzuPC1Fba{h(Cgx&4 zULU(5!9Or!__MqW@5s696^7kt9+1EkUl0&zGZex#1W2qjm+C)4mp?Z(o{$W1o4?da z548=P9bxIfT25t@4k9~YDN#Q5{cGlBkB0+pft3#-8kNnJvAj_6kADs1Bq-a|un!cc zJYCb{9c7@0Stx#V=?BA=|Ga;pMJ`FPYhQfPjMM5XADPYa+8X12t`H{sNBk{j{7!d_ zM+=Q@L%<-!F7sNP40zg0Mz@d`)MZo*leNVLh|3_F2zcgm2!pLJd5cKCG5dlA{!rjx zb!rx+NVA}q<6GET&r}i8_**XID1%bXaL4Csl!GtO9bTr;lu&3P5-{?KRFL9$m};z0 z>9|!$7NvN?YMv@mMBAF#e0QVPfpoR#)wQaPPiwx0`oi#H*@-8Of9m3wzGqrRMv7WX@C@`Lfu3zNx<-IRi~k)A3oz*MwV zIk6tyIwmkHAcKyut_tMjI<>(q)<0uuvD(u8@;`46VIpPT%4NE)b(ta-^NJpp z_}Vs@8%M{}v~cmf>8}yw-!+jLP*!}QI6AVauGG&}cnxmFpPv#V_q+SJV_V|nIA85=*sLQq5x@gPmtt=8{gQ}^hV>frU1!;aDar- z=)9>RxjfrzTasc=l_@6>pQ=EFWBekt@fR+jY~D8^9&3_bIptXG>vTxXZ34pAl)a=} zO%VJMLpcX}fnb|dJI#>g_a0C=eV6UUj-J)wl_!>lcSb&%1Ic#+zi@t$T#4(`Kg>Jb z+24hMO~NVhh{gJnv<1(hcVK;;AIG}dkGqMa=+Q9LaYQCk2LPof3pb?cF`HI|89yC?0`gutAI_FFP$B z!R@q1IP9LOwLTiDbAxf3uIhW!fwFHROvg86faR6Pw^uDYslGu%8152 z`^0DA#c$h1KD!hdH1DNtskC$kAS2O=$;Sc1xr&r{Al`vT-6(iZAn@;c zeTZxz8?&-b@j4y%#yY2Y`k9wVe~;`m@!32&Ka-35*Qat2_uZ1_%^SA$W#5a5;nqrq zb$Z}l^w$pdq@CtJLQfsjI(+~b*k=X4b)K9}ymsXjQ3!!VwTSgFERNi4A}^Hu8eGl% zJ9yl+7});_-P-T*>vB&oV+_3TT8+Sb8z+=^s&B2{zd7< zL}HdI)5bAsbgi{H0F@_7RdO>LUPS8)vlK2~DsG3rW} z2Y(va(!&vu=7!VBXhh*%_h@^e&Tg;;`*=2Q(PbS6@k7!cG2f{Z!a1n3++k4*{_A4| zI_q5589yN$hos9j^^Lw24 zG39#vo1k_>5D9hc(zZ`j(v3Yeru&V)iu=aeTvhvc*=me|FEsZ$5zYWZ1+gu$vRi;i z93LSP@WLJR6~{GYj|)-zN#4EpBklNXkvxJOsE1v_dSXXu{PF}!pWR3SafOaLZVu9C z#+|cm4N~5opS!Q|5RbC7>UtIKlzpEUzY>l-MxA*xZ*|>Y&aV7DQPwv4NyX@%FWF#3upt69spi_Gq=(uPY*tjq-LG zKY64p9~YcVmkSOb_~fJ?U|duDgRJFSY_lcFD(e-#=NCuxOZ$VT z*{%G8BYkpYwJK$zZ%?KCc0vr{edMyVFuPC0iMPC;0x^B`5z54nLlK%z>bEI6;0CGI z90%yfX!0~eod?sw=Ww10%bF&#F@B@5z4j~FKI@yRBT3)kk}B`B>2Q#+HnK74o9xpU z*yl&d#+lw`aPdd&F;m|7My9Ub1OmgTV^2n^Npa zSQqLjv3|%FXQ+Dh!2>S|;UE*7E90FMPBj@e>8~0!)A?k3O)7kgNQeV6a?Shzv(ma1w=0)EmGxTA=n zlbg4#nOUr5Im3|i91Pe-fw9|>uX^IL(qd?JIX>KDQnlftx4Tqo4v%_ujUI;x6iIyQ zm-e9^9qi5KP~#UGz5QghEi+jLFc>|PwEGO>-X1b+v!!Y}yE4km8Lk`F8lRNLS28lde`?N8d;O_<32;nOXEp3aZ&j@ojj`*);05%aw` z765lDtLDmXk2+%j*LF5?1hdDrmKM8tdl^c_e8}pfw4wOn%3=N%81T4h^+QR%l^k}X z%4MuQsq;p&6efVD+EXMzLVCtkp={yw}8DtLf9r~ z!lK#5I1VgV=+7wa68_C|IZVzhQ0aJV0(i@%emU5o(jb4vm@kz5Jl$&5Iegs8r6LhA zq!RPj5l*xm*=$Kbnc;}OD%NVVvC~b#mny`zi){Q4AHX|G26Gx{#JITDnEG0KW-l4J z)=ySwYAo#uJPo%p3)fg@hE&`9o8b4BFycBTqF!lGc}zYRAiSr8qew-XUtMjc*LJf` zEqz1XQR#ATqwo9=2wmI`F`{Kn61#ke0?s;c^(l-Q3M^(3S-SL3Y*Gz2A@X}Mv6kge zq1JGq{8Kq{lK(|m1_H=4>ideZS4>O(EvecJFNp@3kxdP3V9*GeTl$wNDE6ma3Wozm zPXL8aTR6ZgcThbk%gH#Jo{x%kG^{Mq+VcC@R(uxCQ|PKOyHf;m+~ z0IBa@f@=J}oX*)^>=)~`RsjHO=`Bh3vMPKOx@YP+`ENCuSjV^}++s9T*l<34t~~?B1+HD%($IRM_M=vHy)6!EnjBG=2e}IsXPAu%E%t$UbW1^`5UKi{(0MuauMFF$ z*p;OFmeLz<9&GZDB`}kll@78<_iTFS*_vGaV31`SPr7Q?Z9&el{z5!ML20BwjE1)v z`H2{@vzspEZ&7%p90M}#xpr}r@?EoLjA|)?0@mAr1uYf?uypoCX zEBZ1%P7wDZ>!36vk-`R66BAad@B&s!t~Yb?nzf{3bF*usQGlrNfM4#*AkzCE8pD4T7SiaFZycMLLkW>T&$ zPmzr=w%+Q=%cWf{kdD5kU*+}rxx*#q&54EpH>1y{e+P9w4~)jXOI10O(o6Y=QPfX- zoe2WDFHj|G^SegU@nR1KBq4rmvk@TdDHx+OLi&IgTPC!maATCx+`W45c7XZDFxe{QE4DCgs0cN&(P(LTz3?c1*;1FR9yB(?XefOD| z+Qkn)Hm*-?97+xD<7=+KWpwjHHFUmP^R`My7NJYttjhf?ta|J_eAv(QWJ;mC^h(*e zec%TL1b`A*AG^FL}-K;%%5dNy53i_mXvq4&I$Mxse-kI`yQG0Rfdd#guT)dA?k`msLD?|N@$ zZCi}$bUU55P3llPNCK+N`8(5>POzl=61kPmv&DY#!a4NsW&mI(^a`MT5*fAYQ zh|~HU;j%P%sEaArc6A1s!U4bUKWO7A{6AQq;AjC6R~ma3gP8gt;d0>BfID{0fSLi( z^2rX(9sV?!R+;>Hii6JBV5{OnPgBkP75ldil3?e&QU>uST{W~Y@r2qC`P*%d@N8sj zsV03J`AUqWizl|imQ*ts^Z{HB5VjdDG5-tSWyTKhJBUT>Dvi2zdwn4vbCkr@F{qE5 z5=0=it?hOhP0;Y29P>N!=%>Dx{c#TIOLS;8GYa%LyQu-hLHRD9?E<6T#{-*!z=Tc* zx7l7-8^FV(*38o19pNN2zpSDG)s@w; zjn!*026jQN{zuN&x*0XC4=-=vj#LduDPnKZ!Jd^=bJ z2&|?gPO(gt3g94)*N{8mZu!4acc9#*uL^62X`OFajH7twj^P1zb@-YGkVW@*&z0qd z8e!;qm;!rRq4B67-;&U}mdYJt|s(%Rpz6?~Y%^`%9Enol*?3kv3 zPe=VIxZmK-q6&;Ly!_8K&=#IBL#Xno%t;Pkf?ZK}W*G9lGEKJ6Xx~L0QM{%{Q@mPZ zG1hlKKiBxj7m}qq1)V>eN!GmhU^QA--9OmsK-o;UJ4Y0{L7`T1Pr&w>;#*#S1L%u~ z#A?g|IC@(Fx1j@y#YbEP(iW=LW}LLNQlg;s-3+pg|Fpgh%2pX7c<6tDcpZZ0okG1H zV87L@`3z5;L%m1zz7|iY{H#4fh~9bSc2bTqqgFXMt;vuV`D_vBC+@ydvl5mdP0s|H zTwy0b0H27WSxC}m+U>63l#{+TYw_Jh1lM=Aomd{Rnrm7%;bf_*-aK^jhSA{UbVJ_< z6|a3!>US)Gtvs{{-~2=n$%I}y@~Zcn$8TA1d!tyHAuq-)O-r8XQ;ZMR3c4vA#_jan zWl^z{+dyLhF;ky*;oR< zD#oAZkkxY-2KgbbJ{J$;rq?zZxQJjE&s@DLQ(BbPPk0;(1Jk<_iO$OQ;7M|MbiN1N zgaCx9z`*_S0+?s=f65Z=+3fsjSgF#5g00K~hy{}Bl?&MT5zvBf62yIF_$&Wa8c&cf zEIjB)V#^JQRHyDNp0gpzHXl3wL~V57or*unBvfT>cb1jimzf{Y<%p?C2H%@gtMGE) z2eo|>3bbycTQyVR51$5Jr|-uvilSz3h+v3NfUW9Wybfm46`H$FT0~vg*XFZD&Gx`} zhNQ1!E()wRlKg*1VVR*q$>S*XE{pVo5|Qju`*Sf6F7;(If(UqdX?JRD;%fdEZW`yz zOfJvE?e^_p!CBS4se~=-v!$49!cS2Q5yiUG7r7jn667o+L^O6Qt<2P216uiaNXE() zVUB~F6QK9^A0CU_qo^yU+{qb?>)W^gbU^89e|gAtv+44j>$>4`S} zQdOXBDl?RXxgHYu@<3oV_Wh{Xzyu={)JYSm+8sdQs!2FCMc*)&&EL=kXOR+B-_!XJ z_ECnfph)_!uZ*wD5A+k#QlFjeX&8I>M&SL;XdW^34ZKg7xT5$cLR(z2lL4+uNg9^1 zx}e1DH(u4sTfh?UC!pX80T}v5%e5?)y-opRl*&LY<`BB|K^)Ob`P?GEU!7sUh`t;vvp(C zxlhc$t{N-gNg^>H#AYYrUv6!7grl;jGG5n(Z~{Wd?bP4Hvle%bsgSWIw_{kOy7s~9AKse|67XxlYaRYkCPQJ#Y=wG!^Ku} z?lcw_vSyST2Y~EHh+U34Ums@|gf57!lXsa4`TB+Z&%MaqOd$Mcw z5*lw;ClhaM0@mu^w-&9^)`&jt7ZSptXo#YwCSaeuySJOFw8Ep-F|oHS)GEC@mQzaDvCr%#mjx~OTU^oB_fGazv|j={S_Os@qehg? zeOTE->~dCBrm61*;rZ0&U3K8It@>CULeve=*Rc?$isZ~FO=gL&U-Xf*Qh19Y-LzzX+fJwKBZESR6Gdk>iY||a|w19EHC$qN0k664Gf>k z;2X{*nUx5Nsmbm-k|-bCk#as7D40j$9(;XanDOJ7nZC?#i116c(53*?8u^3$MS${o zvA0b;YvT`|#J5iZV)@8{g_8o&mmVQ=rnZMyvm)geg_Xh!#gBT6(Hj-(cN=K&-FlCC zZdpj+{+Rl<-cYQtvTzA7@ZHr9YLxT;G_m}JpSpNZjIR?I{odu=if-<Q6P#Y6)|u>(GnDuIFMWl6_{42+L7Vj#rnQ`AqJl2IiGZ2HVm($$6Tik*eo!;%YUCcCuj&Rh-sIBY!c ztMzR-R_{Bfwi2y`(%Z`B(V0w(JW(~De84>ClBCW_sPHRo=x`M8b%22jvrJ!Jm8_uD z%xeW#6CGXVEC>}#kYY*o?r1G>23K!sYfTm0+-#p;;dD%8Nlm~<0|met?XV4rDE^y; zJ)FJgxmCe$`YE<~;o_>5(bed|J^P7QO1z0u;BKw7)nKkFy$UN%$G=!ob^Droh`)V> zDW`s5lu+h!z&}w?|L}c#6f)E0N{5b_%$YMYY~w6hV%nog)|o}*7tWm7x|>j*72Cx6! OAE_v6-Yd9k9`HZ+MM!Y~ literal 0 HcmV?d00001 diff --git a/src/data/firstLegParties.ts b/src/data/firstLegParties.ts index 3d6755f..46ded97 100644 --- a/src/data/firstLegParties.ts +++ b/src/data/firstLegParties.ts @@ -36,12 +36,3 @@ export function createFirstLegPartySnapshot(party: FirstLegParty, role: FirstLeg address: party.address, } } - -// API 接入前供客户端订单静态流程使用,不代表已确认的往来单位类型或数据范围契约。 -export const DEMO_FIRST_LEG_PARTIES: readonly FirstLegParty[] = [ - { id: 'CP001', code: 'CN-SHIP-001', name: '示例贸易有限公司', roles: ['SHIPPER'], contactName: '王经理', phone: '138****1201', email: 'shipping@example.com', countryRegion: '中国', province: '浙江省', city: '杭州市', postalCode: '310000', address: '滨江区演示产业园 A 座', status: 'ACTIVE' }, - { id: 'CP002', code: 'CN-SHIP-002', name: '华南演示供应链有限公司', roles: ['SHIPPER'], contactName: '陈主管', phone: '139****8820', email: 'ops@example.cn', countryRegion: '中国', province: '广东省', city: '深圳市', postalCode: '518000', address: '宝安区演示供应链园 2 号楼', status: 'ACTIVE' }, - { id: 'CP003', code: 'US-CONS-001', name: 'DEMO GLOBAL LLC', roles: ['CONSIGNEE'], contactName: 'Alex Morgan', phone: '+1 *** *** 2108', email: 'receiving@example.us', countryRegion: '美国', province: 'California', city: 'Los Angeles', postalCode: '90001', address: '100 Demo Logistics Ave', status: 'ACTIVE' }, - { id: 'CP004', code: 'DE-CONS-001', name: 'DEMO EUROPE GMBH', roles: ['CONSIGNEE'], contactName: 'Lena Fischer', phone: '+49 *** *** 4810', email: 'warehouse@example.de', countryRegion: '德国', province: 'Hamburg', city: 'Hamburg', postalCode: '20095', address: '8 Demo Hafenstrasse', status: 'ACTIVE' }, - { id: 'CP005', code: 'US-CONS-OLD', name: '停用演示收货单位', roles: ['CONSIGNEE'], contactName: 'Demo Contact', phone: '', email: '', countryRegion: '美国', province: '', city: '', postalCode: '', address: '', status: 'INACTIVE' }, -] diff --git a/src/data/firstLegPartySource.ts b/src/data/firstLegPartySource.ts index 6496e2f..f6d6182 100644 --- a/src/data/firstLegPartySource.ts +++ b/src/data/firstLegPartySource.ts @@ -41,6 +41,7 @@ export const firstLegPartySource: FirstLegPartySource = { return parties.find((party) => party.id === id && isAvailableForRole(party, role)) }, async load() { - parties.splice(0, parties.length, ...(await getMerchantPartnerCandidates()).map(mapPartner)) + parties.splice(0, parties.length) + parties.push(...(await getMerchantPartnerCandidates()).map(mapPartner)) }, } diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue index f9a33ea..11bac2a 100644 --- a/src/layouts/AppLayout.vue +++ b/src/layouts/AppLayout.vue @@ -8,7 +8,7 @@ import { Menu, X, } from '@lucide/vue' -import { PRODUCT_NAME } from '@chongchong/shared' +import baiyueLogoDark from '@/assets/brand/baiyue-logo-dark.png' import ClientSidebarMenu from '@/components/ClientSidebarMenu.vue' import { useAuthStore } from '@/stores/auth' @@ -106,8 +106,7 @@ async function handleLogout() { :aria-hidden="mobileMenuOpen ? 'true' : undefined" > - CC - {{ PRODUCT_NAME }}客户工作台 +

diff --git a/src/router/index.ts b/src/router/index.ts index ff0866a..f5e3d2e 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -28,7 +28,7 @@ const router = createRouter({ }) router.beforeEach(async (to) => { - document.title = to.meta.title ? `${to.meta.title} - 虫虫出海客户工作台` : '虫虫出海客户工作台' + document.title = to.meta.title ? `${to.meta.title} - 柏悦物流客户工作台` : '柏悦物流客户工作台' const auth = useAuthStore() if (!auth.sessionRestored) { try { diff --git a/src/stores/firstLegOrders.ts b/src/stores/firstLegOrders.ts index 11b5a3a..08461ed 100644 --- a/src/stores/firstLegOrders.ts +++ b/src/stores/firstLegOrders.ts @@ -138,8 +138,8 @@ function timeline(detail: MerchantFirstLegOrderDetail): FirstLegOrderTimelineIte id: String(item.id), event: item.toStatus === 'SUBMITTED' || item.toStatus === 'REJECTED' ? 'SUBMITTED' : item.toStatus === 'CANCELLED' ? 'CANCELLED' : item.toStatus === 'COMPLETED' ? 'COMPLETED' : item.toStatus === 'ACCEPTED' || item.toStatus === 'APPROVED' ? 'ACCEPTED' : 'IN_TRANSIT', title: item.toStatus === 'REJECTED' ? '平台要求补充订单信息' : item.action || `状态更新为 ${item.toStatus}`, - description: item.reason || '订单状态已更新。', - operatorName: item.operatorName || '系统', + description: item.reason ?? '', + operatorName: item.operatorName ?? '', occurredAt: item.occurredAt, })) } @@ -155,7 +155,7 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar receivingWarehouseSnapshot: orderWarehouseSnapshot(order, warehouse), expectedDepartureDate: order.expectedShipDate ?? '', etd: '', eta: '', shipperPartyId: shipper?.id ?? '', shipperPartySnapshot: shipper, shipper: shipper?.name ?? '', consigneePartyId: consignee?.id ?? '', consigneePartySnapshot: consignee, consignee: consignee?.name ?? '', - expressCompanyName: order.expressCompany ?? '', trackingNumber: order.expressTrackingNo ?? '', priority: 'NORMAL', customerRemark: order.customerRemark ?? '', operatorName: '待平台分配', + expressCompanyName: order.expressCompany ?? '', trackingNumber: order.expressTrackingNo ?? '', priority: 'NORMAL', customerRemark: order.customerRemark ?? '', operatorName: '', status: clientStatus(order.status), version: order.version ?? 0, items: (detail?.cargoes ?? []).map((item) => ({ id: String(item.id), sku: item.skuNo ?? '', cargoNameCn: item.cargoName, cargoNameEn: item.cargoNameEn ?? '', @@ -174,9 +174,9 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar function mapWarehouse(item: MerchantWarehouse): PlatformReceivingWarehouse { return { - id: String(item.id), code: item.warehouseCode, name: item.warehouseName, province: item.countryCode, - city: item.countryCode, address: '详情地址待选择后加载', contactName: item.contactName ?? '', contactPhone: item.contactPhone ?? '', - businessHours: item.timezone ?? '以仓库通知为准', status: item.status, remark: item.remark ?? '', updatedAt: item.updatedAt ?? '', + id: String(item.id), code: item.warehouseCode, name: item.warehouseName, province: '', + city: '', address: '', contactName: item.contactName ?? '', contactPhone: item.contactPhone ?? '', + businessHours: '', status: item.status, remark: item.remark ?? '', updatedAt: item.updatedAt ?? '', } } diff --git a/src/stores/tenantAdministration.ts b/src/stores/tenantAdministration.ts index 753577b..fed76ec 100644 --- a/src/stores/tenantAdministration.ts +++ b/src/stores/tenantAdministration.ts @@ -27,17 +27,10 @@ export type TenantRecordStatus = 'ACTIVE' | 'INACTIVE' export interface TenantCompanyProfile { companyName: string creditCode: string - companyType: string - registeredAddress: string - establishedDate: string - registeredCapital: string legalRepresentative: string - legalRepresentativePhone: string contactName: string contactPhone: string contactEmail: string - contactWechat: string - businessAddress: string auditStatus: MerchantTenantStatus } @@ -160,56 +153,32 @@ export const FRONTEND_TO_MERCHANT_PERMISSION_CODES: Readonly { - const company = ref({ - companyName: '示例贸易有限公司', - creditCode: '91330100MA2XXXXXXX', - companyType: '有限责任公司', - registeredAddress: '浙江省杭州市滨江区', - establishedDate: '2018-06-15', - registeredCapital: '500 万人民币', - legalRepresentative: '陈明', - legalRepresentativePhone: '139****8866', - contactName: '张伟', - contactPhone: '138****6789', - contactEmail: 'business@example.com', - contactWechat: 'cc_business', - businessAddress: '浙江省杭州市滨江区演示大道 88 号', - auditStatus: 'PROFILE_REQUIRED', - }) - - const qualifications = ref([ - { id: 'QUAL-001', type: '营业执照', fileName: '示例贸易有限公司营业执照.pdf', status: 'VERIFIED', expiresAt: '2028-06-15', updatedAt: '2026-07-27 14:20', documentUrl: '' }, - { id: 'QUAL-002', type: '法人身份证', fileName: '法人身份证明.pdf', status: 'VERIFIED', expiresAt: '2030-01-01', updatedAt: '2026-07-27 14:22', documentUrl: '' }, - { id: 'QUAL-003', type: '货代资质证书', fileName: '货代资质证书.pdf', status: 'PENDING', expiresAt: '2027-03-01', updatedAt: '2026-07-28 10:08', documentUrl: '' }, - ]) - - const members = ref(structuredClone(initialMembers)) - const roles = ref(structuredClone(initialRoles)) - const rolesLoadedFromApi = ref(false) - const membersLoadedFromApi = ref(false) + const company = ref({ ...emptyCompany }) + const qualifications = ref([]) + const members = ref([]) + const roles = ref([]) const permissionResources = ref([]) const activeMemberCount = computed(() => members.value.filter((member) => member.status === 'ACTIVE').length) async function loadCompanyContext() { + company.value = { ...emptyCompany } + qualifications.value = [] const [profile, qualificationRecords] = await Promise.all([ getTenantProfile(), getTenantQualifications(), ]) company.value = { - ...company.value, companyName: profile.tenantName, creditCode: profile.unifiedSocialCreditCode ?? '', legalRepresentative: profile.legalName, @@ -223,8 +192,8 @@ export const useTenantAdministrationStore = defineStore('tenant-administration', type: item.qualificationType === 'BUSINESS_LICENSE' ? '营业执照' : item.qualificationType, fileName: item.documentUrl.split('/').pop() || '营业执照', status: item.status === 'APPROVED' ? 'VERIFIED' : item.status, - expiresAt: '长期', - updatedAt: '以服务端记录为准', + expiresAt: '-', + updatedAt: '-', documentUrl: item.documentUrl, })) } @@ -264,15 +233,14 @@ export const useTenantAdministrationStore = defineStore('tenant-administration', } async function loadRoles() { - rolesLoadedFromApi.value = true roles.value = [] + permissionResources.value = [] const [roleRecords, resources] = await Promise.all([getMerchantRoles(), getMerchantPermissionResources()]) permissionResources.value = resources.filter((item) => item.status === 'ACTIVE') roles.value = roleRecords.map(mapMerchantRole) } async function loadMembers() { - membersLoadedFromApi.value = true members.value = [] members.value = (await getMerchantMembers()).map(mapMerchantMember) } @@ -286,7 +254,6 @@ export const useTenantAdministrationStore = defineStore('tenant-administration', contactEmail: payload.contactEmail.trim(), }) company.value = { - ...company.value, companyName: updated.tenantName, creditCode: updated.unifiedSocialCreditCode ?? '', legalRepresentative: updated.legalName, @@ -297,22 +264,6 @@ export const useTenantAdministrationStore = defineStore('tenant-administration', } } - function setCompanyAuditStatusForPreview(status: TenantCompanyProfile['auditStatus']) { - company.value.auditStatus = status - } - - function upsertQualification(payload: Omit) { - const existing = qualifications.value.find((item) => item.type === payload.type) - const next = { - ...payload, - status: 'PENDING' as const, - updatedAt: new Date().toLocaleString('zh-CN', { hour12: false }), - } - if (existing) Object.assign(existing, next) - else qualifications.value.unshift({ id: `QUAL-${Date.now()}`, ...next }) - company.value.auditStatus = 'PENDING' - } - async function createMember(payload: { name: string; account: string; password: string; phone: string; email: string; roleIds: string[]; memberNo: string }) { const created = await createMerchantMember({ username: payload.account.trim(), @@ -417,14 +368,10 @@ export const useTenantAdministrationStore = defineStore('tenant-administration', members, roles, activeMemberCount, - rolesLoadedFromApi, - membersLoadedFromApi, loadCompanyContext, loadRoles, loadMembers, updateCompany, - setCompanyAuditStatusForPreview, - upsertQualification, createMember, updateMember, toggleMemberStatus, diff --git a/src/styles/index.css b/src/styles/index.css index e8cab7e..3093944 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -7,11 +7,8 @@ a { color: inherit; } .client-shell { min-height: 100vh; overflow-x: hidden; } .top-header { position: fixed; inset: 0 0 auto 0; z-index: 20; display: flex; width: 100%; max-width: 100vw; height: 68px; align-items: center; padding: 0 28px; border-bottom: 1px solid var(--border); background: #fff; } -.client-brand { display: flex; width: 232px; min-width: 0; align-items: center; gap: 11px; color: var(--navy); text-decoration: none; } -.client-brand-mark, .auth-brand span { display: grid; width: 38px; height: 38px; place-items: center; border-radius: 8px; background: var(--primary); color: #fff; font-size: 13px; font-weight: 800; } -.client-brand > span:last-child { display: flex; flex-direction: column; } -.client-brand strong { font-size: 15px; } -.client-brand small { margin-top: 1px; color: var(--muted); font-size: 10px; } +.client-brand { display: flex; width: 232px; min-width: 0; align-items: center; color: var(--navy); text-decoration: none; } +.client-brand-logo { display: block; width: 150px; height: 54px; object-fit: contain; object-position: left center; } .tenant-name { display: flex; flex: 1; align-items: center; gap: 8px; color: #475467; font-size: 13px; } .client-user { display: flex; align-items: center; gap: 10px; } .client-avatar { display: grid; width: 34px; height: 34px; place-items: center; border-radius: 50%; background: #e7f3f1; color: var(--primary); font-weight: 750; } @@ -57,7 +54,8 @@ a { color: inherit; } .auth-page { min-height: 100vh; background: #eef3f3; } .auth-header { display: flex; height: 72px; align-items: center; justify-content: space-between; padding: 0 clamp(24px, 6vw, 90px); border-bottom: 1px solid var(--border); background: #fff; color: var(--muted); font-size: 13px; } -.auth-brand { display: flex; align-items: center; gap: 10px; color: var(--navy); text-decoration: none; } +.auth-brand { display: flex; min-width: 0; align-items: center; color: var(--navy); text-decoration: none; } +.auth-brand-logo { display: block; width: 158px; height: 56px; object-fit: contain; object-position: left center; } .auth-header a { color: var(--primary); text-decoration: none; } .auth-main { display: grid; min-height: calc(100vh - 72px); grid-template-columns: 1fr 440px; align-items: center; gap: clamp(60px, 10vw, 150px); width: min(1180px, calc(100% - 48px)); margin: 0 auto; padding: 50px 0; } .auth-kicker, .section-label { color: var(--primary); font-size: 11px; font-weight: 750; letter-spacing: .13em; } @@ -74,8 +72,6 @@ a { color: inherit; } .auth-form-options button:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; } .auth-submit { width: 100%; } .auth-submit span { display: flex; align-items: center; gap: 7px; } -.demo-tip { display: flex; flex-direction: column; gap: 3px; margin-top: 18px; padding: 10px 12px; background: #f2f7f6; color: var(--muted); font-size: 12px; line-height: 1.55; } -.demo-tip strong { color: #40534f; } .register-page { min-height: 100vh; background: #f5f7f8; } .register-header { display: flex; height: 68px; align-items: center; justify-content: space-between; padding: 0 clamp(20px, 5vw, 72px); border-bottom: 1px solid var(--border); background: #fff; } @@ -139,12 +135,6 @@ a { color: inherit; } .profile-summary dt { color: var(--muted); } .profile-summary dd { margin: 0; font-weight: 600; } .module-stack { display: flex; flex-direction: column; gap: 14px; } -.module-actions { display: flex; justify-content: flex-end; gap: 10px; } -.module-actions .el-input { width: 280px; } -.module-empty { display: flex; min-height: 430px; align-items: center; justify-content: center; flex-direction: column; text-align: center; } -.module-empty-icon { display: grid; width: 56px; height: 56px; place-items: center; margin-bottom: 17px; background: #eaf2f1; color: var(--primary); } -.module-empty h2 { margin: 0 0 7px; font-size: 20px; } -.module-empty p { max-width: 540px; margin: 0 0 18px; color: var(--muted); } .el-button--primary { --el-button-bg-color: var(--primary); --el-button-border-color: var(--primary); --el-button-hover-bg-color: var(--primary-dark); --el-button-hover-border-color: var(--primary-dark); } @@ -163,6 +153,7 @@ a { color: inherit; } .client-sidebar-header button { display: grid; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--navy); place-items: center; } .client-main { width: 100%; max-width: 100%; margin-left: 0; padding: 88px 14px 30px; } .client-brand { width: auto; } + .client-brand-logo { width: 132px; height: 50px; } .tenant-name, .client-user-copy { display: none; } .client-user { margin-left: auto; } .client-page-heading > button { display: grid; width: 44px; height: 44px; place-items: center; } diff --git a/src/utils/firstLegOrder.test.mjs b/src/utils/firstLegOrder.test.mjs index 04aa4b9..590d251 100644 --- a/src/utils/firstLegOrder.test.mjs +++ b/src/utils/firstLegOrder.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { createFirstLegPartySnapshot, DEMO_FIRST_LEG_PARTIES } from '../data/firstLegParties.ts' +import { createFirstLegPartySnapshot } from '../data/firstLegParties.ts' import { canClientCancelFirstLegOrder, canClientEditFirstLegOrder, @@ -11,6 +11,17 @@ import { validateFirstLegOrderDraft, } from './firstLegOrder.ts' +const shipperParty = { + id: 'CP001', code: 'SHIPPER-001', name: '测试发货企业', roles: ['SHIPPER'], contactName: '测试联系人', + phone: '13800000000', email: 'shipper@example.test', countryRegion: '中国', province: '浙江省', city: '宁波市', + postalCode: '315000', address: '测试发货地址', status: 'ACTIVE', +} +const consigneeParty = { + id: 'CP002', code: 'CONSIGNEE-001', name: 'TEST CONSIGNEE LLC', roles: ['CONSIGNEE'], contactName: 'Test Receiver', + phone: '+1 555 0100', email: 'receiver@example.test', countryRegion: '美国', province: 'California', city: 'Los Angeles', + postalCode: '90001', address: '100 Test Logistics Ave', status: 'ACTIVE', +} + function validDraft() { return { referenceNo: 'REF-001', @@ -21,11 +32,11 @@ function validDraft() { receivingWarehouseId: 'WH005', expectedDepartureDate: '2026-08-08', shipperPartyId: 'CP001', - shipperPartySnapshot: createFirstLegPartySnapshot(DEMO_FIRST_LEG_PARTIES[0], 'SHIPPER'), - shipper: '示例贸易有限公司', + shipperPartySnapshot: createFirstLegPartySnapshot(shipperParty, 'SHIPPER'), + shipper: shipperParty.name, consigneePartyId: 'CP003', - consigneePartySnapshot: createFirstLegPartySnapshot(DEMO_FIRST_LEG_PARTIES[2], 'CONSIGNEE'), - consignee: 'DEMO GLOBAL LLC', + consigneePartySnapshot: createFirstLegPartySnapshot(consigneeParty, 'CONSIGNEE'), + consignee: consigneeParty.name, priority: 'NORMAL', customerRemark: '', tradeTerm: 'FOB', diff --git a/src/views/AuthViews.test.mjs b/src/views/AuthViews.test.mjs index 8516307..756bff2 100644 --- a/src/views/AuthViews.test.mjs +++ b/src/views/AuthViews.test.mjs @@ -13,9 +13,8 @@ const mainSource = readFileSync(new URL('../main.ts', import.meta.url), 'utf8') test('matches the backend username login contract', () => { assert.match(loginSource, /label="用户名"/) assert.match(loginSource, /\^\[A-Za-z0-9_\]/) - assert.match(loginSource, /const isDevelopment = import\.meta\.env\.DEV/) - assert.match(loginSource, /v-if="developmentHint" class="demo-tip"/) - assert.match(loginSource, /merchant_admin/) + assert.match(loginSource, /typeof route\.query\.account === 'string'/) + assert.doesNotMatch(loginSource, /developmentHint|demo-tip|merchant_admin|联调账号|本地后端/) assert.match(loginSource, /form\.remember/) assert.match(loginSource, /忘记密码/) }) diff --git a/src/views/CompanyProfileView.vue b/src/views/CompanyProfileView.vue index 4646bfc..00b0248 100644 --- a/src/views/CompanyProfileView.vue +++ b/src/views/CompanyProfileView.vue @@ -32,21 +32,25 @@ const qualificationFileError = ref('') const qualificationSubmitting = ref(false) const profileSubmitting = ref(false) const loading = ref(false) +const loadError = ref('') const selectedFile = ref(null) const draft = reactive({ ...store.company }) const qualificationDraft = reactive({ type: '营业执照', fileName: '', certificateNo: '' }) -onMounted(async () => { +async function loadCompanyContext() { loading.value = true + loadError.value = '' try { await store.loadCompanyContext() Object.assign(draft, store.company) } catch (error) { - ElMessage.error(error instanceof Error ? error.message : '企业资料加载失败') + loadError.value = error instanceof Error ? error.message : '企业资料加载失败' } finally { loading.value = false } -}) +} + +onMounted(() => void loadCompanyContext()) function startEdit() { Object.assign(draft, store.company) @@ -176,11 +180,16 @@ function qualificationStatus(status: string) {