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();