furniture-3d-system-Wu/furniture-3d-system/docs/mockups/product-development-progress-dashboard-preview.html

1465 lines
49 KiB
HTML
Raw 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>产品开发进度看板预览</title>
<style>
:root {
--bg: #f4f6f8;
--panel: #ffffff;
--panel-soft: #f8fafc;
--line: #dfe5ea;
--line-strong: #c8d2dc;
--text: #07111f;
--muted: #687483;
--ink: #111820;
--ink-soft: #3d5260;
--green: #16a36b;
--green-bg: #e9f8f0;
--amber: #c98918;
--amber-bg: #fff4df;
--red: #dc4252;
--red-bg: #ffe8eb;
--blue: #1d7ed8;
--blue-bg: #e9f3ff;
font-family: Inter, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
color: var(--text);
background: var(--bg);
font-size: 13px;
}
button,
input,
select {
font: inherit;
}
.app {
min-height: 100vh;
display: grid;
grid-template-rows: 64px 1fr;
}
.topbar {
display: flex;
align-items: center;
gap: 28px;
padding: 0 30px;
background: #fff;
border-bottom: 1px solid var(--line);
}
.brand {
width: 220px;
display: flex;
align-items: center;
gap: 12px;
border-right: 1px solid #edf1f4;
padding-right: 26px;
}
.logo {
width: 36px;
height: 36px;
border-radius: 9px;
display: grid;
place-items: center;
background: #090d12;
color: #fff;
font-weight: 800;
font-size: 20px;
}
.brand strong {
display: block;
font-size: 15px;
letter-spacing: 0;
}
.brand span {
color: var(--muted);
font-size: 11px;
}
.nav {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
flex: 1;
}
.nav-item {
display: flex;
align-items: center;
gap: 8px;
min-height: 36px;
padding: 0 14px;
color: #566270;
border: 1px solid transparent;
border-radius: 8px;
white-space: nowrap;
}
.nav-item.active {
color: var(--ink);
background: #f5f7f9;
border-color: #e7ecf1;
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.07);
font-weight: 700;
}
.nav-icon {
width: 15px;
height: 15px;
display: inline-grid;
place-items: center;
color: #71808e;
font-size: 15px;
}
.top-actions {
display: flex;
align-items: center;
gap: 12px;
}
.search {
width: 230px;
height: 38px;
border: 1px solid #e5ebf0;
border-radius: 8px;
background: #f3f6f9;
color: #8a95a1;
display: flex;
align-items: center;
padding: 0 14px;
}
.round {
width: 36px;
height: 36px;
border: 1px solid #e1e7ed;
border-radius: 999px;
display: grid;
place-items: center;
background: #fff;
color: #526171;
}
.user {
min-width: 160px;
height: 38px;
border: 1px solid #e1e7ed;
border-radius: 999px;
display: flex;
align-items: center;
gap: 10px;
padding: 0 14px;
background: #fff;
}
.avatar {
width: 24px;
height: 24px;
border-radius: 999px;
display: grid;
place-items: center;
background: #eef2f5;
color: #71808e;
font-weight: 700;
}
.workspace {
padding: 14px 16px 18px;
min-width: 1180px;
}
.tabline {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 10px;
padding: 5px 8px;
border-radius: 14px;
background: #e9eef3;
border: 1px solid #e2e8ee;
}
.tab-chip {
display: inline-flex;
align-items: center;
gap: 8px;
height: 28px;
border: 1px solid #d6dde5;
border-radius: 8px;
padding: 0 10px;
background: #f8fafc;
color: #41505e;
font-size: 12px;
}
.tab-chip.active {
color: #fff;
background: #0f141a;
border-color: #0f141a;
font-weight: 700;
}
.shell {
display: grid;
grid-template-columns: minmax(0, 1fr) 260px;
gap: 12px;
min-height: calc(100vh - 110px);
padding: 12px;
border-radius: 20px;
background: #e7edf2;
}
.main-pane,
.side-pane {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
overflow: hidden;
}
.main-pane {
display: flex;
flex-direction: column;
min-width: 0;
}
.side-pane {
display: flex;
flex-direction: column;
}
.pane-head {
padding: 16px 18px 12px;
border-bottom: 1px solid var(--line);
}
.pane-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.pane-title h1,
.pane-title h2 {
margin: 0;
font-size: 18px;
line-height: 1.2;
letter-spacing: 0;
}
.pane-title h2 {
font-size: 16px;
}
.pane-desc {
margin: 8px 0 0;
color: var(--muted);
line-height: 1.55;
}
.toolbar {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.btn {
border: 1px solid #d7e0e8;
border-radius: 8px;
min-height: 34px;
padding: 0 14px;
color: #445361;
background: #f8fafc;
cursor: pointer;
white-space: nowrap;
}
.btn.primary {
background: #405865;
border-color: #405865;
color: #fff;
font-weight: 700;
}
.content {
padding: 16px 18px 18px;
min-height: 0;
flex: 1;
overflow: auto;
}
.panel {
display: none;
}
.panel.active {
display: block;
}
.filters {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
margin-bottom: 12px;
}
.field {
display: grid;
gap: 5px;
color: #40505f;
font-size: 12px;
}
.field input,
.field select {
width: 100%;
height: 34px;
border: 1px solid #d9e2ea;
border-radius: 8px;
background: #f7f9fb;
color: #7a8794;
padding: 0 10px;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 10px;
margin-bottom: 12px;
}
.metric {
border: 1px solid var(--line);
border-radius: 10px;
background: var(--panel-soft);
padding: 12px;
min-height: 84px;
text-align: left;
cursor: pointer;
transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.metric strong {
display: block;
font-size: 24px;
line-height: 1.1;
margin-top: 8px;
}
.metric span {
color: var(--muted);
font-size: 12px;
}
.metric.active,
.ring-card.active,
.side-item.active {
border-color: #2a3a44;
background: #111820;
color: #fff;
}
.metric.active span,
.ring-card.active p,
.ring-card.active small,
.side-item.active p {
color: rgba(255, 255, 255, 0.72);
}
.metric.done {
border-color: #bfe8d4;
background: var(--green-bg);
}
.metric.running {
border-color: #d7e9ff;
background: var(--blue-bg);
}
.metric.pending,
.metric.returned {
border-color: #f3dbaa;
background: var(--amber-bg);
}
.metric.scrapped {
border-color: #f3c7cf;
background: var(--red-bg);
}
.metric.active.done,
.metric.active.running,
.metric.active.pending,
.metric.active.returned,
.metric.active.scrapped {
background: #111820;
border-color: #111820;
}
.split-row {
display: grid;
grid-template-columns: minmax(0, 1fr) 350px;
gap: 12px;
margin-bottom: 12px;
}
.note-card,
.chart-card,
.table-card {
border: 1px solid var(--line);
border-radius: 10px;
background: #fff;
}
.note-card {
padding: 12px 14px;
color: #495866;
line-height: 1.65;
}
.note-card strong {
color: var(--ink);
}
.mini-list {
display: grid;
gap: 8px;
}
.mini-row {
display: grid;
grid-template-columns: 80px 1fr 48px;
align-items: center;
gap: 8px;
color: #41505e;
font-size: 12px;
}
.bar {
height: 8px;
border-radius: 99px;
background: #edf2f6;
overflow: hidden;
}
.bar i {
display: block;
height: 100%;
border-radius: inherit;
background: #111820;
}
.ring-layout {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
margin-bottom: 12px;
}
.ring-card {
display: grid;
grid-template-columns: 108px minmax(0, 1fr);
gap: 12px;
align-items: center;
border: 1px solid var(--line);
border-radius: 10px;
background: #fff;
padding: 12px;
cursor: pointer;
min-height: 150px;
}
.donut {
width: 92px;
height: 92px;
border-radius: 999px;
background: conic-gradient(#111820 0 48%, #6d8797 48% 72%, #c7d2dc 72% 88%, #eef2f5 88% 100%);
display: grid;
place-items: center;
}
.donut::after {
content: attr(data-label);
width: 56px;
height: 56px;
border-radius: 999px;
background: #fff;
display: grid;
place-items: center;
font-weight: 800;
color: var(--ink);
font-size: 15px;
}
.ring-card.active .donut::after {
background: #111820;
color: #fff;
}
.ring-card h3 {
margin: 0 0 8px;
font-size: 15px;
}
.ring-card p {
margin: 0 0 10px;
color: var(--muted);
line-height: 1.5;
}
.legend {
display: grid;
gap: 5px;
color: #40505f;
font-size: 12px;
}
.legend span {
display: flex;
align-items: center;
gap: 7px;
}
.dot {
width: 8px;
height: 8px;
border-radius: 999px;
background: #111820;
}
.dot.two {
background: #6d8797;
}
.dot.three {
background: #c7d2dc;
}
.table-card {
overflow: hidden;
}
.table-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px 14px;
border-bottom: 1px solid var(--line);
background: #fbfcfd;
}
.table-head h3 {
margin: 0;
font-size: 15px;
}
.table-head p {
margin: 4px 0 0;
color: var(--muted);
font-size: 12px;
}
.table-wrap {
overflow: auto;
max-height: 470px;
}
table {
border-collapse: separate;
border-spacing: 0;
table-layout: fixed;
min-width: 2350px;
width: 100%;
text-align: left;
font-size: 11px;
}
th,
td {
padding: 8px 8px;
border-bottom: 1px solid #e4eaf0;
border-right: 1px solid #edf1f4;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
th {
position: sticky;
top: 0;
z-index: 2;
color: #41505e;
font-weight: 700;
background: #f7f9fb;
}
td {
background: #fff;
color: #263442;
}
tr:nth-child(4n) td {
background: #f2f8ff;
}
.sticky-left {
position: sticky;
left: 0;
z-index: 3;
width: 54px;
box-shadow: 1px 0 0 #e4eaf0;
}
td.sticky-left {
z-index: 1;
}
.thumb {
width: 42px;
height: 42px;
border: 1px solid #dce4eb;
border-radius: 8px;
background: linear-gradient(180deg, #f6f1ed, #f8fafc);
display: grid;
place-items: center;
overflow: hidden;
}
.thumb svg {
width: 34px;
height: 34px;
}
.tag {
display: inline-flex;
align-items: center;
min-height: 22px;
border-radius: 6px;
padding: 0 7px;
font-size: 12px;
font-weight: 700;
}
.tag.green {
color: #13744d;
background: #dff5e9;
}
.tag.blue {
color: #1d5f99;
background: #e2f1ff;
}
.tag.amber {
color: #9b6410;
background: #fff0d2;
}
.tag.red {
color: #b52d3b;
background: #ffe1e6;
}
.time {
color: #102032;
font-variant-numeric: tabular-nums;
}
.time.empty {
color: #a1abb5;
}
.side-head {
padding: 18px 16px 14px;
border-bottom: 1px solid var(--line);
}
.side-head strong {
display: block;
font-size: 16px;
margin-bottom: 8px;
}
.side-head p {
margin: 0;
color: var(--muted);
line-height: 1.5;
}
.side-body {
padding: 14px;
display: grid;
gap: 10px;
align-content: start;
}
.side-item {
width: 100%;
display: grid;
grid-template-columns: 1fr auto;
gap: 8px;
align-items: center;
padding: 13px 12px;
min-height: 68px;
text-align: left;
border: 1px solid var(--line);
border-radius: 10px;
background: #fff;
cursor: pointer;
}
.side-item strong {
font-size: 15px;
}
.side-item p {
grid-column: 1 / -1;
margin: -2px 0 0;
color: var(--muted);
line-height: 1.45;
font-size: 12px;
}
.badge {
min-width: 25px;
height: 25px;
border-radius: 999px;
display: inline-grid;
place-items: center;
padding: 0 8px;
background: #eef3f7;
color: #465665;
font-size: 12px;
font-weight: 800;
}
.side-item.active .badge,
.metric.active .badge {
background: rgba(255, 255, 255, 0.18);
color: #fff;
}
.empty-panel {
border: 1px dashed var(--line-strong);
border-radius: 10px;
min-height: 360px;
display: grid;
place-items: center;
color: #617181;
text-align: center;
line-height: 1.7;
background: #fbfcfd;
}
@media (max-width: 1400px) {
.summary-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.ring-layout {
grid-template-columns: 1fr;
}
.filters {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
</style>
</head>
<body>
<div class="app">
<header class="topbar">
<div class="brand">
<div class="logo">J</div>
<div>
<strong>壹点产品开发平台</strong>
<span>正式产品</span>
</div>
</div>
<nav class="nav">
<div class="nav-item"><span class="nav-icon">⌂</span>首页概览</div>
<div class="nav-item"><span class="nav-icon">♧</span>资产中心</div>
<div class="nav-item"><span class="nav-icon">▱</span>辅助装配</div>
<div class="nav-item"><span class="nav-icon">◇</span>草稿组</div>
<div class="nav-item active"><span class="nav-icon">↓</span>正式产品</div>
<div class="nav-item"><span class="nav-icon">▤</span>仓库管理</div>
</nav>
<div class="top-actions">
<div class="search">⌕ 搜索组件...</div>
<div class="round">◔</div>
<div class="round">◷</div>
<div class="user"><span class="avatar">L</span>LocalAdmin⌄</div>
</div>
</header>
<main class="workspace">
<div class="tabline">
<div class="tab-chip">非集成系列产品 ×</div>
<div class="tab-chip active">产品开发进度 ×</div>
</div>
<section class="shell">
<div class="main-pane">
<div class="pane-head">
<div class="pane-title">
<div>
<h1 id="panelTitle">产品开发进度总览</h1>
<p class="pane-desc" id="panelDesc">集成系列和非集成系列合并查看。下方明细每一行是一个产品,节点列显示该节点最后一次审批/确认时间。</p>
</div>
<div class="toolbar">
<button class="btn">导出明细</button>
<button class="btn primary">刷新进度</button>
</div>
</div>
</div>
<div class="content">
<section class="panel active" data-panel="total">
<div class="filters">
<label class="field">SPU / 开品名
<input placeholder="搜索 SPU / 开品名" />
</label>
<label class="field">产品类型
<select>
<option>全部</option>
<option>非集成系列</option>
<option>集成系列</option>
</select>
</label>
<label class="field">当前负责人
<input placeholder="设计 / 采购 / 运营" />
</label>
<label class="field">当前节点
<select>
<option>全部节点</option>
<option>待立项</option>
<option>样品评审</option>
<option>包装细节</option>
<option>仓库抽检</option>
</select>
</label>
<label class="field">时间范围
<input value="2026/04/01 - 2026/04/28" />
</label>
</div>
<div class="summary-grid">
<button class="metric active" data-status-filter="all"><span>总数量</span><strong>42</strong></button>
<button class="metric done" data-status-filter="done"><span>已完成</span><strong>9</strong></button>
<button class="metric running" data-status-filter="running"><span>进行中</span><strong>21</strong></button>
<button class="metric pending" data-status-filter="pending"><span>待立项</span><strong>7</strong></button>
<button class="metric returned" data-status-filter="returned"><span>退回修改</span><strong>3</strong></button>
<button class="metric scrapped" data-status-filter="scrapped"><span>废弃不开</span><strong>2</strong></button>
</div>
<div class="split-row">
<div class="note-card">
<strong>明细口径:</strong>这里不是单独的缺口列表,而是集成和非集成产品合并后的产品开发总表。基础字段在左边,后面每个节点一列;节点列记录该节点最后一次审批/确认时间,空白代表还没走到或还没确认。
</div>
<div class="note-card mini-list">
<div class="mini-row"><span>平均总耗时</span><div class="bar"><i style="width: 63%"></i></div><b>8.6 天</b></div>
<div class="mini-row"><span>最长卡点</span><div class="bar"><i style="width: 78%"></i></div><b>样品评审</b></div>
<div class="mini-row"><span>今日更新</span><div class="bar"><i style="width: 42%"></i></div><b>6 条</b></div>
</div>
</div>
<div class="table-card">
<div class="table-head">
<div>
<h3 id="tableTitle">全部产品明细</h3>
<p>横向滚动查看全部节点时间,点击右侧分栏切换不同看板。</p>
</div>
<span class="tag blue" id="rowCountLabel">42 条</span>
</div>
<div class="table-wrap">
<table id="progressTable">
<thead>
<tr>
<th class="sticky-left">序号</th>
<th>图片</th>
<th>类型</th>
<th>流程单号</th>
<th>SPU / 开品名</th>
<th>流程模板</th>
<th>审批状态</th>
<th>审批人</th>
<th>商品类目</th>
<th>销售类目</th>
<th>品牌</th>
<th>SPU负责人</th>
<th>运营负责人</th>
<th>采购负责人</th>
<th>需求部门</th>
<th>开始时间</th>
<th>结束时间</th>
<th>总耗时</th>
<th>开品参考</th>
<th>产品资料</th>
<th>设计卖点</th>
<th>立项评审</th>
<th>基础信息</th>
<th>样品评审</th>
<th>产品实拍</th>
<th>安装方式</th>
<th>包装细节</th>
<th>产品定厂</th>
<th>样包测量</th>
<th>产品核价</th>
<th>工厂质检</th>
<th>仓库抽检</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-status="running" data-brand="基本盘" data-category="书桌" data-designer="徐霞客">
<td class="sticky-left">1</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="9" y="17" width="46" height="11" rx="3" fill="#6b482f"/><rect x="13" y="28" width="6" height="27" fill="#3d281c"/><rect x="45" y="28" width="6" height="27" fill="#3d281c"/></svg></span></td>
<td>非集成</td>
<td>pd20260427154953555</td>
<td>SZ0230</td>
<td>非集成流程</td>
<td><span class="tag amber">进行中</span></td>
<td>徐霞客</td>
<td>住宅家具-书桌</td>
<td>住宅家具-书桌</td>
<td>基本盘</td>
<td>徐霞客</td>
<td>徐霞客</td>
<td>徐霞客</td>
<td>运营中心A</td>
<td class="time">04-27 15:49</td>
<td class="time empty">-</td>
<td>1.05 天</td>
<td class="time">04-27 15:50</td>
<td class="time">04-27 16:02</td>
<td class="time">04-27 16:16</td>
<td class="time">04-28 14:33</td>
<td class="time">04-28 15:02</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="done" data-brand="基本盘" data-category="书桌" data-designer="徐霞客">
<td class="sticky-left">2</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="10" y="20" width="44" height="9" rx="3" fill="#6b482f"/><rect x="14" y="29" width="5" height="25" fill="#402a1d"/><rect x="45" y="29" width="5" height="25" fill="#402a1d"/></svg></span></td>
<td>非集成</td>
<td>pd20260427143243471</td>
<td>GBGJ-SZ0230</td>
<td>非集成流程</td>
<td><span class="tag green">已完成</span></td>
<td>徐霞客</td>
<td>住宅家具-书桌</td>
<td>住宅家具-书桌</td>
<td>基本盘</td>
<td>徐霞客</td>
<td>徐霞客</td>
<td>徐霞客</td>
<td>运营中心A</td>
<td class="time">04-24 10:48</td>
<td class="time">04-28 10:12</td>
<td>3.98 天</td>
<td class="time">04-24 10:55</td>
<td class="time">04-24 11:20</td>
<td class="time">04-24 11:40</td>
<td class="time">04-24 14:10</td>
<td class="time">04-25 09:30</td>
<td class="time">04-25 15:12</td>
<td class="time">04-25 16:21</td>
<td class="time">04-26 10:06</td>
<td class="time">04-26 15:34</td>
<td class="time">04-27 09:20</td>
<td class="time">04-27 11:45</td>
<td class="time">04-27 16:10</td>
<td class="time">04-28 09:34</td>
<td class="time">04-28 10:12</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="pending" data-brand="索菲亚" data-category="餐边柜" data-designer="刘景川">
<td class="sticky-left">3</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="14" y="12" width="36" height="42" rx="3" fill="#c7c3b8"/><rect x="17" y="16" width="30" height="12" fill="#ece9e2"/><rect x="17" y="32" width="30" height="18" fill="#a79f91"/></svg></span></td>
<td>集成</td>
<td>pd202604231040840992</td>
<td>XG0290</td>
<td>业务支持</td>
<td><span class="tag amber">待立项</span></td>
<td>刘景川</td>
<td>住宅家具-餐边柜</td>
<td>住宅家具-餐边柜</td>
<td>索菲亚</td>
<td>刘景川</td>
<td>刘景川</td>
<td>周远荣</td>
<td>业务支持</td>
<td class="time">04-23 10:48</td>
<td class="time empty">-</td>
<td>5.26 天</td>
<td class="time">04-23 11:04</td>
<td class="time">04-24 09:18</td>
<td class="time">04-24 15:00</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="running" data-brand="顾家" data-category="茶几" data-designer="李华">
<td class="sticky-left">4</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="8" y="26" width="48" height="8" rx="4" fill="#ad9b87"/><rect x="13" y="34" width="5" height="15" fill="#725a45"/><rect x="46" y="34" width="5" height="15" fill="#725a45"/></svg></span></td>
<td>集成</td>
<td>pd20260423160356635</td>
<td>SG0150</td>
<td>业务支持</td>
<td><span class="tag amber">进行中</span></td>
<td>李华</td>
<td>住宅家具-茶几</td>
<td>住宅家具-茶几</td>
<td>顾家</td>
<td>李华</td>
<td>王门</td>
<td>钮慧</td>
<td>业务支持</td>
<td class="time">04-23 16:03</td>
<td class="time empty">-</td>
<td>5.04 天</td>
<td class="time">04-23 16:22</td>
<td class="time">04-24 10:03</td>
<td class="time">04-24 15:35</td>
<td class="time">04-25 09:18</td>
<td class="time">04-25 14:20</td>
<td class="time">04-26 16:08</td>
<td class="time">04-27 09:42</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="returned" data-brand="朴美" data-category="电视柜" data-designer="安文">
<td class="sticky-left">5</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="10" y="22" width="44" height="22" rx="3" fill="#d8d6ce"/><rect x="14" y="27" width="15" height="10" fill="#f5f3ee"/><rect x="35" y="27" width="15" height="10" fill="#bcb6aa"/></svg></span></td>
<td>非集成</td>
<td>pd202604221650807963</td>
<td>AD0316</td>
<td>非集成流程</td>
<td><span class="tag amber">退回修改</span></td>
<td>安文</td>
<td>住宅家具-电视柜</td>
<td>住宅家具-电视柜</td>
<td>朴美</td>
<td>安文</td>
<td>安文</td>
<td>周远荣</td>
<td>运营中心A</td>
<td class="time">04-22 16:50</td>
<td class="time empty">-</td>
<td>6.00 天</td>
<td class="time">04-22 17:05</td>
<td class="time">04-23 11:30</td>
<td class="time">04-23 15:04</td>
<td class="time">04-24 09:36</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="scrapped" data-brand="南北北" data-category="床头柜" data-designer="胡月">
<td class="sticky-left">6</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="14" y="16" width="36" height="34" rx="3" fill="#d9c3a2"/><rect x="18" y="21" width="28" height="8" fill="#f4e7d4"/><rect x="18" y="34" width="28" height="9" fill="#a67e59"/></svg></span></td>
<td>集成</td>
<td>pd20260417142239870</td>
<td>CTG0298</td>
<td>现场流程</td>
<td><span class="tag red">废弃不开</span></td>
<td>胡月</td>
<td>住宅家具-床头柜</td>
<td>住宅家具-床头柜</td>
<td>南北北</td>
<td>胡月</td>
<td>刘景川</td>
<td>许晴</td>
<td>运营中心A</td>
<td class="time">04-17 14:22</td>
<td class="time">04-18 11:06</td>
<td>0.86 天</td>
<td class="time">04-17 15:10</td>
<td class="time">04-18 09:28</td>
<td class="time empty">-</td>
<td class="time">04-18 11:06</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="running" data-brand="基本盘" data-category="书柜" data-designer="刘景川">
<td class="sticky-left">7</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="18" y="10" width="28" height="46" rx="3" fill="#b8b8b2"/><path d="M22 20h20M22 31h20M22 42h20" stroke="#f5f5f3" stroke-width="3"/></svg></span></td>
<td>非集成</td>
<td>pd20260421175940602</td>
<td>HX00099</td>
<td>现场流程</td>
<td><span class="tag amber">进行中</span></td>
<td>刘景川</td>
<td>住宅家具-书柜</td>
<td>住宅家具-书柜</td>
<td>基本盘</td>
<td>刘景川</td>
<td>范鑫</td>
<td>周远荣</td>
<td>运营中心A</td>
<td class="time">04-21 17:59</td>
<td class="time empty">-</td>
<td>6.98 天</td>
<td class="time">04-21 18:20</td>
<td class="time">04-22 09:42</td>
<td class="time">04-22 16:35</td>
<td class="time">04-23 10:12</td>
<td class="time">04-23 14:10</td>
<td class="time">04-24 15:08</td>
<td class="time">04-25 11:30</td>
<td class="time">04-26 09:50</td>
<td class="time">04-27 15:28</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td><button class="btn">查看</button></td>
</tr>
<tr data-status="done" data-brand="索菲亚" data-category="电视柜" data-designer="刘景川">
<td class="sticky-left">8</td>
<td><span class="thumb"><svg viewBox="0 0 64 64"><rect x="8" y="24" width="48" height="20" rx="3" fill="#cfd4d5"/><rect x="13" y="29" width="12" height="10" fill="#eef1f2"/><rect x="31" y="29" width="20" height="10" fill="#a5adb0"/></svg></span></td>
<td>集成</td>
<td>pd20260420160852345</td>
<td>XG0288</td>
<td>业务支持</td>
<td><span class="tag green">已完成</span></td>
<td>刘景川</td>
<td>住宅家具-电视柜</td>
<td>住宅家具-电视柜</td>
<td>索菲亚</td>
<td>刘景川</td>
<td>刘景川</td>
<td>刘景川</td>
<td>业务支持</td>
<td class="time">04-20 16:08</td>
<td class="time">04-28 10:22</td>
<td>8.03 天</td>
<td class="time">04-20 16:25</td>
<td class="time">04-21 10:18</td>
<td class="time">04-21 15:06</td>
<td class="time">04-22 10:35</td>
<td class="time">04-22 16:15</td>
<td class="time">04-23 14:30</td>
<td class="time">04-24 10:22</td>
<td class="time">04-25 09:15</td>
<td class="time">04-25 17:32</td>
<td class="time">04-26 13:18</td>
<td class="time">04-27 09:46</td>
<td class="time">04-27 16:34</td>
<td class="time">04-28 09:20</td>
<td class="time">04-28 10:22</td>
<td><button class="btn">查看</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section class="panel" data-panel="rings">
<div class="ring-layout">
<button class="ring-card active" data-ring-filter="all" data-ring-title="全部维度明细">
<div class="donut" data-label="品牌"></div>
<div>
<h3>品牌占比</h3>
<p>看基本盘、索菲亚、顾家等品牌的项目分布。</p>
<div class="legend">
<span><i class="dot"></i>基本盘 48%</span>
<span><i class="dot two"></i>索菲亚 24%</span>
<span><i class="dot three"></i>其他 28%</span>
</div>
</div>
</button>
<button class="ring-card" data-ring-filter="category" data-ring-title="按品类查看明细">
<div class="donut" data-label="品类"></div>
<div>
<h3>品类占比</h3>
<p>看书桌、电视柜、餐边柜、茶几等品类分布。</p>
<div class="legend">
<span><i class="dot"></i>书桌 38%</span>
<span><i class="dot two"></i>柜类 34%</span>
<span><i class="dot three"></i>其他 28%</span>
</div>
</div>
</button>
<button class="ring-card" data-ring-filter="designer" data-ring-title="按设计师查看明细">
<div class="donut" data-label="设计"></div>
<div>
<h3>设计师占比</h3>
<p>看每个设计师名下产品目前走到哪个节点。</p>
<div class="legend">
<span><i class="dot"></i>徐霞客 43%</span>
<span><i class="dot two"></i>刘景川 31%</span>
<span><i class="dot three"></i>其他 26%</span>
</div>
</div>
</button>
</div>
<div class="note-card" style="margin-bottom: 12px;">
环形视图只负责切换观察维度,下面仍然是同一张产品总明细表。后续可以点击某个品牌、品类或设计师后,在明细里只看对应产品。
</div>
<div class="table-card">
<div class="table-head">
<div>
<h3 id="ringTableTitle">全部维度明细</h3>
<p>节点时间继续按“最后一次审批/确认时间”展示,不改成汇总卡片。</p>
</div>
<span class="tag blue">42 条</span>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="sticky-left">序号</th>
<th>类型</th>
<th>SPU / 开品名</th>
<th>品牌</th>
<th>品类</th>
<th>设计师</th>
<th>当前状态</th>
<th>当前节点</th>
<th>开品参考</th>
<th>产品资料</th>
<th>设计卖点</th>
<th>立项评审</th>
<th>基础信息</th>
<th>样品评审</th>
<th>产品实拍</th>
<th>安装方式</th>
<th>包装细节</th>
<th>产品定厂</th>
<th>样包测量</th>
<th>产品核价</th>
<th>工厂质检</th>
<th>仓库抽检</th>
</tr>
</thead>
<tbody>
<tr>
<td class="sticky-left">1</td>
<td>非集成</td>
<td>SZ0230</td>
<td>基本盘</td>
<td>书桌</td>
<td>徐霞客</td>
<td><span class="tag amber">进行中</span></td>
<td>基础信息</td>
<td class="time">04-27 15:50</td>
<td class="time">04-27 16:02</td>
<td class="time">04-27 16:16</td>
<td class="time">04-28 14:33</td>
<td class="time">04-28 15:02</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
<td class="time empty">-</td>
</tr>
<tr>
<td class="sticky-left">2</td>
<td>集成</td>
<td>XG0288</td>
<td>索菲亚</td>
<td>电视柜</td>
<td>刘景川</td>
<td><span class="tag green">已完成</span></td>
<td>仓库抽检</td>
<td class="time">04-20 16:25</td>
<td class="time">04-21 10:18</td>
<td class="time">04-21 15:06</td>
<td class="time">04-22 10:35</td>
<td class="time">04-22 16:15</td>
<td class="time">04-23 14:30</td>
<td class="time">04-24 10:22</td>
<td class="time">04-25 09:15</td>
<td class="time">04-25 17:32</td>
<td class="time">04-26 13:18</td>
<td class="time">04-27 09:46</td>
<td class="time">04-27 16:34</td>
<td class="time">04-28 09:20</td>
<td class="time">04-28 10:22</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section class="panel" data-panel="nodes">
<div class="empty-panel">
<div>
<strong>节点进度</strong><br />
这里后续可以只看某一个节点,例如“样品评审”下还有哪些产品没有通过。<br />
目前先保留入口,不把内容堆满。
</div>
</div>
</section>
<section class="panel" data-panel="risk">
<div class="empty-panel">
<div>
<strong>异常与废弃</strong><br />
这里后续集中看退回修改、废弃不开和超期卡点。<br />
明细仍然回到同一张产品总表。
</div>
</div>
</section>
</div>
</div>
<aside class="side-pane">
<div class="side-head">
<strong>产品开发进度</strong>
<p>右侧切换看板,左侧显示对应明细。</p>
</div>
<div class="side-body">
<button class="side-item active" data-switch="total">
<strong>总进度</strong>
<span class="badge">42</span>
<p>总数、完成、进行中、待立项、退回和废弃。</p>
</button>
<button class="side-item" data-switch="rings">
<strong>环形视图</strong>
<span class="badge">3</span>
<p>按品牌、品类、设计师看占比。</p>
</button>
<button class="side-item" data-switch="nodes">
<strong>节点进度</strong>
<span class="badge">12</span>
<p>按节点看已审批时间和卡点。</p>
</button>
<button class="side-item" data-switch="risk">
<strong>异常与废弃</strong>
<span class="badge">5</span>
<p>退回、废弃和超期集中查看。</p>
</button>
</div>
</aside>
</section>
</main>
</div>
<script>
const title = document.getElementById("panelTitle");
const desc = document.getElementById("panelDesc");
const panelText = {
total: ["产品开发进度总览", "集成系列和非集成系列合并查看。下方明细每一行是一个产品,节点列显示该节点最后一次审批/确认时间。"],
rings: ["环形视图", "按品牌、品类、设计师看占比;点击后仍然回到产品总明细,只是换一个观察维度。"],
nodes: ["节点进度", "按节点查看产品推进情况,后续可展开到节点明细。"],
risk: ["异常与废弃", "集中查看退回修改、废弃不开和卡点项目。"]
};
document.querySelectorAll("[data-switch]").forEach((button) => {
button.addEventListener("click", () => {
const target = button.dataset.switch;
document.querySelectorAll("[data-switch]").forEach((item) => item.classList.toggle("active", item === button));
document.querySelectorAll("[data-panel]").forEach((panel) => panel.classList.toggle("active", panel.dataset.panel === target));
title.textContent = panelText[target][0];
desc.textContent = panelText[target][1];
});
});
const rows = Array.from(document.querySelectorAll("#progressTable tbody tr"));
const tableTitle = document.getElementById("tableTitle");
const rowCountLabel = document.getElementById("rowCountLabel");
const statusNames = {
all: "全部产品明细",
done: "已完成产品明细",
running: "进行中产品明细",
pending: "待立项产品明细",
returned: "退回修改产品明细",
scrapped: "废弃不开产品明细"
};
document.querySelectorAll("[data-status-filter]").forEach((button) => {
button.addEventListener("click", () => {
const status = button.dataset.statusFilter;
document.querySelectorAll("[data-status-filter]").forEach((item) => item.classList.toggle("active", item === button));
let shown = 0;
rows.forEach((row) => {
const visible = status === "all" || row.dataset.status === status;
row.style.display = visible ? "" : "none";
if (visible) shown += 1;
});
tableTitle.textContent = statusNames[status];
rowCountLabel.textContent = status === "all" ? "42 条" : shown + " 条";
});
});
document.querySelectorAll("[data-ring-filter]").forEach((button) => {
button.addEventListener("click", () => {
document.querySelectorAll("[data-ring-filter]").forEach((item) => item.classList.toggle("active", item === button));
document.getElementById("ringTableTitle").textContent = button.dataset.ringTitle;
});
});
</script>
</body>
</html>