feat(project): 项目基本信息修改和分包选择(FR-M2-03、04)
Some checks failed
ci / server (push) Has been cancelled
ci / web (push) Has been cancelled
ci / contract (push) Has been cancelled

- 字段修改:人工值优先、撤销恢复 AI 值、按字段校验(金额可写「286万」,按元存)、
  冗余列同步、审计留痕、只读项目 409;关键日期显示改后的投标截止时间
- 分包:增删改、选包(至少一个)、一键「不分包」;删包时条目归为通用,删到一个不剩回到不分包
- 清单列表 lot_scope 默认只列通用 + 所投的包,响应带 hidden_count
- 检查记下当时用的项目依据(截止时间、限价、所投的包、法律体系):报告按它写,
  之后改了信息检查结果接口给 basis_changed,查标页提示重新检查
- 前端:概览标签页(项目要点、采购包、关键日期)、字段修改对话框、选包页和手工调整;
  解析完识别到多个包时进选包页;读标页清单范围和所属采购包;查标页写明查哪几个包
- 决策 PI1–PI7;方案和落地记录 docs/architecture/project-info-plan.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-04 23:46:07 +08:00
parent 08e3fe7eff
commit ed6a2a907d
29 changed files with 1834 additions and 43 deletions

View File

@@ -360,6 +360,28 @@ export interface paths {
patch?: never;
trace?: never;
};
"/projects/{project_id}/lots/clear": {
parameters: {
query?: never;
header?: never;
path: {
project_id: components["parameters"]["ProjectId"];
};
cookie?: never;
};
get?: never;
put?: never;
/**
* 这个项目不分包(PI2)
* @description 删掉所有包,清单项都归为各包通用,建回默认包。用于把分项误识别成包等情况。
*/
post: operations["clearLots"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/lots/{lot_id}": {
parameters: {
query?: never;
@@ -372,7 +394,10 @@ export interface paths {
get?: never;
put?: never;
post?: never;
/** 删除分包(原属这个包的清单项变为各包通用) */
/**
* 删除分包(原属这个包的清单项变为各包通用,PI3)
* @description 删掉最后一个包时项目回到「不分包」(自动建回默认包,PI2)。
*/
delete: operations["deleteLot"];
options?: never;
head?: never;
@@ -1601,9 +1626,14 @@ export interface components {
fields: components["schemas"]["ProjectField"][];
/** @description 关键日期时间线(FR-M2-09),来自「日期与递交」类清单项 */
key_dates: {
item_id: components["schemas"]["Id"];
/** @description 来自哪条清单项;人工改过的投标截止时间没有对应条目,为 null */
item_id: components["schemas"]["Id"] | null;
label: string;
/** @enum {string} */
kind?: "question_deadline" | "bid_deadline" | "opening" | "deposit_deadline" | "validity" | "other";
at: components["schemas"]["Timestamp"];
/** @description 人工改过(投标截止时间按项目字段的人工值显示) */
edited?: boolean;
/** @description 补遗带来了新值、等用户确认 */
superseded_pending?: boolean;
}[];
@@ -1626,6 +1656,7 @@ export interface components {
ai_value?: components["schemas"]["FieldValue"];
citation?: components["schemas"]["Citation"] | null;
updated_by?: components["schemas"]["UserRef"] | null;
updated_at?: components["schemas"]["Timestamp"] | null;
/** @description 补遗带来的新值(FR-M2-10) */
pending?: {
value?: components["schemas"]["FieldValue"];
@@ -1650,6 +1681,8 @@ export interface components {
is_bidding: boolean;
origin: components["schemas"]["Origin"];
edited_fields: string[];
/** @description AI 识别的原值(包号、名称、预算、限价),人工修改不覆盖 */
ai_values?: Record<string, never> | null;
};
Upload: {
id: components["schemas"]["Id"];
@@ -1999,6 +2032,8 @@ export interface components {
rule_set_version: string;
legal_regime?: components["schemas"]["LegalRegime"];
documents?: components["schemas"]["Document"][];
/** @description 检查之后改过项目依据(截止时间、限价、所投的包、法律体系),查标页提示「重新检查后生效」(PI5) */
basis_changed?: boolean;
/** @description 查了什么、没查什么(报告首页、查标页顶部,FR-M3-09、m3-plan §2.5)。认不出、查不了、没查的都写在这里,不静默跳过。
* */
coverage?: {
@@ -2028,6 +2063,10 @@ export interface components {
rules_verified?: boolean;
};
rule_set_version?: string;
/** @description 资质匹配的计数(qualification-plan §3.4):资质库条数、核对的资质要求、按资质库判断的、没认出类别的、排除的 */
qualification?: Record<string, never>;
/** @description 检查时用的项目依据(PI5):deadline_at、ceiling_total、legal_regime 各为 {value, source},lots 是所投各包 {lot_no, ceiling_amount, source}。报告按它写 */
basis?: Record<string, never>;
prompt_versions?: Record<string, never>;
tokens?: {
in?: number;
@@ -3006,6 +3045,31 @@ export interface operations {
409: components["responses"]["ProjectReadOnly"];
};
};
clearLots: {
parameters: {
query?: never;
header?: never;
path: {
project_id: components["parameters"]["ProjectId"];
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
items: components["schemas"]["Lot"][];
};
};
};
409: components["responses"]["ProjectReadOnly"];
};
};
deleteLot: {
parameters: {
query?: never;
@@ -3024,15 +3088,7 @@ export interface operations {
};
content?: never;
};
/** @description `last_lot`:至少保留一个包;或 `project_read_only` */
409: {
headers: {
[name: string]: unknown;
};
content: {
"application/problem+json": components["schemas"]["Problem"];
};
};
409: components["responses"]["ProjectReadOnly"];
};
};
updateLot: {
@@ -3586,6 +3642,8 @@ export interface operations {
content: {
"application/json": {
items: components["schemas"]["ChecklistItem"][];
/** @description `lot_scope = bidding` 时不在所投包里、没列出的条数 */
hidden_count: number;
};
};
};