From 4f3576905628626887d6e4fe084cf2c109271db3 Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Tue, 16 Dec 2025 21:13:18 +0800 Subject: [PATCH] =?UTF-8?q?Step=20F4=EF=BC=9A=E4=BB=BB=E5=8A=A1=EF=BC=88Ta?= =?UTF-8?q?sk=EF=BC=89&=20=E9=87=8C=E7=A8=8B=E7=A2=91=EF=BC=88Milestone?= =?UTF-8?q?=EF=BC=89=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++++ frontend/src/api/milestones.ts | 11 ++ frontend/src/api/tasks.ts | 11 ++ frontend/src/components/Layout.vue | 2 + frontend/src/components/MilestoneForm.vue | 129 ++++++++++++++++++++++ frontend/src/router/index.ts | 7 ++ frontend/src/views/Milestones.vue | 88 +++++++++++++++ frontend/src/views/StudyHome.vue | 6 +- pg_data/base/16384/1259 | Bin 139264 -> 139264 bytes pg_data/base/16384/24576 | Bin 8192 -> 8192 bytes pg_data/base/16384/24584 | Bin 8192 -> 8192 bytes pg_data/base/16384/24672 | Bin 16384 -> 16384 bytes pg_data/base/16384/24678 | Bin 16384 -> 16384 bytes pg_data/base/16384/24690 | Bin 8192 -> 8192 bytes pg_data/base/16384/24697 | Bin 16384 -> 16384 bytes pg_data/base/16384/24709 | Bin 16384 -> 16384 bytes pg_data/base/16384/24710 | Bin 8192 -> 8192 bytes pg_data/base/16384/24717 | Bin 16384 -> 16384 bytes pg_data/base/16384/24739 | Bin 16384 -> 16384 bytes pg_data/base/16384/2619 | Bin 212992 -> 212992 bytes pg_data/base/16384/2619_fsm | Bin 24576 -> 24576 bytes pg_data/base/16384/2619_vm | Bin 8192 -> 8192 bytes pg_data/base/16384/2696 | Bin 40960 -> 40960 bytes pg_data/global/pg_control | Bin 8192 -> 8192 bytes pg_data/pg_wal/000000010000000000000001 | Bin 16777216 -> 16777216 bytes pg_data/pg_xact/0000 | Bin 8192 -> 8192 bytes 26 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 frontend/src/api/milestones.ts create mode 100644 frontend/src/api/tasks.ts create mode 100644 frontend/src/components/MilestoneForm.vue create mode 100644 frontend/src/views/Milestones.vue diff --git a/README.md b/README.md new file mode 100644 index 00000000..74fce66c --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# CTMS 项目快速上手 + +## 账号 +- 管理员:`admin / admin123`(默认存在,用于创建项目、成员、FAQ 等) +- 示例 PM:`pm_faq / pm123456`(可作为项目 PM 登录) +- 示例 CRA:`cra_faq / cra123456`(只读成员) + +> 若找不到示例用户,可用管理员在 `/api/v1/users` 创建,或在 UI 的登录页使用管理员登录后到“项目列表”添加成员。 + +## 访问方式 +- 前端:`http://localhost`(Nginx 反代到 Vite 开发容器) +- 后端 API:同域 `/api/v1/*`(已在前端代理) + +## 常用流程 +1. 用 `admin / admin123` 登录前端。 +2. 在“项目列表”进入一个项目或新建项目后进入。 +3. Dashboard 查看进度、待办;左侧导航进入“里程碑”“任务”等页面。 +4. 退出登录或切换项目可通过顶部右侧下拉。 + +## 注意 +- 令牌与当前项目上下文保存在浏览器 LocalStorage 中,清除后需重新登录/选择项目。 +- 若后端重启,确认数据库容器仍健康,前端会弹出错误提示。 diff --git a/frontend/src/api/milestones.ts b/frontend/src/api/milestones.ts new file mode 100644 index 00000000..4a03f8ed --- /dev/null +++ b/frontend/src/api/milestones.ts @@ -0,0 +1,11 @@ +import { apiGet, apiPost, apiPatch } from "./axios"; +import type { ApiListResponse } from "../types/api"; + +export const fetchMilestones = (studyId: string) => + apiGet>(`/api/v1/studies/${studyId}/milestones/`); + +export const createMilestone = (studyId: string, payload: Record) => + apiPost(`/api/v1/studies/${studyId}/milestones/`, payload); + +export const updateMilestone = (studyId: string, milestoneId: string, payload: Record) => + apiPatch(`/api/v1/studies/${studyId}/milestones/${milestoneId}`, payload); diff --git a/frontend/src/api/tasks.ts b/frontend/src/api/tasks.ts new file mode 100644 index 00000000..ef493618 --- /dev/null +++ b/frontend/src/api/tasks.ts @@ -0,0 +1,11 @@ +import { apiGet, apiPost, apiPatch } from "./axios"; +import type { ApiListResponse } from "../types/api"; + +export const fetchTasks = (studyId: string, params?: Record) => + apiGet>(`/api/v1/studies/${studyId}/tasks/`, { params }); + +export const createTask = (studyId: string, payload: Record) => + apiPost(`/api/v1/studies/${studyId}/tasks/`, payload); + +export const updateTask = (studyId: string, taskId: string, payload: Record) => + apiPatch(`/api/v1/studies/${studyId}/tasks/${taskId}`, payload); diff --git a/frontend/src/components/Layout.vue b/frontend/src/components/Layout.vue index 67bfc64e..bb9a73de 100644 --- a/frontend/src/components/Layout.vue +++ b/frontend/src/components/Layout.vue @@ -17,6 +17,8 @@ 首页 项目首页 + 里程碑 + 任务 diff --git a/frontend/src/components/MilestoneForm.vue b/frontend/src/components/MilestoneForm.vue new file mode 100644 index 00000000..c868176c --- /dev/null +++ b/frontend/src/components/MilestoneForm.vue @@ -0,0 +1,129 @@ + + + diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index dbb5d3ae..96e4f5f8 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -7,6 +7,7 @@ import Login from "../views/Login.vue"; import StudyList from "../views/StudyList.vue"; import StudyHome from "../views/StudyHome.vue"; import Tasks from "../views/Tasks.vue"; +import Milestones from "../views/Milestones.vue"; import Subjects from "../views/Subjects.vue"; import Aes from "../views/Aes.vue"; import DataQueries from "../views/DataQueries.vue"; @@ -44,6 +45,12 @@ const routes: RouteRecordRaw[] = [ component: Tasks, meta: { title: "任务", requiresStudy: true }, }, + { + path: "study/milestones", + name: "StudyMilestones", + component: Milestones, + meta: { title: "里程碑", requiresStudy: true }, + }, { path: "study/subjects", name: "StudySubjects", diff --git a/frontend/src/views/Milestones.vue b/frontend/src/views/Milestones.vue new file mode 100644 index 00000000..f68eeff9 --- /dev/null +++ b/frontend/src/views/Milestones.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/frontend/src/views/StudyHome.vue b/frontend/src/views/StudyHome.vue index 455bd9fd..abc37349 100644 --- a/frontend/src/views/StudyHome.vue +++ b/frontend/src/views/StudyHome.vue @@ -52,6 +52,7 @@