@seasonkoh/webaz 0.1.28 → 0.1.29
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/README.md +3 -2
- package/README.zh-CN.md +7 -6
- package/dist/currency.js +16 -0
- package/dist/deposit-rails.js +52 -0
- package/dist/direct-pay-aml-monitor.js +67 -0
- package/dist/direct-pay-aml-review.js +40 -0
- package/dist/direct-pay-base-bond-entry.js +5 -0
- package/dist/direct-pay-bond-rail-clearance.js +94 -0
- package/dist/direct-pay-compliance-ingress.js +145 -0
- package/dist/direct-pay-controls.js +136 -0
- package/dist/direct-pay-create.js +162 -0
- package/dist/direct-pay-deferral-quota.js +43 -0
- package/dist/direct-pay-disclosures.js +44 -0
- package/dist/direct-pay-eligibility.js +46 -0
- package/dist/direct-pay-fee-ar.js +241 -0
- package/dist/direct-pay-launch-readiness.js +108 -0
- package/dist/direct-pay-launch-summary.js +68 -0
- package/dist/direct-pay-ledger.js +94 -0
- package/dist/direct-receive-account-qr.js +77 -0
- package/dist/direct-receive-accounts.js +82 -0
- package/dist/direct-receive-deferral.js +142 -0
- package/dist/direct-receive-deposits.js +260 -0
- package/dist/direct-receive-payment-instruction.js +26 -0
- package/dist/fx-rates.js +71 -0
- package/dist/layer0-foundation/L0-1-database/schema.js +531 -1
- package/dist/layer0-foundation/L0-2-state-machine/genuine-sale.js +15 -5
- package/dist/layer0-foundation/L0-2-state-machine/transitions.js +41 -0
- package/dist/layer0-foundation/L0-5-manifest/manifest.js +1 -1
- package/dist/layer1-agent/L1-1-mcp-server/cli.js +64 -0
- package/dist/layer1-agent/L1-1-mcp-server/network-mode.js +11 -0
- package/dist/layer1-agent/L1-1-mcp-server/server.js +18 -16
- package/dist/layer4-economics/L4-4-skill-market/skill-engine.js +4 -4
- package/dist/ledger.js +12 -3
- package/dist/mcp.js +23 -4
- package/dist/merchant-bond-domain.js +64 -0
- package/dist/merchant-bond-exposure.js +78 -0
- package/dist/merchant-bond-watcher.js +26 -0
- package/dist/payment-rails.js +29 -0
- package/dist/product-verification.js +93 -0
- package/dist/pwa/acp-feed.js +3 -2
- package/dist/pwa/contract-fingerprint.js +3 -0
- package/dist/pwa/direct-pay-guards.js +20 -0
- package/dist/pwa/direct-pay-order-redaction.js +24 -0
- package/dist/pwa/endpoint-actions.js +3 -0
- package/dist/pwa/public/app-ai.js +10 -10
- package/dist/pwa/public/app-chat-poll.js +29 -0
- package/dist/pwa/public/app-create-kinds.js +17 -0
- package/dist/pwa/public/app-direct-pay-accounts.js +141 -0
- package/dist/pwa/public/app-direct-pay-buyer.js +72 -0
- package/dist/pwa/public/app-direct-pay-compliance.js +67 -0
- package/dist/pwa/public/app-direct-pay-deferral-admin.js +72 -0
- package/dist/pwa/public/app-direct-pay-deferral.js +61 -0
- package/dist/pwa/public/app-direct-pay-fee-center.js +33 -0
- package/dist/pwa/public/app-direct-pay-fee-ops.js +112 -0
- package/dist/pwa/public/app-direct-pay-product-verify.js +103 -0
- package/dist/pwa/public/app-direct-pay-readiness.js +38 -0
- package/dist/pwa/public/app-direct-pay-store-verify.js +100 -0
- package/dist/pwa/public/app-direct-pay.js +227 -0
- package/dist/pwa/public/app-discover.js +20 -20
- package/dist/pwa/public/app-external-links.js +32 -0
- package/dist/pwa/public/app-listings.js +4 -4
- package/dist/pwa/public/app-prelaunch-waz.js +39 -0
- package/dist/pwa/public/app-price.js +55 -0
- package/dist/pwa/public/app-product-media.js +15 -0
- package/dist/pwa/public/app-profile.js +6 -6
- package/dist/pwa/public/app-seller.js +5 -5
- package/dist/pwa/public/app-shop.js +19 -19
- package/dist/pwa/public/app.js +142 -146
- package/dist/pwa/public/i18n.js +398 -197
- package/dist/pwa/public/index.html +17 -0
- package/dist/pwa/public/openapi.json +495 -1
- package/dist/pwa/routes/admin-analytics.js +4 -2
- package/dist/pwa/routes/admin-direct-receive-deposits.js +321 -0
- package/dist/pwa/routes/buyer-feeds.js +2 -1
- package/dist/pwa/routes/chat.js +6 -1
- package/dist/pwa/routes/dashboards.js +2 -1
- package/dist/pwa/routes/direct-pay-availability.js +196 -0
- package/dist/pwa/routes/direct-pay-disclosure-acks.js +74 -0
- package/dist/pwa/routes/direct-pay-timeouts.js +71 -0
- package/dist/pwa/routes/direct-receive-accounts.js +155 -0
- package/dist/pwa/routes/direct-receive-payment-instructions.js +45 -0
- package/dist/pwa/routes/fx.js +12 -0
- package/dist/pwa/routes/leaderboard.js +47 -9
- package/dist/pwa/routes/listings.js +2 -2
- package/dist/pwa/routes/logistics.js +4 -0
- package/dist/pwa/routes/manifests.js +38 -0
- package/dist/pwa/routes/me-data.js +5 -2
- package/dist/pwa/routes/orders-action.js +117 -9
- package/dist/pwa/routes/orders-create.js +4 -0
- package/dist/pwa/routes/orders-read.js +36 -0
- package/dist/pwa/routes/p2p-products.js +2 -2
- package/dist/pwa/routes/products-create.js +5 -3
- package/dist/pwa/routes/products-links.js +34 -0
- package/dist/pwa/routes/products-list.js +2 -1
- package/dist/pwa/routes/products-update.js +22 -2
- package/dist/pwa/routes/promoter.js +3 -0
- package/dist/pwa/routes/referral.js +4 -0
- package/dist/pwa/routes/returns.js +26 -1
- package/dist/pwa/routes/rewards-apply.js +10 -5
- package/dist/pwa/routes/rewards-clearing-mature.js +96 -0
- package/dist/pwa/routes/rewards-escrow-expire.js +6 -2
- package/dist/pwa/routes/shops.js +2 -1
- package/dist/pwa/routes/url-claim.js +2 -2
- package/dist/pwa/routes/users-public.js +8 -0
- package/dist/pwa/routes/wallet-read.js +3 -0
- package/dist/pwa/routes/webauthn.js +1 -1
- package/dist/pwa/server.js +59 -102
- package/dist/runtime/webaz-schema-helpers.js +104 -0
- package/dist/store-verification.js +77 -0
- package/dist/version.js +1 -1
- package/package.json +71 -2
package/dist/pwa/public/app.js
CHANGED
|
@@ -721,7 +721,7 @@ async function render(page, params) {
|
|
|
721
721
|
if (params[0] === 'public-ideas') return renderAdminPublicIdeas(app)
|
|
722
722
|
if (params[0] === 'task-proposals') return renderAdminTaskProposals(app)
|
|
723
723
|
if (params[0] === 'quota-requests') return renderAdminBuildTaskQuota(app)
|
|
724
|
-
if (params[0] === 'operator-claims') return renderAdminOperatorClaims(app)
|
|
724
|
+
if (params[0] === 'operator-claims') return renderAdminOperatorClaims(app); if (params[0] === 'deferrals') return renderAdminDirectPayDeferrals(app); if (params[0] === 'product-verifications') return renderAdminProductVerifications(app); if (params[0] === 'store-verifications') return renderAdminStoreVerifications(app); if (params[0] === 'compliance') return renderAdminDirectReceiveCompliance(app); if (params[0] === 'dp-ops') return renderAdminDirectPayHub(app); if (params[0] === 'dp-fee') return renderAdminDirectPayFeeOps(app) // PR-②c 缓交 / PR-④b 逐品 / PR-⑤b 店铺 / PR-⑧ 合规录入 / PR-B 商户运营 hub + 平台服务费
|
|
725
725
|
if (params[0] === 'params') return renderAdminParams(app)
|
|
726
726
|
if (params[0] === 'timeline' && params[1]) return renderAdminUserTimeline(app, params[1])
|
|
727
727
|
if (params[0] === 'timeline') return renderAdminUserTimelinePicker(app)
|
|
@@ -1017,7 +1017,7 @@ function roleHome(role) {
|
|
|
1017
1017
|
function preLaunchBannerHTML() {
|
|
1018
1018
|
if (window._protocolPhase && window._protocolPhase !== 'pre_launch') return ''
|
|
1019
1019
|
return `<div style="background:#fef3c7;border:1px solid #fde68a;border-radius:8px;padding:10px 14px;font-size:12px;color:#92400e;text-align:center;line-height:1.5;margin:8px 12px 12px">
|
|
1020
|
-
⚠️ <strong>${t('
|
|
1020
|
+
⚠️ <strong>${t('直付(direct pay)已上线,是你与卖家的真实场外付款;WebAZ 非托管——不代持、不担保、不退款 · 平台托管(escrow)尚未上线(模拟测试币)· 价格按 USDC 计价仅供展示 · 邀请制预发布,勿据此投资或向第三方承诺')}</strong>
|
|
1021
1021
|
<a href="#welcome" style="margin-left:8px;color:#7c2d12;text-decoration:underline;font-weight:600">${t('详情')}</a>
|
|
1022
1022
|
</div>`
|
|
1023
1023
|
}
|
|
@@ -2045,7 +2045,7 @@ window.adminUserBatch = async (action) => {
|
|
|
2045
2045
|
reason = prompt(t('暂停原因(必填,会写入审计)')) || ''
|
|
2046
2046
|
if (!reason.trim()) return alert(t('需填写原因'))
|
|
2047
2047
|
}
|
|
2048
|
-
if (!confirm(t('
|
|
2048
|
+
if (!confirm((action === 'suspend' ? t('确认暂停') : t('确认恢复')) + ' ' + ids.length + ' ' + t('个用户?'))) return
|
|
2049
2049
|
let ok = 0, fail = 0
|
|
2050
2050
|
for (const uid of ids) {
|
|
2051
2051
|
const path = action === 'suspend' ? `/admin/users/${uid}/suspend` : `/admin/users/${uid}/resume`
|
|
@@ -3378,7 +3378,7 @@ window.openResignModal = (role) => {
|
|
|
3378
3378
|
<li>${t('已 assigned 但未完成的 case 必须先完成 / 转交,否则无法卸任')}</li>
|
|
3379
3379
|
</ul>
|
|
3380
3380
|
</div>
|
|
3381
|
-
<div style="font-size:13px;color:#374151;margin-bottom:8px">${t('输入')} <code style="background:#fee2e2;padding:2px 6px;border-radius:4px;color:#991b1b">${expected}</code> ${t('
|
|
3381
|
+
<div style="font-size:13px;color:#374151;margin-bottom:8px">${t('输入')} <code style="background:#fee2e2;padding:2px 6px;border-radius:4px;color:#991b1b">${expected}</code> ${t('以确认')}:</div>
|
|
3382
3382
|
<input id="resign-confirm-input" type="text" placeholder="${expected}" style="width:100%;padding:8px;border:1px solid #d1d5db;border-radius:4px;font-family:monospace" oninput="document.getElementById('resign-submit-btn').disabled = this.value !== '${expected}'">
|
|
3383
3383
|
<div id="resign-msg" style="margin-top:12px"></div>
|
|
3384
3384
|
<div style="margin-top:16px;display:flex;gap:8px;justify-content:flex-end">
|
|
@@ -3505,7 +3505,7 @@ async function renderAdminGovernance(app) {
|
|
|
3505
3505
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px">
|
|
3506
3506
|
<div style="flex:1">
|
|
3507
3507
|
<div style="font-weight:600;font-size:14px">${a.role === 'arbitrator' ? '⚖' : '🛡'} ${escHtml(a.user_name || '')} <span style="color:#6b7280;font-size:12px">(${a.handle ? '@' + escHtml(a.handle) : a.user_id})</span></div>
|
|
3508
|
-
<div style="font-size:12px;color:#6b7280;margin-top:4px">${t('
|
|
3508
|
+
<div style="font-size:12px;color:#6b7280;margin-top:4px">${t('角色')}: ${roleLabel} · ${t('Region')}: ${escHtml(a.region || '—')} · ${t('Email')}: ${a.email ? '✓' : '✗'}</div>
|
|
3509
3509
|
<div style="font-size:12px;margin-top:6px;display:flex;gap:12px">
|
|
3510
3510
|
<span style="color:${quizOk ? '#16a34a' : '#dc2626'}">${quizOk ? '✓' : '✗'} ${t('题目')} ${a.quiz_score != null ? a.quiz_score + '%' : '—'}</span>
|
|
3511
3511
|
<span style="color:${caseOk ? '#16a34a' : '#dc2626'}">${caseOk ? '✓' : '✗'} ${t('案例 review')}</span>
|
|
@@ -3970,7 +3970,7 @@ async function renderAdminQuotaApps(app) {
|
|
|
3970
3970
|
<div style="font-weight:600">${escHtml(a.user_name)} <span style="font-size:11px;color:#6b7280">${a.email || ''}</span></div>
|
|
3971
3971
|
<div style="font-size:11px;color:#9ca3af;margin-top:2px">${a.user_id} · ${fmtTime(a.applied_at)}</div>
|
|
3972
3972
|
<div style="font-size:13px;margin-top:8px">
|
|
3973
|
-
${t('当前配额')}: <strong>${a.current_quota}</strong> → ${t('
|
|
3973
|
+
${t('当前配额')}: <strong>${a.current_quota}</strong> → ${t('申请配额')}: <strong>${a.requested_quota}</strong>
|
|
3974
3974
|
</div>
|
|
3975
3975
|
${a.reason ? `<div style="font-size:12px;color:#6b7280;margin-top:6px;padding:6px;background:#f9fafb;border-radius:4px">${escHtml(a.reason)}</div>` : ''}
|
|
3976
3976
|
<div style="display:flex;gap:6px;margin-top:10px">
|
|
@@ -4392,7 +4392,7 @@ function renderWelcome(app) {
|
|
|
4392
4392
|
<div style="min-height:100vh;background:#FFFFFF;font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','SF Pro Text','PingFang SC',sans-serif;-webkit-font-smoothing:antialiased;position:relative">
|
|
4393
4393
|
<!-- Top nav — frosted glass,左返回,右语言切换(当前语言高亮) -->
|
|
4394
4394
|
<div style="position:sticky;top:0;z-index:10;display:flex;justify-content:space-between;align-items:center;padding:14px 18px;background:rgba(255,255,255,0.85);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);border-bottom:1px solid #E4E4E7">
|
|
4395
|
-
<button class="w-nav-back" onclick="navigate('#
|
|
4395
|
+
<button class="w-nav-back" onclick="navigate('#buy')" style="background:none;border:none;cursor:pointer;font-size:14px;color:#3F3F46;padding:6px 10px;font-weight:500;transition:color 0.15s;font-family:inherit">← ${T('返回首页', 'Back to Home')}</button>
|
|
4396
4396
|
<span class="w-lang" style="font-size:13px;font-weight:500">
|
|
4397
4397
|
<span class="${en ? 'w-lang-inactive' : 'w-lang-active'}" ${en ? `onclick="toggleLang();renderWelcome(document.getElementById('app'))"` : ''}>中文</span>
|
|
4398
4398
|
<span class="w-lang-sep">/</span>
|
|
@@ -5473,7 +5473,7 @@ async function renderPromoter(app) {
|
|
|
5473
5473
|
<div class="card" style="text-align:center;padding:10px 6px">
|
|
5474
5474
|
<div style="font-size:11px;color:#6b7280">💰 ${t('累计收益')}</div>
|
|
5475
5475
|
<div style="font-size:17px;font-weight:700;color:#059669;margin-top:2px">${totalEarnings.toFixed(2)}</div>
|
|
5476
|
-
<div style="font-size:10px;color:#9ca3af">WAZ</div>
|
|
5476
|
+
<div style="font-size:10px;color:#9ca3af">WAZ</div>${(data.earnings?.clearing_total||0)>0?`<div style="font-size:9px;color:#9ca3af;margin-top:1px" title="${t('清算中:退货期满后到账')}">${t('清算中')} ${Number(data.earnings.clearing_total).toFixed(2)}</div>`:''}
|
|
5477
5477
|
</div>
|
|
5478
5478
|
<div class="card" style="text-align:center;padding:10px 6px">
|
|
5479
5479
|
<div style="font-size:11px;color:#6b7280">📊 ${t('近 30 日')}</div>
|
|
@@ -5558,9 +5558,7 @@ async function renderPromoter(app) {
|
|
|
5558
5558
|
const ratioPct = cs.clicks.raw > 0 ? Math.round((cs.clicks.unique / cs.clicks.raw) * 100) : null
|
|
5559
5559
|
// 我买过的(合并进"我的产品分享"作为商品来源子列表)
|
|
5560
5560
|
const bought = shareHub.bought_products || []
|
|
5561
|
-
const buildProductImg = (images) =>
|
|
5562
|
-
try { const arr = typeof images === 'string' ? JSON.parse(images) : (images || []); return arr[0] || '' } catch { return '' }
|
|
5563
|
-
}
|
|
5561
|
+
const buildProductImg = (images) => window.productThumbSrc ? window.productThumbSrc(images) : ''
|
|
5564
5562
|
const renderBoughtRow = (p) => {
|
|
5565
5563
|
const img = buildProductImg(p.images)
|
|
5566
5564
|
const rate = Number(p.commission_rate || 0)
|
|
@@ -5586,7 +5584,7 @@ async function renderPromoter(app) {
|
|
|
5586
5584
|
|
|
5587
5585
|
return `
|
|
5588
5586
|
<div id="bought-${orderId || p.id}" style="display:flex;gap:8px;align-items:center;padding:8px 10px;border:${isHighlight ? '2px solid #4f46e5' : '1px solid #f3f4f6'};border-radius:8px;margin-bottom:6px;background:${isHighlight ? '#eef2ff' : '#fff'}">
|
|
5589
|
-
${img ? `<img src="${escHtml(img)}" style="width:36px;height:36px;border-radius:6px;object-fit:cover;flex-shrink:0">` : `<div style="width:36px;height:36px;background:#f3f4f6;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0">📦</div>`}
|
|
5587
|
+
${img ? `<img src="${escHtml(img)}" onerror="this.outerHTML='📦'" style="width:36px;height:36px;border-radius:6px;object-fit:cover;flex-shrink:0">` : `<div style="width:36px;height:36px;background:#f3f4f6;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0">📦</div>`}
|
|
5590
5588
|
<div style="flex:1;min-width:0">
|
|
5591
5589
|
<div style="font-size:12px;font-weight:600;color:#1f2937;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(p.title)}</div>
|
|
5592
5590
|
<div style="font-size:10px;color:#9ca3af;margin-top:1px">
|
|
@@ -6325,8 +6323,6 @@ async function renderReviewsFeed(app) {
|
|
|
6325
6323
|
const rows = items.length === 0
|
|
6326
6324
|
? `<div style="text-align:center;padding:40px;color:#9ca3af"><div style="font-size:48px">📺</div><div style="font-size:13px;margin-top:8px">${t('暂无评测内容')}</div></div>`
|
|
6327
6325
|
: items.map(s => {
|
|
6328
|
-
let prodImg = ''
|
|
6329
|
-
try { const imgs = typeof s.product_images === 'string' ? JSON.parse(s.product_images) : s.product_images; if (Array.isArray(imgs) && imgs[0]) prodImg = imgs[0] } catch {}
|
|
6330
6326
|
return `
|
|
6331
6327
|
<div class="card" style="padding:10px 12px;margin-bottom:8px;cursor:pointer" onclick="openExternalReview('${s.id}', '${escHtml(s.external_url || '').replace(/'/g, "\\'")}')">
|
|
6332
6328
|
<div style="display:flex;gap:10px;align-items:center">
|
|
@@ -6334,7 +6330,7 @@ async function renderReviewsFeed(app) {
|
|
|
6334
6330
|
<div style="flex:1;min-width:0">
|
|
6335
6331
|
<div style="font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical">${escHtml(s.title || s.external_url || '(无标题)')}</div>
|
|
6336
6332
|
<div style="font-size:11px;color:#9ca3af;margin-top:2px">@${escHtml(s.owner_handle || s.owner_name || '?')} · ${s.click_count} 👁 · ❤ ${s.like_count || 0} · ${fmtTime(s.created_at)}</div>
|
|
6337
|
-
${s.product_title ? `<div style="font-size:11px;color:#6366f1;margin-top:2px">📦 ${escHtml(s.product_title)} · ${s.product_price}
|
|
6333
|
+
${s.product_title ? `<div style="font-size:11px;color:#6366f1;margin-top:2px">📦 ${escHtml(s.product_title)} · ${window.fmtPrice(s.product_price)}</div>` : ''}
|
|
6338
6334
|
</div>
|
|
6339
6335
|
</div>
|
|
6340
6336
|
</div>`
|
|
@@ -6448,20 +6444,16 @@ window.lookupAnchorAction = async () => {
|
|
|
6448
6444
|
// 商品区块
|
|
6449
6445
|
const productBlock = (r.product) ? (() => {
|
|
6450
6446
|
const p = r.product
|
|
6451
|
-
let img =
|
|
6452
|
-
try {
|
|
6453
|
-
const imgs = typeof p.images === 'string' ? JSON.parse(p.images) : p.images
|
|
6454
|
-
if (Array.isArray(imgs) && imgs[0]) img = String(imgs[0])
|
|
6455
|
-
} catch {}
|
|
6447
|
+
let img = window.productThumbSrc(p.images)
|
|
6456
6448
|
const idx = calcIndex(p)
|
|
6457
6449
|
const idxColor = idx == null ? '#9ca3af' : idx >= 8 ? '#dc2626' : idx >= 6 ? '#f59e0b' : '#6b7280'
|
|
6458
6450
|
return `
|
|
6459
6451
|
<div style="border:1px solid #e5e7eb;border-radius:8px;padding:12px;margin-bottom:10px">
|
|
6460
6452
|
<div style="display:flex;gap:10px;margin-bottom:10px">
|
|
6461
|
-
${img ? `<img src="${img}" style="width:64px;height:64px;object-fit:cover;border-radius:6px;flex-shrink:0">` : `<div style="width:64px;height:64px;background:#f3f4f6;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:24px;color:#9ca3af;flex-shrink:0">📦</div>`}
|
|
6453
|
+
${img ? `<img src="${escHtml(img)}" onerror="this.outerHTML='📦'" style="width:64px;height:64px;object-fit:cover;border-radius:6px;flex-shrink:0">` : `<div style="width:64px;height:64px;background:#f3f4f6;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:24px;color:#9ca3af;flex-shrink:0">📦</div>`}
|
|
6462
6454
|
<div style="flex:1;min-width:0">
|
|
6463
6455
|
<div style="font-size:14px;font-weight:600;color:#1f2937;line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden">${escHtml(p.title)}</div>
|
|
6464
|
-
<div style="font-size:17px;font-weight:800;color:#dc2626;margin-top:4px">${
|
|
6456
|
+
<div style="font-size:17px;font-weight:800;color:#dc2626;margin-top:4px">${window.fmtPrice(p.price)}</div>
|
|
6465
6457
|
<div style="font-size:11px;color:#6b7280;margin-top:2px">@${escHtml(p.seller_handle || p.seller_name?.slice(0,8) || '?')}</div>
|
|
6466
6458
|
</div>
|
|
6467
6459
|
</div>
|
|
@@ -6514,17 +6506,17 @@ async function renderGroupBuysLive(app) {
|
|
|
6514
6506
|
? `<div style="text-align:center;padding:40px;color:#9ca3af"><div style="font-size:48px">👥</div><div style="font-size:13px;margin-top:8px">${t('暂无进行中的团购')}</div></div>`
|
|
6515
6507
|
: items.map(it => {
|
|
6516
6508
|
let imageUrl = ''
|
|
6517
|
-
|
|
6509
|
+
imageUrl = window.productThumbSrc(it.images) || imageUrl
|
|
6518
6510
|
const pct = (Number(it.discount_pct) * 100).toFixed(0)
|
|
6519
6511
|
const final = (Number(it.original_price) * (1 - Number(it.discount_pct))).toFixed(2)
|
|
6520
6512
|
const progress = Math.min(100, (Number(it.joined_count) / Number(it.target_count)) * 100)
|
|
6521
6513
|
return `
|
|
6522
6514
|
<div class="card" style="padding:12px;margin-bottom:8px;cursor:pointer;border-left:3px solid #16a34a" onclick="location.hash='#group-buy/${it.id}'">
|
|
6523
6515
|
<div style="display:flex;gap:10px;align-items:center;margin-bottom:8px">
|
|
6524
|
-
<div style="font-size:32px;flex-shrink:0">${imageUrl ? `<img src="${escHtml(imageUrl)}" style="width:48px;height:48px;border-radius:6px;object-fit:cover">` : getCategoryIcon(it.category) || '📦'}</div>
|
|
6516
|
+
<div style="font-size:32px;flex-shrink:0">${imageUrl ? `<img src="${escHtml(imageUrl)}" onerror="this.outerHTML='📦'" style="width:48px;height:48px;border-radius:6px;object-fit:cover">` : getCategoryIcon(it.category) || '📦'}</div>
|
|
6525
6517
|
<div style="flex:1;min-width:0">
|
|
6526
6518
|
<div style="font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(it.product_title)}</div>
|
|
6527
|
-
<div style="font-size:12px;margin-top:2px"><span style="color:#16a34a;font-weight:700">${final}</span>
|
|
6519
|
+
<div style="font-size:12px;margin-top:2px"><span style="color:#16a34a;font-weight:700">${window.fmtPrice(final)}</span> <span style="font-size:10px;color:#9ca3af;text-decoration:line-through margin-left:4px">${it.original_price} USDC</span> <span style="font-size:10px;color:#16a34a;background:#dcfce7;padding:1px 5px;border-radius:99px;margin-left:4px;font-weight:600">-${pct}%</span></div>
|
|
6528
6520
|
<div style="font-size:10px;color:#9ca3af;margin-top:2px">@${escHtml(it.seller_handle || '')} · ${t('截止')} ${fmtTime(it.ends_at)}</div>
|
|
6529
6521
|
</div>
|
|
6530
6522
|
</div>
|
|
@@ -6562,7 +6554,7 @@ async function renderGroupBuyDetail(app, id) {
|
|
|
6562
6554
|
<h1 class="page-title">👥 ${escHtml(r.product_title)}</h1>
|
|
6563
6555
|
<div class="card" style="background:linear-gradient(135deg,#ecfdf5,#fff);padding:14px;margin-bottom:10px">
|
|
6564
6556
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
|
|
6565
|
-
<div><div style="font-size:24px;font-weight:800;color:#16a34a">${final}
|
|
6557
|
+
<div><div style="font-size:24px;font-weight:800;color:#16a34a">${window.fmtPrice(final)}</div><div style="font-size:11px;color:#9ca3af;text-decoration:line-through">${r.original_price} USDC</div></div>
|
|
6566
6558
|
<div style="font-size:18px;font-weight:700;color:#16a34a;background:#dcfce7;padding:6px 12px;border-radius:8px">-${pct}%</div>
|
|
6567
6559
|
</div>
|
|
6568
6560
|
<div style="font-size:12px;color:#374151;margin-bottom:4px">${t('已成团')} <strong>${joined}/${r.target_count}</strong> · ${t('剩余时间')} ${remainingStr}</div>
|
|
@@ -6572,7 +6564,7 @@ async function renderGroupBuyDetail(app, id) {
|
|
|
6572
6564
|
: expired ? `<div style="color:#9ca3af">${t('已结束,等待结算')}</div>`
|
|
6573
6565
|
: isOwn ? `<div style="color:#9ca3af">${t('自己开的团,等待成团')}</div>`
|
|
6574
6566
|
: isParticipant ? `<button class="btn btn-outline btn-sm" style="width:100%;color:#dc2626;border-color:#fca5a5" onclick="leaveGroupBuy('${r.id}')">${t('退出团购')}</button>`
|
|
6575
|
-
: state.user?.role === 'buyer' ? `<button class="btn btn-primary" style="width:100%" onclick="openJoinGroupBuy('${r.id}')">+ ${t('加入团购')} (${r.original_price}
|
|
6567
|
+
: state.user?.role === 'buyer' ? `<button class="btn btn-primary" style="width:100%" onclick="openJoinGroupBuy('${r.id}')">+ ${t('加入团购')} (${window.fmtPrice(r.original_price)} ${t('预付')})</button>`
|
|
6576
6568
|
: `<div style="color:#9ca3af">${t('仅买家可加入')}</div>`}
|
|
6577
6569
|
</div>
|
|
6578
6570
|
<div style="font-size:13px;font-weight:600;margin:14px 0 8px">${t('已加入')} (${joined})</div>
|
|
@@ -6647,7 +6639,7 @@ async function renderSellerFlashSales(app) {
|
|
|
6647
6639
|
<div style="font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60%">${escHtml(it.product_title)}</div>
|
|
6648
6640
|
<span style="font-size:10px;font-weight:600;color:#fff;background:${phaseColor};padding:2px 8px;border-radius:99px">${phaseLabel}</span>
|
|
6649
6641
|
</div>
|
|
6650
|
-
<div style="font-size:12px;color:#374151">${it.sale_price}
|
|
6642
|
+
<div style="font-size:12px;color:#374151">${window.fmtPrice(it.sale_price)} <span style="font-size:11px;color:#9ca3af;text-decoration:line-through;margin-left:4px">${it.original_price} USDC</span></div>
|
|
6651
6643
|
<div style="font-size:11px;color:#9ca3af;margin-top:2px">${fmtTime(it.starts_at)} → ${fmtTime(it.ends_at)}${it.max_qty > 0 ? ' · ' + t('已售') + ' ' + it.sold_count + '/' + it.max_qty : ''}</div>
|
|
6652
6644
|
${phase === 'scheduled' ? `<button class="btn btn-outline btn-sm" style="margin-top:6px;font-size:10px;padding:3px 8px;color:#dc2626;border-color:#fca5a5" onclick="deleteFlashSale('${it.id}')">${t('取消')}</button>` : ''}
|
|
6653
6645
|
</div>`
|
|
@@ -6810,7 +6802,7 @@ window.aiSuggestPrice = async () => {
|
|
|
6810
6802
|
if (res.error) { if (hint) hint.innerHTML = '<span style="color:#dc2626">' + escHtml(res.error) + '</span>'; return }
|
|
6811
6803
|
const priceInp = document.getElementById('ep-price')
|
|
6812
6804
|
if (hint) {
|
|
6813
|
-
hint.innerHTML = `💡 ${t('
|
|
6805
|
+
hint.innerHTML = `💡 ${t('建议价')} <strong style="color:#16a34a;cursor:pointer;text-decoration:underline" onclick="document.getElementById('ep-price').value=${res.suggested_price}">${res.suggested_price}</strong> WAZ · ${t('区间')} ${res.low_price}-${res.high_price} · ${escHtml(res.reasoning || '')}`
|
|
6814
6806
|
}
|
|
6815
6807
|
}
|
|
6816
6808
|
|
|
@@ -6904,10 +6896,10 @@ async function renderReferral(app) {
|
|
|
6904
6896
|
|
|
6905
6897
|
<div class="card" style="background:linear-gradient(135deg,#ecfdf5,#fff);padding:14px;margin-bottom:10px">
|
|
6906
6898
|
<div style="font-size:13px;font-weight:600;margin-bottom:8px">💰 ${t('邀请收益')}</div>
|
|
6907
|
-
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px;text-align:center">
|
|
6899
|
+
<div style="display:grid;grid-template-columns:repeat(${Number(e.clearing_waz||0)>0?4:3},1fr);gap:8px;text-align:center">
|
|
6908
6900
|
<div><div style="font-size:18px;font-weight:700;color:#16a34a">${Number(e.total_waz || 0).toFixed(2)}</div><div style="font-size:10px;color:#9ca3af">${t('累计收益')}</div></div>
|
|
6909
6901
|
<div><div style="font-size:18px;font-weight:700;color:#4f46e5">${Number(e.month_waz || 0).toFixed(2)}</div><div style="font-size:10px;color:#9ca3af">${t('近 30 天')}</div></div>
|
|
6910
|
-
<div><div style="font-size:18px;font-weight:700;color:#d97706">${Number(e.today_waz || 0).toFixed(2)}</div><div style="font-size:10px;color:#9ca3af">${t('今日')}</div></div>
|
|
6902
|
+
<div><div style="font-size:18px;font-weight:700;color:#d97706">${Number(e.today_waz || 0).toFixed(2)}</div><div style="font-size:10px;color:#9ca3af">${t('今日')}</div></div>${Number(e.clearing_waz||0)>0?`<div><div style="font-size:18px;font-weight:700;color:#9ca3af" title="${t('清算中:退货期满后到账')}">${Number(e.clearing_waz).toFixed(2)}</div><div style="font-size:10px;color:#9ca3af">${t('清算中')}</div></div>`:''}
|
|
6911
6903
|
</div>
|
|
6912
6904
|
<div style="font-size:10px;color:#9ca3af;margin-top:6px;text-align:center">${e.total_records} ${t('条记录')} · WAZ</div>
|
|
6913
6905
|
</div>
|
|
@@ -8065,7 +8057,7 @@ async function renderFollowFeed(app) {
|
|
|
8065
8057
|
: items.map(it => {
|
|
8066
8058
|
const meta = TYPE_META[it.type] || { icon: '·', label: it.type, color: '#6b7280' }
|
|
8067
8059
|
let imageUrl = ''
|
|
8068
|
-
|
|
8060
|
+
imageUrl = window.productThumbSrc(it.images) || imageUrl
|
|
8069
8061
|
return `
|
|
8070
8062
|
<div class="card" style="padding:10px 12px;margin-bottom:8px;cursor:pointer" onclick="location.hash='#order-product/${it.product_id}'">
|
|
8071
8063
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">
|
|
@@ -8076,10 +8068,10 @@ async function renderFollowFeed(app) {
|
|
|
8076
8068
|
<span style="font-size:10px;color:#9ca3af">${fmtTime(it.ts)}</span>
|
|
8077
8069
|
</div>
|
|
8078
8070
|
<div style="display:flex;gap:10px;align-items:center">
|
|
8079
|
-
<div style="font-size:28px;flex-shrink:0">${imageUrl ? `<img src="${escHtml(imageUrl)}" style="width:48px;height:48px;border-radius:6px;object-fit:cover">` : getCategoryIcon(it.category) || '📦'}</div>
|
|
8071
|
+
<div style="font-size:28px;flex-shrink:0">${imageUrl ? `<img src="${escHtml(imageUrl)}" onerror="this.outerHTML='📦'" style="width:48px;height:48px;border-radius:6px;object-fit:cover">` : getCategoryIcon(it.category) || '📦'}</div>
|
|
8080
8072
|
<div style="flex:1;min-width:0">
|
|
8081
8073
|
<div style="font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(it.title)}</div>
|
|
8082
|
-
<div style="font-size:13px;color:#4f46e5;margin-top:2px;font-weight:600">${it.price}
|
|
8074
|
+
<div style="font-size:13px;color:#4f46e5;margin-top:2px;font-weight:600">${window.fmtPrice(it.price)} <span style="font-size:11px;color:#9ca3af;font-weight:400">· ${stockBadgeHtml(it)}</span></div>
|
|
8083
8075
|
</div>
|
|
8084
8076
|
</div>
|
|
8085
8077
|
</div>`
|
|
@@ -9176,7 +9168,7 @@ function renderShareBanner(variant) {
|
|
|
9176
9168
|
const tgtKind = ctx.target_kind
|
|
9177
9169
|
const tgtLine = tgt
|
|
9178
9170
|
? (tgtKind === 'product'
|
|
9179
|
-
? `🎁 <strong>${escHtml(tgt.title)}</strong> · ${tgt.price}
|
|
9171
|
+
? `🎁 <strong>${escHtml(tgt.title)}</strong> · ${window.fmtPrice(tgt.price)} <span style="color:#9ca3af">@ ${escHtml(tgt.seller_name)}</span>`
|
|
9180
9172
|
: tgtKind === 'user'
|
|
9181
9173
|
? `👤 <strong>${escHtml(tgt.name)}</strong>${tgt.bio ? ` · ${escHtml(tgt.bio).slice(0, 40)}` : ''}`
|
|
9182
9174
|
: '')
|
|
@@ -10137,7 +10129,7 @@ async function renderBuyPage(app, productId) {
|
|
|
10137
10129
|
const bottomBar = canBuy ? `
|
|
10138
10130
|
<div style="display:flex;gap:8px;align-items:center">
|
|
10139
10131
|
<div style="flex:0 0 auto">
|
|
10140
|
-
<div style="font-size:18px;font-weight:800;color:#dc2626;line-height:1">${livePrice}
|
|
10132
|
+
<div style="font-size:18px;font-weight:800;color:#dc2626;line-height:1">${window.fmtPrice(livePrice)}</div>
|
|
10141
10133
|
${state._flashSale ? `<div style="font-size:10px;color:#9ca3af;text-decoration:line-through">${p.price}</div>` : ''}
|
|
10142
10134
|
</div>
|
|
10143
10135
|
<button class="btn btn-outline" onclick="addToCart('${p.id}')" style="width:auto;padding:11px 14px;font-size:13px" title="${t('加入购物车')}">🛒+</button>
|
|
@@ -10151,18 +10143,18 @@ async function renderBuyPage(app, productId) {
|
|
|
10151
10143
|
${originBadge}
|
|
10152
10144
|
<div class="card">
|
|
10153
10145
|
${productImageGallery(p)}
|
|
10154
|
-
<h2 style="font-size:18px;font-weight:700;margin-bottom:6px">${escHtml(p.title)}</h2
|
|
10146
|
+
<h2 style="font-size:18px;font-weight:700;margin-bottom:6px">${escHtml(p.title)}</h2>${window.extLinksBarHtml ? window.extLinksBarHtml(productId) : ''}
|
|
10155
10147
|
${state._flashSale ? `
|
|
10156
10148
|
<div style="background:linear-gradient(135deg,#dc2626,#f59e0b);color:#fff;border-radius:8px;padding:8px 12px;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center">
|
|
10157
10149
|
<div>
|
|
10158
10150
|
<div style="font-size:10px;font-weight:600;opacity:0.9">⚡ ${t('限时')}</div>
|
|
10159
|
-
<div style="font-size:18px;font-weight:800">${state._flashSale.sale_price}
|
|
10151
|
+
<div style="font-size:18px;font-weight:800">${window.fmtPrice(state._flashSale.sale_price)} <span style="font-size:11px;font-weight:400;text-decoration:line-through;opacity:0.7">${p.price} USDC</span></div>
|
|
10160
10152
|
</div>
|
|
10161
10153
|
<div style="text-align:right;font-size:10px;opacity:0.9">${t('截止')}<br><span style="font-size:11px;font-weight:600">${fmtTime(state._flashSale.ends_at)}</span></div>
|
|
10162
10154
|
</div>` : `
|
|
10163
10155
|
<div style="display:flex;align-items:baseline;gap:8px;margin-bottom:8px">
|
|
10164
10156
|
<span style="font-size:22px;font-weight:800;color:#dc2626">${p.price}</span>
|
|
10165
|
-
<span style="font-size:12px;color:#6b7280">
|
|
10157
|
+
<span style="font-size:12px;color:#6b7280" data-usdc-local="${p.price}">USDC${window._fxLocal(p.price) ? ' ≈ ' + window._fxLocal(p.price) : ''}</span>
|
|
10166
10158
|
</div>`}
|
|
10167
10159
|
${Number(p.trial_quota_remaining) > 0 ? `
|
|
10168
10160
|
<div style="background:linear-gradient(135deg,#faf5ff,#f3e8ff);border:1px solid #e9d5ff;border-radius:8px;padding:10px 12px;margin-bottom:10px">
|
|
@@ -10322,7 +10314,7 @@ async function renderBuyPage(app, productId) {
|
|
|
10322
10314
|
offers: {
|
|
10323
10315
|
'@type': 'Offer',
|
|
10324
10316
|
price: p.price,
|
|
10325
|
-
priceCurrency:
|
|
10317
|
+
priceCurrency: 'USDC', // display/pricing unit (USDC≈USD); matches the human USDC display (PR-1c)
|
|
10326
10318
|
availability: (Number(p.stock) || 0) > 0 ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock',
|
|
10327
10319
|
url: location.origin + '/#order-product/' + p.id,
|
|
10328
10320
|
seller: { '@type': 'Organization', '@id': location.origin + '/#u/' + p.seller_id, name: p.seller_name || p.seller_handle || p.seller_id },
|
|
@@ -10366,14 +10358,14 @@ window.openBuySheet = function(productId) {
|
|
|
10366
10358
|
const summary = hasDefault ? buildAddrString(defaultAddr) : ''
|
|
10367
10359
|
const max = buyMaxFor(prod)
|
|
10368
10360
|
const variants = state._variants || []
|
|
10369
|
-
const firstImg =
|
|
10361
|
+
const firstImg = window.productThumbSrc(prod.images)
|
|
10370
10362
|
|
|
10371
10363
|
const html = `
|
|
10372
10364
|
<div style="display:flex;gap:10px;align-items:center;padding-bottom:12px;border-bottom:1px solid #f3f4f6">
|
|
10373
|
-
${firstImg ? `<img src="${escHtml(firstImg)}" style="width:64px;height:64px;border-radius:8px;object-fit:cover;flex-shrink:0">` : `<div style="width:64px;height:64px;background:#f3f4f6;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:24px;flex-shrink:0">📦</div>`}
|
|
10365
|
+
${firstImg ? `<img src="${escHtml(firstImg)}" onerror="this.outerHTML='📦'" style="width:64px;height:64px;border-radius:8px;object-fit:cover;flex-shrink:0">` : `<div style="width:64px;height:64px;background:#f3f4f6;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:24px;flex-shrink:0">📦</div>`}
|
|
10374
10366
|
<div style="flex:1;min-width:0">
|
|
10375
10367
|
<div style="font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(prod.title)}</div>
|
|
10376
|
-
<div style="font-size:18px;font-weight:800;color:#dc2626;margin-top:2px">${livePrice}
|
|
10368
|
+
<div style="font-size:18px;font-weight:800;color:#dc2626;margin-top:2px">${window.fmtPrice(livePrice)}</div>
|
|
10377
10369
|
</div>
|
|
10378
10370
|
${variants.length === 0 && max > 0 ? `
|
|
10379
10371
|
<div style="display:flex;align-items:center;gap:6px;flex-shrink:0">
|
|
@@ -10471,11 +10463,12 @@ window.openBuySheet = function(productId) {
|
|
|
10471
10463
|
</div>
|
|
10472
10464
|
</details>
|
|
10473
10465
|
|
|
10466
|
+
${window.dpRailSelectorHtml ? window.dpRailSelectorHtml(prod.id, prod.price) : ''}
|
|
10474
10467
|
<div id="buy-msg" style="margin-top:10px"></div>
|
|
10475
10468
|
<div id="tax-preview-slot" style="margin-top:8px"></div>
|
|
10476
10469
|
|
|
10477
10470
|
<div style="position:sticky;bottom:0;left:0;right:0;background:#fff;padding-top:12px;margin-top:12px;border-top:1px solid #f3f4f6">
|
|
10478
|
-
<button class="btn btn-primary" id="btn-doBuy" onclick="doBuy('${prod.id}', ${livePrice})
|
|
10471
|
+
<button class="btn btn-primary" id="btn-doBuy" onclick="doBuy('${prod.id}', ${livePrice})" style="width:100%;padding:14px;font-size:15px;font-weight:700">${t('确认下单')} · ${window.fmtPrice(livePrice)}</button>
|
|
10479
10472
|
</div>
|
|
10480
10473
|
`
|
|
10481
10474
|
openSheet(html, { title: t('下单') })
|
|
@@ -11246,6 +11239,7 @@ window.qtyStep = (delta, max) => {
|
|
|
11246
11239
|
const cur = Math.floor(Number(inp.value) || 1)
|
|
11247
11240
|
const next = Math.max(1, Math.min(max, cur + delta))
|
|
11248
11241
|
inp.value = next
|
|
11242
|
+
if (window.dpRenderAccountFx) window.dpRenderAccountFx() // D3:数量变→刷新分账号 FX(按订单总额,非单价)
|
|
11249
11243
|
}
|
|
11250
11244
|
|
|
11251
11245
|
// B5 捐赠 chip 选择 — 高亮当前选中 + 更新提示文案
|
|
@@ -11275,6 +11269,7 @@ window.qtyClamp = (max) => {
|
|
|
11275
11269
|
if (!Number.isFinite(v) || v < 1) v = 1
|
|
11276
11270
|
if (v > max) v = max
|
|
11277
11271
|
inp.value = v
|
|
11272
|
+
if (window.dpRenderAccountFx) window.dpRenderAccountFx() // D3:数量变→刷新分账号 FX(按订单总额,非单价)
|
|
11278
11273
|
}
|
|
11279
11274
|
|
|
11280
11275
|
window.doBuy = async (productId, price) => {
|
|
@@ -11315,9 +11310,11 @@ window.doBuy = async (productId, price) => {
|
|
|
11315
11310
|
// 数量(默认 1)— 服务端会再校验 stock + MAX_PER_ORDER
|
|
11316
11311
|
const qtyInp = document.getElementById('inp-qty')
|
|
11317
11312
|
const quantity = qtyInp ? Math.max(1, Math.min(Number(qtyInp.max) || 1, Math.floor(Number(qtyInp.value) || 1))) : 1
|
|
11318
|
-
const
|
|
11313
|
+
const payment_rail = window.dpSelectedRail ? window.dpSelectedRail() : 'escrow'; if (!payment_rail) { const _dp=document.querySelector('input[name="dp-rail"]:checked')?.value==='direct_p2p'; const _m=document.getElementById('buy-msg'); if(_m) _m.innerHTML = alert$('error', _dp ? t('直付暂未就绪或不可用,请稍候重试或改选支付方式') : t('请选择支付方式')); const _b=document.getElementById('dp-rail-block'); if(_b) _b.open=true; return } if (window.closeSheet) window.closeSheet() // #28 空 rail 一律拦(永不静默落 escrow);[PRELAUNCH-WAZ-SIM] 未选→空;校验通过才关 sheet(块内 return 不关→提示+展开可见,修 P2)
|
|
11314
|
+
const res = await POST('/orders', { product_id: productId, shipping_address: addr, notes, sponsor_hint, coupon_code, delivery_window, variant_id, expected_price, buy_insurance, anonymous_recipient, donation_pct, quantity, payment_rail, direct_receive_account_id: (payment_rail === 'direct_p2p' && window.dpSelectedAccountId) ? (window.dpSelectedAccountId() || undefined) : undefined, ...giftPayload })
|
|
11315
|
+
if (payment_rail === 'direct_p2p') return void (window.dpAfterCreate && window.dpAfterCreate(res))
|
|
11319
11316
|
if (res.error_code === 'PRICE_CHANGED') {
|
|
11320
|
-
document.getElementById('buy-msg').innerHTML = alert$('error', `${t('价格已变动')}:${res.old_price} → ${res.new_price}
|
|
11317
|
+
document.getElementById('buy-msg').innerHTML = alert$('error', `${t('价格已变动')}:${window.fmtPrice(res.old_price)} → ${window.fmtPrice(res.new_price)} · ${t('请刷新页面')}`)
|
|
11321
11318
|
return
|
|
11322
11319
|
}
|
|
11323
11320
|
if (res.error) { document.getElementById('buy-msg').innerHTML = alert$('error', res.error); return }
|
|
@@ -11339,11 +11336,11 @@ window.checkCoupon = async (productId, basePrice) => {
|
|
|
11339
11336
|
const r = await GET(`/coupons/preview?code=${encodeURIComponent(code)}&product_id=${productId}`)
|
|
11340
11337
|
if (!r.ok) {
|
|
11341
11338
|
resultEl.innerHTML = `<span style="color:#dc2626">✗ ${escHtml(r.error || t('优惠码无效'))}</span>`
|
|
11342
|
-
if (btnEl) btnEl.innerHTML = `${t('立即下单')} · ${basePrice}
|
|
11339
|
+
if (btnEl) btnEl.innerHTML = `${t('立即下单')} · ${window.fmtPrice(basePrice)}`
|
|
11343
11340
|
return
|
|
11344
11341
|
}
|
|
11345
|
-
resultEl.innerHTML = `<span style="color:#16a34a">✓ ${t('已优惠')} ${r.discount}
|
|
11346
|
-
if (btnEl) btnEl.innerHTML = `${t('立即下单')} · ${r.final_price}
|
|
11342
|
+
resultEl.innerHTML = `<span style="color:#16a34a">✓ ${t('已优惠')} ${window.fmtPrice(r.discount)} · ${t('最终')} ${window.fmtPrice(r.final_price)}</span>`
|
|
11343
|
+
if (btnEl) btnEl.innerHTML = `${t('立即下单')} · ${window.fmtPrice(r.final_price)} <span style="font-size:10px;text-decoration:line-through;opacity:0.7">${basePrice} USDC</span>`
|
|
11347
11344
|
}
|
|
11348
11345
|
|
|
11349
11346
|
// ─── P13: 购物车页 ────────────────────────────────────────────
|
|
@@ -12441,9 +12438,10 @@ async function renderOrderDetail(app, orderId) {
|
|
|
12441
12438
|
|
|
12442
12439
|
// 操作按钮
|
|
12443
12440
|
const actions = getActions(order, isBuyer, isSeller, isLogistic)
|
|
12441
|
+
window._dpOrderRail = order.payment_rail // direct_p2p:路由 mark_paid/confirm 到 Passkey 门(动作在渲染后触发,早设即可);hydrate 移到最终 app.innerHTML 之后(见下)——在此调度会撞 claim-task 的 await 间隙、#dp-order-instr 尚未渲染而 if(!box) 静默 bail → 框永久"加载中"
|
|
12444
12442
|
|
|
12445
12443
|
const STATUS_ZH = {
|
|
12446
|
-
created:'待付款', paid:'待接单', accepted:'待发货', shipped:'已发货',
|
|
12444
|
+
created:'待付款', direct_pay_window:'直付待付款', direct_expired_unconfirmed:'直付超时未确认', paid:'待接单', accepted:'待发货', shipped:'已发货',
|
|
12447
12445
|
picked_up:'已揽收', in_transit:'运输中', delivered:'待确认',
|
|
12448
12446
|
confirmed:'已确认', completed:'已完成', disputed:'争议中',
|
|
12449
12447
|
cancelled:'已取消', fault_seller:'卖家违约', fault_buyer:'买家违约', fault_logistics:'物流违约',
|
|
@@ -12451,7 +12449,7 @@ async function renderOrderDetail(app, orderId) {
|
|
|
12451
12449
|
|
|
12452
12450
|
const historyHtml = (history || []).map(h => `
|
|
12453
12451
|
<div class="timeline-item">
|
|
12454
|
-
<div><span class="timeline-status">${STATUS_ZH[h.from_status] || h.from_status} → ${STATUS_ZH[h.to_status] || h.to_status}</span></div>
|
|
12452
|
+
<div><span class="timeline-status">${t(STATUS_ZH[h.from_status] || h.from_status)} → ${t(STATUS_ZH[h.to_status] || h.to_status)}</span></div>
|
|
12455
12453
|
<div class="timeline-actor">${h.actor_name}(${h.actor_role_name || h.actor_role})</div>
|
|
12456
12454
|
<div class="timeline-time">${fmtTime(h.created_at)}</div>
|
|
12457
12455
|
${h.notes ? `<div class="timeline-evidence" style="color:#6b7280">💬 ${h.notes}</div>` : ''}
|
|
@@ -12501,7 +12499,7 @@ async function renderOrderDetail(app, orderId) {
|
|
|
12501
12499
|
</div>
|
|
12502
12500
|
</div>
|
|
12503
12501
|
|
|
12504
|
-
${orderStageTimeline(order, history)}
|
|
12502
|
+
${window.wazEscrowOrderBanner ? window.wazEscrowOrderBanner(order, isBuyer) : ''}${orderStageTimeline(order, history)}
|
|
12505
12503
|
${nextActionCard(order, isBuyer, isSeller, activeDeadline, isOverdue)}
|
|
12506
12504
|
|
|
12507
12505
|
<div class="card">
|
|
@@ -12525,6 +12523,7 @@ async function renderOrderDetail(app, orderId) {
|
|
|
12525
12523
|
${order.content_hash_at_order ? `<div class="detail-row"><span class="detail-label">🔒 ${t('P2P 内容哈希')}</span><span class="detail-value" style="font-family:monospace;font-size:11px;word-break:break-all">${escHtml(order.content_hash_at_order)}</span></div>` : ''}
|
|
12526
12524
|
${activeDeadline?.deadline ? `<div class="detail-row"><span class="detail-label">${t('截止')}</span><span class="detail-value" style="color:${isOverdue ? '#dc2626' : '#6b7280'};font-size:12px">${fmtTime(activeDeadline.deadline)}</span></div>` : ''}
|
|
12527
12525
|
</div>
|
|
12526
|
+
${order.payment_rail === 'direct_p2p' && window.dpOrderDisclosureHtml ? window.dpOrderDisclosureHtml(order) : ''}
|
|
12528
12527
|
|
|
12529
12528
|
${trackingHtml}
|
|
12530
12529
|
${disputeHtml}
|
|
@@ -12591,7 +12590,7 @@ async function renderOrderDetail(app, orderId) {
|
|
|
12591
12590
|
<div class="action-title">${t('完整状态历史')}</div>
|
|
12592
12591
|
<div class="timeline">${historyHtml || `<div style="color:#6b7280;font-size:13px">${t('暂无记录')}</div>`}</div>
|
|
12593
12592
|
</div>
|
|
12594
|
-
`, 'orders')
|
|
12593
|
+
`, 'orders'); if (order.payment_rail === 'direct_p2p' && window.dpHydrateOrderDisclosure) window.dpHydrateOrderDisclosure(order.id) // direct_p2p:最终 DOM 已就位,#dp-order-instr 必命中(both-acked→收款说明快照;否则 D1/D2 门;非买家→错误提示)。退货/评价 widget 注入各自子容器,不动此框
|
|
12595
12594
|
|
|
12596
12595
|
// Wave B-3: 退货 widget — 异步加载(仅 completed 订单可退)
|
|
12597
12596
|
// 买家:有退货窗口可申请/查看;卖家:有退货申请时内联查看+处理(accept/reject/received),无申请则隐藏卡
|
|
@@ -13214,10 +13213,10 @@ window.selectVariantOption = (dim, val, basePrice) => {
|
|
|
13214
13213
|
const stockTag = Number(match.stock) > 0
|
|
13215
13214
|
? `<span style="color:#16a34a">● ${t('有货')}</span>`
|
|
13216
13215
|
: `<span style="color:#dc2626">${t('缺货')}</span>`
|
|
13217
|
-
summary.innerHTML = `✓ ${price}
|
|
13216
|
+
summary.innerHTML = `✓ ${window.fmtPrice(price)} · ${stockTag}`
|
|
13218
13217
|
if (buyBtn) {
|
|
13219
13218
|
buyBtn.disabled = Number(match.stock) <= 0
|
|
13220
|
-
buyBtn.innerHTML = `${t('立即下单')} · ${price}
|
|
13219
|
+
buyBtn.innerHTML = `${t('立即下单')} · ${window.fmtPrice(price)}`
|
|
13221
13220
|
}
|
|
13222
13221
|
}
|
|
13223
13222
|
|
|
@@ -13422,37 +13421,26 @@ function getActions(order, isBuyer, isSeller, isLogistic) {
|
|
|
13422
13421
|
const s = order.status
|
|
13423
13422
|
const isInPerson = order.fulfillment_mode === 'in_person'
|
|
13424
13423
|
const isSelfFulfillSeller = isSeller && !order.logistics_id
|
|
13424
|
+
// 直付(direct_p2p):买家在 direct_pay_window 标记"我已付款"(Passkey 门) 或取消(不门控);其余阶段沿用通用规则
|
|
13425
|
+
if (order.payment_rail === 'direct_p2p' && isBuyer && s === 'direct_pay_window')
|
|
13426
|
+
return [{ action: 'mark_paid', label: '✅ 我已付款', style: 'success' }, { action: 'cancel', label: '取消订单', style: 'secondary' }]
|
|
13425
13427
|
// M8 面交订单:买家在 paid / accepted 都可"面交完成"直接结算
|
|
13426
|
-
if (isInPerson && isBuyer && (s === 'paid' || s === 'accepted'))
|
|
13428
|
+
if (isInPerson && isBuyer && (s === 'paid' || s === 'accepted'))
|
|
13427
13429
|
return [{ action: 'confirm_in_person', label: '🤝 面交完成 / 确认收货', style: 'success' }]
|
|
13428
|
-
}
|
|
13429
13430
|
if (isSeller && s === 'paid')
|
|
13430
|
-
return [
|
|
13431
|
-
{ action: 'accept', label: '接单', style: 'success' },
|
|
13432
|
-
{ action: 'decline', label: '拒绝接单', style: 'danger', custom: 'decline' },
|
|
13433
|
-
]
|
|
13431
|
+
return [{ action: 'accept', label: '接单', style: 'success' }, { action: 'decline', label: '拒绝接单', style: 'danger', custom: 'decline' }]
|
|
13434
13432
|
if (isSeller && s === 'accepted' && !isInPerson)
|
|
13435
|
-
return [{ action: 'ship', label: '确认发货', style: 'success', logisticsSelector: true,
|
|
13436
|
-
trackingInput: true,
|
|
13437
|
-
evidencePlaceholder: '包装状态描述 / 货物说明(可选)' }]
|
|
13433
|
+
return [{ action: 'ship', label: '确认发货', style: 'success', logisticsSelector: true, trackingInput: true, evidencePlaceholder: '包装状态描述 / 货物说明(可选)' }]
|
|
13438
13434
|
if (isSeller && s === 'accepted' && isInPerson)
|
|
13439
13435
|
return [{ action: 'noop_in_person', label: '🤝 面交中(等待买家确认)', style: 'secondary', disabled: true }]
|
|
13440
13436
|
if ((isLogistic || isSelfFulfillSeller) && s === 'shipped')
|
|
13441
|
-
return [{ action: 'pickup', label: '✅ 确认揽收', style: 'success', needsEvidence: true,
|
|
13442
|
-
noteLabel: '快递单号 *', evidencePlaceholder: '如:SF1234567890',
|
|
13443
|
-
helperText: isSelfFulfillSeller ? '自履约订单:你负责回传揽收/单号,超时仍按卖家责任处理。' : '' }]
|
|
13437
|
+
return [{ action: 'pickup', label: '✅ 确认揽收', style: 'success', needsEvidence: true, noteLabel: '快递单号 *', evidencePlaceholder: '如:SF1234567890', helperText: isSelfFulfillSeller ? '自履约订单:你负责回传揽收/单号,超时仍按卖家责任处理。' : '' }]
|
|
13444
13438
|
if ((isLogistic || isSelfFulfillSeller) && s === 'picked_up')
|
|
13445
13439
|
return [{ action: 'transit', label: '🚛 开始运输', style: 'primary' }]
|
|
13446
13440
|
if ((isLogistic || isSelfFulfillSeller) && s === 'in_transit')
|
|
13447
|
-
return [{ action: 'deliver', label: '📬 确认投递', style: 'success', needsEvidence: true,
|
|
13448
|
-
noteLabel: '投递凭证', evidencePlaceholder: '门牌照片描述 / 收件人姓名 / 签收时间',
|
|
13449
|
-
helperText: isSelfFulfillSeller ? '自履约投递需留存签收/门牌/交付说明,买家确认后才结算。' : '' }]
|
|
13441
|
+
return [{ action: 'deliver', label: '📬 确认投递', style: 'success', needsEvidence: true, noteLabel: '投递凭证', evidencePlaceholder: '门牌照片描述 / 收件人姓名 / 签收时间', helperText: isSelfFulfillSeller ? '自履约投递需留存签收/门牌/交付说明,买家确认后才结算。' : '' }]
|
|
13450
13442
|
if (isBuyer && s === 'delivered')
|
|
13451
|
-
return [
|
|
13452
|
-
{ action: 'confirm', label: '确认收货', style: 'success' },
|
|
13453
|
-
{ action: 'dispute', label: '发起争议', style: 'danger', needsEvidence: true,
|
|
13454
|
-
noteLabel: '争议理由', evidencePlaceholder: '描述问题(货不对版/货损/未收到等)' },
|
|
13455
|
-
]
|
|
13443
|
+
return [{ action: 'confirm', label: '确认收货', style: 'success' }, { action: 'dispute', label: '发起争议', style: 'danger', needsEvidence: true, noteLabel: '争议理由', evidencePlaceholder: '描述问题(货不对版/货损/未收到等)' }]
|
|
13456
13444
|
return null
|
|
13457
13445
|
}
|
|
13458
13446
|
|
|
@@ -13507,6 +13495,8 @@ function renderActions(orderId, actions, order, logisticsCompanies = []) {
|
|
|
13507
13495
|
|
|
13508
13496
|
window.handleAction = async (orderId, action, idx, needsEvidence, hasLogisticsSelector) => {
|
|
13509
13497
|
const msgEl = document.getElementById('action-msg')
|
|
13498
|
+
// 直付:买家 mark_paid/confirm/confirm_in_person 是 RISK 动作 → 走两次披露 + Passkey 门(后端硬强制)
|
|
13499
|
+
if (window._dpOrderRail === 'direct_p2p' && ['mark_paid', 'confirm', 'confirm_in_person'].includes(action)) return void (window.dpHandleAction && window.dpHandleAction(orderId, action))
|
|
13510
13500
|
|
|
13511
13501
|
// M8 面交确认:走专用端点,跳过物流状态机
|
|
13512
13502
|
if (action === 'confirm_in_person') {
|
|
@@ -13757,13 +13747,13 @@ function evidenceRequestCard(req, currentUserId) {
|
|
|
13757
13747
|
// evidence_types 存为 JSON 数组字符串
|
|
13758
13748
|
let types = []
|
|
13759
13749
|
try { types = typeof req.evidence_types === 'string' ? JSON.parse(req.evidence_types) : (req.evidence_types || []) } catch(e) {}
|
|
13760
|
-
const typeLabels = types.map(
|
|
13750
|
+
const typeLabels = types.map(et => `${EVIDENCE_TYPE_ICONS[et] || ''}${t(EVIDENCE_TYPE_LABELS[et] || et)}`).join(' ')
|
|
13761
13751
|
|
|
13762
13752
|
const submittedHtml = (req.submitted_items || []).length > 0 ? `
|
|
13763
13753
|
<div style="margin-top:8px">
|
|
13764
13754
|
${req.submitted_items.map(it => `
|
|
13765
13755
|
<div style="background:#f0fdf4;border-radius:6px;padding:6px 8px;margin-top:4px;font-size:12px">
|
|
13766
|
-
<span style="color:#6b7280">${EVIDENCE_TYPE_ICONS[it.type] || ''} ${EVIDENCE_TYPE_LABELS[it.type]
|
|
13756
|
+
<span style="color:#6b7280">${EVIDENCE_TYPE_ICONS[it.type] || ''} ${EVIDENCE_TYPE_LABELS[it.type] ? t(EVIDENCE_TYPE_LABELS[it.type]) : escHtml(it.type)}</span>
|
|
13767
13757
|
<div style="margin-top:2px">${escHtml(it.description)}</div>
|
|
13768
13758
|
${it.file_hash ? `<div style="margin-top:3px;font-family:monospace;font-size:10px;color:#9ca3af" title="Phase 0 模拟锚点,Phase 2 替换为 IPFS CID / 链上 TX">🔒 ${escHtml(it.file_hash)}</div>` : ''}
|
|
13769
13759
|
</div>`).join('')}
|
|
@@ -13771,26 +13761,26 @@ function evidenceRequestCard(req, currentUserId) {
|
|
|
13771
13761
|
|
|
13772
13762
|
const submitForm = isMe && req.status === 'pending' ? `
|
|
13773
13763
|
<div id="er-form-${req.id}" style="margin-top:10px;background:#fffbeb;border-radius:8px;padding:10px">
|
|
13774
|
-
<div style="font-size:12px;font-weight:600;color:#92400e;margin-bottom:6px"
|
|
13764
|
+
<div style="font-size:12px;font-weight:600;color:#92400e;margin-bottom:6px">${t('提交所需证据')}</div>
|
|
13775
13765
|
<div id="er-msg-${req.id}"></div>
|
|
13776
13766
|
<select class="form-control" id="er-type-${req.id}" style="margin-bottom:6px;font-size:13px">
|
|
13777
|
-
<option value=""
|
|
13778
|
-
${types.map(
|
|
13767
|
+
<option value="">${t('— 选择证据类型 —')}</option>
|
|
13768
|
+
${types.map(et => `<option value="${et}">${EVIDENCE_TYPE_ICONS[et]} ${t(EVIDENCE_TYPE_LABELS[et] || et)}</option>`).join('')}
|
|
13779
13769
|
</select>
|
|
13780
13770
|
<textarea class="form-control" id="er-desc-${req.id}" placeholder="${t('详细描述内容(如图片描述、文字陈述、链上 TX hash 等)')}" style="margin-bottom:6px;font-size:13px"></textarea>
|
|
13781
|
-
<input class="form-control" id="er-hash-${req.id}" placeholder="(可选)文件哈希 / IPFS CID / 链上 TX ID" style="margin-bottom:6px;font-size:12px;font-family:monospace">
|
|
13782
|
-
<button class="btn btn-primary btn-sm" style="width:auto" onclick="handleSubmitEvidence('${req.id}','${req.dispute_id}')"
|
|
13771
|
+
<input class="form-control" id="er-hash-${req.id}" placeholder="${t('(可选)文件哈希 / IPFS CID / 链上 TX ID')}" style="margin-bottom:6px;font-size:12px;font-family:monospace">
|
|
13772
|
+
<button class="btn btn-primary btn-sm" style="width:auto" onclick="handleSubmitEvidence('${req.id}','${req.dispute_id}')">${t('提交证据')}</button>
|
|
13783
13773
|
</div>` : ''
|
|
13784
13774
|
|
|
13785
13775
|
return `
|
|
13786
13776
|
<div style="border:1px solid ${isMe && req.status === 'pending' ? '#f59e0b' : '#e5e7eb'};border-radius:8px;padding:10px;margin-top:8px;background:${isMe && req.status === 'pending' ? '#fffdf0' : '#fff'}">
|
|
13787
13777
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:4px">
|
|
13788
|
-
<div style="font-size:13px;font-weight:600">${isMe ? '👤 需要你提供' :
|
|
13778
|
+
<div style="font-size:13px;font-weight:600">${isMe ? t('👤 需要你提供') : `${t('请求')} → ${req.requested_from_name || t('对方')}(${req.requested_from_role || ''})`}</div>
|
|
13789
13779
|
${erStatusBadge(req.status)}
|
|
13790
13780
|
</div>
|
|
13791
|
-
<div style="font-size:12px;color:#6b7280;margin-bottom:4px"
|
|
13781
|
+
<div style="font-size:12px;color:#6b7280;margin-bottom:4px">${t('类型:')}${typeLabels}</div>
|
|
13792
13782
|
${req.description ? `<div style="font-size:13px;margin-bottom:4px">${req.description}</div>` : ''}
|
|
13793
|
-
<div style="font-size:11px;color:#9ca3af"
|
|
13783
|
+
<div style="font-size:11px;color:#9ca3af">${t('截止:')}${fmtTime(req.deadline)}</div>
|
|
13794
13784
|
${submittedHtml}
|
|
13795
13785
|
${submitForm}
|
|
13796
13786
|
</div>`
|
|
@@ -13811,7 +13801,7 @@ const TL_ROLE_META = {
|
|
|
13811
13801
|
}
|
|
13812
13802
|
const TL_TYPE_META = {
|
|
13813
13803
|
open: { icon: '🚩', title: '发起争议', border: '#dc2626' },
|
|
13814
|
-
evidence: { icon: '📎', title: '
|
|
13804
|
+
evidence: { icon: '📎', title: '证据提交', border: '#3b82f6' },
|
|
13815
13805
|
response: { icon: '📝', title: '被告反驳', border: '#f59e0b' },
|
|
13816
13806
|
evidence_request: { icon: '📋', title: '仲裁员索证', border: '#a855f7' },
|
|
13817
13807
|
ruling: { icon: '🏛️', title: '仲裁裁决', border: '#6b21a8' },
|
|
@@ -13849,7 +13839,7 @@ function buildTimelineEvent(ev, dispute, user, actors) {
|
|
|
13849
13839
|
} else if (ev.type === 'evidence') {
|
|
13850
13840
|
const meta = ev.meta || {}
|
|
13851
13841
|
const typeIcon = EVIDENCE_TYPE_ICONS[meta.evidence_type] || '📎'
|
|
13852
|
-
const typeLabel = EVIDENCE_TYPE_LABELS[meta.evidence_type] || meta.evidence_type
|
|
13842
|
+
const typeLabel = t(EVIDENCE_TYPE_LABELS[meta.evidence_type] || meta.evidence_type)
|
|
13853
13843
|
const sizeKb = meta.size ? `${(Number(meta.size)/1024).toFixed(1)} KB` : ''
|
|
13854
13844
|
const blobChip = meta.has_blob ? `<a href="/api/evidence/${escHtml(meta.evidence_id)}/blob" target="_blank" style="display:inline-block;background:#eff6ff;color:#1d4ed8;padding:2px 8px;border-radius:99px;font-size:11px;text-decoration:none;margin-right:4px">📥 ${t('打开附件')}${sizeKb ? ' · '+sizeKb : ''}</a>` : ''
|
|
13855
13845
|
const hashChip = meta.file_hash ? `<span style="font-family:monospace;font-size:10px;color:#9ca3af;background:#f3f4f6;padding:1px 6px;border-radius:4px" title="${escHtml(meta.file_hash)}">🔒 ${escHtml(String(meta.file_hash).slice(0,12))}…</span>` : ''
|
|
@@ -13886,7 +13876,7 @@ function buildTimelineEvent(ev, dispute, user, actors) {
|
|
|
13886
13876
|
} else if (ev.type === 'ruling' || ev.type === 'resolved') {
|
|
13887
13877
|
const meta = ev.meta || {}
|
|
13888
13878
|
const rulingLabel = meta.ruling || meta.ruling_type
|
|
13889
|
-
const rulingText = rulingLabel ? (RULING_LABELS[rulingLabel] || rulingLabel) : ''
|
|
13879
|
+
const rulingText = rulingLabel ? t(RULING_LABELS[rulingLabel] || rulingLabel) : ''
|
|
13890
13880
|
let liability = []
|
|
13891
13881
|
try { liability = typeof meta.liability_parties === 'string' ? JSON.parse(meta.liability_parties) : (meta.liability_parties || []) } catch {}
|
|
13892
13882
|
bodyHtml = `
|
|
@@ -15391,7 +15381,7 @@ async function renderSeller(app) {
|
|
|
15391
15381
|
<div style="flex:1;min-width:0;cursor:pointer" onclick="navigate('#edit-product/${p.id}')">
|
|
15392
15382
|
<div style="font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${escHtml(p.title)}</div>
|
|
15393
15383
|
<div style="font-size:11px;color:#6b7280;margin-top:2px;display:flex;gap:8px;flex-wrap:wrap">
|
|
15394
|
-
<span><strong style="color:#374151">${p.price}</strong
|
|
15384
|
+
<span><strong style="color:#374151">${window.fmtPrice(p.price)}</strong></span>
|
|
15395
15385
|
<span style="color:${outOfStock?'#dc2626':lowStock?'#d97706':'#6b7280'}${outOfStock||lowStock?';font-weight:600':''}">${t('库存')} ${p.stock}${outOfStock?' ⛔':lowStock?' ⚠':''}</span>
|
|
15396
15386
|
${p.completion_count > 0 ? `<span>🛒 ${p.completion_count}</span>` : ''}
|
|
15397
15387
|
</div>
|
|
@@ -15424,7 +15414,7 @@ async function renderSeller(app) {
|
|
|
15424
15414
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px">
|
|
15425
15415
|
<div style="flex:1;min-width:0">
|
|
15426
15416
|
<div style="font-weight:600">${escHtml(p.title)}</div>
|
|
15427
|
-
<div style="font-size:13px;color:#6b7280;margin-top:2px">${p.price}
|
|
15417
|
+
<div style="font-size:13px;color:#6b7280;margin-top:2px">${window.fmtPrice(p.price)} · ${t('库存')} ${p.stock}</div>
|
|
15428
15418
|
${autoDelistedRecently ? `<div style="font-size:11px;color:#92400e;margin-top:2px;padding:4px 8px;background:#fef3c7;border-radius:6px;display:inline-block">📦 ${t('售罄自动下架')} · ${new Date(p.auto_delisted_at).toLocaleDateString()}</div>` : ''}
|
|
15429
15419
|
${p.has_pending_task ? `<div style="font-size:11px;color:#d97706;margin-top:2px">⏳ ${t('链接核验中,请等待验证结果')}</div>` : ''}
|
|
15430
15420
|
${p.all_links_revoked ? `<div style="font-size:11px;color:#ef4444;margin-top:2px">❌ ${t('所有链接已失效,请先添加新链接')}</div>` : ''}
|
|
@@ -15445,7 +15435,7 @@ async function renderSeller(app) {
|
|
|
15445
15435
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px">
|
|
15446
15436
|
<div style="flex:1;min-width:0">
|
|
15447
15437
|
<div style="font-weight:600;text-decoration:line-through;color:#9ca3af">${escHtml(p.title)}</div>
|
|
15448
|
-
<div style="font-size:13px;color:#d1d5db;margin-top:2px">${p.price}
|
|
15438
|
+
<div style="font-size:13px;color:#d1d5db;margin-top:2px">${window.fmtPrice(p.price)}</div>
|
|
15449
15439
|
</div>
|
|
15450
15440
|
<div style="display:flex;gap:6px;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end">
|
|
15451
15441
|
<span class="badge badge-red">${t('回收箱')}</span>
|
|
@@ -15516,8 +15506,10 @@ async function renderSeller(app) {
|
|
|
15516
15506
|
${subTabBtn('products', '📦 ' + t('商品'))}
|
|
15517
15507
|
${subTabBtn('marketing', '💎 ' + t('营销'))}
|
|
15518
15508
|
${subTabBtn('skills', '⚡ ' + t('Skill'))}
|
|
15509
|
+
${subTabBtn('settings', '⚙️ ' + t('设置'))}
|
|
15519
15510
|
</div>
|
|
15520
15511
|
`
|
|
15512
|
+
const settingsSection = sellerSubTab === 'settings' ? ((window.dpSellerReadinessSection ? window.dpSellerReadinessSection() : '') + (window.dpSellerFeeSection ? window.dpSellerFeeSection() : '') + (window.dpSellerDeferralSection ? window.dpSellerDeferralSection() : '') + (window.dpSellerProductVerifySection ? window.dpSellerProductVerifySection() : '') + (window.dpSellerStoreVerifySection ? window.dpSellerStoreVerifySection() : '') + (window.dpSellerInstructionSection ? window.dpSellerInstructionSection() : '') + (window.draAccountsSection ? window.draAccountsSection() : '')) : ''
|
|
15521
15513
|
|
|
15522
15514
|
// 数据中心区块(30 天聚合 — 销售曲线 / Top 商品 / 客户洞察 / 状态分布)
|
|
15523
15515
|
const insightsBlock = insights ? renderInsightsBlock(insights) : ''
|
|
@@ -15600,6 +15592,7 @@ async function renderSeller(app) {
|
|
|
15600
15592
|
${marketingSection}
|
|
15601
15593
|
${skillsSection}
|
|
15602
15594
|
${productsSection}
|
|
15595
|
+
${settingsSection}
|
|
15603
15596
|
|
|
15604
15597
|
<!-- 商品分类标签页(仅 products sub-tab 下显示)-->
|
|
15605
15598
|
${sellerSubTab === 'products' ? `
|
|
@@ -15657,7 +15650,7 @@ async function renderSeller(app) {
|
|
|
15657
15650
|
<div class="form-group"><label class="form-label">${t('规格参数')}<span style="font-size:11px;color:#9ca3af;font-weight:400;margin-left:6px">${t('每行:材质: 陶瓷')}</span></label>
|
|
15658
15651
|
<textarea class="form-control" id="imp-specs" rows="3"></textarea></div>
|
|
15659
15652
|
<div style="display:flex;gap:12px">
|
|
15660
|
-
<div class="form-group" style="flex:1"><label class="form-label">${t('价格(
|
|
15653
|
+
<div class="form-group" style="flex:1"><label class="form-label">${t('价格(USDC)')}</label><input class="form-control" id="imp-price" type="number"></div>
|
|
15661
15654
|
<div class="form-group" style="flex:1"><label class="form-label">${t('库存')}</label><input class="form-control" id="imp-stock" type="number" value="1"></div>
|
|
15662
15655
|
</div>
|
|
15663
15656
|
<div id="imp-price-hint" style="font-size:12px;color:#059669;margin:-8px 0 12px;padding:8px 12px;background:#f0fdf4;border-radius:6px;display:none"></div>
|
|
@@ -15688,7 +15681,7 @@ async function renderSeller(app) {
|
|
|
15688
15681
|
<div id="add-product-form" style="display:none">
|
|
15689
15682
|
<div class="divider"></div>
|
|
15690
15683
|
<div class="card">
|
|
15691
|
-
<div style="font-weight:700;margin-bottom:16px">${t('上架新商品')}</div>
|
|
15684
|
+
${window.createKindChooserHtml ? window.createKindChooserHtml('new') : ''}<div style="font-weight:700;margin-bottom:16px">${t('上架新商品')}</div>
|
|
15692
15685
|
<div id="add-msg"></div>
|
|
15693
15686
|
<div id="seo-score-bar-prd"></div> <!-- #1052 SEO 友好度评分,setupSeoScoreBar('prd') 启用 -->
|
|
15694
15687
|
|
|
@@ -15711,7 +15704,7 @@ async function renderSeller(app) {
|
|
|
15711
15704
|
<div class="form-group"><label class="form-label">${t('商品描述')} *<span style="font-size:11px;color:#9ca3af;font-weight:400;margin-left:6px">${t('面向 Agent 检索,写核心参数而非营销语言')}</span></label>
|
|
15712
15705
|
<textarea class="form-control" id="prd-desc" rows="3" placeholder="${t('材质、尺寸、颜色、适用场景...')}"></textarea></div>
|
|
15713
15706
|
<div style="display:flex;gap:12px">
|
|
15714
|
-
<div class="form-group" style="flex:1"><label class="form-label">${t('价格(
|
|
15707
|
+
<div class="form-group" style="flex:1"><label class="form-label">${t('价格(USDC)')} *</label><input class="form-control" id="prd-price" type="number" placeholder="199" oninput="updateTrialCost()"></div>
|
|
15715
15708
|
<div class="form-group" style="flex:1"><label class="form-label">${t('库存')}</label><input class="form-control" id="prd-stock" type="number" value="1"></div>
|
|
15716
15709
|
</div>
|
|
15717
15710
|
|
|
@@ -15726,7 +15719,7 @@ async function renderSeller(app) {
|
|
|
15726
15719
|
|
|
15727
15720
|
<div class="form-group"><label class="form-label">${t('规格参数')}<span style="font-size:11px;color:#9ca3af;font-weight:400;margin-left:6px">${t('每行一个,格式:材质: 陶瓷')}</span></label>
|
|
15728
15721
|
<textarea class="form-control" id="prd-specs" rows="3" placeholder="${t('材质: 陶瓷 容量: 350ml 颜色: 白色')}"></textarea></div>
|
|
15729
|
-
|
|
15722
|
+
<div class="form-group"><label class="form-label">${t('商品类型')}</label><select class="form-control" id="prd-type"><option value="retail">${t('零售')}</option><option value="wholesale">${t('批发')}</option><option value="service">${t('服务')}</option><option value="digital">${t('数字')}</option></select></div>
|
|
15730
15723
|
<div style="display:flex;gap:12px">
|
|
15731
15724
|
<div class="form-group" style="flex:1"><label class="form-label">${t('分类')}</label>
|
|
15732
15725
|
<select class="form-control" id="prd-cat">
|
|
@@ -15739,7 +15732,7 @@ async function renderSeller(app) {
|
|
|
15739
15732
|
<div class="form-group" style="flex:1"><label class="form-label">${t('备货时间(小时)')}</label>
|
|
15740
15733
|
<input class="form-control" id="prd-handling" type="number" value="24" min="1"></div>
|
|
15741
15734
|
</div>
|
|
15742
|
-
|
|
15735
|
+
<div style="display:flex;gap:12px"><div class="form-group" style="flex:1"><label class="form-label">${t('品牌')}</label><input class="form-control" id="prd-brand"></div><div class="form-group" style="flex:1"><label class="form-label">${t('型号')}</label><input class="form-control" id="prd-model"></div></div>
|
|
15743
15736
|
<details style="margin-bottom:16px">
|
|
15744
15737
|
<summary style="font-size:13px;color:#6b7280;cursor:pointer;padding:4px 0">${t('售后与物流(填写越完整,Agent 越优先选择你)')}</summary>
|
|
15745
15738
|
<div style="margin-top:12px;display:flex;gap:12px">
|
|
@@ -15759,7 +15752,7 @@ async function renderSeller(app) {
|
|
|
15759
15752
|
<label for="prd-fragile" style="font-size:13px">${t('易碎品,需特殊包装')}</label>
|
|
15760
15753
|
</div>
|
|
15761
15754
|
</details>
|
|
15762
|
-
|
|
15755
|
+
<div style="display:flex;gap:8px;align-items:center;margin-bottom:12px"><label class="form-label" style="margin:0;font-size:13px">${t('低库存阈值')}</label><input class="form-control" id="prd-low-stock" type="number" value="3" min="0" style="width:90px"><input type="checkbox" id="prd-auto-delist" checked style="width:16px;height:16px"><label for="prd-auto-delist" style="font-size:13px">${t('售罄自动下架')}</label></div>
|
|
15763
15756
|
<!-- 2026-05-24 #981:测评免单 (Trial Review Refund) -->
|
|
15764
15757
|
<details style="margin-bottom:16px" id="prd-trial-section">
|
|
15765
15758
|
<summary style="font-size:13px;color:#9333ea;cursor:pointer;padding:6px 0;font-weight:600">🎁 ${t('测评免单(新品冷启动)')} <span style="font-size:11px;color:#9ca3af;font-weight:400">${t('(买家原价下单 → 笔记达 reach 阈值后系统自动退款)')}</span></summary>
|
|
@@ -15851,6 +15844,7 @@ async function renderSeller(app) {
|
|
|
15851
15844
|
</div>
|
|
15852
15845
|
</div>
|
|
15853
15846
|
`, 'seller')
|
|
15847
|
+
if (sellerSubTab === 'settings') { window.dpHydrateInstruction && window.dpHydrateInstruction(); window.dpHydrateSellerReadiness && window.dpHydrateSellerReadiness(); window.dpHydrateSellerFee && window.dpHydrateSellerFee(); window.dpHydrateSellerDeferral && window.dpHydrateSellerDeferral(); window.dpHydrateSellerProductVerify && window.dpHydrateSellerProductVerify(); window.dpHydrateSellerStoreVerify && window.dpHydrateSellerStoreVerify(); window.draHydrateAccounts && window.draHydrateAccounts() }
|
|
15854
15848
|
|
|
15855
15849
|
// 智能下单"我也要上架"跳过来时:自动切到商品 tab + 展开手工上架表单 + 预填标题
|
|
15856
15850
|
// hashchange 可能多次触发 renderSeller — 用 window cache 保证每次重渲都能应用
|
|
@@ -16124,13 +16118,13 @@ window.doAddProduct = async () => {
|
|
|
16124
16118
|
const desc = document.getElementById('prd-desc').value.trim()
|
|
16125
16119
|
const price = Number(document.getElementById('prd-price').value)
|
|
16126
16120
|
const stock = Number(document.getElementById('prd-stock').value) || 1
|
|
16127
|
-
const category = document.getElementById('prd-cat').value
|
|
16121
|
+
const category = document.getElementById('prd-cat').value; const productType = document.getElementById('prd-type')?.value || 'retail'
|
|
16128
16122
|
const msgEl = document.getElementById('add-msg')
|
|
16129
16123
|
|
|
16130
16124
|
if (!title || !desc || !price) { msgEl.innerHTML = alert$('error', t('请填写商品名、描述、价格')); return }
|
|
16131
16125
|
|
|
16132
|
-
const extTitle = (document.getElementById('prd-ext-title')?.value || '').trim()
|
|
16133
|
-
const commissionPct = Number(document.getElementById('prd-commission')?.value || 10)
|
|
16126
|
+
const extTitle = (document.getElementById('prd-ext-title')?.value || '').trim(); const brand = (document.getElementById('prd-brand')?.value || '').trim(); const model = (document.getElementById('prd-model')?.value || '').trim()
|
|
16127
|
+
const commissionPct = Number(document.getElementById('prd-commission')?.value || 10); const lowStock = document.getElementById('prd-low-stock')?.value; const autoDelist = document.getElementById('prd-auto-delist')?.checked ? 1 : 0
|
|
16134
16128
|
if (!(commissionPct >= 1 && commissionPct <= 50)) {
|
|
16135
16129
|
msgEl.innerHTML = alert$('error', t('佣金比例需在 1%-50% 之间')); return
|
|
16136
16130
|
}
|
|
@@ -16138,7 +16132,7 @@ window.doAddProduct = async () => {
|
|
|
16138
16132
|
const checkedAliases = Array.from(document.querySelectorAll('#prd-alias-candidates input[type="checkbox"]:checked'))
|
|
16139
16133
|
.map(cb => ({ type: cb.dataset.type, value: cb.dataset.value }))
|
|
16140
16134
|
const payload = {
|
|
16141
|
-
title, description: desc, price, stock, category,
|
|
16135
|
+
title, description: desc, price, stock, category, product_type: productType, brand, model,
|
|
16142
16136
|
specs: parseSpecs(document.getElementById('prd-specs').value),
|
|
16143
16137
|
handling_hours: Number(document.getElementById('prd-handling').value) || 24,
|
|
16144
16138
|
ship_regions: document.getElementById('prd-ship-regions').value.trim() || '全国',
|
|
@@ -16146,7 +16140,7 @@ window.doAddProduct = async () => {
|
|
|
16146
16140
|
return_days: Number(document.getElementById('prd-return').value) ?? 7,
|
|
16147
16141
|
return_condition: document.getElementById('prd-return-cond').value.trim(),
|
|
16148
16142
|
warranty_days: Number(document.getElementById('prd-warranty').value) ?? 0,
|
|
16149
|
-
fragile: document.getElementById('prd-fragile').checked ? 1 : 0,
|
|
16143
|
+
fragile: document.getElementById('prd-fragile').checked ? 1 : 0, low_stock_threshold: lowStock === '' || lowStock == null ? undefined : Number(lowStock), auto_delist_on_zero: autoDelist,
|
|
16150
16144
|
commission_rate: commissionPct / 100,
|
|
16151
16145
|
...(extTitle ? { external_title: extTitle } : {}),
|
|
16152
16146
|
...(checkedAliases.length ? { aliases: checkedAliases } : {}),
|
|
@@ -16604,7 +16598,7 @@ async function renderEditProduct(app, productId) {
|
|
|
16604
16598
|
<div style="display:flex;gap:12px">
|
|
16605
16599
|
<div class="form-group" style="flex:1">
|
|
16606
16600
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
|
|
16607
|
-
<label class="form-label" style="margin:0">${t('价格(
|
|
16601
|
+
<label class="form-label" style="margin:0">${t('价格(USDC)')}</label>
|
|
16608
16602
|
<button class="btn btn-outline btn-sm" style="font-size:10px;padding:3px 8px;color:#16a34a;border-color:#86efac" onclick="aiSuggestPrice()">💰 ${t('AI 建议')}</button>
|
|
16609
16603
|
</div>
|
|
16610
16604
|
<input class="form-control" id="ep-price" type="number" value="${p.price || ''}">
|
|
@@ -17433,7 +17427,7 @@ async function doBatchBuy(urls, addr, auto) {
|
|
|
17433
17427
|
<span style="font-size:12px;font-weight:700;color:${recColor};white-space:nowrap">${recLabel}</span>
|
|
17434
17428
|
</div>
|
|
17435
17429
|
${res.best_product ? `<div style="margin-top:6px;font-size:12px;color:#16a34a;display:flex;align-items:center;gap:6px;flex-wrap:wrap">
|
|
17436
|
-
<span>${t('最佳替代')}:${escHtml(res.best_product.title)} · <strong>${res.best_product.price}
|
|
17430
|
+
<span>${t('最佳替代')}:${escHtml(res.best_product.title)} · <strong>${window.fmtPrice(res.best_product.price)}</strong></span>
|
|
17437
17431
|
<button class="btn btn-primary btn-sm" style="width:auto;padding:3px 10px;font-size:11px" onclick="navigate('#order-product/${res.best_product.id}')">${t('下单')}</button>
|
|
17438
17432
|
</div>` : ''}
|
|
17439
17433
|
${res.auto_bought ? `<div style="margin-top:6px;font-size:12px;color:#16a34a">✅ ${t('已自动下单')} <a href="#order/${res.order_id}" style="color:#16a34a;font-weight:600">${res.order_id}</a></div>` : ''}`
|
|
@@ -17648,7 +17642,7 @@ window.doAgentBuy = async () => {
|
|
|
17648
17642
|
const bestCard = res.best_product ? `
|
|
17649
17643
|
<div style="background:#f0fdf4;border:1px solid #bbf7d0;border-radius:10px;padding:12px;margin:12px 0">
|
|
17650
17644
|
<div style="font-weight:600;font-size:14px;margin-bottom:4px">${res.best_product.title}</div>
|
|
17651
|
-
<div style="font-size:18px;font-weight:700;color:#16a34a;margin-bottom:4px">${res.best_product.price}
|
|
17645
|
+
<div style="font-size:18px;font-weight:700;color:#16a34a;margin-bottom:4px">${window.fmtPrice(res.best_product.price)}</div>
|
|
17652
17646
|
<div style="font-size:12px;color:#6b7280;margin-bottom:8px">${res.best_product.agent_summary || ''}</div>
|
|
17653
17647
|
${!res.auto_bought ? `<button class="btn btn-primary btn-sm" style="width:auto" onclick="navigate('#order-product/${res.best_product.id}')">${t('查看并下单')}</button>` : ''}
|
|
17654
17648
|
</div>` : ''
|
|
@@ -17668,7 +17662,7 @@ window.doAgentBuy = async () => {
|
|
|
17668
17662
|
<div style="font-size:13px;font-weight:500">${p.url_match ? '🎯 ' : ''}${p.title}</div>
|
|
17669
17663
|
<div style="font-size:11px;color:#6b7280">${p.agent_summary || ''}${p.url_match ? ` · <span style="color:#16a34a">${t('同款商品')}</span>` : ''}</div>
|
|
17670
17664
|
</div>
|
|
17671
|
-
<div style="font-weight:700;color:#1d4ed8;white-space:nowrap;margin-left:8px">${p.price}
|
|
17665
|
+
<div style="font-weight:700;color:#1d4ed8;white-space:nowrap;margin-left:8px">${window.fmtPrice(p.price)}</div>
|
|
17672
17666
|
</div>`).join('')}
|
|
17673
17667
|
</div>` : ''
|
|
17674
17668
|
|
|
@@ -18349,7 +18343,7 @@ async function renderWallet(app) {
|
|
|
18349
18343
|
<div style="background:#ecfdf5;border-radius:6px;padding:8px">
|
|
18350
18344
|
<div style="font-size:9px;color:#065f46">📡 ${t('推荐分润')}</div>
|
|
18351
18345
|
<div style="font-size:14px;font-weight:700;color:#059669;margin-top:2px">${((inc.commissions?.l1?.total||0)+(inc.commissions?.l2?.total||0)+(inc.commissions?.l3?.total||0)).toFixed(2)}</div>
|
|
18352
|
-
<div style="font-size:9px;color:#9ca3af">${((inc.commissions?.l1?.count||0)+(inc.commissions?.l2?.count||0)+(inc.commissions?.l3?.count||0))} ${t('单')}</div>
|
|
18346
|
+
<div style="font-size:9px;color:#9ca3af">${((inc.commissions?.l1?.count||0)+(inc.commissions?.l2?.count||0)+(inc.commissions?.l3?.count||0))} ${t('单')}</div>${(inc.commission_clearing||0)>0?`<div style="font-size:8px;color:#9ca3af" title="${t('清算中:退货期满后到账')}">${t('清算中')} ${Number(inc.commission_clearing).toFixed(2)}</div>`:''}
|
|
18353
18347
|
</div>
|
|
18354
18348
|
<div style="background:#fef3c7;border-radius:6px;padding:8px">
|
|
18355
18349
|
<div style="font-size:9px;color:#92400e">⏳ ${t('待结算')}</div>
|
|
@@ -19848,7 +19842,7 @@ async function shInjectStrip(containerId, opts = {}) {
|
|
|
19848
19842
|
${it.cover ? `<img src="${escAttr(it.cover)}" style="width:100%;height:100%;object-fit:cover">` : `<div style="font-size:28px">${shCatIcon(it.category)}</div>`}
|
|
19849
19843
|
</div>
|
|
19850
19844
|
<div style="padding:6px">
|
|
19851
|
-
<div style="font-size:13px;font-weight:700;color:#dc2626">${
|
|
19845
|
+
<div style="font-size:13px;font-weight:700;color:#dc2626">${window.fmtPrice(it.price)}</div>
|
|
19852
19846
|
<div style="font-size:10px;color:#6b7280;line-height:1.3;margin-top:2px;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden">${escHtml(it.title)}</div>
|
|
19853
19847
|
<div style="font-size:9px;color:${cond.color};margin-top:3px;font-weight:600">${t(cond.label)}</div>
|
|
19854
19848
|
</div>
|
|
@@ -19874,8 +19868,8 @@ const SKM_KINDS = [
|
|
|
19874
19868
|
function skmKindMeta(k) { return SKM_KINDS.find(x => x.id === k) || { icon: '⚙️', label: k } }
|
|
19875
19869
|
function skmBillingLabel(mode, price) {
|
|
19876
19870
|
if (mode === 'free') return `🆓 ${t('免费')}`
|
|
19877
|
-
if (mode === 'per_use') return `🔁 ${
|
|
19878
|
-
return `💰 ${
|
|
19871
|
+
if (mode === 'per_use') return `🔁 ${window.fmtPrice(price)}/${t('次')}`
|
|
19872
|
+
return `💰 ${window.fmtPrice(price)}`
|
|
19879
19873
|
}
|
|
19880
19874
|
const SKM_STATUS = {
|
|
19881
19875
|
submitted: { label: '审核中', color: '#f59e0b' },
|
|
@@ -19964,9 +19958,9 @@ async function renderSkillDetail(app, id) {
|
|
|
19964
19958
|
} else if (l.billing_mode === 'one_time') {
|
|
19965
19959
|
actionBtn = owned
|
|
19966
19960
|
? `<button class="btn btn-primary" style="width:100%;font-size:14px;padding:10px" onclick="skmReadContent('${l.id}','one_time')">${t('查看正文')}</button>`
|
|
19967
|
-
: `<button class="btn btn-primary" style="width:100%;font-size:14px;padding:10px" onclick="skmPurchase('${l.id}')">${t('购买')} · ${
|
|
19961
|
+
: `<button class="btn btn-primary" style="width:100%;font-size:14px;padding:10px" onclick="skmPurchase('${l.id}')">${t('购买')} · ${window.fmtPrice(l.price)}</button>`
|
|
19968
19962
|
} else {
|
|
19969
|
-
actionBtn = `<button class="btn btn-primary" style="width:100%;font-size:14px;padding:10px" onclick="skmReadContent('${l.id}','per_use')">${t('使用')} · ${
|
|
19963
|
+
actionBtn = `<button class="btn btn-primary" style="width:100%;font-size:14px;padding:10px" onclick="skmReadContent('${l.id}','per_use')">${t('使用')} · ${window.fmtPrice(l.price)}/${t('次')}</button>
|
|
19970
19964
|
<div style="font-size:10px;color:#9ca3af;text-align:center;margin-top:6px">${t('按次付费:每次查看正文都会扣费')}</div>`
|
|
19971
19965
|
}
|
|
19972
19966
|
app.innerHTML = shell(`
|
|
@@ -20209,7 +20203,7 @@ async function renderSecondhandMarket(app) {
|
|
|
20209
20203
|
<button class="btn btn-outline btn-sm" style="font-size:12px;padding:0 10px;white-space:nowrap" onclick="document.getElementById('sh-adv').style.display=document.getElementById('sh-adv').style.display==='none'?'block':'none'">⚙ ${t('筛选')}</button>
|
|
20210
20204
|
</div>
|
|
20211
20205
|
<div id="sh-adv" style="display:${(_shFilters.minP || _shFilters.maxP || _shFilters.conds.size>0) ? 'block':'none'};background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;padding:10px;margin-bottom:10px">
|
|
20212
|
-
<div style="font-size:11px;color:#6b7280;margin-bottom:6px">${t('价格区间 (
|
|
20206
|
+
<div style="font-size:11px;color:#6b7280;margin-bottom:6px">${t('价格区间 (USDC)')}</div>
|
|
20213
20207
|
<div style="display:flex;gap:6px;align-items:center;margin-bottom:10px">
|
|
20214
20208
|
<input id="sh-minP" class="form-control" type="number" placeholder="${t('最低')}" style="font-size:12px;flex:1" value="${escAttr(_shFilters.minP)}" oninput="_shFilters.minP=this.value">
|
|
20215
20209
|
<span style="color:#9ca3af">—</span>
|
|
@@ -20283,7 +20277,7 @@ function shItemCard(it) {
|
|
|
20283
20277
|
${Number(it.negotiable) === 1 ? `<span style="position:absolute;top:6px;left:6px;background:rgba(0,0,0,0.7);color:#fff;font-size:9px;padding:2px 6px;border-radius:4px">${t('可议价')}</span>` : ''}
|
|
20284
20278
|
</div>
|
|
20285
20279
|
<div style="padding:8px">
|
|
20286
|
-
<div style="font-size:14px;font-weight:700;color:#dc2626">${
|
|
20280
|
+
<div style="font-size:14px;font-weight:700;color:#dc2626">${window.fmtPrice(it.price)}</div>
|
|
20287
20281
|
<div style="font-size:11px;color:#374151;line-height:1.3;margin:2px 0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden">${escHtml(it.title)}</div>
|
|
20288
20282
|
<div style="display:flex;align-items:center;gap:4px;font-size:9px;margin-top:4px">
|
|
20289
20283
|
<span style="background:${cond.color}1a;color:${cond.color};padding:1px 5px;border-radius:3px;font-weight:600">${t(cond.label)}</span>
|
|
@@ -20303,10 +20297,12 @@ async function renderSecondhandPublish(app) {
|
|
|
20303
20297
|
<button onclick="history.back()" style="background:none;border:none;font-size:18px;cursor:pointer;color:#6b7280">←</button>
|
|
20304
20298
|
<h1 style="font-size:18px;font-weight:600;margin:0">${t('发布闲置')}</h1>
|
|
20305
20299
|
</div>
|
|
20300
|
+
${window.createKindChooserHtml ? window.createKindChooserHtml('secondhand') : ''}
|
|
20306
20301
|
|
|
20307
20302
|
<div class="card" style="margin-bottom:12px">
|
|
20308
20303
|
<div class="card-body">
|
|
20309
20304
|
<div style="font-size:12px;color:#374151;font-weight:600;margin-bottom:8px">${t('图片(首张为封面,最多 9 张)')}</div>
|
|
20305
|
+
<div style="font-size:11px;color:#b45309;background:#fffbeb;border:1px solid #fde68a;border-radius:6px;padding:6px 8px;margin-bottom:8px;line-height:1.5">📸 ${t('请上传真实实物照,勿用网图/广告图;如经举报核实为虚假图片,商品可能被下架')}</div>
|
|
20310
20306
|
<input type="file" accept="image/*" multiple id="sh-imgs-input" style="display:none" onchange="shHandleImagesChange(this)">
|
|
20311
20307
|
<div id="sh-imgs-grid" style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px"></div>
|
|
20312
20308
|
<button class="btn btn-outline btn-sm" style="margin-top:8px;font-size:12px" onclick="document.getElementById('sh-imgs-input').click()">+ ${t('选择图片')}</button>
|
|
@@ -20496,7 +20492,7 @@ function shMineRenderItems(allItems) {
|
|
|
20496
20492
|
<span style="position:absolute;top:6px;right:6px;background:${statusColor[it.status] || '#9ca3af'};color:#fff;font-size:9px;padding:2px 6px;border-radius:4px;font-weight:600">${t(statusLabel[it.status] || it.status)}</span>
|
|
20497
20493
|
</div>
|
|
20498
20494
|
<div style="padding:8px">
|
|
20499
|
-
<div style="font-size:14px;font-weight:700;color:#dc2626">${
|
|
20495
|
+
<div style="font-size:14px;font-weight:700;color:#dc2626">${window.fmtPrice(it.price)}</div>
|
|
20500
20496
|
<div style="font-size:11px;color:#374151;line-height:1.3;margin:2px 0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden">${escHtml(it.title)}</div>
|
|
20501
20497
|
<div style="display:flex;justify-content:space-between;font-size:9px;color:#9ca3af;margin-top:4px">
|
|
20502
20498
|
<span>👁 ${it.view_count || 0}</span>
|
|
@@ -20539,12 +20535,11 @@ async function renderSecondhandDetail(app, id) {
|
|
|
20539
20535
|
</div>
|
|
20540
20536
|
<div style="padding:14px">
|
|
20541
20537
|
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:8px">
|
|
20542
|
-
<div style="font-size:24px;font-weight:700;color:#dc2626">${
|
|
20538
|
+
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap"><div style="font-size:24px;font-weight:700;color:#dc2626">${window.fmtPrice(it.price)}</div><span style="background:${cond.color}1a;color:${cond.color};font-size:11px;padding:3px 9px;border-radius:99px;font-weight:600;white-space:nowrap">${t(cond.label)}</span></div>
|
|
20543
20539
|
${Number(it.negotiable) === 1 ? `<span style="background:#fef3c7;color:#92400e;font-size:10px;padding:3px 8px;border-radius:99px;font-weight:600;white-space:nowrap">${t('可议价')}</span>` : ''}
|
|
20544
20540
|
</div>
|
|
20545
20541
|
<h2 style="font-size:16px;color:#111827;line-height:1.4;margin:0 0 10px">${escHtml(it.title)}</h2>
|
|
20546
20542
|
<div style="display:flex;flex-wrap:wrap;gap:6px;font-size:10px;margin-bottom:12px">
|
|
20547
|
-
<span style="background:${cond.color}1a;color:${cond.color};padding:3px 8px;border-radius:4px;font-weight:600">${t(cond.label)}</span>
|
|
20548
20543
|
<span style="background:#f3f4f6;color:#6b7280;padding:3px 8px;border-radius:4px">${shCatIcon(it.category)} ${t(shCatLabel(it.category))}</span>
|
|
20549
20544
|
<span style="background:#f3f4f6;color:#6b7280;padding:3px 8px;border-radius:4px">📦 ${t(ffLabel)}</span>
|
|
20550
20545
|
${it.region ? `<span style="background:#f3f4f6;color:#6b7280;padding:3px 8px;border-radius:4px">📍 ${escHtml(it.region)}</span>` : ''}
|
|
@@ -20558,8 +20553,9 @@ async function renderSecondhandDetail(app, id) {
|
|
|
20558
20553
|
<div style="color:#9ca3af;font-size:10px">@${escHtml(it.seller_handle || '')} · ${t('已浏览')} ${it.view_count}</div>
|
|
20559
20554
|
</div>
|
|
20560
20555
|
</div>
|
|
20561
|
-
<div style="background:#eef2ff;border-radius:8px;padding:10px;margin-bottom:14px;font-size:
|
|
20562
|
-
|
|
20556
|
+
<div style="background:#eef2ff;border-radius:8px;padding:10px 12px;margin-bottom:14px;font-size:10.5px;color:#4338ca;line-height:1.7">
|
|
20557
|
+
<div style="font-weight:600;color:#3730a3;margin-bottom:4px">🛡️ ${t('WebAZ 交易保障')}<span style="font-weight:400;color:#6366f1;margin-left:6px">${t('协议费 1%')}</span></div>
|
|
20558
|
+
🔒 ${t('资金托管·确认收货才放款')} · 🤝 ${t('面交也可托管')} · 🔎 ${t('成色声明可社区验证')}
|
|
20563
20559
|
</div>
|
|
20564
20560
|
${isOwn ? `
|
|
20565
20561
|
<button class="btn btn-outline" style="width:100%;font-size:13px;color:#6b7280;border-color:#d1d5db" onclick="doShToggleClose('${it.id}', '${it.status}')">${it.status === 'closed' ? t('重新上架') : (it.status === 'available' ? t('下架') : '')}</button>
|
|
@@ -20584,7 +20580,7 @@ async function renderSecondhandDetail(app, id) {
|
|
|
20584
20580
|
${o.cover ? `<img src="${escAttr(o.cover)}" style="width:100%;height:100%;object-fit:cover">` : `<div style="font-size:30px">${shCatIcon(o.category)}</div>`}
|
|
20585
20581
|
</div>
|
|
20586
20582
|
<div style="padding:6px">
|
|
20587
|
-
<div style="font-size:13px;font-weight:700;color:#dc2626">${
|
|
20583
|
+
<div style="font-size:13px;font-weight:700;color:#dc2626">${window.fmtPrice(o.price)}</div>
|
|
20588
20584
|
<div style="font-size:10px;color:#6b7280;line-height:1.3;margin-top:2px;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden">${escHtml(o.title)}</div>
|
|
20589
20585
|
<div style="font-size:9px;color:${ocond.color};margin-top:3px;font-weight:600">${t(ocond.label)}</div>
|
|
20590
20586
|
</div>
|
|
@@ -20622,7 +20618,7 @@ window.openShBuyModal = (id, price, ff) => {
|
|
|
20622
20618
|
const canMeet = ff === 'in_person' || ff === 'both'
|
|
20623
20619
|
_openModal(`
|
|
20624
20620
|
<h2 style="font-size:16px;font-weight:600;margin-bottom:6px">${t('购买二手物品')}</h2>
|
|
20625
|
-
<div style="font-size:18px;color:#dc2626;font-weight:700;margin-bottom:14px">${
|
|
20621
|
+
<div style="font-size:18px;color:#dc2626;font-weight:700;margin-bottom:14px">${window.fmtPrice(price)}</div>
|
|
20626
20622
|
<div style="font-size:12px;color:#374151;font-weight:600;margin-bottom:6px">${t('履约方式')}</div>
|
|
20627
20623
|
<div style="display:flex;gap:8px;margin-bottom:12px">
|
|
20628
20624
|
${canShip ? `<label style="flex:1;border:1px solid #e5e7eb;border-radius:6px;padding:8px;cursor:pointer;font-size:12px;display:flex;align-items:center;gap:6px"><input type="radio" name="sh-ff" value="shipping" ${canShip && !canMeet ? 'checked' : ''}>🚚 ${t('快递')}</label>` : ''}
|
|
@@ -21153,7 +21149,7 @@ async function renderRfqFeed(app) {
|
|
|
21153
21149
|
const bidsLabel = it.bid_count > 0 ? `💎 ${it.bid_count} ${t('个报价')}` : t('等待商家报价')
|
|
21154
21150
|
return `<div class="card" style="margin-bottom:8px;padding:12px;cursor:pointer" onclick="navigate('#rfq/${it.id}')">
|
|
21155
21151
|
<div style="font-size:13px;line-height:1.5">
|
|
21156
|
-
✍️ ${feedActor(it.buyer_id, it.buyer_name, it.buyer_handle)} ${t('
|
|
21152
|
+
✍️ ${feedActor(it.buyer_id, it.buyer_name, it.buyer_handle)} ${t('想买')} <strong>${escHtml(it.title || it.category)}</strong>
|
|
21157
21153
|
${it.qty ? ` × ${it.qty}` : ''}
|
|
21158
21154
|
${it.budget ? ` · ${t('预算')} ${it.budget} WAZ` : ''}
|
|
21159
21155
|
</div>
|
|
@@ -21492,7 +21488,7 @@ async function renderMessages(app, deepSub) {
|
|
|
21492
21488
|
body = conversations.length === 0
|
|
21493
21489
|
? `<div style="text-align:center;color:#9ca3af;padding:40px 0;font-size:13px">${t('暂无会话 — 在订单 / RFQ / 跟卖详情页发起聊天')}</div>`
|
|
21494
21490
|
: conversations.map(it => {
|
|
21495
|
-
const kindLabel = it.kind === 'order' ? '📦 ' + t('订单') : it.kind === 'rfq' ? '📩 ' + t('求购') : '🏷 ' + t('问商品')
|
|
21491
|
+
const kindLabel = (it.kind === 'order' ? '📦 ' + t('订单') : it.kind === 'rfq' ? '📩 ' + t('求购') : '🏷 ' + t('问商品')) + (it.context_title ? ' · ' + escHtml(it.context_title) : '') + ((it.kind === 'order' || it.kind === 'rfq') && it.context_id ? ' #' + String(it.context_id).slice(0, 10) : '') // 订单/问商品显商品名 + 订单/求购显短号 → 同一对方多会话可区分
|
|
21496
21492
|
return `
|
|
21497
21493
|
<div class="card" style="padding:12px;margin-bottom:8px;cursor:pointer;${it.my_unread > 0 ? 'border-left:3px solid #4f46e5' : ''}" onclick="location.hash='#chat/${it.id}'">
|
|
21498
21494
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px">
|
|
@@ -21694,7 +21690,7 @@ async function renderChatDetail(app, id) {
|
|
|
21694
21690
|
|
|
21695
21691
|
// 自动滚到底
|
|
21696
21692
|
const msgsEl = document.getElementById('chat-msgs')
|
|
21697
|
-
if (msgsEl) msgsEl.scrollTop = msgsEl.scrollHeight
|
|
21693
|
+
if (msgsEl) { msgsEl.scrollTop = msgsEl.scrollHeight; if (window.startChatPoll) window.startChatPoll(id, messages) } // #30 进入会话后开实时轮询(传初始消息→按末条 id 判新,自清理离开即停)
|
|
21698
21694
|
}
|
|
21699
21695
|
|
|
21700
21696
|
function renderChatBubble(m, myId) {
|
|
@@ -22105,7 +22101,7 @@ async function renderAuctionsFeed(app) {
|
|
|
22105
22101
|
const tag = bidCount > 0 ? `🔥 ${bidCount} ${t('次出价')}` : t('暂无出价 · 先到先得')
|
|
22106
22102
|
return `<div class="card" style="margin-bottom:8px;padding:12px;cursor:pointer" onclick="navigate('#auction/${d.id}')">
|
|
22107
22103
|
<div style="font-size:13px;line-height:1.5">
|
|
22108
|
-
💎 ${feedActor(d.seller_id, d.seller_name, d.seller_handle)} ${t('
|
|
22104
|
+
💎 ${feedActor(d.seller_id, d.seller_name, d.seller_handle)} ${t('发起了拍卖')} <strong>${escHtml(d.title)}</strong>
|
|
22109
22105
|
</div>
|
|
22110
22106
|
<div style="font-size:11px;color:#6b7280;margin-top:4px">${t('当前')} <span style="color:#dc2626;font-weight:600">${d.current_price} WAZ</span> · ${tag} · ${ts}</div>
|
|
22111
22107
|
</div>`
|
|
@@ -22114,7 +22110,7 @@ async function renderAuctionsFeed(app) {
|
|
|
22114
22110
|
<div style="font-size:13px;line-height:1.5">
|
|
22115
22111
|
♻️ ${feedActor(d.seller_id, d.seller_name, d.seller_handle)} ${t('发布二手')} <strong>${escHtml(d.title)}</strong>
|
|
22116
22112
|
</div>
|
|
22117
|
-
<div style="font-size:11px;color:#6b7280;margin-top:4px">${d.price}
|
|
22113
|
+
<div style="font-size:11px;color:#6b7280;margin-top:4px">${window.fmtPrice(d.price)} · ${d.condition_grade || ''} · ${ts}</div>
|
|
22118
22114
|
</div>`
|
|
22119
22115
|
}
|
|
22120
22116
|
}).join('')
|
|
@@ -22433,7 +22429,7 @@ async function renderLeaderboard(app) {
|
|
|
22433
22429
|
const hasRating = u.rating_count > 0
|
|
22434
22430
|
const ratingColor = hasRating && u.avg_rating >= 4.5 ? '#16a34a' : hasRating && u.avg_rating >= 4 ? '#d97706' : '#9ca3af'
|
|
22435
22431
|
return `
|
|
22436
|
-
<div class="card" style="padding:12px;margin-bottom:8px;display:flex;gap:10px;align-items:center
|
|
22432
|
+
<div class="card" style="padding:12px;margin-bottom:8px;display:flex;gap:10px;align-items:center;${u.handle ? 'cursor:pointer' : ''}" ${u.handle ? `onclick="location.hash='#shop/${u.handle}'"` : ''}>
|
|
22437
22433
|
<div style="font-size:24px;font-weight:800;color:${i<3?'#dc2626':'#9ca3af'};min-width:32px;text-align:center">${i+1}</div>
|
|
22438
22434
|
<div style="flex:1;min-width:0">
|
|
22439
22435
|
<div style="font-weight:600;font-size:14px">@${escHtml(u.handle || u.name?.slice(0,8) || '?')}</div>
|
|
@@ -22458,7 +22454,7 @@ async function renderLeaderboard(app) {
|
|
|
22458
22454
|
🤖 @${escHtml(u.handle || u.name?.slice(0,8) || '?')}
|
|
22459
22455
|
<span style="font-size:10px;background:${lvlColor}22;color:${lvlColor};padding:1px 7px;border-radius:99px;font-weight:600">${lvlLabel}</span>
|
|
22460
22456
|
</div>
|
|
22461
|
-
<div style="font-size:11px;color:#6b7280;margin-top:2px">${
|
|
22457
|
+
<div style="font-size:11px;color:#6b7280;margin-top:2px">${t('活跃度')}: ${t({ active: '活跃', quiet: '较少', dormant: '休眠' }[u.activity] || '休眠')}</div>
|
|
22462
22458
|
</div>
|
|
22463
22459
|
<div style="text-align:right">
|
|
22464
22460
|
<div style="font-size:13px;font-weight:700;color:${lvlColor}">${ts}</div>
|
|
@@ -22535,7 +22531,7 @@ async function renderLeaderboard(app) {
|
|
|
22535
22531
|
</div>
|
|
22536
22532
|
</div>
|
|
22537
22533
|
<div style="text-align:right">
|
|
22538
|
-
<div style="font-size:14px;font-weight:800;color:#dc2626">${p.price}
|
|
22534
|
+
<div style="font-size:14px;font-weight:800;color:#dc2626">${window.fmtPrice(p.price)}</div>
|
|
22539
22535
|
<div style="font-size:10px;color:#854d0e;margin-top:1px">${pctLabel}</div>
|
|
22540
22536
|
</div>
|
|
22541
22537
|
</div>`
|
|
@@ -22546,14 +22542,14 @@ async function renderLeaderboard(app) {
|
|
|
22546
22542
|
<div style="flex:1;min-width:0">
|
|
22547
22543
|
<div style="font-weight:600;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(p.title)}</div>
|
|
22548
22544
|
<div style="font-size:11px;color:#6b7280;margin-top:2px">
|
|
22549
|
-
@${escHtml(p.seller_handle || p.seller_name?.slice(0,8) || '?')} · ${p.price}
|
|
22545
|
+
@${escHtml(p.seller_handle || p.seller_name?.slice(0,8) || '?')} · ${window.fmtPrice(p.price)} ·
|
|
22550
22546
|
🛒 ${p.completion_count || 0} · 🤝 ${p.unique_sharer_count || 0} · ❤️ ${p.total_likes || 0}
|
|
22551
22547
|
</div>
|
|
22552
22548
|
</div>
|
|
22553
22549
|
<div style="text-align:right;font-size:12px;font-weight:700;color:#4f46e5">${Number(p.rank_score).toFixed(1)}</div>
|
|
22554
22550
|
</div>
|
|
22555
22551
|
`).join('') : items.map((c, i) => `
|
|
22556
|
-
<div class="card" style="padding:12px;margin-bottom:8px;display:flex;gap:10px;align-items:center
|
|
22552
|
+
<div class="card" style="padding:12px;margin-bottom:8px;display:flex;gap:10px;align-items:center;${c.handle ? 'cursor:pointer' : ''}" ${c.handle ? `onclick="location.hash='#u/${c.handle}'"` : ''}>
|
|
22557
22553
|
<div style="font-size:24px;font-weight:800;color:${i<3?'#dc2626':'#9ca3af'};min-width:32px;text-align:center">${i+1}</div>
|
|
22558
22554
|
<div style="flex:1;min-width:0">
|
|
22559
22555
|
<div style="font-weight:600;font-size:14px">@${escHtml(c.handle || c.name?.slice(0,8) || '?')}${c.region ? ' · ' + regionLabel(c.region) : ''}</div>
|
|
@@ -22608,16 +22604,16 @@ async function renderP2pBoard(app) {
|
|
|
22608
22604
|
<div style="font-size:11px;color:#6b7280;margin-bottom:14px;line-height:1.5">${t('详情存卖家节点 · WebAZ 只锚定哈希 · 客户端验证防作弊')}</div>
|
|
22609
22605
|
${items.length === 0 ? `<div style="text-align:center;color:#9ca3af;padding:40px 0">${t('暂无 P2P 商品')}</div>` : items.map(it => {
|
|
22610
22606
|
let thumb = ''
|
|
22611
|
-
|
|
22607
|
+
thumb = window.productThumbSrc(it.thumbnail_json) || thumb
|
|
22612
22608
|
return `
|
|
22613
22609
|
<div class="card" style="padding:12px;margin-bottom:10px;cursor:pointer;display:flex;gap:10px" onclick="location.hash='#p2p-shop/${it.id}'">
|
|
22614
|
-
${thumb ? `<img src="${escHtml(thumb)}" style="width:80px;height:80px;object-fit:cover;border-radius:6px;flex-shrink:0">` : `<div style="width:80px;height:80px;background:#f3f4f6;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:32px;flex-shrink:0">🌐</div>`}
|
|
22610
|
+
${thumb ? `<img src="${escHtml(thumb)}" onerror="this.outerHTML='🌐'" style="width:80px;height:80px;object-fit:cover;border-radius:6px;flex-shrink:0">` : `<div style="width:80px;height:80px;background:#f3f4f6;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:32px;flex-shrink:0">🌐</div>`}
|
|
22615
22611
|
<div style="flex:1;min-width:0">
|
|
22616
22612
|
<div style="font-weight:600;font-size:14px;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(it.title)}</div>
|
|
22617
22613
|
<div style="font-size:11px;color:#6b7280;margin-bottom:3px">@${escHtml(it.seller_handle || it.seller_id.slice(0,8))} · ${it.region}</div>
|
|
22618
22614
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
22619
22615
|
<span style="font-size:10px;font-family:monospace;color:#9ca3af">🔒 ${it.content_hash.slice(0,12)}…</span>
|
|
22620
|
-
<span style="color:#dc2626;font-weight:700;font-size:14px">${it.price}
|
|
22616
|
+
<span style="color:#dc2626;font-weight:700;font-size:14px">${window.fmtPrice(it.price)}</span>
|
|
22621
22617
|
</div>
|
|
22622
22618
|
</div>
|
|
22623
22619
|
</div>`
|
|
@@ -22712,7 +22708,7 @@ async function renderP2pDetail(app, id) {
|
|
|
22712
22708
|
if (r?.error) { document.getElementById('p2p-detail').innerHTML = alert$('error', r.error); return }
|
|
22713
22709
|
const p = r.product
|
|
22714
22710
|
let thumb = ''
|
|
22715
|
-
|
|
22711
|
+
thumb = window.productThumbSrc(p.thumbnail_json) || thumb
|
|
22716
22712
|
|
|
22717
22713
|
// 客户端尝试从 peer_endpoint 拉详情并验签
|
|
22718
22714
|
let verifyStatus = `<span style="color:#9ca3af">${t('未尝试拉取')}</span>`
|
|
@@ -22746,11 +22742,11 @@ async function renderP2pDetail(app, id) {
|
|
|
22746
22742
|
document.getElementById('p2p-detail').innerHTML = `
|
|
22747
22743
|
<button class="btn btn-sm" onclick="history.back()" style="background:#f3f4f6;margin-bottom:14px">←</button>
|
|
22748
22744
|
<div style="display:flex;gap:14px;margin-bottom:14px">
|
|
22749
|
-
${thumb ? `<img src="${escHtml(thumb)}" style="width:120px;height:120px;object-fit:cover;border-radius:8px;flex-shrink:0">` : ''}
|
|
22745
|
+
${thumb ? `<img src="${escHtml(thumb)}" onerror="this.outerHTML='🌐'" style="width:120px;height:120px;object-fit:cover;border-radius:8px;flex-shrink:0">` : ''}
|
|
22750
22746
|
<div style="flex:1">
|
|
22751
22747
|
<h2 style="font-size:18px;font-weight:700;margin:0 0 4px">${escHtml(p.title)}</h2>
|
|
22752
22748
|
<div style="font-size:12px;color:#6b7280;margin-bottom:6px">@${escHtml(p.seller_handle || p.seller_id.slice(0,8))} · ${p.region}</div>
|
|
22753
|
-
<div style="color:#dc2626;font-weight:700;font-size:22px;margin-bottom:6px">${p.price}
|
|
22749
|
+
<div style="color:#dc2626;font-weight:700;font-size:22px;margin-bottom:6px">${window.fmtPrice(p.price)}</div>
|
|
22754
22750
|
<div style="font-size:11px;color:#6b7280">${t('库存')} ${p.stock}</div>
|
|
22755
22751
|
</div>
|
|
22756
22752
|
</div>
|
|
@@ -22769,7 +22765,7 @@ async function renderP2pDetail(app, id) {
|
|
|
22769
22765
|
</div>` : `
|
|
22770
22766
|
<div class="card" style="padding:14px;margin-bottom:12px;background:#fafafa;color:#9ca3af;text-align:center">${t('完整详情未能从节点获取 — 仅展示 WebAZ 上的最小信息')}</div>`}
|
|
22771
22767
|
|
|
22772
|
-
${state.user?.role === 'buyer' && p.stock > 0 ? `<button class="btn btn-primary" style="width:100%" onclick="location.hash='#order-product/${p.id}'">${t('购买')} ${p.price}
|
|
22768
|
+
${state.user?.role === 'buyer' && p.stock > 0 ? `<button class="btn btn-primary" style="width:100%" onclick="location.hash='#order-product/${p.id}'">${t('购买')} ${window.fmtPrice(p.price)}</button>` : ''}
|
|
22773
22769
|
`
|
|
22774
22770
|
}
|
|
22775
22771
|
|
|
@@ -22830,7 +22826,7 @@ function renderPriceHistoryHtml(r) {
|
|
|
22830
22826
|
<div style="flex:1;background:#fafafa;padding:8px;border-radius:6px;text-align:center">
|
|
22831
22827
|
<div style="font-size:10px;color:#6b7280;margin-bottom:2px">${label}</div>
|
|
22832
22828
|
<div style="font-size:13px;font-weight:600">${fmtPrice(data.avg)} <span style="font-size:9px;color:#9ca3af">${t('均价')}</span></div>
|
|
22833
|
-
<div style="font-size:10px;color:#6b7280;margin-top:2px">${data.sales}${t('单')} · ${fmtPrice(data.volume)}
|
|
22829
|
+
<div style="font-size:10px;color:#6b7280;margin-top:2px">${data.sales}${t('单')} · ${fmtPrice(data.volume)} USDC</div>
|
|
22834
22830
|
</div>`
|
|
22835
22831
|
|
|
22836
22832
|
return `
|
|
@@ -22840,7 +22836,7 @@ function renderPriceHistoryHtml(r) {
|
|
|
22840
22836
|
${windowCard(t('近 90 天'), w.d90)}
|
|
22841
22837
|
${windowCard(t('全部'), w.lifetime)}
|
|
22842
22838
|
</div>
|
|
22843
|
-
${r.category_avg_30d != null ? `<div style="font-size:11px;color:#6b7280;margin-bottom:10px">${t('同类目 30 天均价')}:<strong style="color:#374151">${fmtPrice(r.category_avg_30d)}
|
|
22839
|
+
${r.category_avg_30d != null ? `<div style="font-size:11px;color:#6b7280;margin-bottom:10px">${t('同类目 30 天均价')}:<strong style="color:#374151">${fmtPrice(r.category_avg_30d)} USDC</strong>${r.current_price && r.category_avg_30d ? ` · ${t('当前')}${r.current_price > r.category_avg_30d ? '↑' : '↓'}${(Math.abs((r.current_price - r.category_avg_30d) / r.category_avg_30d) * 100).toFixed(0)}%` : ''}</div>` :
|
|
22844
22840
|
`<div style="font-size:11px;color:#9ca3af;margin-bottom:10px;font-style:italic">${t('未设置具体类目 — 无同类对比(卖家可在商品编辑页选择类目)')}</div>`}
|
|
22845
22841
|
<div style="font-size:11px;color:#374151;margin-bottom:6px;font-weight:600">${t('价位分布')}(${t('90 天,按成交单数')})</div>
|
|
22846
22842
|
${bucketsHtml}
|
|
@@ -22921,7 +22917,7 @@ async function renderAdminProtocol(app) {
|
|
|
22921
22917
|
${adminLinkCard('🛠️', t('任务建议收件箱'), t('陌生人 / agent 提交的共建任务建议;审阅 → 转正式任务'), '#admin/task-proposals')}
|
|
22922
22918
|
${((state.user && state.user.admin_type || 'root') === 'root') ? adminLinkCard('🎟️', t('建任务额度审核'), t('非根管理员的建任务扩容申请;批准 = 限时计数授权(仅 root)'), '#admin/quota-requests') : ''}
|
|
22923
22919
|
${adminLinkCard('🔗', t('关联个人贡献账号'), t('把本管理席位的协调贡献归属到你的真实个人账号(需对方确认 + root 审批)'), '#me/operator-claims')}
|
|
22924
|
-
${((state.user && state.user.admin_type || 'root') === 'root') ? adminLinkCard('🪪', t('操作席位关联审批'), t('管理席位→个人贡献账号的关联申请;确认 + 审批 / 撤销(仅 root)'), '#admin/operator-claims') : ''}
|
|
22920
|
+
${((state.user && state.user.admin_type || 'root') === 'root') ? adminLinkCard('🪪', t('操作席位关联审批'), t('管理席位→个人贡献账号的关联申请;确认 + 审批 / 撤销(仅 root)'), '#admin/operator-claims') : ''}${((state.user && state.user.admin_type || 'root') === 'root') ? adminLinkCard('💳', t('Direct Pay 商户运营'), t('直付:合规录入 / 缓交 / 商品·店铺验证 / 平台服务费预充值 / 上线控制(仅 root)'), '#admin/dp-ops') : ''}
|
|
22925
22921
|
</div>
|
|
22926
22922
|
`, 'admin-protocol')
|
|
22927
22923
|
}
|
|
@@ -22971,7 +22967,7 @@ async function renderAdminWishReports(app) {
|
|
|
22971
22967
|
}
|
|
22972
22968
|
window.setWrStatus = (s) => { state._wrStatus = s; renderAdminWishReports(document.getElementById('app')) }
|
|
22973
22969
|
window.adminWrAction = async (id, action) => {
|
|
22974
|
-
if (!confirm(
|
|
22970
|
+
if (!confirm(action === 'dismiss' ? t('确认驳回?') : t('确认下架?'))) return
|
|
22975
22971
|
const r = await PATCH('/admin/wish-reports/' + id, { action })
|
|
22976
22972
|
if (r?.error) return alert(r.error)
|
|
22977
22973
|
renderAdminWishReports(document.getElementById('app'))
|
|
@@ -24493,7 +24489,7 @@ async function renderNoteLanding(app, noteId) {
|
|
|
24493
24489
|
<div style="flex:1;min-width:0">
|
|
24494
24490
|
<div style="font-size:10px;color:#9a3412;font-weight:600;margin-bottom:2px">📦 ${t('笔记关联商品')}</div>
|
|
24495
24491
|
<div style="font-weight:700;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(product.title || '')}</div>
|
|
24496
|
-
<div style="font-size:15px;font-weight:800;color:#dc2626;margin-top:2px">${
|
|
24492
|
+
<div style="font-size:15px;font-weight:800;color:#dc2626;margin-top:2px">${window.fmtPrice(product.price || 0)}</div>
|
|
24497
24493
|
</div>
|
|
24498
24494
|
<button class="btn btn-primary btn-sm" style="white-space:nowrap" onclick="event.stopPropagation();navigate('#order-product/${product.id}')">${t('去购买')}</button>
|
|
24499
24495
|
</div>` : ''
|
|
@@ -25182,7 +25178,7 @@ async function renderSharesFeed(app, sort) {
|
|
|
25182
25178
|
<span>❤️ ${n.stats.likes || 0} · 🔗 ${n.stats.clicks || 0}</span>
|
|
25183
25179
|
</div>
|
|
25184
25180
|
${noteAuthBadges(n.badges, 'sm') ? `<div style="margin-top:4px">${noteAuthBadges(n.badges, 'sm')}</div>` : ''}
|
|
25185
|
-
${n.product ? `<div style="font-size:11px;color:#92400e;margin-top:4px;background:#fef3c7;padding:3px 8px;border-radius:4px;display:inline-block">📦 ${escHtml((n.product.title || '').slice(0, 20))} · ${
|
|
25181
|
+
${n.product ? `<div style="font-size:11px;color:#92400e;margin-top:4px;background:#fef3c7;padding:3px 8px;border-radius:4px;display:inline-block">📦 ${escHtml((n.product.title || '').slice(0, 20))} · ${window.fmtPrice(n.product.price)}</div>` : ''}
|
|
25186
25182
|
</div>
|
|
25187
25183
|
</div>
|
|
25188
25184
|
</div>
|
|
@@ -25683,7 +25679,7 @@ async function renderBuyerTrials(app) {
|
|
|
25683
25679
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:8px">
|
|
25684
25680
|
<div style="flex:1;min-width:0">
|
|
25685
25681
|
<div style="font-weight:600;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(c.product_title || '商品')}</div>
|
|
25686
|
-
<div style="font-size:11px;color:#6b7280;margin-top:2px">${c.product_price}
|
|
25682
|
+
<div style="font-size:11px;color:#6b7280;margin-top:2px">${window.fmtPrice(c.product_price)} · ${fmtTime(c.claimed_at)}</div>
|
|
25687
25683
|
</div>
|
|
25688
25684
|
<span style="flex-shrink:0;font-size:10px;background:${st.bg};color:${st.color};padding:2px 8px;border-radius:99px;font-weight:600">${st.label}</span>
|
|
25689
25685
|
</div>
|
|
@@ -25724,7 +25720,7 @@ async function renderSellerTrials(app) {
|
|
|
25724
25720
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:8px">
|
|
25725
25721
|
<div style="flex:1;min-width:0">
|
|
25726
25722
|
<div style="font-weight:600;font-size:14px">${escHtml(c.product_title || '商品')}</div>
|
|
25727
|
-
<div style="font-size:11px;color:#6b7280;margin-top:2px">${c.product_price}
|
|
25723
|
+
<div style="font-size:11px;color:#6b7280;margin-top:2px">${window.fmtPrice(c.product_price)} · ${t('阈值')} ${c.reach_threshold} · ${t('启动')} ${fmtTime(c.created_at)}</div>
|
|
25728
25724
|
</div>
|
|
25729
25725
|
<span style="flex-shrink:0;font-size:10px;background:${c.status==='active'?'#dcfce7':'#f3f4f6'};color:${c.status==='active'?'#166534':'#6b7280'};padding:2px 8px;border-radius:99px;font-weight:600">${c.status==='active' ? t('进行中') : t('已关闭')}</span>
|
|
25730
25726
|
</div>
|