参与者管理- PD模块内容补充

This commit is contained in:
Cheng Zhou
2026-02-28 14:33:57 +08:00
parent af0c1b4b7d
commit 9b36a42e6f
14 changed files with 855 additions and 35 deletions
+27 -28
View File
@@ -4,7 +4,7 @@
<div class="filter-container unified-action-bar">
<el-form :inline="true" class="filter-form">
<el-form-item class="filter-item-form">
<el-input v-model="filters.keyword" :placeholder="TEXT.modules.subjectManagement.screeningNo" clearable class="filter-input-comp">
<el-input v-model="filters.keyword" :placeholder="TEXT.common.fields.keyword" clearable class="filter-input-comp">
<template #prefix>
<el-icon><Search /></el-icon>
</template>
@@ -34,29 +34,20 @@
</el-form>
</div>
<div class="unified-section table-section">
<el-table :data="filteredItems" v-loading="loading" style="width: 100%">
<el-table-column prop="subject_no" :label="TEXT.modules.subjectManagement.screeningNo" min-width="160" />
<el-table-column :label="TEXT.common.fields.site" min-width="160">
<el-table :data="filteredItems" v-loading="loading" style="width: 100%" table-layout="fixed">
<el-table-column prop="pd_no" :label="TEXT.common.fields.pdNo" min-width="160" show-overflow-tooltip />
<el-table-column prop="subject_no" :label="TEXT.modules.subjectManagement.screeningNo" min-width="160" show-overflow-tooltip />
<el-table-column :label="TEXT.common.fields.site" min-width="160" show-overflow-tooltip>
<template #default="scope">{{ siteMap[scope.row.site_id] || TEXT.common.fallback }}</template>
</el-table-column>
<el-table-column prop="status" :label="TEXT.common.fields.status" width="120">
<template #default="scope">{{ displayEnum(TEXT.enums.subjectStatus, scope.row.status) }}</template>
<el-table-column prop="status" :label="TEXT.common.fields.status" min-width="160">
<template #default="scope">{{ displayEnum(TEXT.enums.pdStatus, scope.row.status) }}</template>
</el-table-column>
<el-table-column prop="enrollment_date" :label="TEXT.common.fields.enrollmentDate" width="140">
<template #default="scope">{{ displayDate(scope.row.enrollment_date) }}</template>
</el-table-column>
<el-table-column prop="updated_at" :label="TEXT.common.labels.updatedAt" min-width="180">
<template #default="scope">{{ displayDate(scope.row.updated_at) }}</template>
</el-table-column>
<el-table-column :label="TEXT.modules.riskIssuePd.syncStatus" width="120">
<template #default>
<el-tag size="small" type="success" effect="plain">{{ TEXT.modules.riskIssuePd.synced }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="TEXT.common.labels.actions" width="120">
<el-table-column prop="description" :label="TEXT.common.fields.pdDescription" min-width="160" show-overflow-tooltip />
<el-table-column :label="TEXT.common.labels.actions" min-width="160" align="center">
<template #default="scope">
<el-button link type="primary" size="small" @click="goSubject(scope.row.id)">
{{ TEXT.modules.riskIssuePd.toSubject }}
<el-button link type="primary" size="small" @click="goSubject(scope.row.subject_id)">
{{ TEXT.common.actions.view }}
</el-button>
</template>
</el-table-column>
@@ -73,9 +64,9 @@ import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { CircleCheck, Location, Search } from "@element-plus/icons-vue";
import { useStudyStore } from "../../store/study";
import { fetchSubjects } from "../../api/subjects";
import { listStudySubjectPds } from "../../api/subjectPds";
import { fetchSites } from "../../api/sites";
import { displayDate, displayEnum } from "../../utils/display";
import { displayEnum } from "../../utils/display";
import StateEmpty from "../../components/StateEmpty.vue";
import { TEXT } from "../../locales";
@@ -91,7 +82,7 @@ const filters = ref({
status: "",
});
const statusOptions = Object.entries(TEXT.enums.subjectStatus).map(([value, label]) => ({ value, label }));
const statusOptions = Object.entries(TEXT.enums.pdStatus).map(([value, label]) => ({ value, label }));
const resetFilters = () => {
filters.value.keyword = "";
@@ -120,10 +111,16 @@ const load = async () => {
loading.value = true;
try {
await loadSites(studyId);
const { data } = await fetchSubjects(studyId);
items.value = (Array.isArray(data) ? data : data.items || []).sort((a: any, b: any) =>
String(b.updated_at || "").localeCompare(String(a.updated_at || ""))
);
const { data } = await listStudySubjectPds(studyId);
const list = Array.isArray(data) ? data : data.items || [];
const getPdSeq = (pdNo: string) => {
const text = String(pdNo || "");
const matched = text.match(/^PD(\d+)$/i);
if (!matched) return Number.POSITIVE_INFINITY;
const num = Number(matched[1]);
return Number.isFinite(num) ? num : Number.POSITIVE_INFINITY;
};
items.value = list.sort((a: any, b: any) => getPdSeq(a?.pd_no) - getPdSeq(b?.pd_no));
} catch (e: any) {
ElMessage.error(e?.response?.data?.message || TEXT.common.messages.loadFailed);
} finally {
@@ -134,8 +131,10 @@ const load = async () => {
const filteredItems = computed(() => {
const keyword = filters.value.keyword.trim().toLowerCase();
return items.value.filter((item) => {
const pdNo = String(item?.pd_no || "").toLowerCase();
const subjectNo = String(item?.subject_no || "").toLowerCase();
if (keyword && !subjectNo.includes(keyword)) return false;
const description = String(item?.description || "").toLowerCase();
if (keyword && !pdNo.includes(keyword) && !subjectNo.includes(keyword) && !description.includes(keyword)) return false;
if (filters.value.siteId && item?.site_id !== filters.value.siteId) return false;
if (filters.value.status && item?.status !== filters.value.status) return false;
return true;