Files
cn-rdms/项目列表产品分组-后端接口诉求-2026-06-10.html
hongawen 79591e66be refactor(project): 重构权限常量定义并移除需求进度聚合功能
- 将产品和项目查询权限码统一提取到常量类中
- 移除需求进度聚合计算的相关实现代码
- 更新权限验证注解使用新的常量定义
- 清理相关的单元测试代码
- 更新错误码注释说明
2026-06-11 09:17:21 +08:00

267 lines
12 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: #f6f7f9;
--panel: #ffffff;
--border: #e5e7eb;
--border-strong: #d1d5db;
--text: #1f2937;
--text-soft: #6b7280;
--text-muted: #9ca3af;
--primary: #2563eb;
--primary-soft: #dbeafe;
--ok: #047857;
--ok-bg: #d1fae5;
--warn: #b45309;
--warn-bg: #fef3c7;
--bad: #b91c1c;
--bad-bg: #fee2e2;
--code: #b45309;
--code-bg: #f3f4f6;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
background: var(--bg);
color: var(--text);
font-size: 14px;
line-height: 1.7;
}
.wrap {
max-width: 980px;
margin: 0 auto;
padding: 32px 28px 80px;
}
.head { margin-bottom: 22px; }
.head h1 { margin: 0 0 6px; font-size: 24px; font-weight: 700; line-height: 1.4; }
.head .sub { color: var(--text-soft); font-size: 13px; }
section { margin-top: 28px; }
section > h2 {
font-size: 18px;
font-weight: 700;
margin: 0 0 14px;
padding-bottom: 8px;
border-bottom: 2px solid var(--border);
}
section h3 { font-size: 15px; font-weight: 700; margin: 18px 0 8px; }
.card {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
padding: 18px 22px;
margin-bottom: 14px;
}
table.cmp {
width: 100%;
border-collapse: collapse;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
font-size: 13px;
margin: 10px 0 14px;
}
table.cmp th, table.cmp td {
border: 1px solid var(--border);
padding: 8px 12px;
text-align: left;
vertical-align: top;
}
table.cmp th { background: #f9fafb; font-weight: 700; white-space: nowrap; }
table.cmp td code, p code, li code {
font-family: "JetBrains Mono", Consolas, monospace;
font-size: 12.5px;
color: var(--code);
background: var(--code-bg);
padding: 1px 5px;
border-radius: 4px;
}
pre {
background: #1f2937;
color: #e5e7eb;
border-radius: 8px;
padding: 14px 16px;
overflow-x: auto;
font-family: "JetBrains Mono", Consolas, monospace;
font-size: 12.5px;
line-height: 1.6;
}
pre .c { color: #9ca3af; }
.tag-ok, .tag-warn, .tag-bad {
display: inline-block;
font-size: 11px;
font-weight: 700;
border-radius: 999px;
padding: 1px 10px;
vertical-align: 1px;
white-space: nowrap;
}
.tag-ok { color: var(--ok); background: var(--ok-bg); }
.tag-warn { color: var(--warn); background: var(--warn-bg); }
.tag-bad { color: var(--bad); background: var(--bad-bg); }
ul, ol { margin: 8px 0; padding-left: 22px; }
li { margin: 4px 0; }
.note { color: var(--text-soft); font-size: 13px; }
</style>
</head>
<body>
<div class="wrap">
<div class="head">
<h1>项目列表按产品分组:后端待确认事项与接口诉求</h1>
<div class="sub">2026-06-10 · 前端发起 · 涉及模块project/project项目、system/dict字典</div>
</div>
<section>
<h2>0. 背景</h2>
<div class="card">
<p>项目列表页将从"平铺分页"改为"按所属产品聚合展示":同一产品下的项目(基线/合同/技术支持等类型)需要聚拢在一起查看,不能被分页切散。现有 <code>GET /project/project/page</code> 平铺分页无法支撑该口径,需要后端补充以下能力。</p>
<p>前端已按本文档第 2~4 节的契约<b>先行开发</b>(过渡期用现有平铺接口在前端聚合模拟),后端接口就绪后联调切换,<b>不阻塞后端排期</b>,但请反馈预计时间点。</p>
</div>
</section>
<section>
<h2>1. 待查询确认rdms_project_type 字典数据 <span class="tag-warn">请尽快回复,阻塞前端一处常量</span></h2>
<div class="card">
<p>请提供字典 <code>rdms_project_type</code>(项目类型)的<b>完整字典数据清单</b>(每项的 value / label / 启用状态),特别是:</p>
<ul>
<li><b>"基线"类型对应的字典 value 是什么</b>(前端需写入常量,用于"建立基线"入口预填与缺基线判定);</li>
<li>除 基线 / 合同 / 技术支持 外是否还有其他在用类型值。</li>
</ul>
<p class="note">补充确认(口头已确认,烦请最终对齐):"基线项目每产品唯一"由后端在创建/更新项目时做唯一性校验兜底,前端仅做体验层提示。</p>
</div>
</section>
<section>
<h2>2. 接口诉求一:项目按产品分组分页查询(新增) <span class="tag-bad">核心依赖</span></h2>
<h3>2.1 建议路径</h3>
<div class="card">
<p><code>GET /project/project/group-page</code>(路径可由后端按规范调整,前端只在 service 层适配一处)</p>
<p>数据权限口径与现有 <code>/project/project/page</code> 一致:只返回当前用户可见的项目,按其归属产品聚合。</p>
</div>
<h3>2.2 入参</h3>
<table class="cmp">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td><code>pageNo</code> / <code>pageSize</code></td><td>int</td><td></td><td><b>产品组维度</b>分页:一页返回 pageSize 个产品组(含组内项目),不是项目行分页。前端当前 pageSize=10。</td></tr>
<tr><td><code>keyword</code></td><td>string</td><td></td><td>项目编码 / 名称模糊匹配(口径同现有 page 接口)。</td></tr>
<tr><td><code>productId</code></td><td>string</td><td></td><td>限定单个产品。</td></tr>
<tr><td><code>projectType</code></td><td>string</td><td></td><td>项目类型字典 value。</td></tr>
<tr><td><code>statusCode</code></td><td>string</td><td></td><td>单状态过滤。<b>不传 = "全部"口径pending / active / paused / completed 四种状态,不含 cancelled / archived。</b></td></tr>
<tr><td><code>orphanOnly</code></td><td>boolean</td><td></td><td>true = 仅返回"游离组"productId 为空的项目聚合为一个特殊组)。</td></tr>
<tr><td><code>topN</code></td><td>int</td><td></td><td>每组返回的项目条数上限,建议默认 5前端当前固定取 5</td></tr>
</table>
<h3>2.3 返回结构(示例)</h3>
<pre>{
"total": 12, <span class="c">// 当前筛选口径下产品组总数(分页 total含游离组</span>
"projectTotal": 47, <span class="c">// 当前筛选口径下项目总数</span>
"directionCount": 3, <span class="c">// 可见产品去重后的方向directionCode</span>
"orphanTotal": 3, <span class="c">// 游离项目数productId 为空)</span>
"list": [
{
"productId": "1923456789012345678", <span class="c">// 字符串!见 4.1</span>
"productName": "智能网关",
"productCode": "RDMS-P-001",
"directionCode": "platform",
"managerUserId": "1001",
"managerUserNickname": "张三",
"projectTotal": 6, <span class="c">// 当前筛选口径下该组项目总数</span>
"projects": [ /* 前 topN 条,字段同现有 page 接口的项目行 */ ],
"typeCounts": { "baseline值": 1, "合同值": 3, "技术支持值": 2 },
"hasBaseline": true,
"orphan": false
},
{
"productId": null, <span class="c">// 游离组:未挂产品的项目聚合</span>
"productName": "游离项目",
"productCode": null,
"directionCode": "",
"managerUserId": null,
"managerUserNickname": null,
"projectTotal": 3,
"projects": [ /* ... */ ],
"typeCounts": { "合同值": 2, "技术支持值": 1 },
"hasBaseline": false,
"orphan": true
}
]
}</pre>
<h3>2.4 口径约定(关键,请逐条确认)</h3>
<table class="cmp">
<tr><th>#</th><th>约定</th><th>说明</th></tr>
<tr><td>1</td><td>组内项目排序</td><td><code>updateTime</code> 倒序,返回前 topN 条;<code>projectTotal</code> 为该口径下组内全量计数。</td></tr>
<tr><td>2</td><td>无命中组不返回</td><td>传了 <code>statusCode</code> / <code>keyword</code> / <code>projectType</code> 任一筛选时,组内无命中项目的产品组不返回。</td></tr>
<tr><td>3</td><td>零项目产品组</td><td>"全部"口径statusCode 缺省)且无 keyword / projectType 筛选时,<b>返回当前用户可见、状态为 active / paused 的零项目产品组</b>projectTotal=0、projects=[]),用于"该产品暂无项目"占位与新增引导。</td></tr>
<tr><td>4</td><td>typeCounts / hasBaseline 统计口径</td><td>这两个字段是"产品属性"<b>恒按"全部"口径(四种状态)统计</b>,不随 statusCode 入参变化——避免"基线项目已完成时被误判为缺基线"。</td></tr>
<tr><td>5</td><td>游离组位置</td><td>游离组productId 为空)作为列表中<b>最后一个组</b>返回;状态筛选下同样适用约定 2无命中则不返回该组</td></tr>
<tr><td>6</td><td>组的排序</td><td>同方向directionCode的产品组相邻返回方向间顺序、方向内产品顺序由后端按现有产品列表默认排序即可</td></tr>
</table>
<h3>2.5 组内"展开剩余"的数据来源</h3>
<div class="card">
<p>不需要新接口:前端用现有 <code>GET /project/project/page</code><code>productId + statusCode</code> 拉取该组剩余项目。前提是该接口的排序与本接口组内排序一致updateTime 倒序)——若现有 page 接口默认排序不是 updateTime 倒序,请告知或支持排序参数。</p>
</div>
</section>
<section>
<h2>3. 接口诉求二、三:存量接口小改 <span class="tag-warn">两处补充</span></h2>
<h3>3.1 平铺分页支持"未挂产品"筛选</h3>
<div class="card">
<p><code>GET /project/project/page</code> 需要能表达 <b>productId 为空</b>的筛选语义(如新增 <code>orphanOnly=true</code> 参数,或约定 productId 传特殊值),用于查询"游离项目"(未关联任何产品的项目)。具体参数形式由后端定,前端适配。</p>
</div>
<h3>3.2 概览统计补游离计数</h3>
<div class="card">
<p><code>GET /project/project/overview-summary</code> 返回体增加:</p>
<pre>{
"statusCounts": { "active": 10, "pending": 2, ... }, <span class="c">// 现有</span>
"orphanCount": 3 <span class="c">// 新增:未挂产品的项目数(按"全部"口径:四种状态)</span>
}</pre>
</div>
</section>
<section>
<h2>4. 公共约定</h2>
<table class="cmp">
<tr><th>#</th><th>约定</th><th>说明</th></tr>
<tr><td>4.1</td><td>ID 一律字符串 <span class="tag-bad">必须</span></td><td>所有 Long / 雪花 IDproductId、managerUserId、项目 id 等)在 JSON 中<b>按字符串返回</b>。Long 直接作为 JSON 数字返回会在前端丢精度。</td></tr>
<tr><td>4.2</td><td>"全部"状态集合</td><td>pending / active / paused / completedcancelled / archived 仅在显式传对应 statusCode 时返回。</td></tr>
<tr><td>4.3</td><td>项目行字段</td><td>分组接口 <code>projects[]</code> 内的项目对象字段与现有 <code>/project/project/page</code> 返回行保持一致(含 productId / productName / managerUserNickname / progressRate / statusCode / updateTime 等),避免前端双口径。</td></tr>
</table>
</section>
<section>
<h2>5. 需要后端反馈的清单</h2>
<div class="card">
<ol>
<li><b>第 1 节</b><code>rdms_project_type</code> 字典数据清单 + "基线"的 value<span class="tag-warn">最优先</span>,一条查询即可,阻塞前端一处常量)。</li>
<li><b>第 2 节</b>:分组分页接口的可行性确认 + 2.4 六条口径逐条确认(有异议请直接批注替代方案)+ 排期。</li>
<li><b>第 3 节</b>page 接口游离筛选的参数形式 + overview-summary 补 orphanCount 的排期。</li>
<li><b>第 2.5 节</b>:现有 page 接口的默认排序是什么;是否支持/计划支持按 updateTime 倒序。</li>
</ol>
</div>
</section>
</div>
</body>
</html>