feat(review): 重构项目级单方案验收协作
This commit is contained in:
@@ -6,11 +6,11 @@ function toAnnotation(row: AnnotationRow): Annotation { return { ...row, id: Num
|
||||
|
||||
export const annotationsRepository = {
|
||||
async listByImage(imageId: number): Promise<Annotation[]> {
|
||||
return (await database.all<AnnotationRow>('SELECT id, image_id, x, y, content, author_name, status, created_at FROM annotations WHERE image_id = ? ORDER BY id ASC', [imageId])).map(toAnnotation);
|
||||
return (await database.all<AnnotationRow>('SELECT id, image_id, x, y, content, author_name, author_role, status, closure_reason, withdrawn_at, created_at FROM annotations WHERE image_id = ? ORDER BY id ASC', [imageId])).map(toAnnotation);
|
||||
},
|
||||
async create(imageId: number, data: CreateAnnotationRequest): Promise<Annotation> {
|
||||
const id = await database.insertId('INSERT INTO annotations (image_id, x, y, content, author_name) VALUES (?, ?, ?, ?, ?)', [imageId, data.x, data.y, data.content, data.author_name || '客户']);
|
||||
return toAnnotation((await database.one<AnnotationRow>('SELECT id, image_id, x, y, content, author_name, status, created_at FROM annotations WHERE id = ?', [id]))!);
|
||||
const id = await database.insertId('INSERT INTO annotations (image_id, x, y, content, author_name, author_role) VALUES (?, ?, ?, ?, ?, ?)', [imageId, data.x, data.y, data.content, data.author_name || '客户', data.author_role || 'client']);
|
||||
return toAnnotation((await database.one<AnnotationRow>('SELECT id, image_id, x, y, content, author_name, author_role, status, closure_reason, withdrawn_at, created_at FROM annotations WHERE id = ?', [id]))!);
|
||||
},
|
||||
async remove(id: number): Promise<boolean> { return (await database.execute('DELETE FROM annotations WHERE id = ?', [id])).changes > 0; },
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { database } from '../database.js';
|
||||
import type { Note, NoteListQuery, ReviewStatus } from '../../shared/types.js';
|
||||
|
||||
interface NoteRow {
|
||||
id: number; collection_id: number; external_id: string | null; title: string; description: string; tags: string;
|
||||
id: number; project_id: number; collection_id: number; external_id: string | null; title: string; description: string; tags: string;
|
||||
review_status: ReviewStatus; version_number: number; active_round_id: number | null; approved_version_number: number | null; created_at: string;
|
||||
image_count: number | string; annotation_count: number | string; comment_count: number | string; cover_url: string | null;
|
||||
}
|
||||
@@ -10,7 +10,7 @@ interface NoteRow {
|
||||
function toNote(row: NoteRow): Note {
|
||||
return {
|
||||
...row,
|
||||
id: Number(row.id), collection_id: Number(row.collection_id), version_number: Number(row.version_number),
|
||||
id: Number(row.id), project_id: Number(row.project_id), collection_id: Number(row.collection_id), version_number: Number(row.version_number),
|
||||
active_round_id: row.active_round_id == null ? null : Number(row.active_round_id), approved_version_number: row.approved_version_number == null ? null : Number(row.approved_version_number),
|
||||
image_count: Number(row.image_count), annotation_count: Number(row.annotation_count), comment_count: Number(row.comment_count),
|
||||
tags: JSON.parse(row.tags || '[]') as string[],
|
||||
@@ -19,7 +19,7 @@ function toNote(row: NoteRow): Note {
|
||||
}
|
||||
|
||||
const select = `
|
||||
SELECT n.id, n.collection_id, n.external_id, n.title, n.description, n.tags, n.review_status, n.version_number, n.active_round_id, n.approved_version_number, n.created_at,
|
||||
SELECT n.id, n.project_id, n.collection_id, n.external_id, n.title, n.description, n.tags, n.review_status, n.version_number, n.active_round_id, n.approved_version_number, n.created_at,
|
||||
COALESCE(ic.image_count, 0) AS image_count,
|
||||
COALESCE(ac.annotation_count, 0) AS annotation_count,
|
||||
COALESCE(cc.comment_count, 0) AS comment_count,
|
||||
@@ -38,8 +38,8 @@ export const notesRepository = {
|
||||
if (query.status) { conditions.push('n.review_status = ?'); params.push(query.status); }
|
||||
if (query.q?.trim()) { conditions.push('(n.title LIKE ? OR n.description LIKE ?)'); params.push(`%${query.q.trim()}%`, `%${query.q.trim()}%`); }
|
||||
if (query.tag?.trim()) { conditions.push('n.tags LIKE ?'); params.push(`%"${query.tag.trim()}"%`); }
|
||||
if (query.projectId) { conditions.push('n.collection_id IN (SELECT id FROM collections WHERE project_id = ?)'); params.push(query.projectId); }
|
||||
if (query.groupId) { conditions.push('n.collection_id IN (SELECT c.id FROM collections c JOIN projects p ON p.id = c.project_id WHERE p.group_id = ?)'); params.push(query.groupId); }
|
||||
if (query.projectId) { conditions.push('n.project_id = ?'); params.push(query.projectId); }
|
||||
if (query.groupId) { conditions.push('n.project_id IN (SELECT id FROM projects WHERE group_id = ?)'); params.push(query.groupId); }
|
||||
const where = conditions.length ? ` WHERE ${conditions.join(' AND ')}` : '';
|
||||
const order = query.order === 'asc' ? 'ASC' : 'DESC';
|
||||
const sort = query.sort === 'annotations' ? 'annotation_count' : 'n.created_at';
|
||||
@@ -53,6 +53,10 @@ export const notesRepository = {
|
||||
const row = await database.one<NoteRow>(`${select} WHERE n.collection_id = ? AND n.external_id = ?`, [collectionId, externalId]);
|
||||
return row ? toNote(row) : null;
|
||||
},
|
||||
async findByProjectExternalId(projectId: number, externalId: string): Promise<Note | null> {
|
||||
const row = await database.one<NoteRow>(`${select} WHERE n.project_id = ? AND n.external_id = ?`, [projectId, externalId]);
|
||||
return row ? toNote(row) : null;
|
||||
},
|
||||
async create(title: string, description: string, collectionId: number, tags: string[]): Promise<number> {
|
||||
return database.insertId('INSERT INTO notes (title, description, collection_id, tags, review_status) VALUES (?, ?, ?, ?, ?)', [title, description, collectionId, JSON.stringify(tags), 'pending']);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user