Files
OPC/Demo/operator.html
freedakandDevin 13cad398dc feat: OPC 平台功能增强 v1.4 · 8 项需求变更实施
CHG-006 抢单订单池:OPC 工作台加抢单池(REQ-128/129)
CHG-004 政策落地:OPC 加算力券申领/核销+贷款+租金,运营商加政策跟踪(REQ-124/125/126)
CHG-001 组队模块:新增 team.html 组队协同页(REQ-119/120/121)
CHG-003 活动管理:运营工作台加活动创建/发布/报名管理(REQ-122/123)
CHG-005 OPC 财务分析:OPC 工作台加财务看板(REQ-127)
CHG-008 平台撮合归集:运营工作台加录入入口(REQ-130)
CHG-002 入口跳转:确认已正确(OPC→opc.html)
CHG-007 服务中心定位:明确为运营商服务资源管理

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 08:47:29 +08:00

292 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>运营工作台 · OPC 公共服务平台 Demo</title>
<link rel="stylesheet" href="assets/style.css">
</head>
<body data-page="operator">
<header class="topnav" id="topnav"></header>
<div class="container">
<div class="page-title">运营工作台</div>
<div class="page-sub">运营商待办与全业务运营入口 · 审核、仲裁、派单、结算批次</div>
<div class="grid grid-4" id="op-stats"></div>
<!-- 业务方向选择与培育(§1.5 步骤①②) -->
<div class="section">
<h2>业务方向选择与培育 <span class="req">§1.5 ①② · 选方向 → 育人才</span></h2>
<div class="card"><table id="op-biz"></table></div>
<p class="muted" style="margin-top:8px">运营五步闭环:选方向 → 育人才 → 建平台 → 立 SOP → 聚产业。每个方向有对应 SOP 标准体系与质量指标集,支撑蜂群式交付。</p>
</div>
<!-- 待办审核队列 -->
<div class="section">
<h2>待办审核队列 <span class="req">REQ-099/100/114/106/060/010 · ADT_ 统一编号</span></h2>
<div class="card"><table id="op-audits"></table></div>
</div>
<!-- 活动管理(REQ-122/123) -->
<div class="section">
<h2>活动管理 <span class="req">REQ-122/123 · 创建/发布/报名 · 关联线索转化</span>
<span style="margin-left:auto"><button class="btn sm" onclick="createActivity()">创建活动</button></span>
</h2>
<div class="card"><table id="op-acts"></table></div>
<p class="muted" style="margin-top:8px">活动 → 线索 → 订单转化链路(REQ-096/097)。每场活动关联后续线索与订单转化。</p>
</div>
<!-- 政策落地跟踪(REQ-126) -->
<div class="section">
<h2>政策落地跟踪 <span class="req">REQ-126 · 算力券/贷款/租金/社保 · 全链路</span></h2>
<div class="card"><table id="op-policy"></table></div>
<p class="muted" style="margin-top:8px">运营商跟踪政策落地进度:申请 → 审批 → 使用 → 绩效。数据脱敏同步政府驾驶舱。</p>
</div>
<!-- 平台撮合订单归集(REQ-130) -->
<div class="section">
<h2>平台撮合订单归集 <span class="req">REQ-130 · 平台介入撮合 · 统一归集</span>
<span style="margin-left:auto"><button class="btn sm" onclick="brokerOrder()">录入撮合订单</button></span>
</h2>
<div class="card"><table id="op-broker"></table></div>
<p class="muted" style="margin-top:8px">平台介入撮合的订单手动录入或批量导入,标注来源为"平台撮合",走统一订单状态机和结算流程。</p>
</div>
<!-- 项目总览 -->
<div class="section">
<h2>进行中项目 <span class="req">REQ-031/036 · 运营商统一拆单与质检</span></h2>
<div class="card"><table id="op-proj"></table></div>
</div>
<!-- 快捷入口 -->
<div class="section">
<div class="card">
<h3>快捷入口</h3>
<p>
<a class="btn sm" href="leads.html">供需对接</a>
<a class="btn sm" href="order.html">订单协同</a>
<a class="btn sm" href="institution.html">机构管理</a>
<a class="btn sm" href="market.html">橙果商城审核</a>
<a class="btn sm ghost" href="profile.html">画像中心</a>
<a class="btn sm ghost" href="showcase.html">社区大屏</a>
</p>
</div>
</div>
</div>
<div class="footer">OPC 公共服务平台 Demo · 运营工作台</div>
<script src="assets/app.js"></script>
<script src="assets/store.js"></script>
<script>
function renderPage(DB) {
const O = DB.operator;
document.getElementById('op-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('');
renderBizDirections();
renderAudits();
renderActivities();
renderPolicyTracking();
renderBrokerOrders();
document.getElementById('op-proj').innerHTML =
`<tr><th>项目</th><th>客户</th><th>承接</th><th>进度</th><th>状态</th><th>操作</th></tr>` +
O.projects.map(p => `<tr><td>${p.code} ${p.name}</td><td>${p.client}</td><td>${p.opc}</td><td>${BAR(p.pct)}</td><td>${B(p.status)}</td><td><a class="btn sm ghost" href="order.html">进入协同</a></td></tr>`).join('');
}
function renderBizDirections() {
const dirs = DB.operator.bizDirections || [];
document.getElementById('op-biz').innerHTML =
`<tr><th>业务方向</th><th>阶段</th><th>认证 OPC</th><th>在训学员</th><th>累计订单</th><th>收入</th><th>SOP 标准</th><th>状态</th></tr>` +
dirs.map(d => `<tr>
<td><b>${d.name}</b></td>
<td>${d.stage}</td>
<td>${d.opcs} 人</td>
<td>${d.trainees} 人</td>
<td>${d.orders} 单</td>
<td>${d.revenue}</td>
<td><code>${d.sop}</code></td>
<td>${B(d.status)}</td>
</tr>`).join('');
}
function renderAudits() {
document.getElementById('op-audits').innerHTML =
`<tr><th>待办号</th><th>类型</th><th>对象</th><th>要点</th><th>操作</th></tr>` +
DB.operator.audits.map((a, i) => `<tr><td>${a.code}</td><td><span class="badge pri">${a.type}</span></td><td>${a.target}</td><td class="muted">${a.detail}</td><td>${
a.action === 'arbitrate'
? `<button class="btn sm" onclick="arbitrate(${i})">仲裁</button>`
: `<button class="btn sm" onclick="approve(${i})">通过</button> <button class="btn sm ghost" onclick="reject(${i})">驳回</button>`
}</td></tr>`).join('');
}
function applyAuditResult(a, pass) {
// 联动更新对应业务域,演示数据一致性
if (a.domain === 'course') {
const c = DB.institution.courses.find(x => x.code === 'CRS_0104');
if (c) { c.status = pass ? ['已上架', 'ok'] : ['已驳回', 'err']; c.action = pass ? 'edit' : 'withdraw'; }
}
if (a.domain === 'work') {
const w = DB.market.items.find(x => x.code === 'WORK_0060');
if (w) { w.status = pass ? ['已上架', 'ok'] : ['已驳回', 'err']; w.action = pass ? 'buy' : 'audit'; }
}
}
function approve(i) {
const a = DB.operator.audits[i];
confirmDlg('审核通过确认', `确认通过「${a.type} · ${a.target}」?结果将写入对应业务台账并留痕。`, '确认通过', () => {
applyAuditResult(a, true);
DB.operator.audits.splice(i, 1);
renderAudits();
toast(`已通过:${a.target}${a.domain === 'course' ? '(课程已在机构端同步上架)' : a.domain === 'work' ? '(成果已上架商城)' : ''}`);
});
}
function reject(i) {
const a = DB.operator.audits[i];
openModal({
title: '驳回 · ' + a.target,
body: `<div class="field"><label>驳回原因(将反馈给提交方)</label><textarea placeholder="如:材料不全 / 资质不符 / 内容违规"></textarea></div>`,
actions: [
{ label: '取消', cls: 'ghost' },
{ label: '确认驳回', cls: 'danger', onClick: m => {
m.remove();
applyAuditResult(a, false);
DB.operator.audits.splice(i, 1);
renderAudits();
toast('已驳回并通知提交方', 'warn');
} },
],
});
}
function arbitrate(i) {
const a = DB.operator.audits[i];
openModal({
title: '争议仲裁 · ' + a.target,
body: `<p class="muted">争议点:详情页返工责任归属。双方提交材料已归档。</p>
<div class="checks">
<label><input type="radio" name="ab" checked> 判定为客户责任(需求变更),返工费用客户承担</label>
<label><input type="radio" name="ab"> 判定为 OPC 责任,计入返工率并免费返工</label>
<label><input type="radio" name="ab"> 双方分摊(50/50)</label>
</div>`,
actions: [
{ label: '取消', cls: 'ghost' },
{ label: '下达仲裁结论', onClick: m => {
m.remove();
DB.operator.audits.splice(i, 1);
renderAudits();
toast('仲裁结论已下达并留痕(REQ-060),结算节点已解冻');
} },
],
});
}
/* === 活动管理 === */
function renderActivities() {
const acts = DB.operator.activities || [];
document.getElementById('op-acts').innerHTML =
`<tr><th>活动号</th><th>名称</th><th>日期</th><th>报名</th><th>容量</th><th>转化线索</th><th>状态</th><th>操作</th></tr>` +
acts.map((a, i) => `<tr>
<td>${a.code}</td><td>${a.name}</td><td>${a.date}</td>
<td>${a.signups}</td><td>${a.capacity}</td><td>${a.leads}</td><td>${B(a.status)}</td>
<td><button class="btn sm ghost" onclick="actDetail(${i})">详情</button> <button class="btn sm ghost" onclick="actSignups(${i})">报名</button></td>
</tr>`).join('');
}
function createActivity() {
openModal({
title: '创建活动(REQ-122)',
body: `<div class="field"><label>活动名称</label><input placeholder="如:供需对接会 · 智能体专场"></div>
<div class="field-row">
<div class="field"><label>日期</label><input type="date"></div>
<div class="field"><label>容量</label><input value="80"></div>
</div>
<div class="field"><label>活动介绍</label><textarea placeholder="活动主题、目标受众、议程安排"></textarea></div>
<div class="field"><label>关联业务方向</label><select><option>跨境电商视觉</option><option>AI 漫剧</option><option>企业智能体</option><option>华强北硬件供应链</option><option>综合</option></select></div>`,
actions: [
{ label: '取消', cls: 'ghost' },
{ label: '发布活动', onClick: m => { m.remove(); toast('活动已发布,进入报名阶段(REQ-122)'); } },
],
});
}
function actDetail(i) {
const a = DB.operator.activities[i];
openModal({
title: a.name,
body: `<table>
<tr><th>活动号</th><td>${a.code}</td></tr>
<tr><th>日期</th><td>${a.date}</td></tr>
<tr><th>报名</th><td>${a.signups} / ${a.capacity}</td></tr>
<tr><th>转化线索</th><td>${a.leads} 条(REQ-096)</td></tr>
<tr><th>状态</th><td>${B(a.status)}</td></tr>
</table>`,
});
}
function actSignups(i) {
const a = DB.operator.activities[i];
openModal({
title: '报名管理 · ' + a.name,
body: `<p class="muted">已报名 ${a.signups} 人,容量 ${a.capacity} 人</p>
<table>
<tr><th>OPC/企业</th><th>报名时间</th><th>状态</th></tr>
<tr><td>OPC_00017 张设计</td><td>09-10 14:30</td><td><span class="badge ok">已确认</span></td></tr>
<tr><td>OPC_00045 陈视觉</td><td>09-11 09:15</td><td><span class="badge ok">已确认</span></td></tr>
<tr><td>ENT_00009 某科技公司</td><td>09-12 10:00</td><td><span class="badge info">待确认</span></td></tr>
</table>`,
actions: [{ label: '关闭', cls: 'ghost' }],
});
}
/* === 政策落地跟踪 === */
function renderPolicyTracking() {
const tracks = DB.operator.policyTracking || [];
document.getElementById('op-policy').innerHTML =
`<tr><th>政策</th><th>申请数</th><th>已审批</th><th>已使用</th><th>执行率</th><th>状态</th></tr>` +
tracks.map(t => {
const rate = Math.round(t.used / t.applied * 100);
return `<tr><td><b>${t.policy}</b></td><td>${t.applied}</td><td>${t.approved}</td><td>${t.used}</td><td>${BAR(rate, 'ok')}</td><td>${B(t.status)}</td></tr>`;
}).join('');
}
/* === 平台撮合订单归集 === */
function renderBrokerOrders() {
const orders = DB.operator.brokerOrders || [];
document.getElementById('op-broker').innerHTML =
`<tr><th>订单号</th><th>客户</th><th>OPC</th><th>金额</th><th>来源</th><th>状态</th><th>操作</th></tr>` +
orders.map((o, i) => `<tr>
<td>${o.code}</td><td>${o.client}</td><td>${o.opc}</td><td>${o.amount}</td>
<td><span class="badge pri">${o.source}</span></td><td>${B(o.status)}</td>
<td><button class="btn sm ghost" onclick="brokerDetail(${i})">详情</button></td>
</tr>`).join('');
}
function brokerOrder() {
openModal({
title: '录入撮合订单(REQ-130)',
body: `<div class="field"><label>客户</label><input placeholder="如:ENT_00018 某公司"></div>
<div class="field"><label>OPC</label><input placeholder="如:OPC_00017 张设计"></div>
<div class="field-row">
<div class="field"><label>金额</label><input placeholder="如:¥15,000"></div>
<div class="field"><label>来源</label><select><option>平台撮合</option><option>线下转介</option><option>政府推荐</option></select></div>
</div>
<div class="field"><label>备注</label><textarea placeholder="撮合过程说明"></textarea></div>
<p class="muted">录入后走统一订单状态机(签约→进行中→验收→结算),数据自动归集到政府驾驶舱。</p>`,
actions: [
{ label: '取消', cls: 'ghost' },
{ label: '录入', onClick: m => { m.remove(); toast('撮合订单已录入,进入订单状态机'); } },
],
});
}
function brokerDetail(i) {
const o = DB.operator.brokerOrders[i];
openModal({
title: '撮合订单详情 · ' + o.code,
body: `<table>
<tr><th>客户</th><td>${o.client}</td></tr>
<tr><th>OPC</th><td>${o.opc}</td></tr>
<tr><th>金额</th><td>${o.amount}</td></tr>
<tr><th>来源</th><td>${o.source}</td></tr>
<tr><th>状态</th><td>${B(o.status)}</td></tr>
</table>`,
});
}
</script>
</body>
</html>