diff --git a/backend/app/api/v1/aes.py b/backend/app/api/v1/aes.py index 9a112b88..6f81d04b 100644 --- a/backend/app/api/v1/aes.py +++ b/backend/app/api/v1/aes.py @@ -14,7 +14,7 @@ from app.schemas.ae import AECreate, AERead, AEUpdate router = APIRouter() ALLOWED_CREATE_ROLES = {"PM", "CRA", "PV"} -ALLOWED_UPDATE_ROLES = {"PM", "PV"} +ALLOWED_UPDATE_ROLES = {"PM", "PV", "CRA"} async def _ensure_study_exists(db: AsyncSession, study_id: uuid.UUID): diff --git a/frontend/src/api/aes.ts b/frontend/src/api/aes.ts new file mode 100644 index 00000000..85ccb56a --- /dev/null +++ b/frontend/src/api/aes.ts @@ -0,0 +1,11 @@ +import { apiGet, apiPost, apiPatch } from "./axios"; +import type { ApiListResponse } from "../types/api"; + +export const fetchAes = (studyId: string, params?: Record) => + apiGet>(`/api/v1/studies/${studyId}/aes/`, { params }); + +export const createAe = (studyId: string, payload: Record) => + apiPost(`/api/v1/studies/${studyId}/aes/`, payload); + +export const updateAe = (studyId: string, aeId: string, payload: Record) => + apiPatch(`/api/v1/studies/${studyId}/aes/${aeId}`, payload); diff --git a/frontend/src/api/attachments.ts b/frontend/src/api/attachments.ts new file mode 100644 index 00000000..8a87eb88 --- /dev/null +++ b/frontend/src/api/attachments.ts @@ -0,0 +1,12 @@ +import { apiGet, apiPost } from "./axios"; + +export const fetchAttachments = (studyId: string, entityType: string, entityId: string) => + apiGet(`/api/v1/studies/${studyId}/${entityType}/${entityId}/attachments`); + +export const uploadAttachment = (studyId: string, entityType: string, entityId: string, file: File) => { + const formData = new FormData(); + formData.append("file", file); + return apiPost(`/api/v1/studies/${studyId}/${entityType}/${entityId}/attachments`, formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); +}; diff --git a/frontend/src/api/comments.ts b/frontend/src/api/comments.ts new file mode 100644 index 00000000..05952929 --- /dev/null +++ b/frontend/src/api/comments.ts @@ -0,0 +1,11 @@ +import { apiGet, apiPost } from "./axios"; + +export const fetchComments = (studyId: string, entityType: string, entityId: string) => + apiGet(`/api/v1/studies/${studyId}/${entityType}/${entityId}/comments`); + +export const createComment = ( + studyId: string, + entityType: string, + entityId: string, + payload: Record +) => apiPost(`/api/v1/studies/${studyId}/${entityType}/${entityId}/comments`, payload); diff --git a/frontend/src/api/issues.ts b/frontend/src/api/issues.ts new file mode 100644 index 00000000..8c0633f7 --- /dev/null +++ b/frontend/src/api/issues.ts @@ -0,0 +1,11 @@ +import { apiGet, apiPost, apiPatch } from "./axios"; +import type { ApiListResponse } from "../types/api"; + +export const fetchIssues = (studyId: string, params?: Record) => + apiGet>(`/api/v1/studies/${studyId}/issues/`, { params }); + +export const createIssue = (studyId: string, payload: Record) => + apiPost(`/api/v1/studies/${studyId}/issues/`, payload); + +export const updateIssue = (studyId: string, issueId: string, payload: Record) => + apiPatch(`/api/v1/studies/${studyId}/issues/${issueId}`, payload); diff --git a/frontend/src/components/AttachmentList.vue b/frontend/src/components/AttachmentList.vue new file mode 100644 index 00000000..81200a47 --- /dev/null +++ b/frontend/src/components/AttachmentList.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/frontend/src/components/CommentList.vue b/frontend/src/components/CommentList.vue new file mode 100644 index 00000000..f7d16f6a --- /dev/null +++ b/frontend/src/components/CommentList.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/frontend/src/components/IssueForm.vue b/frontend/src/components/IssueForm.vue new file mode 100644 index 00000000..64b8c35f --- /dev/null +++ b/frontend/src/components/IssueForm.vue @@ -0,0 +1,128 @@ + + + diff --git a/frontend/src/components/Layout.vue b/frontend/src/components/Layout.vue index 47c934c9..9ca144b4 100644 --- a/frontend/src/components/Layout.vue +++ b/frontend/src/components/Layout.vue @@ -20,6 +20,8 @@ 里程碑 任务 受试者 + AE + 风险/问题 diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 282c31ea..da059661 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -11,10 +11,13 @@ import Milestones from "../views/Milestones.vue"; import Subjects from "../views/Subjects.vue"; import SubjectDetail from "../views/SubjectDetail.vue"; import Aes from "../views/Aes.vue"; +import AeDetail from "../views/AeDetail.vue"; import DataQueries from "../views/DataQueries.vue"; import Imp from "../views/Imp.vue"; import Finance from "../views/Finance.vue"; import Faq from "../views/Faq.vue"; +import Issues from "../views/Issues.vue"; +import IssueDetail from "../views/IssueDetail.vue"; const routes: RouteRecordRaw[] = [ { @@ -70,12 +73,30 @@ const routes: RouteRecordRaw[] = [ component: Aes, meta: { title: "AE", requiresStudy: true }, }, + { + path: "study/aes/:aeId", + name: "StudyAeDetail", + component: AeDetail, + meta: { title: "AE详情", requiresStudy: true }, + }, { path: "study/data-queries", name: "StudyDataQueries", component: DataQueries, meta: { title: "数据问题", requiresStudy: true }, }, + { + path: "study/issues", + name: "StudyIssues", + component: Issues, + meta: { title: "风险/问题", requiresStudy: true }, + }, + { + path: "study/issues/:issueId", + name: "StudyIssueDetail", + component: IssueDetail, + meta: { title: "风险详情", requiresStudy: true }, + }, { path: "study/imp", name: "StudyImp", diff --git a/frontend/src/views/Aes.vue b/frontend/src/views/Aes.vue index e3d5aea3..1a3f03ae 100644 --- a/frontend/src/views/Aes.vue +++ b/frontend/src/views/Aes.vue @@ -1,13 +1,159 @@ - + diff --git a/frontend/src/views/IssueDetail.vue b/frontend/src/views/IssueDetail.vue new file mode 100644 index 00000000..ad8303eb --- /dev/null +++ b/frontend/src/views/IssueDetail.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/frontend/src/views/Issues.vue b/frontend/src/views/Issues.vue new file mode 100644 index 00000000..69085472 --- /dev/null +++ b/frontend/src/views/Issues.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/pg_data/base/16384/24576 b/pg_data/base/16384/24576 index 8cbdcf86..df72e97b 100644 Binary files a/pg_data/base/16384/24576 and b/pg_data/base/16384/24576 differ diff --git a/pg_data/base/16384/24584 b/pg_data/base/16384/24584 index caa95a55..061d791e 100644 Binary files a/pg_data/base/16384/24584 and b/pg_data/base/16384/24584 differ diff --git a/pg_data/base/16384/24598 b/pg_data/base/16384/24598 index 61c800e1..d1f369e5 100644 Binary files a/pg_data/base/16384/24598 and b/pg_data/base/16384/24598 differ diff --git a/pg_data/base/16384/24633 b/pg_data/base/16384/24633 index 94cb4a14..d4f6211a 100644 Binary files a/pg_data/base/16384/24633 and b/pg_data/base/16384/24633 differ diff --git a/pg_data/base/16384/24640 b/pg_data/base/16384/24640 index b1cc3bcd..028948af 100644 Binary files a/pg_data/base/16384/24640 and b/pg_data/base/16384/24640 differ diff --git a/pg_data/base/16384/24652 b/pg_data/base/16384/24652 index 79071179..adfb0635 100644 Binary files a/pg_data/base/16384/24652 and b/pg_data/base/16384/24652 differ diff --git a/pg_data/base/16384/24672 b/pg_data/base/16384/24672 index d1e43ed7..008cb3ae 100644 Binary files a/pg_data/base/16384/24672 and b/pg_data/base/16384/24672 differ diff --git a/pg_data/base/16384/24678 b/pg_data/base/16384/24678 index 531f00d8..dd24da86 100644 Binary files a/pg_data/base/16384/24678 and b/pg_data/base/16384/24678 differ diff --git a/pg_data/base/16384/24740 b/pg_data/base/16384/24740 index b374bb71..0b9e430a 100644 Binary files a/pg_data/base/16384/24740 and b/pg_data/base/16384/24740 differ diff --git a/pg_data/base/16384/24747 b/pg_data/base/16384/24747 index fef49cf5..a2f7caf6 100644 Binary files a/pg_data/base/16384/24747 and b/pg_data/base/16384/24747 differ diff --git a/pg_data/base/16384/24749 b/pg_data/base/16384/24749 index 28259868..ec51db91 100644 Binary files a/pg_data/base/16384/24749 and b/pg_data/base/16384/24749 differ diff --git a/pg_data/base/16384/24761 b/pg_data/base/16384/24761 index 4ae3413b..1c51e3d0 100644 Binary files a/pg_data/base/16384/24761 and b/pg_data/base/16384/24761 differ diff --git a/pg_data/base/16384/24762 b/pg_data/base/16384/24762 index e6e6fe89..437e3145 100644 Binary files a/pg_data/base/16384/24762 and b/pg_data/base/16384/24762 differ diff --git a/pg_data/base/16384/24763 b/pg_data/base/16384/24763 index 308c7851..e3acf9e5 100644 Binary files a/pg_data/base/16384/24763 and b/pg_data/base/16384/24763 differ diff --git a/pg_data/base/16384/24770 b/pg_data/base/16384/24770 index 4673ca14..fb8bac77 100644 Binary files a/pg_data/base/16384/24770 and b/pg_data/base/16384/24770 differ diff --git a/pg_data/base/16384/24782 b/pg_data/base/16384/24782 index cea27979..310a5413 100644 Binary files a/pg_data/base/16384/24782 and b/pg_data/base/16384/24782 differ diff --git a/pg_data/base/16384/24783 b/pg_data/base/16384/24783 index e88fc022..6693ed10 100644 Binary files a/pg_data/base/16384/24783 and b/pg_data/base/16384/24783 differ diff --git a/pg_data/base/16384/24790 b/pg_data/base/16384/24790 index cf4ef2b7..22a107e5 100644 Binary files a/pg_data/base/16384/24790 and b/pg_data/base/16384/24790 differ diff --git a/pg_data/base/16384/24812 b/pg_data/base/16384/24812 index 8d24aa6b..fa1a3ae5 100644 Binary files a/pg_data/base/16384/24812 and b/pg_data/base/16384/24812 differ diff --git a/pg_data/base/16384/24813 b/pg_data/base/16384/24813 index e4dd5398..3adfa256 100644 Binary files a/pg_data/base/16384/24813 and b/pg_data/base/16384/24813 differ diff --git a/pg_data/base/16384/24814 b/pg_data/base/16384/24814 index a5918683..5da7b5be 100644 Binary files a/pg_data/base/16384/24814 and b/pg_data/base/16384/24814 differ diff --git a/pg_data/base/16384/24815 b/pg_data/base/16384/24815 index cd11be4a..9db191ca 100644 Binary files a/pg_data/base/16384/24815 and b/pg_data/base/16384/24815 differ diff --git a/pg_data/base/16384/24822 b/pg_data/base/16384/24822 index 98785b02..96e19cb2 100644 Binary files a/pg_data/base/16384/24822 and b/pg_data/base/16384/24822 differ diff --git a/pg_data/base/16384/24849 b/pg_data/base/16384/24849 index 248d9664..223ed55d 100644 Binary files a/pg_data/base/16384/24849 and b/pg_data/base/16384/24849 differ diff --git a/pg_data/base/16384/24850 b/pg_data/base/16384/24850 index 164d4297..65d76241 100644 Binary files a/pg_data/base/16384/24850 and b/pg_data/base/16384/24850 differ diff --git a/pg_data/base/16384/24851 b/pg_data/base/16384/24851 index 13ed4cea..3c8c02ed 100644 Binary files a/pg_data/base/16384/24851 and b/pg_data/base/16384/24851 differ diff --git a/pg_data/global/pg_control b/pg_data/global/pg_control index 23cf0730..d0a17a2c 100644 Binary files a/pg_data/global/pg_control and b/pg_data/global/pg_control differ diff --git a/pg_data/pg_wal/000000010000000000000001 b/pg_data/pg_wal/000000010000000000000001 index 17970046..bb30d23c 100644 Binary files a/pg_data/pg_wal/000000010000000000000001 and b/pg_data/pg_wal/000000010000000000000001 differ diff --git a/pg_data/pg_xact/0000 b/pg_data/pg_xact/0000 index 1bc456bd..da7ed3d9 100644 Binary files a/pg_data/pg_xact/0000 and b/pg_data/pg_xact/0000 differ