@seasonkoh/webaz 0.1.20 → 0.1.22
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/dist/layer0-foundation/L0-2-state-machine/engine.js +83 -90
- package/dist/layer1-agent/L1-1-mcp-server/server.js +20 -7
- package/dist/layer3-trust/L3-1-dispute-engine/dispute-engine.js +138 -168
- package/dist/layer4-economics/L4-4-skill-market/skill-engine.js +6 -4
- package/dist/layer4-economics/L4-4-skill-market/skill-listing-engine.js +12 -8
- package/dist/ledger.js +58 -0
- package/dist/money.js +106 -0
- package/dist/pwa/acp-feed.js +103 -0
- package/dist/pwa/public/app.js +55 -54
- package/dist/pwa/public/i18n.js +40 -41
- package/dist/pwa/public/index.html +26 -1
- package/dist/pwa/routes/auction.js +9 -6
- package/dist/pwa/routes/disputes-write.js +12 -11
- package/dist/pwa/routes/orders-create.js +24 -13
- package/dist/pwa/routes/public-utils.js +11 -0
- package/dist/pwa/server.js +59 -41
- package/dist/settlement-math.js +27 -0
- package/package.json +1 -1
package/dist/pwa/public/app.js
CHANGED
|
@@ -3256,7 +3256,7 @@ async function renderAdminDashboard(app) {
|
|
|
3256
3256
|
])
|
|
3257
3257
|
const kpiTokenomics2 = kpiGrid([
|
|
3258
3258
|
{ label: t('累计分享分润'),value: Number(tk.commission_total || 0).toFixed(2), unit: 'WAZ' },
|
|
3259
|
-
{ label: t('
|
|
3259
|
+
{ label: t('累计匹配发放'),value: Number(tk.binary_waz_total || 0).toFixed(2), unit: 'WAZ' },
|
|
3260
3260
|
{ label: t('PV 待处理'), value: tk.ledger_pending ?? 0 },
|
|
3261
3261
|
])
|
|
3262
3262
|
// 异常告警 banner — 多条件聚合
|
|
@@ -3298,7 +3298,7 @@ async function renderAdminDashboard(app) {
|
|
|
3298
3298
|
</div>
|
|
3299
3299
|
<div style="font-size:13px;color:#6b7280;margin:16px 0 8px">⚛ ${t('Tokenomics')}</div>
|
|
3300
3300
|
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:16px">
|
|
3301
|
-
${quickAction('#admin/tokenomics', '⚛', t('
|
|
3301
|
+
${quickAction('#admin/tokenomics', '⚛', t('积分基金 / Tier 配置 / 高额榜'))}
|
|
3302
3302
|
</div>`
|
|
3303
3303
|
|
|
3304
3304
|
// A5 重设:渐变标题 + 分区标题 + 颜色块分组
|
|
@@ -4352,7 +4352,7 @@ async function renderApplyRewards(app) {
|
|
|
4352
4352
|
<div class="card" style="margin-bottom:16px;background:#fef2f2;border-color:#fca5a5">
|
|
4353
4353
|
<div style="font-weight:600;color:#991b1b;margin-bottom:6px;font-size:14px">⚠️ ${t('本流程与购物无关')}</div>
|
|
4354
4354
|
<div style="font-size:12px;color:#7f1d1d;line-height:1.6">
|
|
4355
|
-
${t('你可以随时退出,不影响任何已下单或未来订单。本流程涉及经济关系登记(三级佣金 +
|
|
4355
|
+
${t('你可以随时退出,不影响任何已下单或未来订单。本流程涉及经济关系登记(三级佣金 + 积分配对),请仔细阅读全部条款。')}<br>
|
|
4356
4356
|
<span style="opacity:0.85">This flow is not part of shopping. You can leave anytime without affecting any orders. This is an economic-relationship registration — please read all terms.</span>
|
|
4357
4357
|
</div>
|
|
4358
4358
|
</div>
|
|
@@ -5536,7 +5536,7 @@ async function renderAdminTokenomics(app) {
|
|
|
5536
5536
|
<h2 style="font-size:15px;font-weight:600;margin:16px 0 8px">🎁 ${t('管理津贴池')}</h2>
|
|
5537
5537
|
<div class="card" style="margin-bottom:12px">
|
|
5538
5538
|
<div style="font-size:18px;font-weight:700">${Number(mb.balance ?? 0).toFixed(2)} WAZ</div>
|
|
5539
|
-
<div style="font-size:11px;color:#9ca3af;margin-top:4px">${t('来自协议费 50
|
|
5539
|
+
<div style="font-size:11px;color:#9ca3af;margin-top:4px">${t('来自协议费 50%,用于大博主匹配团队 10/5/2% 补贴')}</div>
|
|
5540
5540
|
<div id="mgmt-bonus-control" style="margin-top:12px;padding:10px;background:#fef9c3;border:1px solid #fde047;border-radius:6px">
|
|
5541
5541
|
<div style="font-size:12px;font-weight:600;margin-bottom:6px">⚠️ ${t('津贴门控')}</div>
|
|
5542
5542
|
<div id="mgmt-bonus-status" style="font-size:11px;color:#92400e;margin-bottom:8px">${t('加载中...')}</div>
|
|
@@ -5560,7 +5560,7 @@ async function renderAdminTokenomics(app) {
|
|
|
5560
5560
|
<div class="card" style="margin-bottom:12px">
|
|
5561
5561
|
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px">
|
|
5562
5562
|
<button class="btn btn-outline btn-sm" style="font-size:11px" onclick="doTkProcess()">${t('处理 PV 流水')}</button>
|
|
5563
|
-
<button class="btn btn-outline btn-sm" style="font-size:11px" onclick="doTkSettle()">${t('
|
|
5563
|
+
<button class="btn btn-outline btn-sm" style="font-size:11px" onclick="doTkSettle()">${t('触发匹配结算')}</button>
|
|
5564
5564
|
<button class="btn btn-outline btn-sm" style="font-size:11px;color:#dc2626;border-color:#dc2626" onclick="if(confirm('${t('确认分发 WAZ?这将清空池子按 N 比例分配')}'))doTkDistribute()">${t('分发 WAZ(清池)')}</button>
|
|
5565
5565
|
</div>
|
|
5566
5566
|
<div style="font-size:12px;color:#6b7280">${t('PV 待处理流水')}: ${data.pv_ledger?.pending ?? 0} ${t('条')} · ${t('待累积 PV')}: ${Number(data.pv_ledger?.pending_pv ?? 0).toLocaleString()}</div>
|
|
@@ -5580,10 +5580,10 @@ async function renderAdminTokenomics(app) {
|
|
|
5580
5580
|
<div style="padding:8px 12px;font-size:11px;color:#6b7280">${t('调整:POST /api/admin/tokenomics/tier with body {tier, pv_threshold, score_per_hit, active}')}</div>
|
|
5581
5581
|
</div>
|
|
5582
5582
|
|
|
5583
|
-
<h2 style="font-size:15px;font-weight:600;margin:16px 0 8px">🏆 ${t('Top
|
|
5583
|
+
<h2 style="font-size:15px;font-weight:600;margin:16px 0 8px">🏆 ${t('Top 三级佣金')} (Top 10)</h2>
|
|
5584
5584
|
<div class="card" style="padding:0;margin-bottom:12px">${commRows}</div>
|
|
5585
5585
|
|
|
5586
|
-
<h2 style="font-size:15px;font-weight:600;margin:16px 0 8px">🏆 ${t('Top
|
|
5586
|
+
<h2 style="font-size:15px;font-weight:600;margin:16px 0 8px">🏆 ${t('Top 匹配收益')} (Top 10)</h2>
|
|
5587
5587
|
<div class="card" style="padding:0;margin-bottom:12px">${binaryRows}</div>
|
|
5588
5588
|
`, 'admin')
|
|
5589
5589
|
setTimeout(loadRequireRefStatus, 100)
|
|
@@ -5643,7 +5643,7 @@ window.doTkProcess = async () => {
|
|
|
5643
5643
|
window.doTkSettle = async () => {
|
|
5644
5644
|
const res = await POST('/admin/atomic/run-settlement', {})
|
|
5645
5645
|
const msg = document.getElementById('tk-msg')
|
|
5646
|
-
if (msg) msg.innerHTML = res.error ? alert$('error', res.error) : alert$('success', `${t('
|
|
5646
|
+
if (msg) msg.innerHTML = res.error ? alert$('error', res.error) : alert$('success', `${t('已触发匹配')}: ${res.settled}`)
|
|
5647
5647
|
setTimeout(() => renderAdminTokenomics(document.getElementById('app')), 800)
|
|
5648
5648
|
}
|
|
5649
5649
|
|
|
@@ -6716,10 +6716,10 @@ async function renderPromoter(app) {
|
|
|
6716
6716
|
const _kpiRestricted = _mlmMax <= 1
|
|
6717
6717
|
// 两个语义独立的 gate(三级奖励 ≠ PV 双轨系统)—— 2026-06-04 已解耦:
|
|
6718
6718
|
// - _kpiRestricted (max ≤ 1):紧张地区 — KPI 改时间线 / team 隐 WAZ
|
|
6719
|
-
// - _pvAllowed:PV
|
|
6719
|
+
// - _pvAllowed:PV 双轨/匹配系统是否开启,读 region_pv_enabled(独立旋钮,不再绑 max≥3)
|
|
6720
6720
|
// commission 层级(max_levels) 与 PV 系统(pv_enabled) 分离:可单独开某辖区到 L2/L3 而 PV 仍关。
|
|
6721
6721
|
const _pvAllowed = Number(state.user?.region_pv_enabled ?? 0) === 1
|
|
6722
|
-
// 紧张地区:拼装最近奖励时间线(commission +
|
|
6722
|
+
// 紧张地区:拼装最近奖励时间线(commission + 匹配 binary 混合,按时间倒序取 5 条)
|
|
6723
6723
|
let kpiBar = ''
|
|
6724
6724
|
if (_kpiRestricted) {
|
|
6725
6725
|
const _cm = (data.recent || []).slice(0, 10).map(r => ({
|
|
@@ -7051,13 +7051,13 @@ async function renderPromoter(app) {
|
|
|
7051
7051
|
|
|
7052
7052
|
// ─── ⑥ WebAZ 发展奖(默认折叠;紧张 PV 地区精简版)───
|
|
7053
7053
|
// 合规:max_levels ≤ 1 的地区(GCC/越南/印尼/菲律宾 + 未审计地区)
|
|
7054
|
-
// 只显示"累计推广 N 人"客观数字,全部金钱/tier
|
|
7054
|
+
// 只显示"累计推广 N 人"客观数字,全部金钱/tier/匹配话术隐藏
|
|
7055
7055
|
// 复用顶部 _kpiRestricted(同一含义,避免重复定义)
|
|
7056
7056
|
const _totalRecruits = Number(data.team?.l1 || 0) + Number(data.team?.l2 || 0) + Number(data.team?.l3 || 0)
|
|
7057
7057
|
// 最右侧地区显示(所有模式都加)
|
|
7058
7058
|
const _userRegion = state.user?.region || 'global'
|
|
7059
7059
|
const _regionChip = `<span style="font-size:11px;color:#6b7280;white-space:nowrap;font-weight:400">${regionLabel(_userRegion)}</span>`
|
|
7060
|
-
// PV 双轨系统:只在 _pvAllowed(region_pv_enabled=1,2026-06-04 解耦,独立于 max_levels)才显示完整 tier
|
|
7060
|
+
// PV 双轨系统:只在 _pvAllowed(region_pv_enabled=1,2026-06-04 解耦,独立于 max_levels)才显示完整 tier/匹配/弱侧;
|
|
7061
7061
|
// 未开启 PV 的地区 → 走精简卡(分数仍后台计算累积,待 pv_enabled 开启/迁移后兑现)
|
|
7062
7062
|
const atomicSection = atomic.left_invite_url
|
|
7063
7063
|
? (!_pvAllowed
|
|
@@ -7080,7 +7080,7 @@ async function renderPromoter(app) {
|
|
|
7080
7080
|
<span>
|
|
7081
7081
|
🌟 ${t('WebAZ 发展奖')}
|
|
7082
7082
|
<span style="font-weight:400;font-size:12px;color:#6b7280;margin-left:6px">
|
|
7083
|
-
${t('
|
|
7083
|
+
${t('弱侧')} ${weak.toLocaleString()} PV · ${t('累计')} ${(atomic.score?.settled_waz || 0).toFixed(2)} WAZ
|
|
7084
7084
|
</span>
|
|
7085
7085
|
</span>
|
|
7086
7086
|
${_regionChip}
|
|
@@ -7266,7 +7266,7 @@ window.setBoughtKw = (kw) => {
|
|
|
7266
7266
|
}, 200)
|
|
7267
7267
|
}
|
|
7268
7268
|
|
|
7269
|
-
//
|
|
7269
|
+
// 积分匹配内部内容(折叠展开后渲染,从 renderAtomicSection 简化抽出)
|
|
7270
7270
|
function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
7271
7271
|
const tiers = a.tier_config || []
|
|
7272
7272
|
const tierTable = tiers.map(x => `
|
|
@@ -7276,7 +7276,7 @@ function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
|
7276
7276
|
<td style="padding:5px 8px;font-size:12px;text-align:right;font-weight:600">${x.score_per_hit}</td>
|
|
7277
7277
|
</tr>`).join('')
|
|
7278
7278
|
|
|
7279
|
-
//
|
|
7279
|
+
// 本月匹配次数 + WAZ
|
|
7280
7280
|
const now = new Date()
|
|
7281
7281
|
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10)
|
|
7282
7282
|
const monthBinary = (a.recent_binary || []).filter(r => (r.created_at || '').slice(0, 10) >= monthStart)
|
|
@@ -7293,7 +7293,7 @@ function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
|
7293
7293
|
<div>tier ${r.tier} · Score <strong>${r.score}</strong> · ${r.settled_at ? `<span style="color:#16a34a">${t('已结')} ${Number(r.waz_amount).toFixed(2)}</span>` : `<span style="color:#d97706">${t('待分配')}</span>`}</div>
|
|
7294
7294
|
<div style="color:#9ca3af">${fmtTime(r.created_at)}</div>
|
|
7295
7295
|
</div>`).join('')
|
|
7296
|
-
: `<div style="text-align:center;color:#9ca3af;padding:10px;font-size:12px">${t('
|
|
7296
|
+
: `<div style="text-align:center;color:#9ca3af;padding:10px;font-size:12px">${t('暂无匹配记录')}</div>`
|
|
7297
7297
|
|
|
7298
7298
|
return `
|
|
7299
7299
|
<!-- 我的位置 -->
|
|
@@ -7302,7 +7302,7 @@ function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
|
7302
7302
|
📍 ${t('我挂位置')}: <strong>${escHtml(a.my_placement.name)}</strong> 的 ${a.my_placement.side === 'left' ? '🔵 左侧' : '🟢 右侧'}
|
|
7303
7303
|
</div>` : `
|
|
7304
7304
|
<div style="background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;padding:8px 10px;font-size:12px;color:#9ca3af;margin-bottom:10px">
|
|
7305
|
-
${t('
|
|
7305
|
+
${t('你还没加入任何上级的积分树(独立根节点)')}
|
|
7306
7306
|
</div>`}
|
|
7307
7307
|
|
|
7308
7308
|
<!-- 左/右 PV -->
|
|
@@ -7319,25 +7319,25 @@ function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
|
7319
7319
|
</div>
|
|
7320
7320
|
</div>
|
|
7321
7321
|
|
|
7322
|
-
<!--
|
|
7322
|
+
<!-- 本月匹配统计 + 总匹配 -->
|
|
7323
7323
|
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:10px">
|
|
7324
7324
|
<div style="text-align:center;background:#fef3c7;border-radius:6px;padding:8px 4px">
|
|
7325
|
-
<div style="font-size:10px;color:#92400e">${t('
|
|
7325
|
+
<div style="font-size:10px;color:#92400e">${t('本月匹配次数')}</div>
|
|
7326
7326
|
<div style="font-size:14px;font-weight:700;color:#78350f">${monthHits}</div>
|
|
7327
7327
|
</div>
|
|
7328
7328
|
<div style="text-align:center;background:#dcfce7;border-radius:6px;padding:8px 4px">
|
|
7329
|
-
<div style="font-size:10px;color:#166534">${t('
|
|
7329
|
+
<div style="font-size:10px;color:#166534">${t('本月匹配 WAZ')}</div>
|
|
7330
7330
|
<div style="font-size:14px;font-weight:700;color:#14532d">${monthWaz.toFixed(2)}</div>
|
|
7331
7331
|
</div>
|
|
7332
7332
|
<div style="text-align:center;background:#eef2ff;border-radius:6px;padding:8px 4px">
|
|
7333
|
-
<div style="font-size:10px;color:#4338ca">${t('
|
|
7333
|
+
<div style="font-size:10px;color:#4338ca">${t('累计匹配次数')}</div>
|
|
7334
7334
|
<div style="font-size:14px;font-weight:700;color:#3730a3">${totalHits}</div>
|
|
7335
7335
|
</div>
|
|
7336
7336
|
</div>
|
|
7337
7337
|
|
|
7338
7338
|
${renderBinaryTree(a.binary_tree)}
|
|
7339
7339
|
|
|
7340
|
-
<div style="font-size:12px;color:#6b7280;margin-bottom:6px">${t('
|
|
7340
|
+
<div style="font-size:12px;color:#6b7280;margin-bottom:6px">${t('弱侧匹配量')}: <strong>${weak.toLocaleString()}</strong> PV</div>
|
|
7341
7341
|
${nextTier ? `
|
|
7342
7342
|
<div style="font-size:11px;color:#6b7280;margin-bottom:4px">${t('距离 tier')} ${nextTier.tier} ${t('门槛')} ${Number(nextTier.pv_threshold).toLocaleString()} PV (+${nextTier.score_per_hit} Score)</div>
|
|
7343
7343
|
<div style="background:#f3f4f6;height:6px;border-radius:3px;overflow:hidden;margin-bottom:10px">
|
|
@@ -7345,7 +7345,7 @@ function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
|
7345
7345
|
</div>` : ''}
|
|
7346
7346
|
|
|
7347
7347
|
<details style="margin-bottom:10px">
|
|
7348
|
-
<summary style="font-size:12px;color:#6366f1;cursor:pointer">${t('
|
|
7348
|
+
<summary style="font-size:12px;color:#6366f1;cursor:pointer">${t('匹配档位表')}</summary>
|
|
7349
7349
|
<table style="width:100%;margin-top:6px;border-collapse:collapse">
|
|
7350
7350
|
<tr style="background:#f9fafb;font-size:11px;color:#6b7280">
|
|
7351
7351
|
<th style="padding:5px 8px;text-align:left">Tier</th>
|
|
@@ -7355,7 +7355,7 @@ function renderAtomicInner(a, leftPv, rightPv, weak, nextTier, nextProgress) {
|
|
|
7355
7355
|
${tierTable}
|
|
7356
7356
|
</table>
|
|
7357
7357
|
</details>
|
|
7358
|
-
<h4 style="font-size:12px;font-weight:600;margin:6px 0">📊 ${t('
|
|
7358
|
+
<h4 style="font-size:12px;font-weight:600;margin:6px 0">📊 ${t('最近匹配')}</h4>
|
|
7359
7359
|
${recentRows}`
|
|
7360
7360
|
}
|
|
7361
7361
|
|
|
@@ -7510,10 +7510,10 @@ function renderAtomicSection(a) {
|
|
|
7510
7510
|
<div>tier ${r.tier} · Score <strong>${r.score}</strong> · ${r.settled_at ? `<span style="color:#16a34a">已结 ${Number(r.waz_amount).toFixed(2)} WAZ</span>` : `<span style="color:#d97706">待分配</span>`}</div>
|
|
7511
7511
|
<div style="color:#9ca3af">${fmtTime(r.created_at)}</div>
|
|
7512
7512
|
</div>`).join('')
|
|
7513
|
-
: `<div style="text-align:center;color:#9ca3af;padding:16px;font-size:12px">${t('
|
|
7513
|
+
: `<div style="text-align:center;color:#9ca3af;padding:16px;font-size:12px">${t('暂无匹配记录')}</div>`
|
|
7514
7514
|
|
|
7515
7515
|
return `
|
|
7516
|
-
<h2 style="font-size:15px;font-weight:600;margin:24px 0 8px">⚛ ${t('
|
|
7516
|
+
<h2 style="font-size:15px;font-weight:600;margin:24px 0 8px">⚛ ${t('积分 — 积分匹配')}</h2>
|
|
7517
7517
|
|
|
7518
7518
|
<div class="card" style="margin-bottom:12px;background:linear-gradient(135deg,#dbeafe,#f0fdf4)">
|
|
7519
7519
|
<div style="font-size:13px;color:#6b7280;margin-bottom:6px">🔗 ${t('左右码(完全对称 / 末端垂直挂靠)')}</div>
|
|
@@ -7568,7 +7568,7 @@ function renderAtomicSection(a) {
|
|
|
7568
7568
|
${renderBinaryTree(a.binary_tree)}
|
|
7569
7569
|
|
|
7570
7570
|
<div class="card" style="margin-bottom:12px">
|
|
7571
|
-
<div style="font-size:13px;color:#6b7280;margin-bottom:6px">${t('
|
|
7571
|
+
<div style="font-size:13px;color:#6b7280;margin-bottom:6px">${t('弱侧匹配量')}: <strong>${pair.toLocaleString()}</strong> PV</div>
|
|
7572
7572
|
${nextTier ? `
|
|
7573
7573
|
<div style="font-size:11px;color:#6b7280;margin-bottom:4px">${t('距离 tier')} ${nextTier.tier} ${t('门槛')} ${Number(nextTier.pv_threshold).toLocaleString()} PV (${nextTier.score_per_hit} Score)</div>
|
|
7574
7574
|
<div style="background:#f3f4f6;height:6px;border-radius:3px;overflow:hidden">
|
|
@@ -7588,7 +7588,7 @@ function renderAtomicSection(a) {
|
|
|
7588
7588
|
</div>
|
|
7589
7589
|
|
|
7590
7590
|
<details style="margin-bottom:12px">
|
|
7591
|
-
<summary style="font-size:12px;color:#6366f1;cursor:pointer">${t('
|
|
7591
|
+
<summary style="font-size:12px;color:#6366f1;cursor:pointer">${t('匹配档位表')}</summary>
|
|
7592
7592
|
<table style="width:100%;margin-top:8px;border-collapse:collapse">
|
|
7593
7593
|
<tr style="background:#f9fafb;font-size:11px;color:#6b7280">
|
|
7594
7594
|
<th style="padding:6px 8px;text-align:left">Tier</th>
|
|
@@ -7599,13 +7599,13 @@ function renderAtomicSection(a) {
|
|
|
7599
7599
|
</table>
|
|
7600
7600
|
</details>
|
|
7601
7601
|
|
|
7602
|
-
<h3 style="font-size:13px;font-weight:600;margin:8px 0">📊 ${t('
|
|
7602
|
+
<h3 style="font-size:13px;font-weight:600;margin:8px 0">📊 ${t('最近匹配')}</h3>
|
|
7603
7603
|
<div class="card" style="padding:0">
|
|
7604
7604
|
${recentRows}
|
|
7605
7605
|
</div>`
|
|
7606
7606
|
}
|
|
7607
7607
|
|
|
7608
|
-
// P12:
|
|
7608
|
+
// P12: 三层积分树(你 + 左右 + 各自左右)
|
|
7609
7609
|
function renderBinaryTree(tree) {
|
|
7610
7610
|
if (!tree || !tree.me) return ''
|
|
7611
7611
|
const node = (n, bg, fg, label) => n
|
|
@@ -7617,7 +7617,7 @@ function renderBinaryTree(tree) {
|
|
|
7617
7617
|
|
|
7618
7618
|
return `
|
|
7619
7619
|
<details style="margin-bottom:12px" open>
|
|
7620
|
-
<summary style="font-size:12px;color:#6366f1;cursor:pointer;margin-bottom:6px">🌳 ${t('
|
|
7620
|
+
<summary style="font-size:12px;color:#6366f1;cursor:pointer;margin-bottom:6px">🌳 ${t('团队组织图(3 层)')} <span style="color:#9ca3af;font-size:10px">${t('点击节点查看 PV')}</span></summary>
|
|
7621
7621
|
<div style="padding:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px">
|
|
7622
7622
|
<!-- L0: 你 -->
|
|
7623
7623
|
<div style="margin-bottom:6px">
|
|
@@ -7693,8 +7693,8 @@ window.showNodePvModal = async (userId) => {
|
|
|
7693
7693
|
</div>
|
|
7694
7694
|
|
|
7695
7695
|
<div style="background:#f9fafb;border-radius:6px;padding:8px 10px;font-size:11px;color:#6b7280;line-height:1.7;margin-bottom:10px">
|
|
7696
|
-
${t('
|
|
7697
|
-
${t('
|
|
7696
|
+
${t('弱侧匹配量')}: <strong style="color:#374151">${weak.toLocaleString()}</strong> PV · ${t('双腿均衡')} ${ratio}%<br>
|
|
7697
|
+
${t('累计匹配')}: <strong style="color:#374151">${data.total_hits || 0}</strong> ${t('次')} · ${t('累计获 WAZ')}: <strong style="color:#16a34a">${Number(data.settled_waz || 0).toFixed(2)}</strong><br>
|
|
7698
7698
|
${t('待结 Score')}: <strong style="color:#d97706">${Number(data.pending_score || 0).toFixed(1)}</strong>
|
|
7699
7699
|
</div>
|
|
7700
7700
|
|
|
@@ -7829,11 +7829,11 @@ async function maybePromptPlacementBind() {
|
|
|
7829
7829
|
const st = await GET('/profile/placement-status')
|
|
7830
7830
|
if (!st.can_bind) return // 已有 placement 或 有下线 → 不弹
|
|
7831
7831
|
setTimeout(() => {
|
|
7832
|
-
const ok = confirm(`📍 ${t('系统检测到邀请链接')}\n\n${t('inviter')}: ${inviter}\n\n${t('
|
|
7832
|
+
const ok = confirm(`📍 ${t('系统检测到邀请链接')}\n\n${t('inviter')}: ${inviter}\n\n${t('是否加入对方的积分配对?')}\n${t('系统将按推荐人偏好自动选择左/右区。一旦加入永久不变。')}`)
|
|
7833
7833
|
if (ok) {
|
|
7834
7834
|
POST('/profile/bind-placement', { inviter_id: inviter, side: hint.placement_side || undefined }).then(res => {
|
|
7835
7835
|
if (res.error) alert(`✗ ${res.error}`)
|
|
7836
|
-
else alert(`✓ ${t('
|
|
7836
|
+
else alert(`✓ ${t('已加入积分树')}\n${t('侧')}: ${res.side}\n${t('深度')}: ${res.depth}`)
|
|
7837
7837
|
})
|
|
7838
7838
|
}
|
|
7839
7839
|
localStorage.setItem(askedKey, Date.now().toString())
|
|
@@ -10209,7 +10209,7 @@ async function renderMyAgents(app) {
|
|
|
10209
10209
|
<summary style="cursor:pointer;color:#6366f1;padding:4px 0">📊 ${t('为什么是')} ${lvlLabel} ${t('级?')}</summary>
|
|
10210
10210
|
<div style="background:#f9fafb;border-radius:6px;padding:8px 10px;margin-top:4px;font-family:monospace;line-height:1.6">
|
|
10211
10211
|
<div>${t('加分')}:${t('账号年龄')} +${rep.signals.age_pts} · ${t('订单数')} +${rep.signals.order_pts} · ${t('分享转化')} +${rep.signals.share_pts} · ${t('调用多样性')} +${rep.signals.diversity_pts}</div>
|
|
10212
|
-
${(rep.signals.dispute_penalty + rep.signals.sybil_penalty + rep.signals.cross_penalty + rep.signals.ratelimit_penalty) < 0 ? `<div style="color:#dc2626">${t('扣分')}:${t('争议败诉')} ${rep.signals.dispute_penalty} · ${t('同 IP 异户')} ${rep.signals.sybil_penalty} · ${t('
|
|
10212
|
+
${(rep.signals.dispute_penalty + rep.signals.sybil_penalty + rep.signals.cross_penalty + rep.signals.ratelimit_penalty) < 0 ? `<div style="color:#dc2626">${t('扣分')}:${t('争议败诉')} ${rep.signals.dispute_penalty} · ${t('同 IP 异户')} ${rep.signals.sybil_penalty} · ${t('匹配命中')} ${rep.signals.cross_penalty} · ${t('限速命中')} ${rep.signals.ratelimit_penalty}</div>` : ''}
|
|
10213
10213
|
<div style="color:#9ca3af;margin-top:4px">${t('阈值')}:new<20 · trusted≥20 · quality≥50 · legend≥80</div>
|
|
10214
10214
|
</div>
|
|
10215
10215
|
</details>
|
|
@@ -11688,8 +11688,8 @@ window.doLoginByPassword = async () => {
|
|
|
11688
11688
|
|
|
11689
11689
|
|
|
11690
11690
|
// 从 URL 解析分享 hint(30 天 cookie 持久化)
|
|
11691
|
-
// ?ref=usr_xxx →
|
|
11692
|
-
// ?placement=usr_xxx&side=left|right →
|
|
11691
|
+
// ?ref=usr_xxx → 仅三级佣金 sponsor
|
|
11692
|
+
// ?placement=usr_xxx&side=left|right → 仅积分挂靠
|
|
11693
11693
|
// ?ref=xxx&side=left|right → 两轨道(ref 同时作 placement)
|
|
11694
11694
|
// ?ref=xxx&placement=xxx&side=... → 显式两轨道
|
|
11695
11695
|
function readShareHint() {
|
|
@@ -12059,10 +12059,10 @@ function showRegisterSuccessModal(res) {
|
|
|
12059
12059
|
const targetBtn = (intended && intended !== '#' && intended !== '')
|
|
12060
12060
|
? `<button class="btn btn-primary" style="width:100%;margin-bottom:10px" onclick="window._closeRegModal(true)">🎯 ${t('回到原页')} ${tgt?.title ? '— ' + escHtml(tgt.title) : ''} →</button>`
|
|
12061
12061
|
: ''
|
|
12062
|
-
// P1 (QA 轮 14.a): 区分"邀请人"(referral sponsor) 与"
|
|
12062
|
+
// P1 (QA 轮 14.a): 区分"邀请人"(referral sponsor) 与"积分树挂靠"(binary placement)
|
|
12063
12063
|
// 旧版挤一行 "已绑定邀请人 X · 左区 depth N" → 用户误以为 depth 是相对邀请人
|
|
12064
12064
|
const placementLine = res.placement
|
|
12065
|
-
? `<div style="font-size:11px;color:#9ca3af;margin-bottom:14px">${t('
|
|
12065
|
+
? `<div style="font-size:11px;color:#9ca3af;margin-bottom:14px">${t('积分树挂靠')}: ${res.placement.side === 'left' ? '🔵 ' + t('左区') : '🟢 ' + t('右区')} · ${t('深度')} ${res.placement.depth}<br><span style="font-size:10px">${t('(挂靠位置由系统按弱区自动决定,与邀请人不一定相邻)')}</span></div>`
|
|
12066
12066
|
: ''
|
|
12067
12067
|
_openModal(`
|
|
12068
12068
|
<h2 style="font-size:18px;font-weight:600;margin-bottom:8px;color:#16a34a">🎉 ${t('注册成功!')}</h2>
|
|
@@ -13570,7 +13570,7 @@ async function renderUserProfile(app, userId) {
|
|
|
13570
13570
|
<input type="checkbox" id="feed-visible-tg" style="width:16px;height:16px" ${data.feed_visible ? 'checked' : ''} onchange="toggleFeedVisible(this.checked)">
|
|
13571
13571
|
<label for="feed-visible-tg" style="font-size:13px;cursor:pointer">${t('在公开动态流显示我的活动')}</label>
|
|
13572
13572
|
</div>
|
|
13573
|
-
<p style="font-size:11px;color:#9ca3af;margin-top:4px;margin-left:26px">${t('
|
|
13573
|
+
<p style="font-size:11px;color:#9ca3af;margin-top:4px;margin-left:26px">${t('关闭后,你的购买/匹配/分润事件不会出现在 发现好物 > 动态')}</p>
|
|
13574
13574
|
|
|
13575
13575
|
<div id="social-msg" style="margin-top:10px"></div>
|
|
13576
13576
|
|
|
@@ -20959,7 +20959,7 @@ window.handleArbitrate = async (disputeId) => {
|
|
|
20959
20959
|
const amtEl = document.querySelector(`.arb-liable-amount[data-party="${partyId}"]`)
|
|
20960
20960
|
const amt = parseFloat(amtEl?.value || '0')
|
|
20961
20961
|
if (!amt || amt <= 0) {
|
|
20962
|
-
msgEl.innerHTML = alert$('error', `${t('请填写 ')}${chk.dataset.name}${t(' 的赔付金额')}`); return
|
|
20962
|
+
msgEl.innerHTML = alert$('error', `${t('请填写 ')}${escHtml(chk.dataset.name)}${t(' 的赔付金额')}`); return
|
|
20963
20963
|
}
|
|
20964
20964
|
const entry = { user_id: partyId, role: chk.dataset.role, amount: amt }
|
|
20965
20965
|
const insuranceChk = document.querySelector(`.arb-liable-insurance[data-party="${partyId}"]`)
|
|
@@ -21736,13 +21736,13 @@ async function renderSeller(app) {
|
|
|
21736
21736
|
)}
|
|
21737
21737
|
${featureCard(
|
|
21738
21738
|
'🎯',
|
|
21739
|
-
t('买家 Agent
|
|
21739
|
+
t('买家 Agent 意图匹配'),
|
|
21740
21740
|
t('零推广费'),
|
|
21741
21741
|
t('全网买家 Agent 携精准需求(Alias)全天候巡航,与商品语义刚需匹配,订单全自动闭合成交。')
|
|
21742
21742
|
)}
|
|
21743
21743
|
${featureCard(
|
|
21744
21744
|
'🌊',
|
|
21745
|
-
t('
|
|
21745
|
+
t('智能体扩散分润'),
|
|
21746
21746
|
t('秒级自动分账'),
|
|
21747
21747
|
t('商品由其他节点或达人 Agent 智能分享成交,下游分润通过智能合约去中心化自动清算,即刻到账。')
|
|
21748
21748
|
)}
|
|
@@ -22122,8 +22122,9 @@ async function renderSeller(app) {
|
|
|
22122
22122
|
|
|
22123
22123
|
const skillsSection = sellerSubTab === 'skills' ? `
|
|
22124
22124
|
<div style="font-size:12px;color:#6b7280;margin-bottom:10px">${t('Skill 自动化 · 让 Agent 替你接单/报价/发货')}</div>
|
|
22125
|
-
<div id="skill-mgmt-content">${loading$()}</div>
|
|
22126
22125
|
` : ''
|
|
22126
|
+
// 注:Skill 真实内容由下方 #my-skills-list 同步渲染(mySkills 已同步就绪);
|
|
22127
|
+
// 此前这里有个 #skill-mgmt-content loading$() 占位但全文件无人填充 → spinner 永转,已删除。
|
|
22127
22128
|
|
|
22128
22129
|
const productsSection = sellerSubTab === 'products' ? `
|
|
22129
22130
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">
|
|
@@ -24733,7 +24734,7 @@ function renderTrustCard(trust) {
|
|
|
24733
24734
|
const neg = []
|
|
24734
24735
|
if (s.dispute_penalty < 0) neg.push(`${t('仲裁败诉')} ${s.dispute_penalty}`)
|
|
24735
24736
|
if (s.sybil_penalty < 0) neg.push(`${t('同 IP 多号')} ${s.sybil_penalty}`)
|
|
24736
|
-
if (s.cross_penalty < 0) neg.push(`${t('
|
|
24737
|
+
if (s.cross_penalty < 0) neg.push(`${t('同支')} ${s.cross_penalty}`)
|
|
24737
24738
|
if (s.ratelimit_penalty < 0) neg.push(`${t('限速命中')} ${s.ratelimit_penalty}`)
|
|
24738
24739
|
|
|
24739
24740
|
const nextHint = trust.trust_score < trust.raw_mode_min_trust
|
|
@@ -24912,7 +24913,7 @@ async function renderWallet(app) {
|
|
|
24912
24913
|
</div>
|
|
24913
24914
|
</div>
|
|
24914
24915
|
|
|
24915
|
-
<!-- 卖家收入分类速览(仅 seller 显示)- 2026-05-24
|
|
24916
|
+
<!-- 卖家收入分类速览(仅 seller 显示)- 2026-05-24 匹配列只在 PV 允许地区显示 -->
|
|
24916
24917
|
${state.user?.role === 'seller' ? (() => {
|
|
24917
24918
|
const _pvOK = Number(state.user?.region_pv_enabled ?? 0) === 1 // 2026-06-04 解耦:PV 列读 pv_enabled,不再绑 max≥3
|
|
24918
24919
|
const cols = _pvOK ? 4 : 3
|
|
@@ -24931,7 +24932,7 @@ async function renderWallet(app) {
|
|
|
24931
24932
|
<div style="font-size:9px;color:#9ca3af">${((inc.commissions?.l1?.count||0)+(inc.commissions?.l2?.count||0)+(inc.commissions?.l3?.count||0))} ${t('单')}</div>
|
|
24932
24933
|
</div>
|
|
24933
24934
|
${_pvOK ? `<div style="background:#fefce8;border-radius:6px;padding:8px">
|
|
24934
|
-
<div style="font-size:9px;color:#854d0e">⚛ ${t('
|
|
24935
|
+
<div style="font-size:9px;color:#854d0e">⚛ ${t('匹配已结')}</div>
|
|
24935
24936
|
<div style="font-size:14px;font-weight:700;color:#a16207;margin-top:2px">${(inc.binary?.settled_waz||0).toFixed(2)}</div>
|
|
24936
24937
|
<div style="font-size:9px;color:#9ca3af">${inc.binary?.settled_count||0} ${t('次')}</div>
|
|
24937
24938
|
</div>` : ''}
|
|
@@ -24967,7 +24968,7 @@ async function renderWallet(app) {
|
|
|
24967
24968
|
})()}
|
|
24968
24969
|
${getMaxLevels() >= 3 ? `
|
|
24969
24970
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:10px">
|
|
24970
|
-
<div style="background:#fefce8;border-radius:6px;padding:10px"><div style="font-size:10px;color:#854d0e">⚛ ${t('
|
|
24971
|
+
<div style="background:#fefce8;border-radius:6px;padding:10px"><div style="font-size:10px;color:#854d0e">⚛ ${t('积分已结算')}</div><div style="font-size:15px;font-weight:700;color:#a16207">${inc.binary.settled_waz.toFixed(2)} WAZ</div><div style="font-size:9px;color:#9ca3af">${inc.binary.settled_count} ${t('次')}</div></div>
|
|
24971
24972
|
<div style="background:#fef3c7;border-radius:6px;padding:10px"><div style="font-size:10px;color:#92400e">⏳ ${t('待结 Score')}</div><div style="font-size:15px;font-weight:700;color:#d97706">${inc.binary.pending_score.toFixed(1)}</div><div style="font-size:9px;color:#9ca3af">${t('每月结算')}</div></div>
|
|
24972
24973
|
</div>` : ''}
|
|
24973
24974
|
${inc.sales.count > 0 ? `
|
|
@@ -25200,7 +25201,7 @@ window.doWithdraw = async () => {
|
|
|
25200
25201
|
msgEl.innerHTML = ''
|
|
25201
25202
|
return
|
|
25202
25203
|
}
|
|
25203
|
-
msgEl.innerHTML = alert$('success', `✅ ${res.message}`)
|
|
25204
|
+
msgEl.innerHTML = alert$('success', `✅ ${escHtml(res.message)}`)
|
|
25204
25205
|
setTimeout(() => renderWallet(document.getElementById('app')), 2000)
|
|
25205
25206
|
}
|
|
25206
25207
|
|
|
@@ -26636,7 +26637,7 @@ async function renderSkillPublish(app) {
|
|
|
26636
26637
|
<textarea class="form-control" id="skm-preview" rows="3" maxlength="500" placeholder="${t('展示部分内容吸引购买,可留空')}" style="font-size:13px;resize:vertical;margin-bottom:12px"></textarea>
|
|
26637
26638
|
|
|
26638
26639
|
<div style="font-size:12px;color:#374151;font-weight:600;margin-bottom:6px">${t('技能正文(购买后解锁)')}</div>
|
|
26639
|
-
<textarea class="form-control" id="skm-
|
|
26640
|
+
<textarea class="form-control" id="skm-body" rows="8" maxlength="20000" placeholder="${t('完整的模板 / 提示词 / 指南 / 清单内容…')}" style="font-size:13px;resize:vertical"></textarea>
|
|
26640
26641
|
</div></div>
|
|
26641
26642
|
<div id="skm-publish-msg" style="margin-bottom:8px"></div>
|
|
26642
26643
|
<button class="btn btn-primary" style="width:100%;font-size:14px;padding:10px" onclick="doSkmPublish()">${t('提交审核')}</button>
|
|
@@ -26655,7 +26656,7 @@ window.doSkmPublish = async () => {
|
|
|
26655
26656
|
const price = parseFloat(document.getElementById('skm-price')?.value) || 0
|
|
26656
26657
|
const summary = document.getElementById('skm-summary')?.value?.trim()
|
|
26657
26658
|
const preview = document.getElementById('skm-preview')?.value?.trim()
|
|
26658
|
-
const content = document.getElementById('skm-
|
|
26659
|
+
const content = document.getElementById('skm-body')?.value
|
|
26659
26660
|
const msg = document.getElementById('skm-publish-msg')
|
|
26660
26661
|
if (!title || title.length < 2) { msg.innerHTML = alert$('error', t('请填写标题')); return }
|
|
26661
26662
|
if (!content || !content.trim()) { msg.innerHTML = alert$('error', t('请填写技能正文内容')); return }
|
|
@@ -27554,7 +27555,7 @@ async function renderListingFollow(app, listingId) {
|
|
|
27554
27555
|
if (!state.user) { location.hash = '#login'; return }
|
|
27555
27556
|
if (state.user.role !== 'seller') { app.innerHTML = `<div style="padding:24px">${alert$('warn', t('仅卖家可跟卖'))}</div>`; return }
|
|
27556
27557
|
const r = await GET('/listings/' + encodeURIComponent(listingId))
|
|
27557
|
-
if (r?.error) { app.innerHTML = `<div style="padding:24px">${alert$('error', r.error)}</div>`; return }
|
|
27558
|
+
if (r?.error) { app.innerHTML = `<div style="padding:24px">${alert$('error', escHtml(r.error))}</div>`; return }
|
|
27558
27559
|
const l = r.listing
|
|
27559
27560
|
|
|
27560
27561
|
app.innerHTML = `
|
|
@@ -33287,7 +33288,7 @@ window.submitNote = async (orderId, parentId, draftKey) => {
|
|
|
33287
33288
|
body: buf,
|
|
33288
33289
|
})
|
|
33289
33290
|
const j = await upResp.json()
|
|
33290
|
-
if (!upResp.ok || j.error) { msg.innerHTML = alert$('error', t('图片上传失败') + `:${j.error}`); btn.disabled = false; return }
|
|
33291
|
+
if (!upResp.ok || j.error) { msg.innerHTML = alert$('error', t('图片上传失败') + `:${escHtml(j.error)}`); btn.disabled = false; return }
|
|
33291
33292
|
hashes.push(hash)
|
|
33292
33293
|
}
|
|
33293
33294
|
// 步骤 2: 创建笔记(带 parent_id 时为转发)
|