trustbase-seller-backend 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trustbase-seller-backend",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "TrustBase Seller Backend (merchant edition) — 商品上链/订单/支付/质押 write API for TrustBase 保障链生态. 单卖家自托管形态: 签名 key 即卖家身份, 私钥不出门.",
5
5
  "main": "run-unified.js",
6
6
  "bin": {
@@ -289,14 +289,13 @@ img.auprev{display:none;width:100%;max-height:140px;object-fit:cover;border-radi
289
289
  <div class="acard-h"><span class="anum">4</span><span id="acard4-title">门店信息</span></div>
290
290
  <div id="scene_fields_app">
291
291
  <div class="agrid">
292
- <div class="afield"><label for="a_app_appid">应用 AppID</label><input id="a_app_appid" placeholder="默认由服务商提供">
293
- <div class="hint" id="a_appid_note" style="display:none;font-size:12px;color:#16A34A;margin-top:3px">✓ 由服务商提供, 无需自备</div></div>
292
+ <div class="afield" id="a_appid_field"><label for="a_app_appid">应用 AppID</label><input id="a_app_appid" placeholder="wx 开头">
293
+ <div class="hint" id="a_appid_note" style="display:none;font-size:12px;color:#16A34A;margin-top:3px">✓ 由服务商提供</div></div>
294
294
  <div class="afield"><label for="a_app_provider">应用归属</label>
295
295
  <select id="a_app_provider"><option value="sp">服务商应用 (默认, 零自备)</option><option value="own">商户自有应用</option></select></div>
296
296
  </div>
297
- <div class="ahint" id="a_app_reuse_row" style="display:none;margin-top:8px">
298
- <label style="cursor:pointer"><input type="checkbox" id="a_app_reuse" checked style="width:auto;margin-right:6px">使用服务商提供的应用截图 ✓ (推荐, 不用自己传)</label>
299
- </div>
297
+ <div class="ahint" id="a_app_provided" style="display:none;margin-top:8px;background:#F0FDF4;border-color:#BBF7D0;color:#166534"></div>
298
+ <div class="ahint" id="a_app_missing" style="display:none;margin-top:8px">⚠️ 服务商尚未配置应用,请联系服务商配置,或改用下方"商户自有应用"填写</div>
300
299
  <div class="ahint" id="a_app_own_hint" style="display:none;margin-top:8px">使用自有应用: 请填自己的 AppID 并上传 4 张应用截图</div>
301
300
  </div>
302
301
  <div class="agrid" id="scene_fields_store">
@@ -698,22 +697,40 @@ function setScene(scene){
698
697
  });
699
698
  paintAppScene(); // APP 场景: 服务商素材复用行显隐 + 截图槽联动
700
699
  }
701
- // APP 场景 (普通商户零自备): 服务商已配素材 → 默认勾选"使用服务商提供的应用截图", 截图槽隐藏;
702
- // 取消勾选或选自有应用 → 显示 4 个截图槽自己传
700
+ // APP 场景 (2026-10-03 UX 修正): 服务商配置完整 (AppID+4素材) → AppID 框和截图槽全隐藏,
701
+ // 只留绿标"应用和截图由服务商提供, 无需操作"; 未配齐 → 提示联系服务商 + 展开自有字段组;
702
+ // 选自有应用 → AppID 输入框 + 4 张截图槽。
703
+ function appSpComplete(){
704
+ var sp=window._spInfo||{}, a=sp.app_screenshots||{};
705
+ return !!(sp.app_appid&&a.home&&a.tail&&a.inner&&a.pay);
706
+ }
707
+ function maskAppid(a){ a=String(a||''); return a.length>8?a.slice(0,4)+'****'+a.slice(-4):a; }
703
708
  function paintAppScene(){
704
709
  if(currentScene()!=='SALES_SCENES_APP') return;
705
- var spAssets=(window._spInfo&&window._spInfo.app_screenshots)||{};
706
- var hasSp=Object.keys(spAssets).length>0;
707
- var reuseRow=document.getElementById('a_app_reuse_row');
708
- if(reuseRow) reuseRow.style.display=hasSp?'':'none';
710
+ var complete=appSpComplete();
709
711
  var provider=(document.getElementById('a_app_provider')||{}).value||'sp';
710
- var reuse=hasSp&&provider==='sp'&&(document.getElementById('a_app_reuse')||{}).checked;
712
+ var zeroMode=provider==='sp'&&complete; // 零操作: 全隐藏
713
+ var missing=provider==='sp'&&!complete; // 服务商未配齐 → 提示+自有组
714
+ var fAppid=document.getElementById('a_appid_field');
715
+ if(fAppid) fAppid.style.display=zeroMode?'none':'';
716
+ var provided=document.getElementById('a_app_provided');
717
+ if(provided){
718
+ provided.style.display=zeroMode?'':'none';
719
+ if(zeroMode) provided.textContent='✓ 应用和截图由服务商提供 (AppID: '+maskAppid((window._spInfo||{}).app_appid)+'), 无需操作';
720
+ }
721
+ var missEl=document.getElementById('a_app_missing');
722
+ if(missEl) missEl.style.display=missing?'':'none';
723
+ var ownHint=document.getElementById('a_app_own_hint');
724
+ if(ownHint) ownHint.style.display=provider==='own'?'':'none';
711
725
  ['a_up_s1','a_up_s2','a_up_s3','a_up_s4'].forEach(function(id){
712
- var el=document.getElementById(id);
713
- if(el) el.style.display=reuse?'none':'';
726
+ var el=document.getElementById(id); if(el) el.style.display=zeroMode?'none':'';
714
727
  });
715
- var ownHint=document.getElementById('a_app_own_hint');
716
- if(ownHint) ownHint.style.display=(provider==='own'||!reuse)&&!hasSp?'':'none';
728
+ // AppID: 服务商配了 → 预填 (隐藏提交也要用); 未配 → 不显示误导占位, 占位统一 "wx 开头"
729
+ var appidEl=document.getElementById('a_app_appid');
730
+ if(appidEl){
731
+ if((window._spInfo||{}).app_appid&&!appidEl.value) appidEl.value=(window._spInfo||{}).app_appid;
732
+ appidEl.placeholder='wx 开头';
733
+ }
717
734
  }
718
735
  setScene('SALES_SCENES_APP'); // 默认 APP (普通商户零自备)
719
736
  function aval(id){var e=document.getElementById(id);return e?e.value.trim():''}
@@ -742,13 +759,14 @@ function applyFormBody(){
742
759
  body.web_home_media_id=_aMedia.web_home_media_id||'';body.web_product_media_id=_aMedia.web_product_media_id||'';
743
760
  }else if(scene==='SALES_SCENES_APP'){
744
761
  var provider=aval('a_app_provider')||'sp';
745
- body.appid=aval('a_app_appid');
746
762
  body.appid_provider=provider; // sp=服务商应用(默认零自备) / own=商户自有应用
747
- var spAssets=(window._spInfo&&window._spInfo.app_screenshots)||{};
748
- var reuse=provider==='sp'&&Object.keys(spAssets).length>0&&(document.getElementById('a_app_reuse')||{}).checked;
749
- if(reuse){
750
- body.app_screenshots=['home','tail','inner','pay'].map(function(k){return spAssets[k];}).filter(Boolean); // 复用服务商素材
763
+ if(provider==='sp'&&appSpComplete()){
764
+ // 零操作: AppID 和截图全部用服务商配置 (商户页面全隐藏)
765
+ body.appid=(window._spInfo||{}).app_appid;
766
+ var sa=(window._spInfo||{}).app_screenshots||{};
767
+ body.app_screenshots=['home','tail','inner','pay'].map(function(k){return sa[k];}).filter(Boolean);
751
768
  }else{
769
+ body.appid=aval('a_app_appid');
752
770
  body.app_screenshots=[_aMedia.app_home_media_id,_aMedia.app_tail_media_id,_aMedia.app_inner_media_id,_aMedia.app_pay_media_id].filter(Boolean);
753
771
  }
754
772
  }else{
@@ -1004,12 +1022,8 @@ async function loadSpInfo(){
1004
1022
  if(!j||!j.name) return;
1005
1023
  window._spInfo=j; // APP 场景零自备: app_appid/app_screenshots 预填复用
1006
1024
  var appidEl=document.getElementById('a_app_appid');
1007
- if(appidEl&&j.app_appid&&!appidEl.value){
1008
- appidEl.value=j.app_appid;
1009
- var note=document.getElementById('a_appid_note');
1010
- if(note) note.style.display='block';
1011
- }
1012
- paintAppScene(); // 素材复用行按服务商配置刷新
1025
+ if(appidEl&&j.app_appid&&!appidEl.value) appidEl.value=j.app_appid;
1026
+ paintAppScene(); // 三态显隐按服务商配置完整度刷新
1013
1027
  card.style.display='block';
1014
1028
  card.classList.toggle('offline', !!j.offline);
1015
1029
  document.getElementById('sp-name').textContent=j.offline&&!j.stale?'服务商暂时不可达':j.name;
@@ -1159,7 +1173,10 @@ function wzValidate(n){
1159
1173
  }else if(scene==='SALES_SCENES_MP'){
1160
1174
  r=need('a_appid','公众号/小程序 AppID','appid');
1161
1175
  }else{
1162
- r=need('a_app_appid','应用 AppID','app_appid');
1176
+ // APP 场景: 服务商配置完整(零操作)时 AppID 框隐藏且用服务商值, 不校验输入框
1177
+ if(!((document.getElementById('a_app_provider')||{}).value!=='own'&&appSpComplete())){
1178
+ r=need('a_app_appid','应用 AppID','app_appid');
1179
+ }
1163
1180
  }
1164
1181
  if(r) return r;
1165
1182
  var ind=aval('a_settlement_id');
@@ -1168,11 +1185,10 @@ function wzValidate(n){
1168
1185
  return {ok:false,field:'qual_media_id',msg:'请上传: '+ind+' 所需资质 ('+QUAL_REQUIRED[ind]+')'};
1169
1186
  }
1170
1187
  if(scene==='SALES_SCENES_APP'){
1171
- var spA=(window._spInfo&&window._spInfo.app_screenshots)||{};
1172
1188
  var provider=(document.getElementById('a_app_provider')||{}).value||'sp';
1173
- var reuse=provider==='sp'&&Object.keys(spA).length>0&&(document.getElementById('a_app_reuse')||{}).checked;
1174
- if(!reuse&&!(_aMedia.app_home_media_id&&_aMedia.app_tail_media_id&&_aMedia.app_inner_media_id&&_aMedia.app_pay_media_id)){
1175
- return {ok:false,field:'app_screenshots',msg:'请上传 4 张应用截图 (或勾选使用服务商提供的应用截图)'};
1189
+ if(!(provider==='sp'&&appSpComplete())
1190
+ &&!(_aMedia.app_home_media_id&&_aMedia.app_tail_media_id&&_aMedia.app_inner_media_id&&_aMedia.app_pay_media_id)){
1191
+ return {ok:false,field:'app_screenshots',msg:'请上传 4 张应用截图 (或等服务商配置后重试)'};
1176
1192
  }
1177
1193
  }
1178
1194
  return {ok:true};
@@ -1225,7 +1241,7 @@ function renderWzPreview(){
1225
1241
  var docs=[['营业执照',_aMedia.license_media_id],['身份证人像面',_aMedia.legal_id_front_media_id],['身份证国徽面',_aMedia.legal_id_back_media_id]];
1226
1242
  var sceneDocs={store_entrance_media_id:'门店门头照',store_indoor_media_id:'门店内部照',web_home_media_id:'网站首页截图',web_product_media_id:'商品/服务页截图',mp_media_id:'公众号/小程序截图',app_home_media_id:'应用首页截图',app_tail_media_id:'应用尾页截图',app_inner_media_id:'应用内页截图',app_pay_media_id:'应用支付页截图'};
1227
1243
  for(var k in sceneDocs){ if(_aMedia[k]) docs.push([sceneDocs[k],_aMedia[k]]); }
1228
- if(scene==='SALES_SCENES_APP'&&f.app_screenshots&&f.app_screenshots.length&&(document.getElementById('a_app_reuse')||{}).checked){
1244
+ if(scene==='SALES_SCENES_APP'&&f.appid_provider==='sp'&&appSpComplete()){
1229
1245
  docs.push(['应用截图','服务商素材 ✓']);
1230
1246
  }
1231
1247
  grp('证件',docs.map(function(d){return [d[0], d[1]?(d[1]==='服务商素材 ✓'?d[1]:'已上传 ✓'):'未上传 ✗'];}));
@@ -1381,9 +1397,7 @@ async function restoreIdentity(){
1381
1397
  }
1382
1398
  }
1383
1399
  if(stl){ stl.addEventListener('change',paintQualSlot); }
1384
- // APP 场景联动: 复用勾选/应用归属切换 → 截图槽显隐
1385
- var appReuse=document.getElementById('a_app_reuse');
1386
- if(appReuse) appReuse.addEventListener('change',function(){ paintAppScene(); saveApplyDraft(); });
1400
+ // APP 场景联动: 应用归属切换 → 字段组/截图槽显隐
1387
1401
  var appProv=document.getElementById('a_app_provider');
1388
1402
  if(appProv) appProv.addEventListener('change',function(){ paintAppScene(); saveApplyDraft(); });
1389
1403
  if(catEl){ catEl.addEventListener('change',function(){ renderIndustrySubs(false); }); }
@@ -782,14 +782,18 @@ test("APP 场景零自备: 默认场景=APP + 服务商素材复用提交组装
782
782
  } finally { srv.close(); }
783
783
  });
784
784
 
785
- test("APP 场景页面: 默认选中 APP + 字段组 + 复用勾选 + 4 截图槽", async () => {
785
+ test("APP 场景页面: 默认选中 APP + 三态显隐 (配齐全隐藏/未配提示/自有展开)", async () => {
786
786
  const { srv, base } = await startSeller();
787
787
  try {
788
788
  const html = await (await fetch(base + "/onboard/")).text();
789
789
  assert.ok(html.includes('value="SALES_SCENES_APP" checked'), "默认场景=APP");
790
790
  assert.ok(html.includes("scene_fields_app"), "APP 字段组");
791
791
  assert.ok(html.includes("a_app_appid") && html.includes("a_app_provider"), "AppID + 归属");
792
- assert.ok(html.includes("a_app_reuse") && html.includes("使用服务商提供的应用截图"), "素材复用勾选");
792
+ assert.ok(html.includes("a_app_provided") && html.includes("无需操作"), "零操作绿标");
793
+ assert.ok(html.includes("a_app_missing") && html.includes("尚未配置应用"), "未配提示");
794
+ assert.ok(html.includes("appSpComplete") && html.includes("maskAppid"), "完整度判定 + AppID 打码");
795
+ assert.ok(html.includes("a_appid_field"), "AppID 字段容器 (可整体隐藏)");
796
+ assert.ok(!html.includes("a_app_reuse"), "复用勾选已移除 (零自备=默认行为)");
793
797
  assert.ok(html.includes("a_up_s3") && html.includes("a_up_s4"), "4 截图槽");
794
798
  assert.ok(html.includes("paintAppScene"), "场景联动");
795
799
  assert.ok(html.includes("app_screenshots"), "提交字段");