From a6f7ad12dad72d8026608e51931c685aa346d598 Mon Sep 17 00:00:00 2001 From: zhouxiaofeng <2946471396@qq.com> Date: Tue, 26 May 2026 10:10:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 7 + .gitignore | 25 + index.html | 12 + package.json | 31 + pnpm-lock.yaml | 1569 +++++++++++ .../templates/purchase-contract-template.docx | Bin 0 -> 10390 bytes .../templates/sales-contract-template.docx | Bin 0 -> 10324 bytes scripts/generate-contract-templates.mjs | 213 ++ src/App.vue | 3 + src/api/manifest.js | 73 + src/api/partner.js | 45 + src/api/seal.js | 185 ++ src/layouts/ContractManageLayout.vue | 194 ++ src/main.js | 18 + src/router/index.js | 67 + src/stores/useCounter.js | 17 + src/styles/global.css | 12 + src/utils/request.js | 72 + src/views/Home.vue | 311 +++ src/views/bak/preSign.vue | 1844 +++++++++++++ src/views/bak/preSignModal.vue | 496 ++++ src/views/bak/standardSign.vue | 1862 +++++++++++++ src/views/bak/standardSignModal.vue | 577 ++++ src/views/bak/trusteeshipSign.vue | 769 ++++++ src/views/bak/trusteeshipSignModal.vue | 449 +++ src/views/contract/launch/api.js | 309 +++ .../ContractPartyPlaceholderModal.vue | 1761 ++++++++++++ .../ContractTemplateFillDemoModal.vue | 1297 +++++++++ .../launch/components/mixedSignModal.vue | 18 + src/views/contract/launch/index.vue | 577 ++++ .../ContractTemplateManageModal.vue | 1165 ++++++++ src/views/contract/manifest/index.vue | 422 +++ .../partner/components/PartnerModal.vue | 628 +++++ src/views/contract/partner/index.vue | 579 ++++ src/views/seal/externalSign.vue | 42 + src/views/seal/mixedSignModal copy.vue | 1709 ++++++++++++ src/views/seal/mixedSignModal.vue | 2428 +++++++++++++++++ src/views/seal/preSign.vue | 1844 +++++++++++++ src/views/seal/preSignModal.vue | 554 ++++ src/views/seal/standardSign.vue | 1862 +++++++++++++ src/views/seal/standardSignModal.vue | 1897 +++++++++++++ src/views/seal/trusteeshipSign.vue | 769 ++++++ src/views/seal/trusteeshipSignModal.vue | 463 ++++ task.txt | 220 ++ vite.config.js | 40 + 45 files changed, 27435 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 .gitignore create mode 100644 index.html create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 public/assets/templates/purchase-contract-template.docx create mode 100644 public/assets/templates/sales-contract-template.docx create mode 100644 scripts/generate-contract-templates.mjs create mode 100644 src/App.vue create mode 100644 src/api/manifest.js create mode 100644 src/api/partner.js create mode 100644 src/api/seal.js create mode 100644 src/layouts/ContractManageLayout.vue create mode 100644 src/main.js create mode 100644 src/router/index.js create mode 100644 src/stores/useCounter.js create mode 100644 src/styles/global.css create mode 100644 src/utils/request.js create mode 100644 src/views/Home.vue create mode 100644 src/views/bak/preSign.vue create mode 100644 src/views/bak/preSignModal.vue create mode 100644 src/views/bak/standardSign.vue create mode 100644 src/views/bak/standardSignModal.vue create mode 100644 src/views/bak/trusteeshipSign.vue create mode 100644 src/views/bak/trusteeshipSignModal.vue create mode 100644 src/views/contract/launch/api.js create mode 100644 src/views/contract/launch/components/ContractPartyPlaceholderModal.vue create mode 100644 src/views/contract/launch/components/ContractTemplateFillDemoModal.vue create mode 100644 src/views/contract/launch/components/mixedSignModal.vue create mode 100644 src/views/contract/launch/index.vue create mode 100644 src/views/contract/manifest/components/ContractTemplateManageModal.vue create mode 100644 src/views/contract/manifest/index.vue create mode 100644 src/views/contract/partner/components/PartnerModal.vue create mode 100644 src/views/contract/partner/index.vue create mode 100644 src/views/seal/externalSign.vue create mode 100644 src/views/seal/mixedSignModal copy.vue create mode 100644 src/views/seal/mixedSignModal.vue create mode 100644 src/views/seal/preSign.vue create mode 100644 src/views/seal/preSignModal.vue create mode 100644 src/views/seal/standardSign.vue create mode 100644 src/views/seal/standardSignModal.vue create mode 100644 src/views/seal/trusteeshipSign.vue create mode 100644 src/views/seal/trusteeshipSignModal.vue create mode 100644 task.txt create mode 100644 vite.config.js diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..da5b91c --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(npm install *)" + ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..092808d --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +.DS_Store +node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +**/*.log + +**/dist.zip + +tests/**/coverage/ +tests/e2e/reports +selenium-debug.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.local + +package-lock.json +yarn.lock diff --git a/index.html b/index.html new file mode 100644 index 0000000..f6d9399 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + +
+ + +O0Z>FCNUX4HX*)8nXBeBAfDTlu%W?)NKyqX2-dKbW5$eEYC}@9f4SzchI63%K7uxD}v>eaF;K|8x`X3%Fms-wGhX zxg+48TK+!ze(8LRo(H4<%>GY}avy&;^V}3)w_^_Xf0^Nrlz%nE{rc!uR0!TbqVDqM z|4Wmb9C$n2z@6Va4sln=zbbN{5#LH80t@~r=`KIMugHA@b_?GDuh38U-K2aUes@Lx zp2q_CrLjBnxGUse=W##X-YODC`i~@Ya0BvB^8LRw`P;T*WPfS$my~~0f%zE$Z~?dg MDDXEQ@|%bM4}75?761SM literal 0 HcmV?d00001 diff --git a/public/assets/templates/sales-contract-template.docx b/public/assets/templates/sales-contract-template.docx new file mode 100644 index 0000000000000000000000000000000000000000..8dbb93782d6f981a5ee0435f364e68bdbe40ad06 GIT binary patch literal 10324 zcmc(FbySs2*Z!fqyGug48>FQhDM{&$LrDtK4TqGHE~N#LgVNI7Aq|4G2q^J8=%XOt z^M335{q@dTH|LziT>IWLd(WP|uNhSZ7+7S$bt6K4{rKmXfBwKhK0O>=%-B@_V;7X) zU5s4J?OgwKMEog>ttS@@3k3kYgarUd|L$n!_{7cL+yThyX>Z4R4Sfabw`pU?d~PJY zY1peg$_-+83le+X;R}#9yu#c@u+~VguaIBSWEKCKvl5e^7Hd9aaZ)042sMBq 8 zOPf<*4L|Sv-Efa$0$4xa)WX0%w|`+Qf}~QrQTwo#Ey`;;2)mgbAINVVtpVM(DQFQa z9F9Jf%dFkkK@QxNLq{vx9nu7i5ujWh@Y)N>dh#5Wi>+iLt{-p)V#Kt%1!P?IN$ z;&)DM*(6#<(@@!E6!-!Z=-G!fOdK?0+!O-&p|k!RFn?~63c_vGm|z8%PI=FTlqE>$ ztVzYm_) 7pav$svsmG>t } z(ntdHFtu^$iYV%5lr=Y=HE~ijM2 FqwfF?3 zgF*!;%uY3wQJGxa5UHy!qFVxDkey1P-$)n%qj9IrFRj~U8-lS+FrP^?;cor-n#Lfj zUPk6|Pbs<~e&HJ+R|u;1%O(6ql=7h-p3)4(jKHx?K!-~+8na`ZtpV4!hZYQ>wUjWy zwy&OfId|=wHpNK_c1)HM#=jANdbZ+Ijm0nng~?AC%`I_Ui-xyBR0f}e|HKOcv(iS) zhNIYnn#Y-Sfk?d;>;5p2x(bbYHCKL!Q(*Y24T7pVPgmRs&70`BMLcTLw?%?PGRx2o z93tnB6`pqYplJCM#*9%@P|%Yv%GUV^(rCaKhiUfJ1!Es?SY%C8N4R|aI8ObBFH^kv zyOT5=w`s6SdYH8Pct%BJqbpIaG?8oY7< (0u$h+fR zBd7L^_Zy8*k}r9?IvLA6`jXIGo0^I|j<>Qq!n7)e4d5xUL$L{Duq5LHV5syonyUp5 zP0YsfF7oYCWEl4pCN||YLbzGH2~^^0&sl(qk;HAd3{Rl&6z`FWE~^I ~&4?0uqwcVQHPBiDmj|7JUEYoDa?g*oi*`L{bG7bnnaB{8s1q3)k{?!umm<*_oE zJI>W*$GB^h`01oSKq)YM_2T{fZlQV#)V8atjkk~ck7*wQP${T)qF2||4TQq|LxRdH z30*dXE^m1WfAFcW^@X5`h~G#wVOtt1eld3xo2dcy^3tQyYQIl +xc{{{7 zO#R-f&ht9v6n#IqeFVepl%hbrPkP_y8->t?l6x#_#$95;$z2l3Q@VO8O|LFwrW^gc zSXo|-YG8hzI9GCAuIQP`KhyZU(g_kdX{`SC!Pl(Wr(>MJhEyT0if`AVO1&9upjVT^ zTc4b*8%tnNAsTh=6gMyx8CmIHy{?eaYi+w#c(%FI6&<>WaAa(O-(+H_JgCV_p#>)D zDXRD&><1(K`qiEo$?N9Dt-uFs_q!;H_yaCV!IzO>AB@My-0l=D7ZWblg9W6*bL14E zWSsR+1lRl4?%SGn2JdxNDsl4dyrr*96>?D4Q5dwDN1gDp)O2TUvRj>FU>VfaNOV8L zI2wocsbB7f+TEe2`cyBEvOYC6(WC$IU6AH<;=$*Ji~ZzTp^vk1& {8_T5&9iM|~ll_sN%wVSW%G-WkKcL(qmqh&$8DRLuw!N5VV+Pmr z0In1#_-!3LC)EdG{6UADW0+4P$k?_w+MmDZ&~x8x^w`A~7`V)0$#-GaOAwKBR{`T!CJ8=C0S9{@Npbm05Pe3nsM%s+2-FM&ub}JlW9@LaV{oE8O@onbYV6=ijHp zGm{Hn2E)_YJ6^B~h;F acMCPfv=kr_Sr<6U=4)ixrM6)Iw$ z)hcV8)8L@;h9ngMEE0WC+cuFosbYA zN+j a5)0a%6Am)K7TlT^2kKCt (^_%Uv1jeYTBc(KQjdu}nVYnqHWq>W%0QR&sH<742(MNVve|9+Xs mS^5a>xwF)kLni@;J`{>CcKcx0&DBM3R*lt09U 6&Ys!eBmEPP$-YZ$OMk%c_3%FvYb3~efMjy2E{;xjbLLm9 zrJwj9Idc$X>0D=hf4V(!bTPkPI0XsA4y}~9Aw~sD&2Yf<=-O1fNNp}%&i>?iEPh7a zm$0eh^%SpWtk>sRm#$6^vqzI_z$G YLU6}XDn0_^73P6s< z*#V!cN{u{+ qh-mNGg90fBGWm4E0* z4nn2 7fWLVCiDdF1KHC7nH!RNDzsW3a8WJw+rJv1pt*u zUvLe~5l<~ObQI&_$ (u z0@holhE$K>(4L+Hw=wA;QOV {td`xU>I4{n#p7>1Gb zMa6@nQVN+B@~sNC)kV~zQSz-76afLsH=*B$gEKNt8&$?**j87gT1B;l-r^o7LO#Hl z$1A4|r5)aU%Q9N3SG~q{qej}jsW)n#Y~_B*q5=zNq74@a z|2bGdN z^2jAU%u`Fby(Bz~FXREhTTvc?#@y`Czry^H8K;;j1ZZnE;^ zNctI~l5oz`$C~!x(ruIpdsvZV45=geid751@SymotK>CRY=!h0bvrDFD)1Sc eTSH7238O+ zhZ5(c1HQ_desQDlgo^-O=kxW+#~5VKb7}Zqo4Js4HNGv3pC^!8%Elw(GLrW^ K`BZc9hwSNx XWB8D5sHK0r=huh0U?FVyvqnNwIJZu1S%OP;WQ^~ zcieppOx(>;9r1-+kaf2*3aoO|T&C>8-ep%1|CA7pmnu8^<8D~#c}zG(b)I#Xgq(`5 zY$4xTK2ngg4VBZwf^Y>T9FT6=lPI+QRLVjoemHYYn|GQ> M#Ck>Bdm<3#&1V+^1B-h>kbUlXZwg{5A<+?KdK1@Znn8|O(CcY z)TPTo&1#*06dNA>mc%$eHFtJrbB+?C*FZ_9D2&a!;4UK4t@)^UEQ z?dGpxaD^oJ45Rc@P0_oqtu0G8SN)*!F0V|KZNraCMt__6L$&LRJcyYa5CH%jh?(^z z9UXuWy30t@%gNl;;Mx=G9`!0i2(R-b2JNv1Co#mjwGS(Zq>C_*y%UK|E6g2{&qcPs zQo*IG=e#u+;S$2xlj&LAnxB})mf+qjJhSE);BrE)a~|jR_iH3ESk Xbk1Ib zTo){lnzubh)5{jC)7U{0_#GI=u=teOi4Od#k%sYp;U2M*5f{h!O;ZKk_q&t=)V^bw z9tb)nSJj`G16u(!yx%ZCe%W6Mh>eno59{(V8JCjqPIXfdDHO=JAIZU}-k1ndp5bvv zf0pfm;f;bpoGW!NbgbT4-*X64I8lU%ce65^4D&$aQ)s;mLUhg$T@HOKJeem+Lwv^M zP(7Nh=YG=jq4%+v%6yl(7kFvD(0|)h$7_~40b +TTN1KF^# Mro{t0YWSir1=2 z3jnpN!peH0A+t-=aF#&>%+GVy(3yX{2Gd8xRU_cTiA}f+2=K~RWl|BomhV)Tk#AY$ z9L={P1qU-tYXkbWG$$?L^x=Vv=m!Wr6;tJBMq}|8=PMhPUCSlAcLtCV-W@*xSy!(h zo8q6m?K*rqKqCClx^f)Uue@>{Kxq%bZt75a(n mZEaVG6gav*H zrmuhDmZA-45yKP}4?OU)^b+5~v{NqGs2l2It6N1E)->rB*C=M}hTHj&1WdB{%wB`u zuutAL&oRoWLaltI0>gw#{%DaKr2!~Zn&xf$1^RO`+! y6bY%->2YlUE4J1f+|3GYZQlXbDzw8k(uMeD+9}723svZ$ zM4mC{F2E5RO~3Ti0!v{2Lq+lp*;BrC@o ST76MW zOc~DVn{D4>`$nKs)!kKc*4u7pYjFT?ll5Q+mH%6*D%Kn3mQwl)N2QqTjQrlVh1_6* zWC8pSSaS*H;`r0XR-uD6+X#+CU5Hj6N-6iP;%XZ?b5>d4<^+O3{)wr%?;atk{Ug{J?QY5Fr~9=gI_&Dy0M=jc~Uy)m)@L{f@(V z#T}%f#jkhTe}kDZ8$rrytO;r+0hS^gTy(z2?JI|Yf8lI9Pt0yGneZ7YWotAiaw2g zKn@DU aMR=FA`PzPZ6@$pH1A0>Yl)Mx=`21I zk$uJ*ULi%g>JnxcR!kSzPmy=kocq$X0Vt~nyn9zJ@Sc?0y|BC2Dt4WxI_ebH*5=UJ z=8}_RHeI*rS^7q-5KIi1LGw9_Lgkj+m40F#0sZI0%6hBCVDlI_C)j#3-8gC9sp+Mo z)$c9(og4t-N=C${Icvvqv+TnyM%JtsqSUs~n2oxlo1%V&XS`puD8S~WlqY$qmTE|$ zdwHqnboy8-MLUR*xhqg)xTBk2)k;Yf;|ht$Q+H--NB6RiL%*wN8fX3JfADu$z3rEG z&be+|{lD#&O4&U O$f!~t%6szY-a?k)eUG{TL?d6+Sg(Dv6hS`=$I}MLp zvt+EjeqE>P<0O6<+4Rvvh$2Ik1A9}*7$bhi`I|_;S1@k5L1o+~7x$dR6wpr^h#~jD zHg7a}>TEp98E+dp*}Hwq*h=v}z2pz`0mQCN<@+bfz(*!C_YZSWy_^X3cT#M9l4V-l zL%vcN 8bh%R3Mx{!Rz5Ka(r6@nf0%pKQWD`7>>ts{>b0iYTG{@4i_D{UnGB& z+t9IQ9S~U$_>?i35xOY&e(0-L?ZY`zot1Z@&*~fxd&@eG`h@EiKf~#%iSlkj3zN7= zvGf*iO`q!5I4{eRfuHU0VZI2ldFGPR*%h~ixA5|uWlaSxp-`6>B$662Zk%iSj%yU8 z c#Io}8kWTafmF&2y?FDid1oyc}{xPHg&B0~h)J0SM#gd~}N?D@pe z{`y??mp#YkU6v^c;TQFt`Lz>tH26kq=`(k}dd{Nc1hjIWqvj01Gg7COOUYCYe7JS* zQ)0^Ghqh5U?noM*WG3AppQLASNjg}pCp@11KfrT=!EUnHV+?Y(PKEfwBBHf;k0ew- ze`$pod334?v!3yqvNl!i*%x^yJCK%8{o#p3-K?`B6-V(gFLU)dx@kyM9{mu>nVlJo ze~UdT9+GNS3w3PCv0dqNgHpssg+QND*_nK~E8WLwba++3Y`RxZtY6ScS0sMG%I8kH zTvjG}mT_hMO_lP 4V}0e4?m%< z!A8o34*|Hb&*(wx^R(*A-j6k{p$ Z(_|CXW4He^O z?K>lkl8w#P6^=6uim#5zM2$*GKiog4xQJX&IJe{&q&ue}8&**a-@izs3g35J+F#7K zky%^E!H5IkVyT)69(=&){AMF2{AFlh38!Ahsb^uyY&Aca2r8Ms)#ASNCZ2oEN2(BJ zl1QLovC?2>M==ffy**76q1#YUr{kz$=#y7TNBF5pS8rbL*qdCk=id*A^@sXDhnm}# z|8IwyCp(4{WDwVsg!wB^a{y|ZnA-iMF*AqfuW3w#eQl~arn +%I=1^4$N0O&d? z^rEH3F$jtI#&$V+9uM>IYR$*)MBC|07i{$=Q?s5$22q8ozJK}Y$z+#l8 K zhhxa8Up*Ma^Iev?KqM)LaiM)GSt8B`RaVc`*5`XUM?lnPq8Mm1{><562`lqjgl)T~ zaN%C$OXF51 J$h^LGl+PeNQCkW*mP-i%*46d1$cH|+l-6c z>t4F$R0y%2+sQke>H3UuY?*Aw4 zxizK#4WmOr;{yKk k@NRele?1cUbMK86ajJJpDNszaTk8~pz8)M2MNqS;Wx)#H{gFi75D|d9=^Ui?Vu-|6}cj0&G?;H3!gb@F!@?T{54gP;>4asr;Y1dkZK#ux; zla+tl>n>gS8wCKA{=xk8;G38IJF#~Id<%KwEf2Xxqy4L(yWHE2AS1~3`BTs>5qH(N zOX=L8Wgu+8zYsik1>EHiZUhkH-7@u)KWxHX0e7qS8v*mT1^iRX-$maooo~=t__s#? zr$)Jpzn$b>7hg9mgYbWt;g6JmHN@Te=th(j(LbVY=gt3{CfDiqP2+|TzqcIXwvc~S z 8vH2K@MiBx}S@|To + new TableRow({ + children: [ + new TableCell({ + width: { + size: 22, + type: WidthType.PERCENTAGE, + }, + children: [ + new Paragraph({ + children: [ + new TextRun({ + text: label, + bold: true, + }), + ], + }), + ], + }), + new TableCell({ + width: { + size: 78, + type: WidthType.PERCENTAGE, + }, + children: [ + new Paragraph({ + text: value, + }), + ], + }), + ], + }), + ), + borders: { + top: { style: BorderStyle.SINGLE, size: 1, color: 'D9DDE7' }, + bottom: { style: BorderStyle.SINGLE, size: 1, color: 'D9DDE7' }, + left: { style: BorderStyle.SINGLE, size: 1, color: 'D9DDE7' }, + right: { style: BorderStyle.SINGLE, size: 1, color: 'D9DDE7' }, + insideHorizontal: { style: BorderStyle.SINGLE, size: 1, color: 'E5E7EB' }, + insideVertical: { style: BorderStyle.SINGLE, size: 1, color: 'E5E7EB' }, + }, + }) +} + +function sectionTitle(text) { + return new Paragraph({ + text, + heading: HeadingLevel.HEADING_2, + spacing: { + before: 280, + after: 160, + }, + }) +} + +function clause(text) { + return new Paragraph({ + text, + spacing: { + after: 160, + line: 360, + }, + }) +} + +async function writeTemplate(filename, config) { + const doc = new Document({ + sections: [ + { + properties: {}, + footers: { + default: new Footer({ + children: [ + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [ + new TextRun({ + text: `${config.title} - 模板演示文档`, + color: '6B7280', + size: 18, + }), + ], + }), + ], + }), + }, + children: [ + new Paragraph({ + text: config.title, + heading: HeadingLevel.TITLE, + alignment: AlignmentType.CENTER, + spacing: { + after: 240, + }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [ + new TextRun({ + text: '用于演示合同发起模块模板填充与导出', + italics: true, + color: '64748B', + }), + ], + spacing: { + after: 280, + }, + }), + sectionTitle('一、合同基础信息'), + createInfoTable(), + sectionTitle('二、合同正文示例'), + ...config.clauses.map(clause), + sectionTitle('三、补充说明'), + clause('合同标的说明:{contractSubject}'), + clause('业务备注:{businessRemark}'), + clause('模板来源:{templateLabel}'), + new Paragraph({ + spacing: { + before: 360, + after: 180, + }, + children: [ + new TextRun({ + text: '甲方(业务方):__________________', + }), + ], + }), + new Paragraph({ + spacing: { + after: 180, + }, + children: [ + new TextRun({ + text: '乙方(相对方):__________________', + }), + ], + }), + new Paragraph({ + children: [ + new TextRun({ + text: '签署日期:{signDate}', + }), + ], + }), + ], + }, + ], + }) + + const buffer = await Packer.toBuffer(doc) + await writeFile(path.join(outputDir, filename), buffer) +} + +await mkdir(outputDir, { recursive: true }) + +await writeTemplate('purchase-contract-template.docx', { + title: '采购合同模板', + clauses: [ + '甲乙双方经友好协商,就 {contractName} 项下采购合作事宜达成一致,并共同遵守本合同。', + '第一条 合作内容:乙方根据甲方需求提供 {contractSubject},具体交付内容以双方确认的技术资料和补充协议为准。', + '第二条 合同金额:本合同总金额为人民币 {contractAmountDisplay},付款方式采用 {paymentMethod}。', + '第三条 合同期限:本合同自 {effectiveStart} 起生效,至 {effectiveEnd} 止。', + ], +}) + +await writeTemplate('sales-contract-template.docx', { + title: '销售合同模板', + clauses: [ + '为明确双方权利义务,甲乙双方就 {contractName} 相关销售事项签订本合同。', + '第一条 销售范围:甲方向乙方提供 {contractSubject},合同编码为 {contractCode}。', + '第二条 金额与结算:本合同金额合计人民币 {contractAmountDisplay},采用 {paymentMethod} 完成结算。', + '第三条 生效与终止:本合同有效期为 {effectivePeriod},双方应按约履约。', + ], +}) + +console.log(`Generated templates in ${outputDir}`) diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..98240ae --- /dev/null +++ b/src/App.vue @@ -0,0 +1,3 @@ + + + diff --git a/src/api/manifest.js b/src/api/manifest.js new file mode 100644 index 0000000..3abf8e4 --- /dev/null +++ b/src/api/manifest.js @@ -0,0 +1,73 @@ +import request from "@/utils/request"; + +function isSuccessResponse(res) { + return String(res?.code || "") === "0000"; +} + +function getResult(res) { + return res?.result; +} + +export function queryManifestList(data) { + return request({ + url: "/manifest/manage/list", + method: "post", + data, + }); +} + +export function queryPublishedManifestList() { + return request({ + url: "/manifest/manage/published", + method: "get", + }).then((res) => (isSuccessResponse(res) ? getResult(res) || [] : [])); +} + +export function queryManifestOrgOptions() { + return request({ + url: "/manifest/manage/org/options", + method: "get", + }).then((res) => (isSuccessResponse(res) ? getResult(res) || [] : [])); +} + +export function getManifestDetail(templateId) { + return request({ + url: `/manifest/manage/${templateId}`, + method: "get", + }); +} + +export function saveManifest(record, mode = "create") { + return request({ + url: "/manifest/manage", + method: mode === "edit" ? "put" : "post", + data: record, + }); +} + +export function changeManifestStatus(templateId, status) { + return request({ + url: `/manifest/manage/${templateId}/status/${status}`, + method: "put", + }); +} + +export function uploadTemplateFile(formData) { + return request({ + url: "/trans/minio/file/uploadOutie", + method: "post", + data: formData, + headers: { + "Content-Type": "multipart/form-data", + }, + }); +} + +export function downloadTemplateFile(fileName) { + return request({ + url: "/trans/minio/file/download", + method: "get", + params: { fileName }, + responseType: "arraybuffer", + }); +} diff --git a/src/api/partner.js b/src/api/partner.js new file mode 100644 index 0000000..b7613f8 --- /dev/null +++ b/src/api/partner.js @@ -0,0 +1,45 @@ +import request from '@/utils/request' +export function queryPartnerList(params) { + return request({ + url: "/partner/manage/list", + method: "post", + data: params, + }); +} + +export function getPartnerInfo(id) { + return request({ + url: `/partner/manage/${id}`, + method: "get", + }); +} + +export function createPartner(data) { + return request({ + url: "/partner/manage", + method: "post", + data, + }); +} + +export function updatePartner(data) { + return request({ + url: "/partner/manage", + method: "put", + data, + }); +} + +export function deletePartnerByIds(ids) { + return request({ + url: `/partner/manage/${ids.join(",")}`, + method: "delete", + }); +} + +export function mockSyncPartner(id) { + return request({ + url: `/partner/manage/${id}/sync`, + method: "post", + }); +} diff --git a/src/api/seal.js b/src/api/seal.js new file mode 100644 index 0000000..f235130 --- /dev/null +++ b/src/api/seal.js @@ -0,0 +1,185 @@ +import request from '@/utils/request' + +// ======================================== +// Token管理 +// ======================================== +export function refreshToken() { + return request({ + url: '/seal/api/token/getAccessToken', + method: 'post', + }) +} + +// ======================================== +// 身份认证 +// ======================================== +export function getLoginQrCode(notifyUrl) { + return request({ + url: '/seal/api/qrcode/getLoginQrCode', + method: 'post', + data: { notifyUrl }, + }) +} + +// ======================================== +// 签署流程管理 +// ======================================== +export function startContract(formData) { + return request({ + url: '/seal/api/contract/start', + method: 'post', + data: formData, + headers: { 'Content-Type': 'multipart/form-data' }, + }) +} + +export function completeContract(contractId) { + return request({ + url: '/seal/api/contract/complete', + method: 'post', + data: { contractId }, + }) +} + +export function cancelContract(contractId) { + return request({ + url: '/seal/api/contract/cancel', + method: 'post', + data: { contractId }, + }) +} + +// ======================================== +// 标准签章 +// ======================================== +export function getStandardSignQrCode(params) { + return request({ + url: '/seal/api/qrcode/getStandardSignQrCode', + method: 'post', + data: params, + }) +} + +// ======================================== +// 预盖章 +// ======================================== +export function getPreSignQrCode(params) { + return request({ + url: '/seal/api/qrcode/getPreSignQrCode', + method: 'post', + data: params, + }) +} + +// ======================================== +// 托管签章 +// ======================================== +export function getTrusteeshipSealQrCode(notifyUrl) { + return request({ + url: '/seal/api/qrcode/getTrusteeshipSealQrCode', + method: 'post', + data: { notifyUrl }, + }) +} + +export function confirmSign(params) { + return request({ + url: '/seal/api/contract/confirmSign', + method: 'post', + data: params, + }) +} + +// ======================================== +// 时间签章 +// ======================================== +export function getTimestamp(formatPattern = 'yyyy-MM-dd') { + return request({ + url: '/seal/api/seal/getTimestamp', + method: 'post', + data: { formatPattern }, + }) +} + +export function signTimestamp(params) { + return request({ + url: '/seal/api/contract/signTimestamp', + method: 'post', + data: params, + }) +} + +// ======================================== +// 批注签章 +// ======================================== +export function getCommentSeal(params) { + return request({ + url: '/seal/api/seal/getCommentSeal', + method: 'post', + data: params, + }) +} + +export function signCommentSeal(params) { + return request({ + url: '/seal/api/contract/signCommentSeal', + method: 'post', + data: params, + }) +} + +// ======================================== +// 印章信息 +// ======================================== +export function getUserUniqueId(params) { + return request({ + url: '/seal/api/user/getUserUniqueId', + method: 'post', + data: params, + }) +} + +export function getSealBySignerId(params) { + return request({ + url: '/seal/api/seal/getSealBySignerId', + method: 'post', + data: params, + }) +} + +// ======================================== +// 文件信息 +// ======================================== +export function getContractDetail(contractId) { + return request({ + url: '/seal/api/contract/getDetail', + method: 'post', + data: { contractId }, + }) +} + +export function previewContract(contractId) { + return request({ + url: '/seal/api/contract/preview', + method: 'post', + data: { contractId }, + }) +} + +export function downloadContract(contractId) { + return request({ + url: '/seal/api/contract/download', + method: 'post', + data: { contractId }, + }) +} + +// ======================================== +// 回调轮询 +// ======================================== +export function pollCallback(requestId) { + return request({ + url: '/seal/callback/poll/' + requestId, + method: 'get', + }) +} diff --git a/src/layouts/ContractManageLayout.vue b/src/layouts/ContractManageLayout.vue new file mode 100644 index 0000000..bb5ab4b --- /dev/null +++ b/src/layouts/ContractManageLayout.vue @@ -0,0 +1,194 @@ + + + + + + + + diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..5e33a14 --- /dev/null +++ b/src/main.js @@ -0,0 +1,18 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import Antd from 'ant-design-vue' +import VxeUITable from 'vxe-table' +import 'ant-design-vue/dist/reset.css' +import 'vxe-table/lib/style.css' +import App from './App.vue' +import router from './router' +import './styles/global.css' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(Antd) +app.use(VxeUITable) + +app.mount('#app') diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 0000000..4f565e6 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,67 @@ +import { createRouter, createWebHistory } from 'vue-router' + +const routes = [ + { + path: '/', + name: 'Home', + component: () => import('@/views/Home.vue'), + }, + { + path: '/contract-console', + component: () => import('@/layouts/ContractManageLayout.vue'), + redirect: '/contract-console/launch', + children: [ + { + path: 'launch', + name: 'ContractInitiateManage', + component: () => import('@/views/contract/launch/index.vue'), + meta: { + title: '发起合同', + }, + }, + { + path: 'manifest', + name: 'ContractTemplateManage', + component: () => import('@/views/contract/manifest/index.vue'), + meta: { + title: '模板管理', + }, + }, + { + path: 'partner', + name: 'ContractPartnerManage', + component: () => import('@/views/contract/partner/index.vue'), + meta: { + title: '相关方管理', + }, + }, + ], + }, + { + path: '/standardSign', + name: 'StandardSign', + component: () => import('@/views/seal/standardSign.vue'), + }, + { + path: '/preSign', + name: 'PreSign', + component: () => import('@/views/seal/preSign.vue'), + }, + { + path: '/trusteeshipSign', + name: 'TrusteeshipSign', + component: () => import('@/views/seal/trusteeshipSign.vue'), + }, + { + path: '/external-sign/:contractId?', + name: 'ExternalSign', + component: () => import('@/views/seal/externalSign.vue'), + }, +] + +const router = createRouter({ + history: createWebHistory(), + routes, +}) + +export default router diff --git a/src/stores/useCounter.js b/src/stores/useCounter.js new file mode 100644 index 0000000..1dc9d38 --- /dev/null +++ b/src/stores/useCounter.js @@ -0,0 +1,17 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + + function increment() { + count.value++ + } + + function decrement() { + count.value-- + } + + return { count, doubleCount, increment, decrement } +}) diff --git a/src/styles/global.css b/src/styles/global.css new file mode 100644 index 0000000..9cb50fc --- /dev/null +++ b/src/styles/global.css @@ -0,0 +1,12 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, 'Noto Sans', sans-serif; + background: #f0f2f5; + color: rgba(0, 0, 0, 0.88); +} diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..699ceff --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,72 @@ +import axios from 'axios' +import { message, Modal, notification } from 'ant-design-vue' + +const service = axios.create({ + baseURL: import.meta.env.VITE_APP_BASE_API || '/', + timeout: 30000, +}) + +service.interceptors.request.use( + (config) => { + const token = localStorage.getItem('token') + if (token) { + config.headers['Authorization'] = 'Bearer ' + token + } + return config + }, + (error) => Promise.reject(error), +) + +service.interceptors.response.use( + (res) => { + if ( + res.request.responseType === 'blob' || + res.request.responseType === 'arraybuffer' + ) { + return res.data + } + const code = res.data?.code + const normalizedCode = + code === undefined || code === null ? undefined : String(code) + const msg = res.data?.message || res.data?.msg || '系统错误' + + if (normalizedCode === '401') { + Modal.confirm({ + title: '系统提示', + content: '登录状态已过期,请重新登录', + okText: '重新登录', + cancelText: '取消', + onOk: () => { + localStorage.removeItem('token') + location.reload() + }, + }) + return Promise.reject('无效的会话,或者会话已过期。') + } else if (normalizedCode === '500') { + message.error(msg) + return Promise.reject(new Error(msg)) + } else if ( + normalizedCode !== undefined && + normalizedCode !== '200' && + normalizedCode !== '0000' + ) { + notification.error({ message: '提示', description: msg }) + return Promise.reject('error') + } + return Promise.resolve(res.data) + }, + (error) => { + let msg = error.message + if (msg === 'Network Error') { + msg = '后端接口连接异常' + } else if (msg.includes('timeout')) { + msg = '系统接口请求超时' + } else if (msg.includes('Request failed with status code')) { + msg = '系统接口' + msg.substr(msg.length - 3) + '异常' + } + message.error(msg) + return Promise.reject(error) + }, +) + +export default service diff --git a/src/views/Home.vue b/src/views/Home.vue new file mode 100644 index 0000000..ec9df67 --- /dev/null +++ b/src/views/Home.vue @@ -0,0 +1,311 @@ + ++ + +++ +合同管理+业务示例控制台
+模拟业务系统中的发起合同与模板管理菜单结构。
++ + + ++ ++ 发起合同 + + ++ 模板管理 + + ++ 相关方管理 + + ++ + +++{{ currentTitle }}++ 按需求文档模拟“业务人员发起合同、合同管理员维护模板”的真实菜单入口。 ++Mock + 本地测试 ++ ++ ++ + + + + diff --git a/src/views/bak/preSign.vue b/src/views/bak/preSign.vue new file mode 100644 index 0000000..60a9593 --- /dev/null +++ b/src/views/bak/preSign.vue @@ -0,0 +1,1844 @@ + +++ + +签章平台
+请选择签章模式
+++ + +++ + 合同发起 Demo:基础信息录入、模板变量填充、Word 预览与导出,以及菜单化台账页面 + ++ ++ 模板填充示例 + + ++ 合同管理菜单示例 + + + + ++ ++ + ++ + 一印一扫,在指定位置添加印章,扫码签署每个印章 + + + + +打开页面 + + + 弹窗模式 + + + + ++ + ++ + 一文一授,获取用户印章后一次扫码确认全部印章 + + + + +打开页面 + + + 弹窗模式 + + + + ++ + ++ + 托管印章,直接签署无需扫码,支持自动签章 + + + + +打开页面 + + + 弹窗模式 + + + + ++ + ++ + 三合一,在同一页面自由切换标准/预盖/托管三种签署模式 + + + + +打开弹窗 + + + + ++或通过合约ID打开已有合约++ ++ +标准模式 +预盖章模式 +托管盖章模式 +混合模式 ++ + + + + + + ++ + + + + diff --git a/src/views/bak/preSignModal.vue b/src/views/bak/preSignModal.vue new file mode 100644 index 0000000..bd74313 --- /dev/null +++ b/src/views/bak/preSignModal.vue @@ -0,0 +1,496 @@ + +++ + +++ ++++ 上传文件后此处将显示文件预览
++ + + + ++ + + + + + +++ + + ++++ +
++ ++
+ {{ seal.sealName || "印章" }} +++ ++ + ++
时间戳++++ {{ ts.status === "signing" ? "签署中..." : "确认" }} +++ + ++++ + +添加骑缝章+++ ++
+ {{ pagingSeal.sealName || "骑缝章" }} +++ ++++++
+++ 二维码加载中...
++ +++ + 有效期剩余:{{ qrTxt }} +
+++关闭 +刷新二维码 ++ + + + + + diff --git a/src/views/bak/standardSign.vue b/src/views/bak/standardSign.vue new file mode 100644 index 0000000..c78d937 --- /dev/null +++ b/src/views/bak/standardSign.vue @@ -0,0 +1,1862 @@ + +++++ +++ ++++ 上传文件后此处将显示文件预览
++ ++ + + + +++ ++++
+++
{{ seal.sealName || '印章' }}++ +++
时间戳++++ {{ ts.status === 'signing' ? '签署中...' : '确认' }} +++ + +++ + +添加骑缝章++ ++
{{ pagingSeal.sealName || '骑缝章' }}++ +++++二维码加载中...
+ +++ 有效期剩余:{{ qrTxt }}
+++关闭 +刷新二维码 ++ ++ + + + + diff --git a/src/views/bak/standardSignModal.vue b/src/views/bak/standardSignModal.vue new file mode 100644 index 0000000..a89e66c --- /dev/null +++ b/src/views/bak/standardSignModal.vue @@ -0,0 +1,577 @@ + ++ ++ + +++ + ++++ 上传文件后此处将显示文件预览
++ + ++ + + + + + +++ + + ++++ + + +
+ + ++ + + +++圆章+++椭圆章+++方章+++签名++++ +
++ + + ++ {{ seal.status === "signing" ? "等待扫码..." : "确认签署" }} +++++ + + +
++ ++ {{ seal._signer || "已签署" }} +++ + ++++ + + +添加骑缝章+++ +已添加骑缝章++ + + ++++ +++ +奇数页 +偶数页 +自定义页数 ++ +++ + +++ +圆章 +椭圆章 +方章 +签名 ++ 印章将放置在右键位置(第 {{ ctxMenu.pageNum }} 页,坐标 + {{ ctxMenu.originalX }}, {{ ctxMenu.originalY }}) +++ ++++++
+++ 二维码加载中...
++ +++ + 有效期剩余:{{ + qrCountdownText + }} +
++++ + +复制 + ++ 将链接发送到手机端,可在浏览器中直接跳转微信小程序签署 +
+++关闭 +刷新二维码 ++ + + + + + diff --git a/src/views/bak/trusteeshipSign.vue b/src/views/bak/trusteeshipSign.vue new file mode 100644 index 0000000..6fcb803 --- /dev/null +++ b/src/views/bak/trusteeshipSign.vue @@ -0,0 +1,769 @@ + ++ ++++ + +++ ++++ 上传文件后此处将显示文件预览
++ ++ + + + + + +++ ++++ +
+ ++ ++圆章+椭圆章+方章+签名+++ +
++ + ++ {{ seal.status === 'signing' ? '等待扫码...' : '确认签署' }} +++++ + +
+ +{{ seal._signer || '已签署' }}+ +++ + +添加骑缝章+ +已添加骑缝章+ + + ++++++ +奇数页 偶数页 自定义页数 ++ +++ +++ +圆章 椭圆章 方章 签名 +印章将放置在右键位置(第 {{ ctxMenu.pageNum }} 页,坐标 {{ ctxMenu.originalX }}, {{ ctxMenu.originalY }})++ +++++二维码加载中...
+ +++ 有效期剩余:{{ qrCountdownText }}
++++ +复制 +将链接发送到手机端,可在浏览器中直接跳转微信小程序签署
+++关闭 +刷新二维码 ++ ++ + + + + diff --git a/src/views/bak/trusteeshipSignModal.vue b/src/views/bak/trusteeshipSignModal.vue new file mode 100644 index 0000000..bea4abe --- /dev/null +++ b/src/views/bak/trusteeshipSignModal.vue @@ -0,0 +1,449 @@ + +++ + +++ ++++ 上传文件后此处将显示文件预览
++ + + + ++ + +++ + + ++++ + +
++ + ++
{{ seal.sealName }}++ ++ + ++
时间戳++++ {{ ts.status === 'signing' ? '签署中...' : '确认' }} +++ + +++ + +添加骑缝章++ ++
{{ pagingSeal.sealName || '骑缝章' }}++ + + +++++二维码加载中...
+ +++ 有效期剩余:{{ hostQrTxt }}
+++关闭 ++ ++++ +++ {{ sig.owner }}{{ sig.signer }}{{ sig.signatureTime }} ++++关闭 ++ + + + + + diff --git a/src/views/contract/launch/api.js b/src/views/contract/launch/api.js new file mode 100644 index 0000000..38faf48 --- /dev/null +++ b/src/views/contract/launch/api.js @@ -0,0 +1,309 @@ +/** + * 合同发起模块 - API 层 + * + * 当前使用 mock 数据模拟接口返回。 + * 【接入后端】:直接替换每个函数内部实现为 axios 请求即可,函数签名不改。 + */ + +// ========== 合同发起列表 mock 数据 ========== + +const mockLaunchRecords = [ + { + id: 'INIT-202605-001', + // 合同编码 + contractCode: 'HT-2026-0008', + // 合同名称 + contractName: '智慧园区设备采购合同', + // 合同类型 + contractType: '采购合同', + // 合同金额(元) + contractAmount: 368000, + // 有效期起 YYYY-MM-DD + effectiveStart: '2026-05-10', + // 有效期止 YYYY-MM-DD + effectiveEnd: '2027-05-09', + // 付款方式 + paymentMethod: '银行转账(30%预付款,70%验收后支付)', + // 所选模板标识 + templateKey: 'purchase', + // 所选模板名称 + templateName: '采购合同模板', + // 合同标的 + contractSubject: '园区门禁一体机、访客终端及部署实施服务', + // 业务备注 + businessRemark: '首次发起,等待业务确认后提交法务。', + // 发起人 + initiator: '张晓明', + // 所属部门 + initiatorDept: '供应链运营部', + // 发起人公司 + companyName: '浙港物流平台有限公司', + // 状态: draft/reviewing/rejected/pending_sign/signing/completed + status: 'draft', + // 查询级别: personal/company/admin + queryScope: 'personal', + // 创建时间 + createTime: '2026-05-10 09:20:00', + // 更新时间 + updateTime: '2026-05-13 14:30:00', + // 附件列表 + attachmentList: [ + { uid: 'a1', name: '技术方案V1.pdf', size: 283011, status: 'done' }, + { uid: 'a2', name: '补充协议草案.docx', size: 125880, status: 'done' }, + ], + // 合同方信息(详见下方 partyState 结构) + partyState: { + isThreePartyContract: false, + partyA: { + companyName: '浙港物流平台有限公司', + contactPhone: '', + registeredAddress: '', + bankAccount: '', + bankName: '', + contactName: '', + legalRepresentative: '', + creditCode: '', + }, + partyB: { + companyName: '宁波港船务货运代理有限公司', + companyType: '供应商', + contactPhone: '15757460062', + registeredAddress: '', + bankAccount: '', + bankName: '', + contactName: '周经理', + legalRepresentative: '', + creditCode: '', + }, + partyC: { companyName: '' }, + }, + }, + { + id: 'INIT-202605-002', + contractCode: 'XS-2026-0015', + contractName: '保税燃料油销售合同', + contractType: '销售合同', + contractAmount: 1580000, + effectiveStart: '2026-05-01', + effectiveEnd: '2026-12-31', + paymentMethod: '银行转账(按月结算)', + templateKey: 'sales', + templateName: '销售合同模板', + contractSubject: '保税燃料油销售及船舶供油服务', + businessRemark: '已提交法务,等待审批中。', + initiator: '王倩', + initiatorDept: '国际贸易事业部', + companyName: '浙港物流平台有限公司', + status: 'reviewing', + queryScope: 'company', + createTime: '2026-05-08 16:15:00', + updateTime: '2026-05-14 08:30:00', + attachmentList: [ + { uid: 'a3', name: '报价确认函.pdf', size: 90211, status: 'done' }, + ], + partyState: { + isThreePartyContract: false, + partyA: { + companyName: '宁波浙港供应链科技有限公司', + contactPhone: '13900000088', + contactName: '陈经理', + }, + partyB: { + companyName: '上海远洋能源有限公司', + companyType: '客户', + legalRepresentative: '孙先生', + contactName: '吴经理', + contactPhone: '13600000015', + contactEmail: 'sales@oceanenergy.com', + bankName: '招商银行上海分行', + bankAccount: '621483000000000015', + }, + partyC: { companyName: '' }, + }, + }, + { + id: 'INIT-202605-003', + contractCode: 'FW-2026-0021', + contractName: '数字化平台运维服务合同', + contractType: '服务合同', + contractAmount: 520000, + effectiveStart: '2026-04-15', + effectiveEnd: '2027-04-14', + paymentMethod: '银行转账(一次性结清)', + templateKey: 'purchase', + templateName: '采购合同模板', + contractSubject: '合同管理板块运维与驻场实施服务', + businessRemark: '法务要求补充服务SLA附件后重新提交。', + initiator: '李娜', + initiatorDept: '数字化办公室', + companyName: '浙港物流平台有限公司', + status: 'rejected', + queryScope: 'company', + createTime: '2026-04-15 10:25:00', + updateTime: '2026-05-07 18:05:00', + attachmentList: [ + { uid: 'a4', name: '实施范围说明.pdf', size: 70123, status: 'done' }, + ], + partyState: { + isThreePartyContract: false, + partyA: { companyName: '浙港物流平台有限公司' }, + partyB: { + companyName: '杭州智云实施服务有限公司', + companyType: '供应商', + contactName: '刘经理', + contactPhone: '13888886666', + contactEmail: 'liu@cloudservice.com', + }, + partyC: { companyName: '' }, + }, + }, + { + id: 'INIT-202605-004', + contractCode: 'KJ-2026-0011', + contractName: '港口智能设备年度框架合同', + contractType: '框架合同', + contractAmount: 980000, + effectiveStart: '2026-03-01', + effectiveEnd: '2027-02-28', + paymentMethod: '银行转账(按月结算)', + templateKey: 'purchase', + templateName: '采购合同模板', + contractSubject: '港口智能硬件、集成服务及年度维保合作', + businessRemark: '审批完成,待发起线上签署。', + initiator: '周立', + initiatorDept: '装备采购中心', + companyName: '浙港物流平台有限公司', + status: 'pending_sign', + queryScope: 'admin', + createTime: '2026-03-01 11:12:00', + updateTime: '2026-05-11 09:45:00', + attachmentList: [ + { uid: 'a5', name: '年度采购清单.xlsx', size: 154933, status: 'done' }, + ], + partyState: { + isThreePartyContract: true, + partyA: { companyName: '浙港物流平台有限公司' }, + partyB: { + companyName: '宁波保税区港航设备有限公司', + companyType: '合作伙伴', + contactName: '赵主管', + contactPhone: '13500000021', + }, + partyC: { + companyName: '浙江临港数智科技有限公司', + companyType: '合作伙伴', + creditCode: '91330000MAABCDE123', + legalRepresentative: '钱先生', + registeredAddress: '浙江省杭州市滨江区江南大道2888号', + contactName: '何经理', + contactPhone: '13700000078', + contactAddress: '浙江省杭州市滨江区江南大道2888号', + contactEmail: 'hz@example.com', + }, + }, + }, + { + id: 'INIT-202605-005', + contractCode: 'XS-2026-0022', + contractName: '沿海航线供应服务合同', + contractType: '销售合同', + contractAmount: 760000, + effectiveStart: '2026-02-18', + effectiveEnd: '2026-11-30', + paymentMethod: '银行转账(按月结算)', + templateKey: 'sales', + templateName: '销售合同模板', + contractSubject: '沿海航线供应链服务与结算支持', + businessRemark: '甲方已签章,等待乙方签署。', + initiator: '徐晨', + initiatorDept: '客户服务中心', + companyName: '浙港物流平台有限公司', + status: 'signing', + queryScope: 'personal', + createTime: '2026-02-18 13:40:00', + updateTime: '2026-05-12 17:16:00', + attachmentList: [], + partyState: { + isThreePartyContract: false, + partyA: { + companyName: '宁波浙港供应链科技有限公司', + contactPhone: '13900000088', + contactName: '陈经理', + }, + partyB: { + companyName: '上海远洋能源有限公司', + companyType: '客户', + legalRepresentative: '孙先生', + contactName: '吴经理', + contactPhone: '13600000015', + contactEmail: 'sales@oceanenergy.com', + bankName: '招商银行上海分行', + bankAccount: '621483000000000015', + }, + partyC: { companyName: '' }, + }, + }, + { + id: 'INIT-202605-006', + contractCode: 'CG-2026-0033', + contractName: '港区安防升级采购合同', + contractType: '采购合同', + contractAmount: 2860000, + effectiveStart: '2026-01-10', + effectiveEnd: '2026-12-31', + paymentMethod: '银行转账(30%预付款,70%验收后支付)', + templateKey: 'purchase', + templateName: '采购合同模板', + contractSubject: '港区安防摄像头、门禁和施工实施采购', + businessRemark: '合同已签署完毕并推送法务归档。', + initiator: '高翔', + initiatorDept: '工程保障部', + companyName: '浙港物流平台有限公司', + status: 'completed', + queryScope: 'admin', + createTime: '2026-01-10 08:45:00', + updateTime: '2026-05-09 16:28:00', + attachmentList: [ + { uid: 'a6', name: '验收报告.pdf', size: 188221, status: 'done' }, + ], + partyState: { + isThreePartyContract: false, + partyA: { companyName: '浙港物流平台有限公司' }, + partyB: { + companyName: '宁波港船务货运代理有限公司', + companyType: '供应商', + contactPhone: '15757460062', + contactName: '周经理', + }, + partyC: { companyName: '' }, + }, + }, +] + +// ========== API 函数(接入后端时替换内部实现) ========== + +/** 查询合同发起列表 */ +export function queryLaunchList() { + return Promise.resolve(mockLaunchRecords) +} + +/** 查询合同发起详情 */ +export function getLaunchDetail(id) { + const record = mockLaunchRecords.find((item) => item.id === id) || null + return Promise.resolve(record) +} + +/** 保存合同发起 */ +export function saveLaunchRecord(record) { + return Promise.resolve(record) +} + +/** 提交合同到法务 */ +export function submitLaunchRecord(record) { + return Promise.resolve(record) +} + +/** 删除合同发起记录 */ +export function deleteLaunchRecord(idList) { + return Promise.resolve(idList) +} diff --git a/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue b/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue new file mode 100644 index 0000000..efe5c72 --- /dev/null +++ b/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue @@ -0,0 +1,1761 @@ + +++++ +++ ++++ 上传文件后此处将显示文件预览
++ ++ + +++ ++++
+++
{{ seal.sealName }}++ +++
时间戳++++ {{ ts.status === 'signing' ? '签署中...' : '确认' }} +++ + +++ + +添加骑缝章++ ++
{{ pagingSeal.sealName || '骑缝章' }}++ + + +++++二维码加载中...
+ +++ 有效期剩余:{{ hostQrTxt }}
++关闭 + ++++ ++{{ sig.owner }}{{ sig.signer }}{{ sig.signatureTime }}++关闭 + + + + + + diff --git a/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue b/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue new file mode 100644 index 0000000..c5fd43a --- /dev/null +++ b/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue @@ -0,0 +1,1297 @@ + +++ +++ ++合同主信息
+ ++ {{ creationMode === "manual" ? "手动创建" : "模板创建" }} + ++ {{ templateName }} + +++ + ++ ++ + +++ +++++ +合同主信息+++ + + +我方++ +++ 我方{{ + detailState.partyState.partyA.companyName || "/" + }} +++ 电话{{ + detailState.partyState.partyA.contactPhone || "/" + }} +++ 公司地址{{ + detailState.partyState.partyA.registeredAddress || "/" + }} +++ 银行/账号{{ + detailState.partyState.partyA.bankAccount || "/" + }} +++ ++ + ++ 备选开票抬头选择 + ++ +++{{ party.displayName }}++ 删除 + ++++ + ++ +++ {{ party.displayName }}{{ + party.companyName || "/" + }} +++ 电话{{ party.contactPhone || "/" }} +++ 公司地址{{ party.registeredAddress || "/" }} +++ 银行/账号{{ party.bankAccount || "/" }} +++ ++ + 暂无相对方,请点击右上角“添加” ++ +++ ++ ++ + ++ + ++ ++ +合同起止时间++ +固定期限 +无固定期限 ++++ + + +++ ++ + ++ + ++ + ++ + ++ + ++ ++++++ ++ + 基本信息 ++++ ++ 合同名称{{ detailState.contractName || "未填写" }} +++ 我方{{ + detailState.partyState.partyA.companyName || "未填写" + }} +++ 合同编号{{ detailState.contractCode || "未填写" }} +++ 相对方{{ counterpartySummaryText }} ++++ +合同正文++++ {{ contractBodyDisplayText }} +++ {{ contractBodyHint }} ++++ +其他附件++ +其他附件(可上传多个文件)++ + ++ + + ++ + + 合同属性 ++ +++ ++ ++ + ++ + ++ + ++ + ++ + ++ + ++ ++ ++ 是否涉及港澳台 +++ +是 +否 ++ 是否公开招标 +++ +是 +否 ++ 签约主体是否涉外 +++ +是 +否 ++ 是否列入当年预算 +++ +是 +否 ++ 是否共享 +++ +是 +否 ++ 是否重大合同 +++ +是 +否 +++ +额外金额++ +++++ +++ + 履行计划 ++ ++ ++ + ++ + + + ++ + + + ++ + + + ++ + + + ++ + + + ++ + + + + ++ 删除 + + +暂无数据+ ++ ++ ++++ ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + + + + + + + diff --git a/src/views/contract/launch/components/mixedSignModal.vue b/src/views/contract/launch/components/mixedSignModal.vue new file mode 100644 index 0000000..e6a930e --- /dev/null +++ b/src/views/contract/launch/components/mixedSignModal.vue @@ -0,0 +1,18 @@ + +++ ++ + +++ +合同正文配置
++ + + ++ + ++ + ++ ++ {{ item.label }} + ++ + ++ +++ {{ activeTemplate?.templateName || "未选择模板" }} +++ {{ activeTemplate?.description || "请选择已发布模板" }} +++ ++++ ++ + ++ + +上传合同正文 Word 文件
++ 手动创建模式下,右侧将直接渲染当前上传的 `.docx` 文件。 +
++ +++ +++Word 渲染预览
+{{ previewDescription }}
++ ++ {{ + creationMode === "manual" + ? "手动创建" + : activeTemplate?.templateName || "未选择模板" + }} + +可导出 ++ +++++ {{ emptyPreviewText }}
++++ 正在生成并渲染 Word 文档...
+++文档预览失败
+{{ previewError }}
++ + + diff --git a/src/views/contract/launch/index.vue b/src/views/contract/launch/index.vue new file mode 100644 index 0000000..42300e2 --- /dev/null +++ b/src/views/contract/launch/index.vue @@ -0,0 +1,577 @@ + + + + + + + + diff --git a/src/views/contract/manifest/components/ContractTemplateManageModal.vue b/src/views/contract/manifest/components/ContractTemplateManageModal.vue new file mode 100644 index 0000000..450609c --- /dev/null +++ b/src/views/contract/manifest/components/ContractTemplateManageModal.vue @@ -0,0 +1,1165 @@ + ++ + ++++ ++ ++ + ++ ++ + ++ ++ + ++ ++ + ++ ++ + + ++ + + ++ + ++ 查询 + ++ 重置 + ++ 发起合同 + ++ 删除 + ++ + ++ + + + + + + + + + ++ {{ getStatusLabel(row.status) }} + + ++ + + + + + + + ++ + + + + + + + + diff --git a/src/views/contract/manifest/index.vue b/src/views/contract/manifest/index.vue new file mode 100644 index 0000000..6e5c5a3 --- /dev/null +++ b/src/views/contract/manifest/index.vue @@ -0,0 +1,422 @@ + ++++ + +++ +++合同范本维护
+支持模板分类、Word 文件上传、变量自动识别与业务字段匹配。
+++ + ++ ++ + ++++ + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + ++ + + + + ++ + +上传 Word 模板文件(支持 `.docx`)
++ 上传后会自动识别花括号变量,如 `{contractName}`、`{partyAName}`,并生成变量匹配清单。 +
++ + +++ ++ + +++ ++ 手动新增变量 + ++ +可绑定业务字段++++ {{ item.label }} + +++ ++++ 变量 {{ index + 1 }} ++ ++ 删除 + ++++ + ++ + ++ + + ++++ ++ + ++ + +++ +++模板预览
+右侧基于当前变量匹配渲染 Word 模板效果,便于检查变量位置是否正确。
++ +{{ formState.source || '未分类' }} +{{ variableMappings.length }} 个变量 +++++ ++ 上传 `.docx` 模板文件后,这里会显示填充后的预览。
++++ 正在渲染模板预览...
+++预览失败
+{{ previewError }}
++ + + + + + diff --git a/src/views/contract/partner/components/PartnerModal.vue b/src/views/contract/partner/components/PartnerModal.vue new file mode 100644 index 0000000..105e9e1 --- /dev/null +++ b/src/views/contract/partner/components/PartnerModal.vue @@ -0,0 +1,628 @@ + ++ + ++++ ++ ++ + ++ ++ + + ++ ++ + ++ ++ + + ++ + + ++ + ++ 查询 + ++ 重置 + ++ 新增模板 + ++ + ++ + + + + + + + ++ {{ getStatusLabel(row.status) }} + + ++ + + + + + + + + + ++ + + + + + + + diff --git a/src/views/contract/partner/index.vue b/src/views/contract/partner/index.vue new file mode 100644 index 0000000..f3b1044 --- /dev/null +++ b/src/views/contract/partner/index.vue @@ -0,0 +1,579 @@ + ++++ + + ++ + ++ +++ ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ +是 +否 ++ ++ +是 +否 ++ ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + + + ++ 联系人信息 ++ + +组织类型必填 +个人类型可选 ++ 暂无联系人信息 +++++ 联系人{{ index + 1 }} +++ 删除 + ++++ ++ + ++ + ++ + ++ + ++++ ++ + ++ + ++ + ++ + + + + + + diff --git a/src/views/seal/externalSign.vue b/src/views/seal/externalSign.vue new file mode 100644 index 0000000..f4b7000 --- /dev/null +++ b/src/views/seal/externalSign.vue @@ -0,0 +1,42 @@ + ++ + ++++ ++ ++ ++ ++ + ++ ++ + ++ ++ + ++ ++ + ++ ++ + + ++ + + ++ + ++ 查询 + ++ 重置 + ++ 新增相对方 + ++ 批量删除 + ++ + ++ + + + + {{ row.oppositeId || "未同步" }} + + ++ + + {{ getLabel(optionSets.relativeTypeOptions, row.relativeType) }} + + ++ + {{ getLabel(optionSets.oppositeCharacterOptions, row.oppositeCharacter) }} + + ++ + {{ getLabel(optionSets.natureOfEnterpriseOrgOptions, row.natureOfEnterpriseOrg) }} + + ++ + {{ row.groupFlag === "Y" ? "是" : "否" }} + + ++ + {{ row.gatFlag === "Y" ? "是" : "否" }} + + ++ + {{ row.customerTaxno || row.certificateNum || row.tinCode || "-" }} + + ++ + {{ getLabel(optionSets.countryOptions, row.country) || "-" }} + + ++ + {{ getContactSummary(row.contacts) }} + + ++ + ++ {{ getLabel(optionSets.syncStatusOptions, row.syncStatus) }} + + ++ + + + + ++ + ++ + + + + diff --git a/src/views/seal/mixedSignModal copy.vue b/src/views/seal/mixedSignModal copy.vue new file mode 100644 index 0000000..9618aa6 --- /dev/null +++ b/src/views/seal/mixedSignModal copy.vue @@ -0,0 +1,1709 @@ + ++ + + + + + + diff --git a/src/views/seal/mixedSignModal.vue b/src/views/seal/mixedSignModal.vue new file mode 100644 index 0000000..b9f2f87 --- /dev/null +++ b/src/views/seal/mixedSignModal.vue @@ -0,0 +1,2428 @@ + +++++++ ++++ 上传文件后此处将显示文件预览
++ ++ + +++ + ++++ + +
+ ++ + ++圆章+椭圆章+方章+签名+++ +
+++
批注+++ + ++ {{ seal.status === 'signing' ? '等待扫码...' : '确认签署' }} +++++ + +
++ +{{ seal._signer || '已签署' }}+++ ++
+ {{ getImageSealFallbackLabel(seal) }} ++ +++ ++ {{ seal.status === 'signing' ? '签署中...' : '确认' }} +++ + + +++ + +添加骑缝章++ +已添加骑缝章++ ++++奇数页 偶数页 自定义页数 ++圆章 椭圆章 方章 签名 印章将放置在右键位置(第 {{ ctxMenu.pageNum }} 页,坐标 {{ ctxMenu.originalX }}, {{ ctxMenu.originalY }})++ +++++二维码加载中...
+ +++ 有效期剩余:{{ qrCountdownText }}
++++ +复制 +将链接发送到手机端,可在浏览器中直接跳转微信小程序签署
+++关闭 +刷新二维码 +模拟回调成功 ++ +++++二维码加载中...
+ +++ 有效期剩余:{{ trHostQrTxt }}
+++关闭 +模拟回调成功 ++ + ++++ ++{{ sig.owner }}{{ sig.signer }}{{ sig.signatureTime }}++关闭 + ++ +++ + +++ + + + + + + diff --git a/src/views/seal/preSign.vue b/src/views/seal/preSign.vue new file mode 100644 index 0000000..60a9593 --- /dev/null +++ b/src/views/seal/preSign.vue @@ -0,0 +1,1844 @@ + +++++ +++ + ++++ 上传文件后此处将显示文件预览
++ + ++ + + + + +++ + ++++ +
++ ++
+ {{ + seal.sealName || + (seal._type === "timestamp" ? "时间戳" : "印章") + }} ++ +++ ++ {{ seal.status === "signing" ? "签署中..." : "确认" }} +++ + + ++++ + +添加骑缝章+++ ++
+ {{ pagingSeal.sealName || "骑缝章" }} +++ +++ ++++
++ ++ 二维码加载中...
++ + +++ + 有效期剩余:{{ qrText }} +
+++关闭 ++ 刷新二维码 + ++ ++ + + + + diff --git a/src/views/seal/preSignModal.vue b/src/views/seal/preSignModal.vue new file mode 100644 index 0000000..6bcdcda --- /dev/null +++ b/src/views/seal/preSignModal.vue @@ -0,0 +1,554 @@ + +++ + +++ ++++ 上传文件后此处将显示文件预览
++ + + + ++ + + + + + +++ + + ++++ +
++ ++
+ {{ seal.sealName || "印章" }} +++ ++ + ++
时间戳++++ {{ ts.status === "signing" ? "签署中..." : "确认" }} +++ + ++++ + +添加骑缝章+++ ++
+ {{ pagingSeal.sealName || "骑缝章" }} +++ ++++++
+++ 二维码加载中...
++ +++ + 有效期剩余:{{ qrTxt }} +
+++关闭 +刷新二维码 ++ + + + + + diff --git a/src/views/seal/standardSign.vue b/src/views/seal/standardSign.vue new file mode 100644 index 0000000..c78d937 --- /dev/null +++ b/src/views/seal/standardSign.vue @@ -0,0 +1,1862 @@ + +++++ +++ ++++ 上传文件后此处将显示文件预览
++ ++ + + + +++ ++++
+++
{{ seal.sealName || '印章' }}++ +++
时间戳++++ {{ ts.status === 'signing' ? '签署中...' : '确认' }} +++ + +++ + +添加骑缝章++ ++
{{ pagingSeal.sealName || '骑缝章' }}++ +++++二维码加载中...
+ +++ 有效期剩余:{{ qrTxt }}
+++关闭 +刷新二维码 + +模拟回调成功 ++ ++ + + + + diff --git a/src/views/seal/standardSignModal.vue b/src/views/seal/standardSignModal.vue new file mode 100644 index 0000000..9b22061 --- /dev/null +++ b/src/views/seal/standardSignModal.vue @@ -0,0 +1,1897 @@ + ++ ++ + +++ + ++++ 上传文件后此处将显示文件预览
++ + ++ + + + + + +++ + + ++++ + + +
+ + ++ + + +++圆章+++椭圆章+++方章+++签名++++ +
++ + + ++ {{ seal.status === "signing" ? "等待扫码..." : "确认签署" }} +++++ + + +
++ ++ {{ seal._signer || "已签署" }} +++ + ++++ + + +添加骑缝章+++ +已添加骑缝章++ + + ++++ +++ +奇数页 +偶数页 +自定义页数 ++ +++ + +++ +圆章 +椭圆章 +方章 +签名 ++ 印章将放置在右键位置(第 {{ ctxMenu.pageNum }} 页,坐标 + {{ ctxMenu.originalX }}, {{ ctxMenu.originalY }}) +++ ++++++
+++ 二维码加载中...
++ +++ + 有效期剩余:{{ + qrCountdownText + }} +
++++ + +复制 + ++ 将链接发送到手机端,可在浏览器中直接跳转微信小程序签署 +
+++关闭 +刷新二维码 ++ + + + + + diff --git a/src/views/seal/trusteeshipSign.vue b/src/views/seal/trusteeshipSign.vue new file mode 100644 index 0000000..6fcb803 --- /dev/null +++ b/src/views/seal/trusteeshipSign.vue @@ -0,0 +1,769 @@ + ++ ++++ + +++ ++++ 上传文件后此处将显示文件预览
++ ++ + + + + + +++ ++++ +
+ ++ +++圆章+++椭圆章+++方章+++签名++++ +
++ + ++ {{ + seal.status === "signing" ? "等待扫码..." : "确认签署" + }} +++++ + +
++ ++ {{ seal._signer || "已签署" }} +++ ++++ + +添加骑缝章+++ +已添加骑缝章++ + + ++++ +++ +奇数页 偶数页 自定义页数 ++ +++ + +++ +圆章 椭圆章 方章 签名 ++ 印章将放置在右键位置(第 {{ ctxMenu.pageNum }} 页,坐标 + {{ ctxMenu.originalX }}, {{ ctxMenu.originalY }}) +++ ++++++
+++ 二维码加载中...
++ +++ + 有效期剩余:{{ + qrCountdownText + }} +
++++ +复制 ++ 将链接发送到手机端,可在浏览器中直接跳转微信小程序签署 +
+++关闭 +刷新二维码 + +模拟回调成功 ++ ++ + + + + diff --git a/src/views/seal/trusteeshipSignModal.vue b/src/views/seal/trusteeshipSignModal.vue new file mode 100644 index 0000000..3a336d7 --- /dev/null +++ b/src/views/seal/trusteeshipSignModal.vue @@ -0,0 +1,463 @@ + +++ + +++ ++++ 上传文件后此处将显示文件预览
++ + + + ++ + +++ + + ++++ + +
++ + ++
{{ seal.sealName }}++ ++ + ++
时间戳++++ {{ ts.status === 'signing' ? '签署中...' : '确认' }} +++ + +++ + +添加骑缝章++ ++
{{ pagingSeal.sealName || '骑缝章' }}++ + + +++++二维码加载中...
+ +++ 有效期剩余:{{ hostQrTxt }}
+++关闭 ++ ++++ +++ {{ sig.owner }}{{ sig.signer }}{{ sig.signatureTime }} ++++关闭 ++ + + + + + diff --git a/task.txt b/task.txt new file mode 100644 index 0000000..13cb987 --- /dev/null +++ b/task.txt @@ -0,0 +1,220 @@ +文件信息 +获取合约签署信息 +请求方式 POST + +请求接口 / saas/api/contract/getDetail + +请求参数 +名称 位置 类型 必选 中文名 说明 +access_token header string 是 访问令牌 详见身份鉴权API +Content-Type header string 是 内容类型 application/json +body body object 是 Body 请求体 +» contractId body string 是 签署流程ID +参数示例 + +{ + "contractId": "CCFSENSDKGIUOLK" +} +返回参数 +返回参数 + +名称 类型 必选 中文名 说明 +» isSuccess boolean true 成功标志 true 成功 false失败 +» msg string true 消息 +» code integer true 状态码 +» data object true 数据体 +»» contractId string true 签署流程ID +»» contractName string true 合约名称 +»» status string true 合约状态 -1:已终⽌ +0:已取消 +10:等待签署 +20:签署中 +2000:已完成 +»» statusName string true 合约状态名称 已完成 +»» startTime string true 合约发起时间 +»» fileSize integer true 合约⼤⼩ +»» signatureList [object] true 签署列表 +»»» signatureId string true +»»» signer string true +»»»signatureTime string true +»»» entName string true +参数示例 + +{ + "isSuccess": true, + "msg": "成功", + "code": 200, + "data": { + "contractId": "123", + "contractName": "某某合同", + "status": 20, + "statusName": "签署中", + "startTime": "2021-10-10 10:10:10", + "fileSize": 23, + "signatureList": [ + { + "signatureId": "45642164816", + "signer": "张三", + "signatureTime": "2021-10-10 10:10:11", + "entName": "ZJCA" + } + ] + } +} +状态码 + +状态码 状态码含义 说明 +200 OK 成功 +400 HTTP 消息不可读 系统内部错误 +500 请求方式有误,请检查 GET/POST +401 Token失效 +查看合约文件 +请求方式 POST + +请求接口 /saas/api/contract/preview + +请求参数 +名称 位置 类型 必选 中文名 说明 +access_token header string 是 访问令牌 详见身份鉴权API +Content-Type header string 是 内容类型 application/json +body body object 是 Body 请求体 +» contractId body string 是 签署流程ID +参数示例 + +{ + "contractId": "CCFSENSDKGIUOLK" +} +返回参数 +返回参数 + +名称 类型 必选 中文名 说明 +» isSuccess boolean true 成功标志 true 成功 false失败 +» msg string true 消息 +» code integer true 状态码 +» data object true 数据体 +»» contractId string true 签署流程ID +»» imageHeight string true pdf转成图⽚的宽 +»» imageWidth string true pdf转成图⽚的⾼ +»» pdfUrl string true pdf预览地址 +»» pdfToImageList [string] true pdf转成图⽚的预览地址 +参数示例 + +{ + "isSuccess": true, + "msg": "成功", + "code": 200, + "data": { + "contractId": "5cf5ab68024063bb2ccf4f055549ef55", + "imageHeight": 1122, + "imageWidth": 793, + "pdfUrl": "https://testeseal.cert8.pdf", + "pdfToImageList": ["https://t/abc", + "https://t/dsd"] + } +} +状态码 + +状态码 状态码含义 说明 +200 OK 成功 +400 HTTP 消息不可读 系统内部错误 +500 请求方式有误,请检查 GET/POST +401 Token失效 +下载合约文件 +请求方式 POST + +请求接口 /saas/api/contract/download + +请求参数 +名称 位置 类型 必选 中文名 说明 +access_token header string 是 访问令牌 详见身份鉴权API +Content-Type header string 是 内容类型 application/json +body body object 是 Body 请求体 +» contractId body string 是 签署流程ID +参数示例 + +{ + "contractId": "CCFSENSDKGIUOLK" +} +返回参数 +返回参数 + +名称 类型 必选 中文名 说明 +» isSuccess boolean true 成功标志 true 成功 false失败 +» msg string true 消息 +» code integer true 状态码 +» data object true 数据体 +»» downloadUrl string true 下载链接 +参数示例 + +{ + "isSuccess": true, + "msg": "成功", + "code": 200, + "data": { + "downloadUrl": "https://tdas08.pdf" + } +} +状态码 + +状态码 状态码含义 说明 +200 OK 成功 +400 HTTP 消息不可读 系统内部错误 +500 请求方式有误,请检查 GET/POST +401 Token失效 +隐私信息 +获取用户隐私数据 +请求方式 POST + +请求接口 /api/user/getUserInfos + +请求参数 +名称 位置 类型 必选 中文名 说明 +access_token header string 是 访问令牌 详见身份鉴权API +Content-Type header string 是 内容类型 application/json +body body object 是 Body 请求体 +» requestId body string 是 二维码请求ID +参数示例 + +{ + "requestId": "8613F36DAF1B0B98" +} +返回参数 +返回参数 + +名称 类型 必选 中文名 说明 +» isSuccess boolean true 成功标志 true 成功 false失败 +» msg string true 消息 +» code integer true 状态码 +» data object true 数据体 +»» name string true 用户姓名 +»» mobile string true 手机号 +»» code string true 身份证号 +参数示例 + +{ + "isSuccess": true, + "msg": "成功", + "code": 200, + "data": + { + "name":"张三", + "mobile":"13888888888", + "code":"330111111111111111" + } +} +状态码 + +状态码 状态码含义 说明 +200 OK 成功 +400 HTTP 消息不可读 系统内部错误 +500 请求方式有误,请检查 GET/POST +401 Token失效 + + + +目前输入合约id打开合约文件没有显示出来,可能需要 调用接口获取文件和合约信息,相关接口在上方,然后打开的时候同样支持三种模式,这个你看看Home.vue怎么设计好 +src\views\seal\preSignModal.vue +src\views\seal\standardSignModal.vue +src\views\seal\trusteeshipSignModal.vue +src\views\Home.vue +修改这几个文件,同时要注意初始化的问题 \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..c7bd768 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,40 @@ +import { defineConfig } from 'vite' +import { fileURLToPath, URL } from 'node:url' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + port: 1088, + host: true, + open: true, + proxy: { + '/manifest': { + target: 'http://127.0.0.1:8899', + changeOrigin: true, + }, + '/partner': { + target: 'http://127.0.0.1:8899', + changeOrigin: true, + }, + '/trans': { + target: 'http://127.0.0.1:8899', + changeOrigin: true, + }, + '/seal': { + target: 'http://127.0.0.1:8899', + changeOrigin: true, + }, + '/seal/ws': { + target: 'ws://127.0.0.1:8899', + ws: true, + changeOrigin: true, + }, + }, + }, +})++++ +++ ++++ 上传文件后此处将显示文件预览
++ ++ + +++ ++++
+++
{{ seal.sealName }}++ +++
时间戳++++ {{ ts.status === 'signing' ? '签署中...' : '确认' }} +++ + +++ + +添加骑缝章++ ++
{{ pagingSeal.sealName || '骑缝章' }}++ + + +++++二维码加载中...
+ +++ 有效期剩余:{{ hostQrTxt }}
+++关闭 + +模拟回调成功 ++ ++++ ++{{ sig.owner }}{{ sig.signer }}{{ sig.signatureTime }}++关闭