- index.html 已登录也不显示侧边栏(公开展示页) - 政策落地三栏表格精简为 3 列,加 word-break: keep-all 防止中文竖排 - 结算总览和质量与信用从 list 改为表格布局,更紧凑 - 智能体服务菜单移到「服务与政策」分组 - 门户"我要接订单"恢复为 login.html(先选角色) Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
379 lines
18 KiB
HTML
379 lines
18 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>OPC 工作台 · OPC 公共服务平台 Demo</title>
|
||
<link rel="stylesheet" href="assets/style.css">
|
||
</head>
|
||
<body data-page="opc">
|
||
<header class="topnav" id="topnav"></header>
|
||
|
||
<div class="container">
|
||
<div class="page-title">OPC 工作台</div>
|
||
<div class="page-sub" id="opc-sub"></div>
|
||
|
||
<!-- REQ-013 五态入驻状态 -->
|
||
<div class="card">
|
||
<h3>入驻状态 <span class="req">REQ-013</span></h3>
|
||
<div id="opc-steps"></div>
|
||
<p class="muted" style="margin-top:10px">距离"优质供应商":复购率需 ≥50%(当前 62% ✓)、累计交付 ≥50 单(当前 38 单)、连续 90 天零投诉 ✓</p>
|
||
<p class="muted">支持自然人/个体户/一人公司/机构等主体类型(REQ-011);注销保留法定审计数据并匿名化个人信息(REQ-018)。</p>
|
||
</div>
|
||
|
||
<div class="section grid grid-4" id="opc-stats"></div>
|
||
|
||
<!-- REQ-019~021 能力档案与认证 -->
|
||
<div class="section">
|
||
<div class="two-col">
|
||
<div class="card">
|
||
<h3>能力档案 <span class="req">REQ-019/020</span></h3>
|
||
<div id="opc-profile"></div>
|
||
<button class="btn sm" style="margin-top:10px" onclick="uploadWork()">上传作品</button>
|
||
<button class="btn sm ghost" style="margin-top:10px" onclick="toast('能力名片已生成: opc.card/OPC_00017 (演示链接)')">生成对外能力名片</button>
|
||
<button class="btn sm ghost" style="margin-top:10px" onclick="identity()">实名认证信息</button>
|
||
<p class="muted" style="margin-top:6px">REQ-006 对外能力名片 · REQ-012/016/017 实名核验</p>
|
||
</div>
|
||
<div class="card">
|
||
<h3>能力认证 <span class="req">REQ-021/022/024/025</span></h3>
|
||
<div id="opc-cert"></div>
|
||
<a class="btn ghost sm" href="training.html" style="margin-top:10px">进入培训认证</a>
|
||
<button class="btn sm ghost" style="margin-top:10px" onclick="verifyCert()">查验证书</button>
|
||
<button class="btn sm ghost" style="margin-top:10px" onclick="scoreBasis()">评分依据</button>
|
||
<button class="btn sm ghost" style="margin-top:10px" onclick="toast('复评申请已登记,运营商将在到期前 30 天安排复评')">预约复评</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- REQ-031 订单池与智能推荐 -->
|
||
<div class="section">
|
||
<h2>订单池 · 推荐任务 <span class="req">REQ-026/031 · 能力档案作为派单/资源券/信用输入,按标签/等级/表现匹配</span></h2>
|
||
<div class="card"><table id="pool-tbl"></table></div>
|
||
</div>
|
||
|
||
<!-- REQ-128 抢单订单池 -->
|
||
<div class="section">
|
||
<h2>抢单订单池 <span class="req">REQ-128/129 · 标准化任务公开抢单 · 先到先得</span></h2>
|
||
<div class="card"><table id="grab-tbl"></table></div>
|
||
<p class="muted" style="margin-top:8px">运营商将标准化任务放入抢单池,OPC 按 SOP 标准自主抢单;抢单后锁定 30 分钟内确认接单,超时释放回池。</p>
|
||
</div>
|
||
|
||
<!-- REQ-124/125 政策落地:算力券 + 贷款 + 租金 -->
|
||
<div class="section">
|
||
<h2>政策落地 · 算力券 / 贷款 / 租金 <span class="req">REQ-124/125 · 全链路可见</span></h2>
|
||
<div class="three-col" style="display:grid;grid-template-columns:repeat(3,1fr);gap:16px">
|
||
<div class="card">
|
||
<h3>算力券申领与核销 <span class="req">REQ-124</span></h3>
|
||
<p class="muted">余额 <b id="vc-bal">¥8,000</b> / ¥10,000</p>
|
||
<table id="vc-tbl" style="margin-top:8px"></table>
|
||
<button class="btn sm" style="margin-top:8px" onclick="applyCompute()">申领算力券</button>
|
||
</div>
|
||
<div class="card">
|
||
<h3>贷款支持 <span class="req">REQ-125</span></h3>
|
||
<table id="loan-tbl"></table>
|
||
<button class="btn sm" style="margin-top:8px" onclick="applyLoan()">申请贷款</button>
|
||
</div>
|
||
<div class="card">
|
||
<h3>租金补贴</h3>
|
||
<table id="rent-tbl"></table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- REQ-127 OPC 财务分析 -->
|
||
<div class="section">
|
||
<h2>财务分析 <span class="req">REQ-127 · 接单收入 - 算力 - 社保 = 净收益</span></h2>
|
||
<div class="two-col">
|
||
<div class="card">
|
||
<h3>本月收支概览</h3>
|
||
<table id="fin-tbl"></table>
|
||
</div>
|
||
<div class="card">
|
||
<h3>财务建议</h3>
|
||
<ul class="list" id="fin-suggest"></ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- REQ-043/046 收入与结算 -->
|
||
<div class="section">
|
||
<h2>收入与结算 <span class="req">REQ-043/046 · 分账核算 + 保证金托管</span></h2>
|
||
<div class="two-col">
|
||
<div class="card">
|
||
<h3>结算总览</h3>
|
||
<table id="stl-summary"></table>
|
||
<button class="btn sm" style="margin-top:10px" onclick="withdraw()">申请提现</button>
|
||
</div>
|
||
<div class="card">
|
||
<h3>结算单 <span class="req">SETL_ 编号</span></h3>
|
||
<table id="stl-tbl"></table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- REQ-023 质量预警 + REQ-044 评价 -->
|
||
<div class="section">
|
||
<div class="two-col">
|
||
<div class="card">
|
||
<h3>质量与信用 <span class="req">REQ-023/050</span></h3>
|
||
<table id="opc-quality"></table>
|
||
</div>
|
||
<div class="card">
|
||
<h3>最新客户评价 <span class="req">REQ-044</span></h3>
|
||
<ul class="list" id="opc-reviews"></ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer">OPC 公共服务平台 Demo · OPC 工作台</div>
|
||
<script src="assets/app.js"></script>
|
||
<script src="assets/store.js"></script>
|
||
<script>
|
||
let avail = { h: '40h', cap: 25 };
|
||
|
||
function renderPage(DB) {
|
||
const O = DB.opc;
|
||
const role = currentRole();
|
||
document.getElementById('opc-sub').textContent = role === 'operator'
|
||
? `${O.id} · ${O.name} · 运营商管理视角(查看 OPC 档案与运营状态)`
|
||
: `${O.id} · ${O.name} · 入驻五态与能力档案一览`;
|
||
document.getElementById('opc-steps').innerHTML = STEPS(O.steps);
|
||
document.getElementById('opc-stats').innerHTML = O.stats.map(s =>
|
||
`<div class="card"><h3>${s.label}</h3><div class="num">${s.num}</div><p class="muted">${s.sub}</p></div>`).join('');
|
||
|
||
const p = O.profile;
|
||
document.getElementById('opc-profile').innerHTML = `
|
||
<p class="muted">五层标签:${p.tags}</p>
|
||
<div>${p.skills.map(TAG).join('')}</div>
|
||
<table style="margin-top:12px">
|
||
<tr><th>档案项</th><th>内容</th></tr>
|
||
${p.rows.map(r => `<tr><td>${r[0]}</td><td>${r[1]}</td></tr>`).join('')}
|
||
<tr><td>可接单时间</td><td id="avail-cell"></td></tr>
|
||
<tr><td>保密/合规</td><td><span class="badge ok">NDA 已签</span> <span class="badge ok">合规培训通过</span></td></tr>
|
||
</table>`;
|
||
renderAvail();
|
||
|
||
const c = O.cert;
|
||
document.getElementById('opc-cert').innerHTML = `
|
||
<div class="num">${c.level} <small>${c.desc}</small></div>
|
||
<p class="muted" style="margin:8px 0">证书 ${c.no} · 有效期至 ${c.expire}</p>
|
||
${BAR(c.progress, 'ok')}
|
||
<p class="muted" style="margin-top:6px">${c.next}</p>`;
|
||
|
||
renderPool();
|
||
renderGrab();
|
||
renderPolicySupport();
|
||
renderFinance();
|
||
document.getElementById('stl-summary').innerHTML = O.settlement.summary.map(s =>
|
||
`<tr><td>${s[0]}</td><td style="text-align:right;font-weight:600">${s[1]}</td></tr>`).join('');
|
||
document.getElementById('stl-tbl').innerHTML =
|
||
`<tr><th>结算单</th><th>关联订单</th><th>金额</th><th>状态</th></tr>` +
|
||
O.settlement.rows.map(r => `<tr><td>${r.code}</td><td>${r.order}</td><td>${r.amount}</td><td>${B(r.status)}</td></tr>`).join('');
|
||
|
||
document.getElementById('opc-quality').innerHTML = O.quality.map(q =>
|
||
`<tr><td>${q[0]}</td><td style="text-align:right">${B(q[1])}</td></tr>`).join('');
|
||
document.getElementById('opc-reviews').innerHTML = O.reviews.map(r =>
|
||
`<li><span>${r[0]}</span><span class="badge ok">${r[1]}</span></li>`).join('');
|
||
}
|
||
|
||
function renderAvail() {
|
||
document.getElementById('avail-cell').innerHTML =
|
||
`每周 ${avail.h} · 月产能约 ${avail.cap} 任务件 <button class="btn sm ghost" onclick="editAvail()">调整</button>`;
|
||
}
|
||
|
||
function renderPool() {
|
||
const acts = {
|
||
quote: o => `<button class="btn sm" onclick="quote(this,'${o.id}')">参与报价</button>`,
|
||
claim: o => `<button class="btn sm" onclick="claim(this,'${o.id}')">领取任务</button>`,
|
||
view: o => `<a class="btn sm ghost" href="order.html">查看</a>`,
|
||
};
|
||
document.getElementById('pool-tbl').innerHTML =
|
||
`<tr><th>订单</th><th>类型</th><th>交付物</th><th>预算</th><th>截止</th><th>匹配度</th><th>操作</th></tr>` +
|
||
DB.opc.orderPool.map(o => `<tr><td>${o.id}</td><td>${B(o.type)}</td><td>${o.items}</td><td>${o.budget}</td><td>${o.ddl}</td><td>${B(o.match)}</td><td>${acts[o.action](o)}</td></tr>`).join('');
|
||
}
|
||
|
||
function claim(btn, id) {
|
||
const o = DB.opc.orderPool.find(x => x.id === id);
|
||
confirmDlg('领取派单任务', `${o.items} · ${o.budget} · 截止 ${o.ddl}。领取后将按 SOP 提交清单执行并计入产能。`, '确认领取', () => {
|
||
btn.outerHTML = '<span class="badge ok">已领取 · 进入任务协同</span>';
|
||
toast('任务已领取,可在「订单与协同」查看 SOP 与提交清单');
|
||
});
|
||
}
|
||
function quote(btn, id) {
|
||
const o = DB.opc.orderPool.find(x => x.id === id);
|
||
openModal({
|
||
title: '参与询价报价 · ' + id,
|
||
body: `
|
||
<div class="field"><label>报价金额(客户预算 ${o.budget})</label><input id="q-price" value="22500"></div>
|
||
<div class="field"><label>交付周期</label><select><option>10 天</option><option>14 天</option><option>20 天</option></select></div>
|
||
<div class="field"><label>方案说明</label><textarea placeholder="交付物拆分、样例、排产说明"></textarea></div>
|
||
<p class="muted">小样试做:本单要求小样,报价后进入小样环节(REQ-032)。</p>`,
|
||
actions: [
|
||
{ label: '取消', cls: 'ghost' },
|
||
{ label: '提交报价', onClick: m => {
|
||
m.remove();
|
||
btn.outerHTML = '<span class="badge info">已报价 ¥22,500</span>';
|
||
toast('报价已提交,等待运营商组织评审');
|
||
} },
|
||
],
|
||
});
|
||
}
|
||
function uploadWork() {
|
||
openModal({
|
||
title: '上传作品',
|
||
body: `
|
||
<div class="field"><label>作品名称</label><input placeholder="如:夏季新品主图系列"></div>
|
||
<div class="field"><label>关联能力标签</label><input value="跨境电商 / 视觉设计 / 商品场景图"></div>
|
||
<div class="field"><label>客户授权说明(REQ-004)</label><select><option>已获客户授权展示</option><option>仅展示脱敏能力描述</option></select></div>
|
||
<div class="field"><label>文件</label><input type="file"></div>`,
|
||
actions: [
|
||
{ label: '取消', cls: 'ghost' },
|
||
{ label: '提交审核', onClick: m => { m.remove(); toast('作品已提交,运营商审核通过后进入对外名片'); } },
|
||
],
|
||
});
|
||
}
|
||
function editAvail() {
|
||
openModal({
|
||
title: '调整可接单时间',
|
||
body: `<div class="field-row">
|
||
<div class="field"><label>每周可投入</label><select id="a-h"><option>20h</option><option selected>40h</option><option>60h</option></select></div>
|
||
<div class="field"><label>月产能(任务件)</label><input id="a-cap" value="${avail.cap}"></div></div>`,
|
||
actions: [
|
||
{ label: '取消', cls: 'ghost' },
|
||
{ label: '保存', onClick: m => {
|
||
avail.h = document.getElementById('a-h').value;
|
||
avail.cap = document.getElementById('a-cap').value;
|
||
m.remove(); renderAvail();
|
||
toast('可接单时间已更新,派单匹配将按新产能计算');
|
||
} },
|
||
],
|
||
});
|
||
}
|
||
function identity() {
|
||
openModal({
|
||
title: '实名认证信息(REQ-012/017)',
|
||
body: `<table>
|
||
<tr><th>主体类型</th><td>个体工商户(个人通道已完成实名+支付验证)</td></tr>
|
||
<tr><th>手机核验</th><td><span class="badge ok">已通过</span> 138****6688</td></tr>
|
||
<tr><th>身份证核验</th><td><span class="badge ok">已通过</span> 3301**********1234</td></tr>
|
||
<tr><th>营业执照</th><td><span class="badge ok">已核验</span> 统一社会信用代码 92****XU</td></tr>
|
||
<tr><th>法人/操作人/收款主体</th><td>三者一致 · 已关联</td></tr>
|
||
<tr><th>变更触发</th><td>法人、收款账户变更将自动触发重新核验(REQ-016)</td></tr>
|
||
</table>`,
|
||
actions: [
|
||
{ label: '关闭', cls: 'ghost' },
|
||
{ label: '模拟收款账户变更', cls: 'danger', onClick: m => { m.remove(); toast('检测到收款主体变更:已触发重新核验流程,期间接单权限临时锁定(REQ-016)', 'warn'); } },
|
||
],
|
||
});
|
||
}
|
||
function scoreBasis() {
|
||
openModal({
|
||
title: '认证评分依据 · L3(REQ-022/024)',
|
||
body: `<p class="muted">评分由系统自动计算,全部依据可追溯至业务单据;不以缴费培训作为认证条件。</p>
|
||
<table>
|
||
<tr><th>依据来源</th><th>指标</th><th>得分贡献</th></tr>
|
||
<tr><td>ORDER_2026071501 验收记录</td><td>一次验收通过率 95%</td><td>+28</td></tr>
|
||
<tr><td>DLV_ 质检批次 ×14</td><td>三级质检通过率 / 返工率 4%</td><td>+24</td></tr>
|
||
<tr><td>TRP_20260802 实训评审</td><td>真实单实训 95 分</td><td>+18</td></tr>
|
||
<tr><td>EVAL_ 客户评价 ×23</td><td>均分 4.9 / 复购率 62%</td><td>+20</td></tr>
|
||
<tr><td>CERT_20260042 机构认证</td><td>中级能力附加</td><td>+10</td></tr>
|
||
<tr><th>综合</th><th>L3 阈值 ≥85</th><th>96 · 达标</th></tr>
|
||
</table>`,
|
||
});
|
||
}
|
||
function withdraw() {
|
||
confirmDlg('申请提现', '可提现余额 ¥46,800,提至已核验收款账户(REQ-012 实名关联)。预计 T+1 到账。', '确认提现', () => {
|
||
toast('提现申请已提交财务通道,到账后将生成结算回单');
|
||
});
|
||
}
|
||
function verifyCert() {
|
||
const c = DB.opc.cert;
|
||
openModal({
|
||
title: '证书查验 · ' + c.no,
|
||
body: `<table>
|
||
<tr><th>证书编号</th><td>${c.no}</td></tr>
|
||
<tr><th>颁发主体</th><td>OPC 公共服务平台</td></tr>
|
||
<tr><th>认证等级</th><td>${c.level} · ${c.desc}</td></tr>
|
||
<tr><th>能力标签</th><td>跨境电商 / 视觉设计 / 商品场景图</td></tr>
|
||
<tr><th>有效期</th><td>2026-04-01 ~ ${c.expire}</td></tr>
|
||
<tr><th>状态</th><td><span class="badge ok">有效 · 防伪校验通过</span></td></tr>
|
||
</table>`,
|
||
});
|
||
}
|
||
|
||
/* === 抢单订单池 === */
|
||
function renderGrab() {
|
||
const pool = DB.opc.grabPool || [];
|
||
document.getElementById('grab-tbl').innerHTML =
|
||
`<tr><th>订单号</th><th>类型</th><th>交付物</th><th>预算</th><th>截止</th><th>SOP</th><th>已抢单/上限</th><th>状态</th><th>操作</th></tr>` +
|
||
pool.map((o, i) => `<tr>
|
||
<td>${o.id}</td><td>${B(o.type)}</td><td>${o.items}</td><td>${o.budget}</td><td>${o.ddl}</td>
|
||
<td><code>${o.sop}</code></td><td>${o.count}</td><td>${B(o.status)}</td>
|
||
<td>${o.status[1] === 'ok' ? `<button class="btn sm" onclick="grabOrder(${i})">立即抢单</button>` : '<span class="muted">已满</span>'}</td>
|
||
</tr>`).join('');
|
||
}
|
||
function grabOrder(i) {
|
||
const o = DB.opc.grabPool[i];
|
||
confirmDlg('抢单确认', `${o.items} · ${o.budget} · 截止 ${o.ddl}。抢单后 30 分钟内确认接单,超时释放。`, '确认抢单', () => {
|
||
toast('抢单成功!请在 30 分钟内确认接单,否则任务释放回池');
|
||
o.count = o.count.split('/')[0] + '/' + o.count.split('/')[1];
|
||
const cur = parseInt(o.count) + 1;
|
||
o.count = cur + '/' + o.count.split('/')[1];
|
||
if (cur >= parseInt(o.count.split('/')[1])) o.status = ['已满', 'gray'];
|
||
renderGrab();
|
||
});
|
||
}
|
||
|
||
/* === 政策落地 === */
|
||
function renderPolicySupport() {
|
||
const P = DB.opc.policySupport;
|
||
if (!P) return;
|
||
// 算力券:3列紧凑
|
||
document.getElementById('vc-bal').textContent = `¥${P.compute.balance.toLocaleString()}`;
|
||
document.getElementById('vc-tbl').innerHTML =
|
||
`<tr><th>金额</th><th>关联订单</th><th>状态</th></tr>` +
|
||
P.compute.records.map(r => `<tr><td>${r.amount}</td><td class="muted">${r.target.split(' ')[0]}</td><td>${B(r.status)}</td></tr>`).join('');
|
||
// 贷款:3列紧凑
|
||
document.getElementById('loan-tbl').innerHTML =
|
||
`<tr><th>类型</th><th>金额</th><th>状态</th></tr>` +
|
||
P.loan.records.map(r => `<tr><td>${r.type}<br><small class="muted">${r.rate}</small></td><td>${r.amount}</td><td>${B(r.status)}</td></tr>`).join('');
|
||
// 租金:3列紧凑
|
||
document.getElementById('rent-tbl').innerHTML =
|
||
`<tr><th>类型</th><th>金额</th><th>状态</th></tr>` +
|
||
P.rent.records.map(r => `<tr><td>${r.type}</td><td>${r.amount}</td><td>${B(r.status)}</td></tr>`).join('');
|
||
}
|
||
function applyCompute() {
|
||
confirmDlg('申领算力券', '按细则可申领 ≤¥10,000/年。当前余额 ¥8,000,可追加申领 ¥2,000。', '确认申领', () => {
|
||
toast('算力券申领已提交,经信局审核后发放至券台账');
|
||
});
|
||
}
|
||
function applyLoan() {
|
||
openModal({
|
||
title: '申请贷款支持',
|
||
body: `<div class="field"><label>贷款类型</label><select><option>创业担保贷款(政府贴息 2%)</option><option>算力信用贷(年化 3.85%)</option><option>经营性贷款(年化 4.5%)</option></select></div>
|
||
<div class="field-row"><div class="field"><label>申请额度</label><input placeholder="如:¥20 万"></div>
|
||
<div class="field"><label>期限</label><select><option>6 个月</option><option selected>12 个月</option><option>24 个月</option></select></div></div>
|
||
<p class="muted">贷款申请将关联 OPC 信用档案与订单收入流水,运营商初审后推送合作金融机构。</p>`,
|
||
actions: [
|
||
{ label: '取消', cls: 'ghost' },
|
||
{ label: '提交申请', onClick: m => { m.remove(); toast('贷款申请已提交,运营商初审中'); } },
|
||
],
|
||
});
|
||
}
|
||
|
||
/* === 财务分析 === */
|
||
function renderFinance() {
|
||
const F = DB.opc.finance;
|
||
if (!F) return;
|
||
document.getElementById('fin-tbl').innerHTML =
|
||
`<tr><th>项目</th><th>金额</th><th>占比</th><th>说明</th></tr>` +
|
||
`<tr><td><b>接单收入</b></td><td><b>${F.income.total}</b></td><td>—</td><td>${F.income.orders} 单 · 均 ${F.income.avg}</td></tr>` +
|
||
F.costs.map(c => `<tr><td>${c.item}</td><td style="color:var(--danger)">-${c.amount}</td><td>${c.pct || '—'}%</td><td class="muted">${c.detail}</td></tr>`).join('') +
|
||
`<tr style="border-top:2px solid var(--primary)"><td><b>净收益</b></td><td><b style="color:var(--success)">${F.net}</b></td><td>—</td><td>税后</td></tr>`;
|
||
document.getElementById('fin-suggest').innerHTML = F.suggestions.map(s => `<li><span>${s}</span></li>`).join('');
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|