diff --git a/database/init.sql b/database/init.sql index a68dcb63..737ba507 100644 --- a/database/init.sql +++ b/database/init.sql @@ -321,6 +321,7 @@ CREATE TABLE public.milestones ( planned_date date, actual_date date, status character varying(20) NOT NULL, + site_id uuid, owner_id uuid, notes text, created_at timestamp with time zone DEFAULT now() NOT NULL, @@ -603,8 +604,8 @@ bbbbbbb1-bbbb-bbbb-bbbb-bbbbbbbbbbb1 44444444-4444-4444-4444-444444444444 555555 -- Data for Name: milestones; Type: TABLE DATA; Schema: public; Owner: ctms_user -- -COPY public.milestones (id, study_id, type, name, planned_date, actual_date, status, owner_id, notes, created_at, updated_at) FROM stdin; -66666666-6666-6666-6666-666666666666 44444444-4444-4444-4444-444444444444 SIV 启动会 2025-01-10 2025-01-12 DONE 22222222-2222-2222-2222-222222222222 现场启动完成 2025-12-18 00:55:17.568504+00 2025-12-18 00:55:17.568504+00 +COPY public.milestones (id, study_id, type, name, planned_date, actual_date, status, site_id, owner_id, notes, created_at, updated_at) FROM stdin; +66666666-6666-6666-6666-666666666666 44444444-4444-4444-4444-444444444444 SIV 启动会 2025-01-10 2025-01-12 DONE 55555555-5555-5555-5555-555555555555 22222222-2222-2222-2222-222222222222 现场启动完成 2025-12-18 00:55:17.568504+00 2025-12-18 00:55:17.568504+00 \. @@ -1503,6 +1504,13 @@ ALTER TABLE ONLY public.issues ALTER TABLE ONLY public.milestones ADD CONSTRAINT milestones_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES public.users(id); +-- +-- Name: milestones milestones_site_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: ctms_user +-- + +ALTER TABLE ONLY public.milestones + ADD CONSTRAINT milestones_site_id_fkey FOREIGN KEY (site_id) REFERENCES public.sites(id); + -- -- Name: milestones milestones_study_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: ctms_user diff --git a/frontend/dist/index.html b/frontend/dist/index.html index cc220893..0dc8eb64 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -4,8 +4,8 @@ CTMS - - + +
diff --git a/frontend/src/views/admin/AuditLogs.vue b/frontend/src/views/admin/AuditLogs.vue index dc4a3f7c..39885449 100644 --- a/frontend/src/views/admin/AuditLogs.vue +++ b/frontend/src/views/admin/AuditLogs.vue @@ -101,6 +101,23 @@ import { exportAuditCsv } from "../../audit/export/auditExportService"; import { logAudit } from "../../audit"; import { displayDateTime } from "../../utils/display"; +const buildLogKey = (log: any) => { + if (log.id) return `id:${log.id}`; + return `${log.action || log.eventType || "event"}-${log.entity_id || log.entityId || ""}-${log.created_at || log.timestamp || ""}`; +}; + +const dedupeLogs = (list: any[]) => { + const seen = new Set(); + const result: any[] = []; + list.forEach((log) => { + const key = buildLogKey(log); + if (seen.has(key)) return; + seen.add(key); + result.push(log); + }); + return result; +}; + const study = useStudyStore(); const auth = useAuthStore(); const router = useRouter(); @@ -163,7 +180,7 @@ const loadLogs = async () => { const { data } = await fetchAuditLogs(study.currentStudy.id, params); const items = Array.isArray(data) ? data : (data as any).items || []; const local = loadLocalLogs(); - const merged = [...items, ...local]; + const merged = dedupeLogs([...items, ...local]); rawLogs.value = merged; total.value = (data as any).total || merged.length; enrichLogs(); @@ -233,7 +250,7 @@ const fetchAllForExport = async () => { const { data } = await fetchAuditLogs(study.currentStudy.id, params); const items = Array.isArray(data) ? data : (data as any).items || []; const local = loadLocalLogs(); - const merged = [...items, ...local]; + const merged = dedupeLogs([...items, ...local]); const userMap = users.value.reduce>((acc, cur) => { acc[cur.id] = cur.username; return acc; diff --git a/frontend/src/views/admin/ProjectDetail.vue b/frontend/src/views/admin/ProjectDetail.vue index 7de155a4..42fdf617 100644 --- a/frontend/src/views/admin/ProjectDetail.vue +++ b/frontend/src/views/admin/ProjectDetail.vue @@ -21,7 +21,7 @@ {{ project.name }} {{ project.sponsor || "—" }} {{ statusLabel(project.status) }} - {{ project.created_at || "—" }} + {{ displayDateTime(project.created_at) }} @@ -48,6 +48,7 @@ import { fetchStudyDetail } from "../../api/studies"; import type { Study } from "../../types/api"; import AttachmentList from "../../components/attachments/AttachmentList.vue"; import { useStudyStore } from "../../store/study"; +import { displayDateTime } from "../../utils/display"; const route = useRoute(); const router = useRouter();