feat(review): 支持多候选稿验收轮次

- 支持每轮提交 1–5 个候选稿并按指定稿验收
- 保留历史轮次只读并兼容单候选稿版本接口
- 同步 SQLite/PostgreSQL schema、迁移验证、测试与项目文档
This commit is contained in:
yuzhe
2026-07-21 20:25:52 +08:00
parent 721e971dd8
commit 6091d61612
26 changed files with 586 additions and 97 deletions

View File

@@ -57,6 +57,8 @@ CREATE TABLE IF NOT EXISTS notes (
tags TEXT NOT NULL DEFAULT '[]',
review_status TEXT NOT NULL DEFAULT 'pending' CHECK (review_status IN ('draft', 'pending', 'changes_requested', 'approved')),
version_number INTEGER NOT NULL DEFAULT 1 CHECK (version_number > 0),
active_round_id BIGINT,
approved_version_number INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
@@ -117,11 +119,32 @@ CREATE TABLE IF NOT EXISTS work_versions (
description TEXT NOT NULL DEFAULT '',
tags TEXT NOT NULL DEFAULT '[]',
review_status TEXT NOT NULL DEFAULT 'pending' CHECK (review_status IN ('draft', 'pending', 'changes_requested', 'approved')),
review_round_id BIGINT,
candidate_name TEXT NOT NULL DEFAULT '方案 A',
candidate_status TEXT NOT NULL DEFAULT 'pending' CHECK (candidate_status IN ('draft', 'pending', 'changes_requested', 'selected', 'not_selected')),
created_by BIGINT REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (note_id, version_number)
);
CREATE TABLE IF NOT EXISTS review_rounds (
id BIGSERIAL PRIMARY KEY,
note_id BIGINT NOT NULL REFERENCES notes(id) ON DELETE CASCADE,
round_number INTEGER NOT NULL CHECK (round_number > 0),
status TEXT NOT NULL DEFAULT 'reviewing' CHECK (status IN ('draft', 'reviewing', 'completed')),
selected_version_number INTEGER,
created_by BIGINT REFERENCES users(id) ON DELETE SET NULL,
completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(note_id, round_number)
);
ALTER TABLE notes ADD COLUMN IF NOT EXISTS active_round_id BIGINT;
ALTER TABLE notes ADD COLUMN IF NOT EXISTS approved_version_number INTEGER;
ALTER TABLE work_versions ADD COLUMN IF NOT EXISTS review_round_id BIGINT;
ALTER TABLE work_versions ADD COLUMN IF NOT EXISTS candidate_name TEXT NOT NULL DEFAULT '方案 A';
ALTER TABLE work_versions ADD COLUMN IF NOT EXISTS candidate_status TEXT NOT NULL DEFAULT 'pending';
CREATE TABLE IF NOT EXISTS review_events (
id BIGSERIAL PRIMARY KEY,
note_id BIGINT NOT NULL REFERENCES notes(id) ON DELETE CASCADE,
@@ -205,6 +228,7 @@ CREATE INDEX IF NOT EXISTS annotations_image_id_idx ON annotations(image_id);
CREATE INDEX IF NOT EXISTS comments_note_id_idx ON work_comments(note_id);
CREATE INDEX IF NOT EXISTS customer_sessions_project_id_idx ON customer_sessions(project_id);
CREATE INDEX IF NOT EXISTS review_events_note_version_idx ON review_events(note_id, version_number);
CREATE INDEX IF NOT EXISTS review_rounds_note_id_idx ON review_rounds(note_id, round_number);
CREATE INDEX IF NOT EXISTS audit_logs_group_id_idx ON audit_logs(group_id);
-- COLLECTION_STATUS_REPAIR_START
@@ -227,4 +251,34 @@ FROM (
WHERE c.id = s.collection_id AND c.status != 'archived';
-- COLLECTION_STATUS_REPAIR_END
-- REVIEW_ROUND_REPAIR_START
INSERT INTO review_rounds (note_id, round_number, status, selected_version_number, completed_at, created_at)
SELECT v.note_id, v.version_number,
CASE WHEN v.version_number = n.version_number AND n.review_status != 'approved' THEN 'reviewing' ELSE 'completed' END,
CASE WHEN v.review_status = 'approved' THEN v.version_number ELSE NULL END,
CASE WHEN v.version_number = n.version_number AND n.review_status != 'approved' THEN NULL ELSE v.created_at END,
v.created_at
FROM work_versions v JOIN notes n ON n.id = v.note_id
ON CONFLICT (note_id, round_number) DO NOTHING;
UPDATE work_versions v
SET review_round_id = r.id,
candidate_name = COALESCE(NULLIF(v.candidate_name, ''), '方案 A'),
candidate_status = CASE
WHEN v.review_status = 'approved' THEN 'selected'
WHEN v.version_number = n.version_number AND v.review_status = 'changes_requested' THEN 'changes_requested'
WHEN v.version_number = n.version_number AND v.review_status = 'pending' THEN 'pending'
WHEN v.version_number = n.version_number AND v.review_status = 'draft' THEN 'draft'
ELSE 'not_selected'
END
FROM review_rounds r, notes n
WHERE r.note_id = v.note_id AND r.round_number = v.version_number AND n.id = v.note_id AND v.review_round_id IS NULL;
UPDATE notes n
SET active_round_id = r.id,
approved_version_number = (SELECT MAX(v.version_number) FROM work_versions v WHERE v.note_id = n.id AND v.review_status = 'approved')
FROM review_rounds r
WHERE r.note_id = n.id AND r.round_number = n.version_number AND n.active_round_id IS NULL;
-- REVIEW_ROUND_REPAIR_END
COMMIT;