@deppon/deppon-skills 2.4.18 → 2.4.21
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/deppon-npm-skills/SKILL.md +3 -3
- package/dist/deppon-prd-generator/SKILL.md +81 -18
- package/dist/deppon-prd-generator/examples/README.md +17 -0
- package/dist/deppon-prd-generator/examples/app-shell-navigation/layout-spec.md +54 -0
- package/dist/deppon-prd-generator/examples/app-shell-navigation/pages/demo-form.html +57 -0
- package/dist/deppon-prd-generator/examples/app-shell-navigation/pages/demo-home.html +92 -0
- package/dist/deppon-prd-generator/examples/app-shell-navigation/pages/demo-list.html +47 -0
- package/dist/deppon-prd-generator/examples/app-shell-navigation/prd.md +164 -0
- package/dist/deppon-prd-generator/examples/app-shell-navigation/prototype.html +794 -0
- package/dist/deppon-prd-generator/examples/backend-list/prd.md +91 -0
- package/dist/deppon-prd-generator/examples/backend-list/prototype.html +369 -0
- package/dist/deppon-prd-generator/examples/data-dashboard/prd.md +127 -0
- package/dist/deppon-prd-generator/examples/data-dashboard/prototype.html +281 -0
- package/dist/deppon-prd-generator/examples/form-edit/prd.md +108 -0
- package/dist/deppon-prd-generator/examples/form-edit/prototype.html +280 -0
- package/dist/deppon-prd-generator/examples/form-preview/prd.md +106 -0
- package/dist/deppon-prd-generator/examples/form-preview/prototype.html +240 -0
- package/dist/deppon-prd-generator/{user-management → examples/list-crud}/prd.md +9 -4
- package/dist/deppon-prd-generator/{user-management → examples/list-crud}/prototype.html +246 -94
- package/dist/deppon-prd-generator/examples/user-frontend/prd.md +86 -0
- package/dist/deppon-prd-generator/examples/user-frontend/prototype.html +223 -0
- package/dist/deppon-prd-generator/quick-reference.md +23 -6
- package/dist/deppon-prd-generator/template/app-shell-navigation-prd-template.md +180 -0
- package/dist/deppon-prd-generator/template/backend-form-edit-prd-template.md +4 -0
- package/dist/deppon-prd-generator/template/backend-form-preview-prd-template.md +4 -0
- package/dist/deppon-prd-generator/template/backend-list-prd-template.md +4 -0
- package/dist/deppon-prd-generator/template/data-prd-template.md +4 -0
- package/dist/deppon-prd-generator/template/user-frontend-prd-template.md +4 -0
- package/dist/deppon-prd-generator/workflow.md +34 -16
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# 公告台账 PRD(产品需求文档)
|
|
2
|
+
|
|
3
|
+
> **文档说明**:本文件位于技能目录 `examples/backend-list/`,对应 **`backend-list-prd-template.md`** 的**纯列表 + 筛选 + 分页**(无详情/表单弹层 CRUD),供与 `list-crud`(含完整 CRUD)对照。实际产出仍写入 `src/prototypes/<page-name>/prd.md`。
|
|
4
|
+
|
|
5
|
+
> **交互原型**:[打开 prototype.html](./prototype.html)(Tailwind + `marked` + `fetch` 同目录 `prd.md`);须 **HTTP** 打开目录。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 引言
|
|
10
|
+
|
|
11
|
+
### 1.1 背景
|
|
12
|
+
|
|
13
|
+
为运营与合规人员提供系统公告的检索与浏览能力:按标题、类型、时间范围筛选,分页查看,支持导出当前筛选结果(可选)。
|
|
14
|
+
|
|
15
|
+
### 1.2 功能清单
|
|
16
|
+
|
|
17
|
+
| 模块 | 功能点 | 功能描述 |
|
|
18
|
+
| -------- | -------- | -------------------------------- |
|
|
19
|
+
| 公告台账 | 条件查询 | 标题、类型、发布时间范围;查询/重置 |
|
|
20
|
+
| 公告台账 | 列表展示 | 分页表格;发布时间降序默认 |
|
|
21
|
+
| 公告台账 | 导出 | 导出 CSV(可选,受导出权限控制) |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 2. 页面菜单与权限规划
|
|
26
|
+
|
|
27
|
+
### 2.1 页面菜单
|
|
28
|
+
|
|
29
|
+
**菜单路径**:内容管理 / 公告台账
|
|
30
|
+
|
|
31
|
+
### 2.2 权限规划
|
|
32
|
+
|
|
33
|
+
| 权限点 | 操作范围 | 数据范围 |
|
|
34
|
+
| ------ | ---------------------------- | -------- |
|
|
35
|
+
| 查看 | 列表、筛选、分页 | 全量 |
|
|
36
|
+
| 导出 | 导出当前筛选结果 | 全量 |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3. 公告台账需求说明
|
|
41
|
+
|
|
42
|
+
### 3.1 筛选查询区
|
|
43
|
+
|
|
44
|
+
变更筛选后点击「查询」生效;「重置」恢复默认并回到第 1 页。
|
|
45
|
+
|
|
46
|
+
| 筛选字段 | 类型 | 输入限制 | 匹配规则 |
|
|
47
|
+
| :------- | :------- | :-------------- | :------- |
|
|
48
|
+
| 标题 | 文本 | 1~128,trim | 模糊 |
|
|
49
|
+
| 公告类型 | 下拉 | 全部 / 系统 / 活动 | 精准 |
|
|
50
|
+
| 发布时间 | 日期范围 | 起止合法 | 范围 |
|
|
51
|
+
|
|
52
|
+
- **查询** / **重置**:同上。
|
|
53
|
+
- **导出**(可选):需「导出」权限;导出字段与列表列一致。
|
|
54
|
+
|
|
55
|
+
### 3.2 数据列表
|
|
56
|
+
|
|
57
|
+
| 列表字段 | 字段说明 | 排序 |
|
|
58
|
+
| :------- | :--------- | :--- |
|
|
59
|
+
| 标题 | 公告标题 | 否 |
|
|
60
|
+
| 类型 | 系统/活动 | 是 |
|
|
61
|
+
| 发布时间 | 发布时间 | 是 |
|
|
62
|
+
| 发布人 | 操作账号 | 否 |
|
|
63
|
+
|
|
64
|
+
- **分页**:默认 10 条;可切换 10 / 20 / 50。
|
|
65
|
+
- **行操作**:本示例页**无**编辑/删除行操作;跳转详情若做则为另页路由(不在本模板最小范围)。
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 4. 交互设计
|
|
70
|
+
|
|
71
|
+
加载态、空态、导出中的防重复点击;筛选与列表区域与 `aria` 规范对齐。主操作「查询」「导出」使用主题蓝实心按钮;「重置」为次要样式。
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 9. 原型与 PRD 对应关系
|
|
76
|
+
|
|
77
|
+
| PRD 章节 | prototype.html 演示点 |
|
|
78
|
+
| -------- | ---------------------- |
|
|
79
|
+
| §1 | 页头「PRD §1」 |
|
|
80
|
+
| §3.1 | 筛选区「PRD §3.1」+ 查询/重置 |
|
|
81
|
+
| §3.2 | 表格区「PRD §3.1」旁列表标题「PRD §3.2」+ 分页 |
|
|
82
|
+
| §4 | 导出按钮与 Toast 模拟(对应 §3.1 导出条款) |
|
|
83
|
+
| 走查说明 | 左下角「标注说明」+ prd.md §9 原文联动 |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 10. 修订记录
|
|
88
|
+
|
|
89
|
+
| 版本 | 日期 | 说明 |
|
|
90
|
+
| ---- | ---------- | ---- |
|
|
91
|
+
| v0.1 | 2026-05-14 | 初版:对齐 backend-list 模板示例 |
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
技能示例 examples/backend-list/ — 对齐 backend-list-prd-template(纯列表+筛选)
|
|
3
|
+
fetch 同目录 prd.md;须 HTTP 打开。
|
|
4
|
+
-->
|
|
5
|
+
<!DOCTYPE html>
|
|
6
|
+
<html lang="zh-CN">
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8" />
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
10
|
+
<title>公告台账 — 原型</title>
|
|
11
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
12
|
+
<style>
|
|
13
|
+
.anno-trigger {
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
border-radius: 0.375rem;
|
|
18
|
+
border: 1px solid rgba(217, 119, 6, 0.85);
|
|
19
|
+
background: rgba(254, 243, 199, 0.95);
|
|
20
|
+
padding: 0.15rem 0.5rem;
|
|
21
|
+
font-size: 0.625rem;
|
|
22
|
+
font-weight: 700;
|
|
23
|
+
letter-spacing: 0.04em;
|
|
24
|
+
color: rgb(69 26 3);
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
}
|
|
27
|
+
.anno-trigger:hover {
|
|
28
|
+
background: rgb(253 230 138);
|
|
29
|
+
}
|
|
30
|
+
#annoDlgBody .prd-md table {
|
|
31
|
+
width: 100%;
|
|
32
|
+
border-collapse: collapse;
|
|
33
|
+
font-size: 0.75rem;
|
|
34
|
+
}
|
|
35
|
+
#annoDlgBody .prd-md th,
|
|
36
|
+
#annoDlgBody .prd-md td {
|
|
37
|
+
border: 1px solid rgb(226 232 240);
|
|
38
|
+
padding: 0.35rem 0.5rem;
|
|
39
|
+
}
|
|
40
|
+
#annoDlgBody .prd-md th {
|
|
41
|
+
background: rgb(248 250 252);
|
|
42
|
+
font-weight: 600;
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
</head>
|
|
46
|
+
<body class="min-h-screen bg-slate-100 text-slate-800">
|
|
47
|
+
<div
|
|
48
|
+
id="prdLoadBanner"
|
|
49
|
+
class="hidden border-b border-amber-300 bg-amber-100 px-4 py-2 text-center text-xs text-amber-950"
|
|
50
|
+
></div>
|
|
51
|
+
<div
|
|
52
|
+
id="toast"
|
|
53
|
+
class="fixed top-4 right-4 z-[60] hidden max-w-sm rounded-lg bg-slate-900 px-4 py-3 text-sm text-white shadow-lg"
|
|
54
|
+
></div>
|
|
55
|
+
<button
|
|
56
|
+
type="button"
|
|
57
|
+
id="btnAnnoLegend"
|
|
58
|
+
class="fixed bottom-5 left-5 z-[65] flex items-center gap-2 rounded-full border border-amber-400 bg-white px-3 py-2 text-xs font-medium text-amber-950 shadow-lg"
|
|
59
|
+
>
|
|
60
|
+
<span class="flex h-6 w-6 items-center justify-center rounded-full bg-amber-500 text-xs font-bold text-white"
|
|
61
|
+
>?</span
|
|
62
|
+
>
|
|
63
|
+
标注说明
|
|
64
|
+
</button>
|
|
65
|
+
|
|
66
|
+
<header class="border-b border-slate-200 bg-white">
|
|
67
|
+
<div class="mx-auto flex max-w-5xl items-start gap-2 px-4 py-4">
|
|
68
|
+
<h1 class="text-lg font-semibold text-slate-900">公告台账</h1>
|
|
69
|
+
<button type="button" class="anno-trigger mt-0.5" data-anno-key="s1">PRD §1</button>
|
|
70
|
+
</div>
|
|
71
|
+
</header>
|
|
72
|
+
|
|
73
|
+
<main class="mx-auto max-w-5xl px-4 py-6">
|
|
74
|
+
<section class="mb-6 rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
|
|
75
|
+
<div class="mb-3 flex items-center justify-between">
|
|
76
|
+
<h2 class="text-sm font-semibold text-slate-900">筛选</h2>
|
|
77
|
+
<button type="button" class="anno-trigger" data-anno-key="s31">PRD §3.1</button>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="grid gap-3 sm:grid-cols-3">
|
|
80
|
+
<label class="text-xs font-medium text-slate-600"
|
|
81
|
+
>标题
|
|
82
|
+
<input id="fTitle" type="text" class="mt-1 w-full rounded-md border border-slate-300 px-2 py-2 text-sm" />
|
|
83
|
+
</label>
|
|
84
|
+
<label class="text-xs font-medium text-slate-600"
|
|
85
|
+
>类型
|
|
86
|
+
<select id="fType" class="mt-1 w-full rounded-md border border-slate-300 px-2 py-2 text-sm">
|
|
87
|
+
<option value="">全部</option>
|
|
88
|
+
<option>系统</option>
|
|
89
|
+
<option>活动</option>
|
|
90
|
+
</select>
|
|
91
|
+
</label>
|
|
92
|
+
<label class="text-xs font-medium text-slate-600"
|
|
93
|
+
>发布日期
|
|
94
|
+
<input id="fDate" type="date" class="mt-1 w-full rounded-md border border-slate-300 px-2 py-2 text-sm" />
|
|
95
|
+
</label>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="mt-3 flex flex-wrap gap-2">
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
id="btnQuery"
|
|
101
|
+
class="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white shadow hover:bg-blue-700"
|
|
102
|
+
>
|
|
103
|
+
查询
|
|
104
|
+
</button>
|
|
105
|
+
<button type="button" id="btnReset" class="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm">
|
|
106
|
+
重置
|
|
107
|
+
</button>
|
|
108
|
+
<button type="button" id="btnExport" class="anno-trigger ml-auto" data-anno-key="s4">PRD §4</button>
|
|
109
|
+
<button type="button" id="btnDoExport" class="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white">
|
|
110
|
+
导出 CSV
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
</section>
|
|
114
|
+
|
|
115
|
+
<section class="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
|
116
|
+
<div class="flex items-center justify-between border-b border-slate-100 px-4 py-3">
|
|
117
|
+
<div class="flex items-center gap-2">
|
|
118
|
+
<h2 class="text-sm font-semibold">公告列表</h2>
|
|
119
|
+
<button type="button" class="anno-trigger" data-anno-key="s32">PRD §3.2</button>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="overflow-x-auto">
|
|
123
|
+
<table class="min-w-full text-left text-sm">
|
|
124
|
+
<thead class="bg-slate-50 text-xs uppercase text-slate-600">
|
|
125
|
+
<tr>
|
|
126
|
+
<th class="px-4 py-2">标题</th>
|
|
127
|
+
<th class="px-4 py-2">类型</th>
|
|
128
|
+
<th class="px-4 py-2">发布时间</th>
|
|
129
|
+
<th class="px-4 py-2">发布人</th>
|
|
130
|
+
</tr>
|
|
131
|
+
</thead>
|
|
132
|
+
<tbody id="tbody"></tbody>
|
|
133
|
+
</table>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="flex items-center justify-between border-t border-slate-100 px-4 py-2 text-xs text-slate-600">
|
|
136
|
+
<span id="pageInfo"></span>
|
|
137
|
+
<div class="flex gap-2">
|
|
138
|
+
<button type="button" id="btnPrev" class="rounded border border-slate-300 px-2 py-1">上一页</button>
|
|
139
|
+
<button type="button" id="btnNext" class="rounded border border-slate-300 px-2 py-1">下一页</button>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</section>
|
|
143
|
+
</main>
|
|
144
|
+
|
|
145
|
+
<div
|
|
146
|
+
id="modalAnno"
|
|
147
|
+
class="fixed inset-0 z-[70] hidden items-center justify-center bg-slate-900/55 p-4"
|
|
148
|
+
role="dialog"
|
|
149
|
+
aria-modal="true"
|
|
150
|
+
aria-labelledby="annoDlgTitle"
|
|
151
|
+
>
|
|
152
|
+
<div class="flex max-h-[88vh] w-full max-w-2xl flex-col overflow-hidden rounded-xl border-2 border-amber-400 bg-white shadow-2xl">
|
|
153
|
+
<div class="flex shrink-0 items-center justify-between border-b border-amber-200 bg-amber-50 px-4 py-2">
|
|
154
|
+
<div class="min-w-0 pr-2">
|
|
155
|
+
<p class="text-[10px] font-bold uppercase text-amber-900">需求标注</p>
|
|
156
|
+
<h3 id="annoDlgTitle" class="truncate text-sm font-semibold"></h3>
|
|
157
|
+
</div>
|
|
158
|
+
<button type="button" id="btnAnnoClose" class="shrink-0 rounded p-1 text-slate-600 hover:bg-amber-200/60">
|
|
159
|
+
✕
|
|
160
|
+
</button>
|
|
161
|
+
</div>
|
|
162
|
+
<div
|
|
163
|
+
id="annoDlgBody"
|
|
164
|
+
class="min-h-0 flex-1 overflow-y-auto overflow-x-auto p-4 text-sm"
|
|
165
|
+
tabindex="-1"
|
|
166
|
+
></div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<script src="https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js"></script>
|
|
171
|
+
<script>
|
|
172
|
+
function runPrototype(prdMd, prdLoadError) {
|
|
173
|
+
var DATA = [
|
|
174
|
+
{ title: '系统维护通知', type: '系统', at: '2026-05-01 10:00', by: 'admin' },
|
|
175
|
+
{ title: '五一活动上线', type: '活动', at: '2026-04-28 09:00', by: 'ops01' },
|
|
176
|
+
{ title: '隐私政策更新', type: '系统', at: '2026-04-20 14:30', by: 'legal' },
|
|
177
|
+
];
|
|
178
|
+
var f = { title: '', type: '', date: '' };
|
|
179
|
+
var page = 1;
|
|
180
|
+
var pageSize = 10;
|
|
181
|
+
|
|
182
|
+
function $(id) {
|
|
183
|
+
return document.getElementById(id);
|
|
184
|
+
}
|
|
185
|
+
function escapeHtml(s) {
|
|
186
|
+
return String(s)
|
|
187
|
+
.replace(/&/g, '&')
|
|
188
|
+
.replace(/</g, '<')
|
|
189
|
+
.replace(/>/g, '>')
|
|
190
|
+
.replace(/"/g, '"');
|
|
191
|
+
}
|
|
192
|
+
if (typeof marked !== 'undefined' && marked.use) marked.use({ gfm: true, breaks: true });
|
|
193
|
+
var b = $('prdLoadBanner');
|
|
194
|
+
if (b && (!prdMd || prdLoadError)) {
|
|
195
|
+
b.textContent =
|
|
196
|
+
'未加载 prd.md:请在本目录启动静态服务后打开(勿 file://)。';
|
|
197
|
+
b.classList.remove('hidden');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function sliceBetween(md, startRe, endRe) {
|
|
201
|
+
if (!md) return '';
|
|
202
|
+
var m = md.match(startRe);
|
|
203
|
+
if (!m || m.index === undefined) return '';
|
|
204
|
+
var i0 = m.index;
|
|
205
|
+
if (!endRe) return md.slice(i0).trim();
|
|
206
|
+
var tail = md.slice(i0 + m[0].length);
|
|
207
|
+
var j = tail.search(endRe);
|
|
208
|
+
if (j === -1) return md.slice(i0).trim();
|
|
209
|
+
return md.slice(i0, i0 + m[0].length + j).trim();
|
|
210
|
+
}
|
|
211
|
+
function mdToHtml(src) {
|
|
212
|
+
if (!src) return '<p class="text-xs text-slate-500">(未匹配到章节)</p>';
|
|
213
|
+
if (typeof marked !== 'undefined' && marked.parse)
|
|
214
|
+
return '<div class="prd-md">' + marked.parse(src) + '</div>';
|
|
215
|
+
return '<pre class="text-xs">' + escapeHtml(src) + '</pre>';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
var LEGEND_INTRO =
|
|
219
|
+
'<ul class="list-disc space-y-2 pl-4 text-sm"><li>正文来自同目录 <strong>prd.md</strong> 切片。</li><li>长内容可在弹框内滚动。</li></ul>';
|
|
220
|
+
var ANNO_EXTRACT = {
|
|
221
|
+
s1: { start: /^## 1\./m, end: /^## 2\./m, title: 'prd.md §1' },
|
|
222
|
+
s31: { start: /^### 3\.1/m, end: /^### 3\.2/m, title: 'prd.md §3.1' },
|
|
223
|
+
s32: { start: /^### 3\.2/m, end: /^## 4\./m, title: 'prd.md §3.2' },
|
|
224
|
+
s4: { start: /^## 4\./m, end: /^## 9\./m, title: 'prd.md §4' },
|
|
225
|
+
};
|
|
226
|
+
var FB = {
|
|
227
|
+
s1: { title: '§1 兜底', html: '<p class="text-xs">加载 prd.md 后显示原文。</p>' },
|
|
228
|
+
s31: { title: '§3.1 兜底', html: '<p class="text-xs">筛选字段见 PRD。</p>' },
|
|
229
|
+
s32: { title: '§3.2 兜底', html: '<p class="text-xs">列表列见 PRD。</p>' },
|
|
230
|
+
s4: { title: '§4 兜底', html: '<p class="text-xs">交互与按钮样式见 PRD。</p>' },
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
function openAnno(key) {
|
|
234
|
+
var warn =
|
|
235
|
+
!prdMd || prdLoadError
|
|
236
|
+
? '<div class="mb-2 rounded border border-amber-200 bg-amber-50 p-2 text-xs">prd.md 未联动</div>'
|
|
237
|
+
: '';
|
|
238
|
+
if (key === 'legend') {
|
|
239
|
+
$('annoDlgTitle').textContent = '标注说明 · §9';
|
|
240
|
+
var s9 = prdMd ? sliceBetween(prdMd, /^## 9\./m, /^## 10\./m) : '';
|
|
241
|
+
$('annoDlgBody').innerHTML =
|
|
242
|
+
warn + LEGEND_INTRO + (s9 ? '<div class="mt-3 border-t pt-2">' + mdToHtml(s9) + '</div>' : '');
|
|
243
|
+
showAnno();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
var spec = ANNO_EXTRACT[key];
|
|
247
|
+
if (!spec) return;
|
|
248
|
+
var slice = prdMd ? sliceBetween(prdMd, spec.start, spec.end) : '';
|
|
249
|
+
if (slice) {
|
|
250
|
+
$('annoDlgTitle').textContent = spec.title;
|
|
251
|
+
$('annoDlgBody').innerHTML = warn + mdToHtml(slice);
|
|
252
|
+
} else if (FB[key]) {
|
|
253
|
+
$('annoDlgTitle').textContent = FB[key].title;
|
|
254
|
+
$('annoDlgBody').innerHTML = warn + FB[key].html;
|
|
255
|
+
} else return;
|
|
256
|
+
showAnno();
|
|
257
|
+
}
|
|
258
|
+
function showAnno() {
|
|
259
|
+
$('modalAnno').classList.remove('hidden');
|
|
260
|
+
$('modalAnno').classList.add('flex');
|
|
261
|
+
$('annoDlgBody').scrollTop = 0;
|
|
262
|
+
}
|
|
263
|
+
function closeAnno() {
|
|
264
|
+
$('modalAnno').classList.add('hidden');
|
|
265
|
+
$('modalAnno').classList.remove('flex');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
document.addEventListener(
|
|
269
|
+
'click',
|
|
270
|
+
function (e) {
|
|
271
|
+
var t = e.target.closest('[data-anno-key]');
|
|
272
|
+
if (!t) return;
|
|
273
|
+
e.preventDefault();
|
|
274
|
+
e.stopPropagation();
|
|
275
|
+
openAnno(t.getAttribute('data-anno-key'));
|
|
276
|
+
},
|
|
277
|
+
true,
|
|
278
|
+
);
|
|
279
|
+
$('btnAnnoClose').addEventListener('click', closeAnno);
|
|
280
|
+
$('modalAnno').addEventListener('click', function (e) {
|
|
281
|
+
if (e.target === $('modalAnno')) closeAnno();
|
|
282
|
+
});
|
|
283
|
+
$('btnAnnoLegend').addEventListener('click', function () {
|
|
284
|
+
openAnno('legend');
|
|
285
|
+
});
|
|
286
|
+
document.addEventListener('keydown', function (e) {
|
|
287
|
+
if (e.key === 'Escape' && !$('modalAnno').classList.contains('hidden')) closeAnno();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
function filtered() {
|
|
291
|
+
return DATA.filter(function (r) {
|
|
292
|
+
if (f.title && r.title.indexOf(f.title) === -1) return false;
|
|
293
|
+
if (f.type && r.type !== f.type) return false;
|
|
294
|
+
if (f.date && r.at.slice(0, 10) !== f.date) return false;
|
|
295
|
+
return true;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function render() {
|
|
299
|
+
var rows = filtered();
|
|
300
|
+
$('pageInfo').textContent = '共 ' + rows.length + ' 条(示例分页略)';
|
|
301
|
+
var tb = $('tbody');
|
|
302
|
+
tb.innerHTML = '';
|
|
303
|
+
rows.forEach(function (r) {
|
|
304
|
+
var tr = document.createElement('tr');
|
|
305
|
+
tr.className = 'border-t border-slate-100';
|
|
306
|
+
tr.innerHTML =
|
|
307
|
+
'<td class="px-4 py-2">' +
|
|
308
|
+
escapeHtml(r.title) +
|
|
309
|
+
'</td><td class="px-4 py-2">' +
|
|
310
|
+
escapeHtml(r.type) +
|
|
311
|
+
'</td><td class="px-4 py-2 font-mono text-xs">' +
|
|
312
|
+
escapeHtml(r.at) +
|
|
313
|
+
'</td><td class="px-4 py-2">' +
|
|
314
|
+
escapeHtml(r.by) +
|
|
315
|
+
'</td>';
|
|
316
|
+
tb.appendChild(tr);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
$('btnQuery').addEventListener('click', function () {
|
|
320
|
+
f.title = $('fTitle').value.trim();
|
|
321
|
+
f.type = $('fType').value;
|
|
322
|
+
f.date = $('fDate').value;
|
|
323
|
+
render();
|
|
324
|
+
toast('已查询(mock)');
|
|
325
|
+
});
|
|
326
|
+
$('btnReset').addEventListener('click', function () {
|
|
327
|
+
$('fTitle').value = '';
|
|
328
|
+
$('fType').value = '';
|
|
329
|
+
$('fDate').value = '';
|
|
330
|
+
f = { title: '', type: '', date: '' };
|
|
331
|
+
render();
|
|
332
|
+
});
|
|
333
|
+
$('btnDoExport').addEventListener('click', function () {
|
|
334
|
+
toast('导出(模拟):当前 ' + filtered().length + ' 条');
|
|
335
|
+
});
|
|
336
|
+
$('btnPrev').addEventListener('click', function () {
|
|
337
|
+
toast('分页示例:上一页');
|
|
338
|
+
});
|
|
339
|
+
$('btnNext').addEventListener('click', function () {
|
|
340
|
+
toast('分页示例:下一页');
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
function toast(m) {
|
|
344
|
+
var el = $('toast');
|
|
345
|
+
el.textContent = m;
|
|
346
|
+
el.classList.remove('hidden');
|
|
347
|
+
clearTimeout(el._t);
|
|
348
|
+
el._t = setTimeout(function () {
|
|
349
|
+
el.classList.add('hidden');
|
|
350
|
+
}, 2000);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
render();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
fetch('prd.md', { cache: 'no-store' })
|
|
357
|
+
.then(function (r) {
|
|
358
|
+
if (!r.ok) throw new Error(String(r.status));
|
|
359
|
+
return r.text();
|
|
360
|
+
})
|
|
361
|
+
.then(function (t) {
|
|
362
|
+
runPrototype(t, null);
|
|
363
|
+
})
|
|
364
|
+
.catch(function () {
|
|
365
|
+
runPrototype('', new Error('x'));
|
|
366
|
+
});
|
|
367
|
+
</script>
|
|
368
|
+
</body>
|
|
369
|
+
</html>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# 渠道运营看板 PRD(产品需求文档)
|
|
2
|
+
|
|
3
|
+
> **文档说明**:本文件位于技能目录 `examples/data-dashboard/`,对应 **`data-prd-template.md`**(筛选 + 指标卡 + 图表 + 列表 + 指标总览)。实际产出写入 `src/prototypes/<page-name>/prd.md`。
|
|
4
|
+
|
|
5
|
+
> **交互原型**:[打开 prototype.html](./prototype.html);标注 **`fetch` 同目录 `prd.md`**;须 **HTTP** 打开。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 引言
|
|
10
|
+
|
|
11
|
+
### 1.1 背景
|
|
12
|
+
|
|
13
|
+
为运营负责人提供渠道投放与转化的日级监控:核心 KPI 卡片、趋势简图与渠道明细表,支撑周会与异常排查。
|
|
14
|
+
|
|
15
|
+
### 1.2 功能清单
|
|
16
|
+
|
|
17
|
+
| 模块 | 功能点 | 功能描述 |
|
|
18
|
+
| ------ | -------- | ------------------ |
|
|
19
|
+
| 运营看板 | 筛选 | 日期、渠道类型 |
|
|
20
|
+
| 运营看板 | 指标卡 | UV、转化率、消耗 |
|
|
21
|
+
| 运营看板 | 趋势图 | 近 7 日转化趋势(示意) |
|
|
22
|
+
| 运营看板 | 明细表 | 分渠道指标表 |
|
|
23
|
+
| 运营看板 | 指标总览 | 全量指标清单表 |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. 页面菜单与权限规划
|
|
28
|
+
|
|
29
|
+
### 2.1 页面菜单
|
|
30
|
+
|
|
31
|
+
**菜单路径**:数据中心 / 渠道运营看板
|
|
32
|
+
|
|
33
|
+
### 2.2 权限规划
|
|
34
|
+
|
|
35
|
+
| 权限点 | 操作范围 | 数据范围 |
|
|
36
|
+
| ------ | ---------- | -------- |
|
|
37
|
+
| 查看 | 看板全部模块 | 全量 |
|
|
38
|
+
| 导出 | 导出明细(可选) | 全量 |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 3. 渠道运营看板需求说明
|
|
43
|
+
|
|
44
|
+
### 3.1 筛选查询区
|
|
45
|
+
|
|
46
|
+
支持多维度组合筛选,变更后点击「查询」生效。
|
|
47
|
+
|
|
48
|
+
| 筛选字段 | 类型 | 输入限制 | 匹配规则 |
|
|
49
|
+
| :------- | :------- | :--------- | :------- |
|
|
50
|
+
| 统计日期 | 单日选择 | 默认昨日 | 精准 |
|
|
51
|
+
| 渠道类型 | 下拉 | 全部/付费/自然 | 精准 |
|
|
52
|
+
|
|
53
|
+
- **查询** / **重置**:刷新卡片、图表与列表。
|
|
54
|
+
|
|
55
|
+
### 3.2 核心指标卡说明
|
|
56
|
+
|
|
57
|
+
- **指标列表**
|
|
58
|
+
|
|
59
|
+
| 指标名称 | 业务价值 | 指标定义 |
|
|
60
|
+
| :------- | :----------- | :----------------- |
|
|
61
|
+
| 渠道 UV | 流量规模 | 统计日独立访客去重 |
|
|
62
|
+
| 转化率 | 投放效率 | 订单数 / UV |
|
|
63
|
+
| 消耗金额 | 成本控制 | 投放账户汇总消耗 |
|
|
64
|
+
|
|
65
|
+
- **交互说明**:卡片数字与筛选联动;hover 显示环比(可选)。
|
|
66
|
+
|
|
67
|
+
### 3.3 转化趋势说明
|
|
68
|
+
|
|
69
|
+
- **图表描述**:以折线图展示近 7 日转化率(原型为占位块 + 图例)。
|
|
70
|
+
- **图表指标列表**
|
|
71
|
+
|
|
72
|
+
| 指标名称 | 业务价值 | 指标定义 |
|
|
73
|
+
| :------- | :------- | :----------- |
|
|
74
|
+
| 日转化率 | 趋势监控 | 当日订单/UV |
|
|
75
|
+
|
|
76
|
+
- **交互说明**:随筛选日期范围变化(本示例固定 7 日 mock)。
|
|
77
|
+
|
|
78
|
+
### 3.4 渠道明细列表
|
|
79
|
+
|
|
80
|
+
- **列表字段**
|
|
81
|
+
|
|
82
|
+
| 列表字段 | 字段说明 |
|
|
83
|
+
| :------- | :--------- |
|
|
84
|
+
| 渠道名称 | 投放渠道名 |
|
|
85
|
+
| UV | 独立访客 |
|
|
86
|
+
| 订单数 | 成交笔数 |
|
|
87
|
+
|
|
88
|
+
- **交互说明**:支持按 UV 排序;导出见权限。
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 4. 指标总览
|
|
93
|
+
|
|
94
|
+
| 指标名称 | 筛选维度 | 数据来源 | 指标定义 |
|
|
95
|
+
| -------- | ---------- | -------- | --------------- |
|
|
96
|
+
| 渠道 UV | 日期、渠道类型 | 埋点+业务库 | 见 §3.2 |
|
|
97
|
+
| 转化率 | 日期、渠道类型 | 计算指标 | 订单/UV |
|
|
98
|
+
| 消耗金额 | 日期 | 财务接口 | 账户日汇总 |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 5. 交互设计
|
|
103
|
+
|
|
104
|
+
### 5.1 全局交互
|
|
105
|
+
|
|
106
|
+
加载骨架、空态、响应式;图表区懒加载(可选)。
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 9. 原型与 PRD 对应关系
|
|
111
|
+
|
|
112
|
+
| PRD 章节 | prototype.html 演示点 |
|
|
113
|
+
| -------- | ---------------------- |
|
|
114
|
+
| §1 | 页头「PRD §1」 |
|
|
115
|
+
| §3.1 | 筛选区「PRD §3.1」 |
|
|
116
|
+
| §3.2~§3.4 | 卡片区、趋势占位、表格 |
|
|
117
|
+
| §4 | 「PRD §4」指标总览说明 |
|
|
118
|
+
| §5 | 全局交互说明入口 |
|
|
119
|
+
| 走查说明 | 左下角「标注说明」 |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 10. 修订记录
|
|
124
|
+
|
|
125
|
+
| 版本 | 日期 | 说明 |
|
|
126
|
+
| ---- | ---------- | ---- |
|
|
127
|
+
| v0.1 | 2026-05-14 | 初版:对齐 data 模板示例 |
|