简单汉化
This commit is contained in:
Generated
+1722
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
|
"date-fns": "^3.6.0",
|
||||||
"element-plus": "^2.4.4",
|
"element-plus": "^2.4.4",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"vue": "^3.4.15",
|
"vue": "^3.4.15",
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="严重性" prop="seriousness">
|
<el-form-item label="严重性" prop="seriousness">
|
||||||
<el-select v-model="form.seriousness" placeholder="请选择">
|
<el-select v-model="form.seriousness" placeholder="请选择">
|
||||||
<el-option label="SERIOUS" value="SERIOUS" />
|
<el-option label="SERIOUS(重)" value="SERIOUS" />
|
||||||
<el-option label="NON_SERIOUS" value="NON_SERIOUS" />
|
<el-option label="NON_SERIOUS(非重)" value="NON_SERIOUS" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="严重程度" prop="severity">
|
<el-form-item label="严重程度" prop="severity">
|
||||||
<el-select v-model="form.severity" placeholder="请选择">
|
<el-select v-model="form.severity" placeholder="请选择">
|
||||||
<el-option v-for="s in severities" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in severities" :key="s" :label="severityLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="描述" prop="description">
|
<el-form-item label="描述" prop="description">
|
||||||
@@ -57,6 +57,14 @@ const submitting = ref(false);
|
|||||||
const study = useStudyStore();
|
const study = useStudyStore();
|
||||||
|
|
||||||
const severities = ["G1", "G2", "G3", "G4", "G5"];
|
const severities = ["G1", "G2", "G3", "G4", "G5"];
|
||||||
|
const severityLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
G1: "G1(轻)",
|
||||||
|
G2: "G2(中)",
|
||||||
|
G3: "G3(重)",
|
||||||
|
G4: "G4(危重)",
|
||||||
|
G5: "G5(致死)",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
subject_id: "",
|
subject_id: "",
|
||||||
|
|||||||
@@ -9,17 +9,17 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="类别" prop="category">
|
<el-form-item label="类别" prop="category">
|
||||||
<el-select v-model="form.category" placeholder="请选择">
|
<el-select v-model="form.category" placeholder="请选择">
|
||||||
<el-option label="MISSING" value="MISSING" />
|
<el-option label="缺失(MISSING)" value="MISSING" />
|
||||||
<el-option label="INCONSISTENT" value="INCONSISTENT" />
|
<el-option label="不一致(INCONSISTENT)" value="INCONSISTENT" />
|
||||||
<el-option label="OUT_OF_RANGE" value="OUT_OF_RANGE" />
|
<el-option label="超范围(OUT_OF_RANGE)" value="OUT_OF_RANGE" />
|
||||||
<el-option label="OTHER" value="OTHER" />
|
<el-option label="其他(OTHER)" value="OTHER" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="优先级" prop="priority">
|
<el-form-item label="优先级" prop="priority">
|
||||||
<el-select v-model="form.priority" placeholder="请选择">
|
<el-select v-model="form.priority" placeholder="请选择">
|
||||||
<el-option label="LOW" value="LOW" />
|
<el-option label="低" value="LOW" />
|
||||||
<el-option label="MEDIUM" value="MEDIUM" />
|
<el-option label="中" value="MEDIUM" />
|
||||||
<el-option label="HIGH" value="HIGH" />
|
<el-option label="高" value="HIGH" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="指派给" prop="assigned_to">
|
<el-form-item label="指派给" prop="assigned_to">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="类别" prop="category">
|
<el-form-item label="类别" prop="category">
|
||||||
<el-select v-model="form.category" placeholder="请选择">
|
<el-select v-model="form.category" placeholder="请选择">
|
||||||
<el-option v-for="c in categories" :key="c" :label="c" :value="c" />
|
<el-option v-for="c in categories" :key="c" :label="categoryLabel(c)" :value="c" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题" prop="title">
|
<el-form-item label="标题" prop="title">
|
||||||
@@ -51,6 +51,13 @@ const formRef = ref<FormInstance>();
|
|||||||
const submitting = ref(false);
|
const submitting = ref(false);
|
||||||
|
|
||||||
const categories = ["SITE_FEE", "SUBJECT_STIPEND", "TRAVEL", "OTHER"];
|
const categories = ["SITE_FEE", "SUBJECT_STIPEND", "TRAVEL", "OTHER"];
|
||||||
|
const categoryLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
SITE_FEE: "中心费用",
|
||||||
|
SUBJECT_STIPEND: "受试者补贴",
|
||||||
|
TRAVEL: "差旅",
|
||||||
|
OTHER: "其他",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
category: "SITE_FEE",
|
category: "SITE_FEE",
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const change = async (status: string, reject_reason?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const reject = async () => {
|
const reject = async () => {
|
||||||
const reason = await ElMessageBox.prompt("请输入驳回原因", "驳回", {
|
const reason = await ElMessageBox.prompt("请输入驳回原因", "驳回审批", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
}).catch(() => null);
|
}).catch(() => null);
|
||||||
|
|||||||
@@ -16,11 +16,13 @@
|
|||||||
<el-date-picker v-model="form.manufacture_date" type="date" value-format="YYYY-MM-DD" />
|
<el-date-picker v-model="form.manufacture_date" type="date" value-format="YYYY-MM-DD" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态">
|
<el-form-item label="状态">
|
||||||
<el-select v-model="form.status">
|
<el-select v-model="form.status" placeholder="请选择状态">
|
||||||
<el-option label="ACTIVE" value="ACTIVE" />
|
<el-option
|
||||||
<el-option label="QUARANTINED" value="QUARANTINED" />
|
v-for="s in statusOptions"
|
||||||
<el-option label="EXPIRED" value="EXPIRED" />
|
:key="s"
|
||||||
<el-option label="CLOSED" value="CLOSED" />
|
:label="`${statusLabel(s)}(${s})`"
|
||||||
|
:value="s"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -44,6 +46,8 @@ const study = useStudyStore();
|
|||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const submitting = ref(false);
|
const submitting = ref(false);
|
||||||
|
|
||||||
|
const statusOptions = ["ACTIVE", "QUARANTINED", "EXPIRED", "CLOSED"];
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
product_id: "",
|
product_id: "",
|
||||||
batch_no: "",
|
batch_no: "",
|
||||||
@@ -115,4 +119,7 @@ const onSubmit = async () => {
|
|||||||
submitting.value = false;
|
submitting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({ ACTIVE: "在库", QUARANTINED: "隔离", EXPIRED: "过期", CLOSED: "关闭" }[v] || v);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -10,8 +10,13 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="交易类型" prop="tx_type">
|
<el-form-item label="交易类型" prop="tx_type">
|
||||||
<el-select v-model="form.tx_type">
|
<el-select v-model="form.tx_type" placeholder="请选择类型">
|
||||||
<el-option v-for="t in txTypes" :key="t" :label="t" :value="t" />
|
<el-option
|
||||||
|
v-for="t in txTypes"
|
||||||
|
:key="t"
|
||||||
|
:label="`${txTypeLabel(t)}(${t})`"
|
||||||
|
:value="t"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="数量" prop="quantity">
|
<el-form-item label="数量" prop="quantity">
|
||||||
@@ -21,7 +26,7 @@
|
|||||||
<SubjectSelect
|
<SubjectSelect
|
||||||
v-model="form.subject_id"
|
v-model="form.subject_id"
|
||||||
:study-id="study.currentStudy?.id || null"
|
:study-id="study.currentStudy?.id || null"
|
||||||
placeholder="DISPENSE 时必填"
|
placeholder="发放时必填"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="日期" prop="tx_date">
|
<el-form-item label="日期" prop="tx_date">
|
||||||
@@ -70,7 +75,7 @@ const form = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
site_id: [{ required: true, message: "请输入中心ID", trigger: "blur" }],
|
site_id: [{ required: true, message: "请选择中心", trigger: "change" }],
|
||||||
batch_id: [{ required: true, message: "请选择批次", trigger: "change" }],
|
batch_id: [{ required: true, message: "请选择批次", trigger: "change" }],
|
||||||
tx_type: [{ required: true, message: "请选择类型", trigger: "change" }],
|
tx_type: [{ required: true, message: "请选择类型", trigger: "change" }],
|
||||||
quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
|
quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
|
||||||
@@ -92,7 +97,7 @@ const onSubmit = async () => {
|
|||||||
if (!study.currentStudy || !formRef.value) return;
|
if (!study.currentStudy || !formRef.value) return;
|
||||||
await formRef.value.validate();
|
await formRef.value.validate();
|
||||||
if (form.tx_type === "DISPENSE" && !form.subject_id) {
|
if (form.tx_type === "DISPENSE" && !form.subject_id) {
|
||||||
ElMessage.error("DISPENSE 时受试者必填");
|
ElMessage.error("发放时受试者必填");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
submitting.value = true;
|
submitting.value = true;
|
||||||
@@ -112,4 +117,14 @@ const onSubmit = async () => {
|
|||||||
submitting.value = false;
|
submitting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const txTypeLabel = (t: string) =>
|
||||||
|
({
|
||||||
|
RECEIPT: "入库",
|
||||||
|
DISPENSE: "发放",
|
||||||
|
RETURN: "回收",
|
||||||
|
DESTROY: "销毁",
|
||||||
|
TRANSFER_IN: "调入",
|
||||||
|
TRANSFER_OUT: "调出",
|
||||||
|
}[t] || t);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="类别" prop="category">
|
<el-form-item label="类别" prop="category">
|
||||||
<el-select v-model="form.category" placeholder="请选择">
|
<el-select v-model="form.category" placeholder="请选择">
|
||||||
<el-option v-for="c in categories" :key="c" :label="c" :value="c" />
|
<el-option v-for="c in categories" :key="c" :label="categoryLabel(c)" :value="c" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="等级" prop="level">
|
<el-form-item label="等级" prop="level">
|
||||||
<el-select v-model="form.level" placeholder="请选择">
|
<el-select v-model="form.level" placeholder="请选择">
|
||||||
<el-option v-for="l in levels" :key="l" :label="l" :value="l" />
|
<el-option v-for="l in levels" :key="l" :label="levelLabel(l)" :value="l" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="截止日期" prop="due_date">
|
<el-form-item label="截止日期" prop="due_date">
|
||||||
@@ -132,4 +132,19 @@ const onSubmit = async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const categoryLabel = (c: string) =>
|
||||||
|
({
|
||||||
|
RISK: "风险",
|
||||||
|
ISSUE: "问题",
|
||||||
|
PROTOCOL_DEVIATION: "方案偏差",
|
||||||
|
}[c] || c);
|
||||||
|
|
||||||
|
const levelLabel = (l: string) =>
|
||||||
|
({
|
||||||
|
LOW: "低",
|
||||||
|
MEDIUM: "中",
|
||||||
|
HIGH: "高",
|
||||||
|
CRITICAL: "关键",
|
||||||
|
}[l] || l);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
<el-aside width="200px" class="aside" v-if="study.currentStudy">
|
<el-aside width="200px" class="aside" v-if="study.currentStudy">
|
||||||
<el-menu router :default-active="$route.path">
|
<el-menu router :default-active="$route.path">
|
||||||
<el-menu-item index="/home">首页</el-menu-item>
|
<el-menu-item index="/home">首页</el-menu-item>
|
||||||
<el-menu-item index="/study/home">项目首页</el-menu-item>
|
<el-menu-item index="/study/home">项目概览</el-menu-item>
|
||||||
<el-menu-item index="/study/milestones">里程碑</el-menu-item>
|
<el-menu-item index="/study/milestones">伦理与启动管理</el-menu-item>
|
||||||
<el-menu-item index="/study/tasks">任务</el-menu-item>
|
<el-menu-item index="/study/tasks">任务</el-menu-item>
|
||||||
<el-menu-item index="/study/subjects">受试者</el-menu-item>
|
<el-menu-item index="/study/subjects">受试者</el-menu-item>
|
||||||
<el-menu-item index="/study/aes">AE</el-menu-item>
|
<el-menu-item index="/study/aes">不良事件</el-menu-item>
|
||||||
<el-menu-item index="/study/issues">风险/问题</el-menu-item>
|
<el-menu-item index="/study/issues">风险与问题</el-menu-item>
|
||||||
<el-menu-item index="/study/data-queries">数据问题</el-menu-item>
|
<el-menu-item index="/study/data-queries">数据问题</el-menu-item>
|
||||||
<el-menu-item index="/study/verifications">SDV/SDR</el-menu-item>
|
<el-menu-item index="/study/verifications">数据核查</el-menu-item>
|
||||||
<el-sub-menu index="imp">
|
<el-sub-menu index="imp">
|
||||||
<template #title>药品</template>
|
<template #title>药品</template>
|
||||||
<el-menu-item index="/study/imp/inventory">库存</el-menu-item>
|
<el-menu-item index="/study/imp/inventory">库存</el-menu-item>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<el-menu-item index="/study/imp/transactions">交易台账</el-menu-item>
|
<el-menu-item index="/study/imp/transactions">交易台账</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-menu-item index="/study/finance">费用</el-menu-item>
|
<el-menu-item index="/study/finance">费用</el-menu-item>
|
||||||
<el-menu-item index="/study/faq">FAQ</el-menu-item>
|
<el-menu-item index="/study/faq">知识库</el-menu-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
<el-main>
|
<el-main>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
<el-checkbox v-model="keepCreating" class="mr-8">提交后继续新建</el-checkbox>
|
||||||
<el-button @click="onClose">取消</el-button>
|
<el-button @click="onClose">取消</el-button>
|
||||||
<el-button type="primary" :loading="submitting" @click="onSubmit">提交</el-button>
|
<el-button type="primary" :loading="submitting" @click="onSubmit">提交</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, reactive, ref } from "vue";
|
import { computed, reactive, ref } from "vue";
|
||||||
|
import { format } from "date-fns";
|
||||||
import type { FormInstance, FormRules } from "element-plus";
|
import type { FormInstance, FormRules } from "element-plus";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { createSubject } from "../api/subjects";
|
import { createSubject } from "../api/subjects";
|
||||||
@@ -49,6 +51,7 @@ const form = reactive({
|
|||||||
subject_no: "",
|
subject_no: "",
|
||||||
screening_date: "",
|
screening_date: "",
|
||||||
});
|
});
|
||||||
|
const keepCreating = ref(false);
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
site_id: [{ required: true, message: "请选择中心", trigger: "change" }],
|
site_id: [{ required: true, message: "请选择中心", trigger: "change" }],
|
||||||
@@ -59,6 +62,15 @@ const onClose = () => {
|
|||||||
visible.value = false;
|
visible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
const studyId = study.currentStudy?.id;
|
||||||
|
const recentSite = studyId ? localStorage.getItem(`recent_site_${studyId}`) : null;
|
||||||
|
const recentSubject = studyId ? localStorage.getItem(`recent_subject_${studyId}`) : null;
|
||||||
|
form.site_id = recentSite || "";
|
||||||
|
form.subject_no = recentSubject || "";
|
||||||
|
form.screening_date = format(new Date(), "yyyy-MM-dd");
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
if (!formRef.value) return;
|
if (!formRef.value) return;
|
||||||
await formRef.value.validate(async (valid) => {
|
await formRef.value.validate(async (valid) => {
|
||||||
@@ -69,10 +81,18 @@ const onSubmit = async () => {
|
|||||||
}
|
}
|
||||||
submitting.value = true;
|
submitting.value = true;
|
||||||
try {
|
try {
|
||||||
await createSubject(study.currentStudy.id, { ...form });
|
const { data } = await createSubject(study.currentStudy.id, { ...form });
|
||||||
ElMessage.success("提交成功");
|
ElMessage.success("提交成功");
|
||||||
|
if (study.currentStudy?.id) {
|
||||||
|
localStorage.setItem(`recent_site_${study.currentStudy.id}`, form.site_id || "");
|
||||||
|
if (data?.id) localStorage.setItem(`recent_subject_${study.currentStudy.id}`, data.id);
|
||||||
|
}
|
||||||
emit("success");
|
emit("success");
|
||||||
onClose();
|
if (keepCreating.value) {
|
||||||
|
resetForm();
|
||||||
|
} else {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
ElMessage.error(e?.response?.data?.message || "提交失败");
|
ElMessage.error(e?.response?.data?.message || "提交失败");
|
||||||
} finally {
|
} finally {
|
||||||
@@ -80,4 +100,6 @@ const onSubmit = async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
resetForm();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="优先级" prop="priority">
|
<el-form-item label="优先级" prop="priority">
|
||||||
<el-select v-model="form.priority" placeholder="请选择">
|
<el-select v-model="form.priority" placeholder="请选择">
|
||||||
<el-option v-for="p in priorities" :key="p" :label="p" :value="p" />
|
<el-option v-for="p in priorities" :key="p" :label="priorityLabel(p)" :value="p" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="截止日期" prop="due_date">
|
<el-form-item label="截止日期" prop="due_date">
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-select v-model="form.status" placeholder="请选择">
|
<el-select v-model="form.status" placeholder="请选择">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -62,6 +62,14 @@ const visible = computed({
|
|||||||
|
|
||||||
const priorities = ["LOW", "MEDIUM", "HIGH"];
|
const priorities = ["LOW", "MEDIUM", "HIGH"];
|
||||||
const statuses = ["TODO", "DOING", "DONE", "BLOCKED"];
|
const statuses = ["TODO", "DOING", "DONE", "BLOCKED"];
|
||||||
|
const priorityLabel = (v: string) => ({ LOW: "低", MEDIUM: "中", HIGH: "高" }[v] || v);
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
TODO: "待处理",
|
||||||
|
DOING: "进行中",
|
||||||
|
DONE: "已完成",
|
||||||
|
BLOCKED: "阻塞",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
title: "",
|
title: "",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div>
|
<div>
|
||||||
<h3>AE 详情</h3>
|
<h3>AE(不良事件)</h3>
|
||||||
<p>{{ ae.term }}</p>
|
<p>{{ ae.term }}</p>
|
||||||
</div>
|
</div>
|
||||||
<PermissionAction action="ae.close">
|
<PermissionAction action="ae.close">
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<el-descriptions-item label="严重性">{{ ae.seriousness }}</el-descriptions-item>
|
<el-descriptions-item label="严重性">{{ ae.seriousness }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="严重程度">{{ ae.severity }}</el-descriptions-item>
|
<el-descriptions-item label="严重程度">{{ ae.severity }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="发生日期">{{ ae.onset_date }}</el-descriptions-item>
|
<el-descriptions-item label="发生日期">{{ ae.onset_date }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="状态">{{ ae.status }}</el-descriptions-item>
|
<el-descriptions-item label="状态">{{ statusLabel(ae.status) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="描述">{{ ae.description }}</el-descriptions-item>
|
<el-descriptions-item label="描述">{{ ae.description }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -88,7 +88,7 @@ const toggleClose = async () => {
|
|||||||
if (!study.currentStudy || !ae.value) return;
|
if (!study.currentStudy || !ae.value) return;
|
||||||
const targetStatus = ae.value.status === "CLOSED" ? "FOLLOW_UP" : "CLOSED";
|
const targetStatus = ae.value.status === "CLOSED" ? "FOLLOW_UP" : "CLOSED";
|
||||||
await ElMessageBox.confirm(
|
await ElMessageBox.confirm(
|
||||||
`确认将该 AE 状态设置为 ${targetStatus === "CLOSED" ? "CLOSED" : "FOLLOW_UP"}?`,
|
`确定将该 AE 状态设置为 ${targetStatus === "CLOSED" ? "已关闭" : "随访中"}?该操作不可撤销,请谨慎确认。`,
|
||||||
"提示"
|
"提示"
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
@@ -101,6 +101,13 @@ const toggleClose = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
NEW: "新增",
|
||||||
|
FOLLOW_UP: "随访中",
|
||||||
|
CLOSED: "已关闭",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user && auth.token) {
|
if (!auth.user && auth.token) {
|
||||||
await auth.fetchMe().catch(() => {});
|
await auth.fetchMe().catch(() => {});
|
||||||
|
|||||||
@@ -3,15 +3,14 @@
|
|||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadAes">
|
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadAes">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="filters.seriousness" placeholder="严重性" clearable @change="loadAes">
|
<el-select v-model="filters.seriousness" placeholder="严重性" clearable @change="loadAes">
|
||||||
<el-option label="SERIOUS" value="SERIOUS" />
|
<el-option v-for="s in seriousnessOptions" :key="s" :label="seriousnessLabel(s)" :value="s" />
|
||||||
<el-option label="NON_SERIOUS" value="NON_SERIOUS" />
|
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-switch v-model="filters.overdue" active-text="仅逾期" @change="loadAes" />
|
<el-switch v-model="filters.overdue" active-text="仅逾期" @change="loadAes" />
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<el-button type="primary" v-if="canCreate" @click="showForm = true">新建 AE</el-button>
|
<el-button type="primary" v-if="canCreate" @click="showForm = true">新建不良事件</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -23,12 +22,16 @@
|
|||||||
{{ subjectMap[scope.row.subject_id] || scope.row.subject_id || "-" }}
|
{{ subjectMap[scope.row.subject_id] || scope.row.subject_id || "-" }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="seriousness" label="严重性" width="140" />
|
<el-table-column prop="seriousness" label="严重性" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ seriousnessLabel(scope.row.seriousness) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="onset_date" label="发生日期" width="140" />
|
<el-table-column prop="onset_date" label="发生日期" width="140" />
|
||||||
<el-table-column prop="report_due_date" label="报告截止" width="140" />
|
<el-table-column prop="report_due_date" label="报告截止" width="140" />
|
||||||
<el-table-column prop="status" label="状态" width="120">
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag :type="scope.row.is_overdue ? 'danger' : 'info'">{{ scope.row.status }}</el-tag>
|
<el-tag :type="scope.row.is_overdue ? 'danger' : 'info'">{{ statusLabel(scope.row.status) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -74,6 +77,7 @@ const subjectMap = computed(() =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
const statuses = ["NEW", "FOLLOW_UP", "CLOSED"];
|
const statuses = ["NEW", "FOLLOW_UP", "CLOSED"];
|
||||||
|
const seriousnessOptions = ["SERIOUS", "NON_SERIOUS"];
|
||||||
|
|
||||||
const filters = ref({
|
const filters = ref({
|
||||||
status: "",
|
status: "",
|
||||||
@@ -138,6 +142,19 @@ const goDetail = (row: any) => {
|
|||||||
router.push(`/study/aes/${row.id}`);
|
router.push(`/study/aes/${row.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
NEW: "新增",
|
||||||
|
FOLLOW_UP: "随访中",
|
||||||
|
CLOSED: "已关闭",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
|
const seriousnessLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
SERIOUS: "严重",
|
||||||
|
NON_SERIOUS: "非严重",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user && auth.token) {
|
if (!auth.user && auth.token) {
|
||||||
await auth.fetchMe().catch(() => {});
|
await auth.fetchMe().catch(() => {});
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadQueries">
|
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadQueries">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-switch v-model="filters.overdue" active-text="仅逾期" @change="loadQueries" />
|
<el-switch v-model="filters.overdue" active-text="仅逾期" @change="loadQueries" />
|
||||||
<el-input v-model="filters.assigned_to" placeholder="指派人ID" style="width: 180px" @change="loadQueries" />
|
<el-input v-model="filters.assigned_to" placeholder="负责人" style="width: 180px" @change="loadQueries" />
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<el-button type="primary" v-if="canEdit" @click="showForm = true">新建 Query</el-button>
|
<el-button type="primary" v-if="canEdit" @click="showForm = true">新建数据问题</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -20,12 +20,20 @@
|
|||||||
{{ subjectMap[scope.row.subject_id] || scope.row.subject_id || "-" }}
|
{{ subjectMap[scope.row.subject_id] || scope.row.subject_id || "-" }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="category" label="类别" width="140" />
|
<el-table-column prop="category" label="类别" width="140">
|
||||||
<el-table-column prop="priority" label="优先级" width="120" />
|
<template #default="scope">
|
||||||
|
{{ categoryLabel(scope.row.category) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="priority" label="优先级" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ priorityLabel(scope.row.priority) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="due_date" label="截止日期" width="140" />
|
<el-table-column prop="due_date" label="截止日期" width="140" />
|
||||||
<el-table-column prop="status" label="状态" width="120">
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag :type="scope.row.is_overdue ? 'danger' : 'info'">{{ scope.row.status }}</el-tag>
|
<el-tag :type="scope.row.is_overdue ? 'danger' : 'info'">{{ statusLabel(scope.row.status) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -71,6 +79,8 @@ const subjectMap = computed(() =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
const statuses = ["OPEN", "IN_PROGRESS", "ANSWERED", "CLOSED"];
|
const statuses = ["OPEN", "IN_PROGRESS", "ANSWERED", "CLOSED"];
|
||||||
|
const categories = ["MISSING", "INCONSISTENT", "OUT_OF_RANGE", "OTHER"];
|
||||||
|
const priorities = ["LOW", "MEDIUM", "HIGH"];
|
||||||
|
|
||||||
const filters = ref({
|
const filters = ref({
|
||||||
status: "",
|
status: "",
|
||||||
@@ -124,6 +134,29 @@ const goDetail = (row: any) => {
|
|||||||
router.push(`/study/data-queries/${row.id}`);
|
router.push(`/study/data-queries/${row.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
OPEN: "待处理",
|
||||||
|
IN_PROGRESS: "处理中",
|
||||||
|
ANSWERED: "已回复",
|
||||||
|
CLOSED: "已关闭",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
|
const categoryLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
MISSING: "缺失",
|
||||||
|
INCONSISTENT: "不一致",
|
||||||
|
OUT_OF_RANGE: "超范围",
|
||||||
|
OTHER: "其他",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
|
const priorityLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
LOW: "低",
|
||||||
|
MEDIUM: "中",
|
||||||
|
HIGH: "高",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user && auth.token) {
|
if (!auth.user && auth.token) {
|
||||||
await auth.fetchMe().catch(() => {});
|
await auth.fetchMe().catch(() => {});
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadList">
|
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadList">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="filters.category" placeholder="类别" clearable @change="loadList">
|
<el-select v-model="filters.category" placeholder="类别" clearable @change="loadList">
|
||||||
<el-option v-for="c in categories" :key="c" :label="c" :value="c" />
|
<el-option v-for="c in categories" :key="c" :label="categoryLabel(c)" :value="c" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="filters.date_from"
|
v-model="filters.date_from"
|
||||||
@@ -34,7 +34,11 @@
|
|||||||
<el-card>
|
<el-card>
|
||||||
<el-table :data="items" v-loading="loading" @row-click="goDetail" style="width: 100%">
|
<el-table :data="items" v-loading="loading" @row-click="goDetail" style="width: 100%">
|
||||||
<el-table-column prop="title" label="标题" min-width="160" />
|
<el-table-column prop="title" label="标题" min-width="160" />
|
||||||
<el-table-column prop="category" label="类别" width="140" />
|
<el-table-column prop="category" label="类别" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ categoryLabel(scope.row.category) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="amount" label="金额" width="140" align="right">
|
<el-table-column prop="amount" label="金额" width="140" align="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
¥{{ formatAmount(scope.row.amount) }}
|
¥{{ formatAmount(scope.row.amount) }}
|
||||||
@@ -43,7 +47,7 @@
|
|||||||
<el-table-column prop="occur_date" label="发生日期" width="140" />
|
<el-table-column prop="occur_date" label="发生日期" width="140" />
|
||||||
<el-table-column prop="status" label="状态" width="120">
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag :type="statusTag(scope.row.status)">{{ scope.row.status }}</el-tag>
|
<el-tag :type="statusTag(scope.row.status)">{{ statusLabel(scope.row.status) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="submitted_at" label="提交时间" width="160" />
|
<el-table-column prop="submitted_at" label="提交时间" width="160" />
|
||||||
@@ -123,6 +127,22 @@ const statusTag = (status?: string) => {
|
|||||||
return "info";
|
return "info";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const statusLabel = (status?: string) =>
|
||||||
|
({
|
||||||
|
DRAFT: "草稿",
|
||||||
|
SUBMITTED: "已提交",
|
||||||
|
APPROVED: "已审批",
|
||||||
|
REJECTED: "已驳回",
|
||||||
|
PAID: "已支付",
|
||||||
|
}[status || ""] || status || "");
|
||||||
|
|
||||||
|
const categoryLabel = (c?: string) =>
|
||||||
|
({
|
||||||
|
SITE_FEE: "中心费用",
|
||||||
|
SUBJECT_STIPEND: "受试者补偿",
|
||||||
|
TRAVEL: "差旅",
|
||||||
|
OTHER: "其他",
|
||||||
|
}[c || ""] || c || "");
|
||||||
|
|
||||||
const loadSummary = async () => {
|
const loadSummary = async () => {
|
||||||
if (!study.currentStudy) return;
|
if (!study.currentStudy) return;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<div>
|
<div>
|
||||||
<h3>{{ item?.title }}</h3>
|
<h3>{{ item?.title }}</h3>
|
||||||
<el-tag :type="statusTag(item?.status)">{{ item?.status }}</el-tag>
|
<el-tag :type="statusTag(item?.status)">{{ statusLabel(item?.status) }}</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions" v-if="item">
|
<div class="header-actions" v-if="item">
|
||||||
<PermissionAction action="finance.create">
|
<PermissionAction action="finance.create">
|
||||||
@@ -94,6 +94,14 @@ const statusTag = (status?: string) => {
|
|||||||
return "info";
|
return "info";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const statusLabel = (status?: string) =>
|
||||||
|
({
|
||||||
|
DRAFT: "草稿",
|
||||||
|
SUBMITTED: "已提交",
|
||||||
|
APPROVED: "已审批",
|
||||||
|
REJECTED: "已驳回",
|
||||||
|
PAID: "已支付",
|
||||||
|
}[status || ""] || status || "");
|
||||||
|
|
||||||
const formatAmount = (num?: number | string) => {
|
const formatAmount = (num?: number | string) => {
|
||||||
const n = Number(num);
|
const n = Number(num);
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<el-option v-for="p in products" :key="p.id" :label="p.name" :value="p.id" />
|
<el-option v-for="p in products" :key="p.id" :label="p.name" :value="p.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="filters.status" placeholder="状态" clearable @change="load">
|
<el-select v-model="filters.status" placeholder="状态" clearable @change="load">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<el-button type="primary" v-if="canEdit" @click="openForm()">新增批次</el-button>
|
<el-button type="primary" v-if="canEdit" @click="openForm()">新建批次</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card>
|
<el-card>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<el-table-column prop="expiry_date" label="失效日期" width="140" />
|
<el-table-column prop="expiry_date" label="失效日期" width="140" />
|
||||||
<el-table-column prop="status" label="状态" width="120">
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag>{{ scope.row.status }}</el-tag>
|
<el-tag>{{ statusLabel(scope.row.status) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="120" v-if="canEdit">
|
<el-table-column label="操作" width="120" v-if="canEdit">
|
||||||
@@ -129,6 +129,14 @@ onMounted(async () => {
|
|||||||
await loadProducts();
|
await loadProducts();
|
||||||
load();
|
load();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
ACTIVE: "在库",
|
||||||
|
QUARANTINED: "隔离",
|
||||||
|
EXPIRED: "过期",
|
||||||
|
CLOSED: "关闭",
|
||||||
|
}[v] || v);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<el-table :data="rows" v-loading="loading" style="width: 100%">
|
<el-table :data="rows" v-loading="loading" style="width: 100%">
|
||||||
<el-table-column prop="site_id" label="中心" />
|
<el-table-column prop="site_id" label="中心" />
|
||||||
<el-table-column prop="batch_id" label="批次" />
|
<el-table-column prop="batch_id" label="批次" />
|
||||||
<el-table-column prop="quantity_on_hand" label="结余" width="120" align="right" />
|
<el-table-column prop="quantity_on_hand" label="当前结余" width="120" align="right" />
|
||||||
<el-table-column prop="updated_at" label="更新时间" width="180" />
|
<el-table-column prop="updated_at" label="更新时间" width="180" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" v-if="canEdit" @click="openForm()">新建产品</el-button>
|
<el-button type="primary" v-if="canEdit" @click="openForm()">新建 IMP 产品</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-card>
|
<el-card>
|
||||||
<el-table :data="products" v-loading="loading" style="width: 100%">
|
<el-table :data="products" v-loading="loading" style="width: 100%">
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<div class="filters">
|
<div class="filters">
|
||||||
<el-input v-model="filters.site_id" placeholder="中心ID" clearable @change="load" style="width: 160px" />
|
<el-input v-model="filters.site_id" placeholder="中心ID" clearable @change="load" style="width: 160px" />
|
||||||
<el-input v-model="filters.batch_id" placeholder="批次ID" clearable @change="load" style="width: 160px" />
|
<el-input v-model="filters.batch_id" placeholder="批次ID" clearable @change="load" style="width: 160px" />
|
||||||
<el-select v-model="filters.tx_type" placeholder="类型" clearable @change="load" style="width: 160px">
|
<el-select v-model="filters.tx_type" placeholder="交易类型" clearable @change="load" style="width: 160px">
|
||||||
<el-option v-for="t in txTypes" :key="t" :label="t" :value="t" />
|
<el-option v-for="t in txTypes" :key="t" :label="txTypeLabel(t)" :value="t" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="filters.date_from"
|
v-model="filters.date_from"
|
||||||
@@ -23,14 +23,18 @@
|
|||||||
/>
|
/>
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<PermissionAction action="imp.transaction">
|
<PermissionAction action="imp.transaction">
|
||||||
<el-button type="primary" @click="showForm = true">新增交易</el-button>
|
<el-button type="primary" @click="showForm = true">新建交易</el-button>
|
||||||
</PermissionAction>
|
</PermissionAction>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card>
|
<el-card>
|
||||||
<el-table :data="txs" v-loading="loading" style="width: 100%">
|
<el-table :data="txs" v-loading="loading" style="width: 100%">
|
||||||
<el-table-column prop="tx_date" label="日期" width="120" />
|
<el-table-column prop="tx_date" label="日期" width="120" />
|
||||||
<el-table-column prop="tx_type" label="类型" width="140" />
|
<el-table-column prop="tx_type" label="类型" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ txTypeLabel(scope.row.tx_type) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="site_id" label="中心" width="180" />
|
<el-table-column prop="site_id" label="中心" width="180" />
|
||||||
<el-table-column prop="batch_id" label="批次" width="180" />
|
<el-table-column prop="batch_id" label="批次" width="180" />
|
||||||
<el-table-column prop="subject_id" label="受试者" width="180" />
|
<el-table-column prop="subject_id" label="受试者" width="180" />
|
||||||
@@ -115,6 +119,16 @@ const onPageChange = (p: number) => {
|
|||||||
load();
|
load();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const txTypeLabel = (t: string) =>
|
||||||
|
({
|
||||||
|
RECEIPT: "入库",
|
||||||
|
DISPENSE: "发放",
|
||||||
|
RETURN: "回收",
|
||||||
|
DESTROY: "销毁",
|
||||||
|
TRANSFER_IN: "调入",
|
||||||
|
TRANSFER_OUT: "调出",
|
||||||
|
}[t] || t);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user && auth.token) {
|
if (!auth.user && auth.token) {
|
||||||
await auth.fetchMe().catch(() => {});
|
await auth.fetchMe().catch(() => {});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div>
|
<div>
|
||||||
<h3>Issue 详情</h3>
|
<h3>风险与问题</h3>
|
||||||
<p>{{ issue.title }}</p>
|
<p>{{ issue.title }}</p>
|
||||||
</div>
|
</div>
|
||||||
<PermissionAction action="issue.close">
|
<PermissionAction action="issue.close">
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<el-descriptions-item label="类别">{{ issue.category }}</el-descriptions-item>
|
<el-descriptions-item label="类别">{{ issue.category }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="等级">{{ issue.level }}</el-descriptions-item>
|
<el-descriptions-item label="等级">{{ issue.level }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="截止日期">{{ issue.due_date }}</el-descriptions-item>
|
<el-descriptions-item label="截止日期">{{ issue.due_date }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="状态">{{ issue.status }}</el-descriptions-item>
|
<el-descriptions-item label="状态">{{ statusLabel(issue.status) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="描述">{{ issue.description }}</el-descriptions-item>
|
<el-descriptions-item label="描述">{{ issue.description }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -70,7 +70,7 @@ const load = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const closeIssue = async () => {
|
const closeIssue = async () => {
|
||||||
await ElMessageBox.confirm("确认将 Issue 关闭?", "提示");
|
await ElMessageBox.confirm("确定要关闭该风险/问题吗?该操作不可撤销,请谨慎确认。", "提示");
|
||||||
if (!study.currentStudy || !issue.value) return;
|
if (!study.currentStudy || !issue.value) return;
|
||||||
try {
|
try {
|
||||||
await updateIssue(study.currentStudy.id, issue.value.id, { status: "CLOSED" });
|
await updateIssue(study.currentStudy.id, issue.value.id, { status: "CLOSED" });
|
||||||
@@ -81,6 +81,13 @@ const closeIssue = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
OPEN: "开放",
|
||||||
|
MITIGATING: "处理中",
|
||||||
|
CLOSED: "已关闭",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user && auth.token) {
|
if (!auth.user && auth.token) {
|
||||||
await auth.fetchMe().catch(() => {});
|
await auth.fetchMe().catch(() => {});
|
||||||
|
|||||||
@@ -3,29 +3,37 @@
|
|||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadIssues">
|
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadIssues">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="filters.level" placeholder="等级" clearable @change="loadIssues">
|
<el-select v-model="filters.level" placeholder="等级" clearable @change="loadIssues">
|
||||||
<el-option v-for="l in levels" :key="l" :label="l" :value="l" />
|
<el-option v-for="l in levels" :key="l" :label="levelLabel(l)" :value="l" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="filters.category" placeholder="类别" clearable @change="loadIssues">
|
<el-select v-model="filters.category" placeholder="类别" clearable @change="loadIssues">
|
||||||
<el-option v-for="c in categories" :key="c" :label="c" :value="c" />
|
<el-option v-for="c in categories" :key="c" :label="categoryLabel(c)" :value="c" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-switch v-model="filters.overdue" active-text="仅逾期" @change="loadIssues" />
|
<el-switch v-model="filters.overdue" active-text="仅逾期" @change="loadIssues" />
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<el-button type="primary" v-if="canCreate" @click="showForm = true">新建 Issue</el-button>
|
<el-button type="primary" v-if="canCreate" @click="showForm = true">新建风险/问题</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card>
|
<el-card>
|
||||||
<el-table :data="issues" v-loading="loading" style="width: 100%" @row-click="goDetail">
|
<el-table :data="issues" v-loading="loading" style="width: 100%" @row-click="goDetail">
|
||||||
<el-table-column prop="title" label="标题" />
|
<el-table-column prop="title" label="标题" />
|
||||||
<el-table-column prop="level" label="等级" width="120" />
|
<el-table-column prop="level" label="等级" width="120">
|
||||||
<el-table-column prop="category" label="类别" width="140" />
|
<template #default="scope">
|
||||||
|
{{ levelLabel(scope.row.level) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="category" label="类别" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ categoryLabel(scope.row.category) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="due_date" label="截止日期" width="140" />
|
<el-table-column prop="due_date" label="截止日期" width="140" />
|
||||||
<el-table-column prop="status" label="状态" width="120">
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag :type="scope.row.is_overdue ? 'danger' : 'info'">{{ scope.row.status }}</el-tag>
|
<el-tag :type="scope.row.is_overdue ? 'danger' : 'info'">{{ statusLabel(scope.row.status) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -120,6 +128,28 @@ const goDetail = (row: any) => {
|
|||||||
router.push(`/study/issues/${row.id}`);
|
router.push(`/study/issues/${row.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
OPEN: "开放",
|
||||||
|
MITIGATING: "处理中",
|
||||||
|
CLOSED: "已关闭",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
|
const levelLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
LOW: "低",
|
||||||
|
MEDIUM: "中",
|
||||||
|
HIGH: "高",
|
||||||
|
CRITICAL: "关键",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
|
const categoryLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
RISK: "风险",
|
||||||
|
ISSUE: "问题",
|
||||||
|
PROTOCOL_DEVIATION: "方案偏差",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user && auth.token) {
|
if (!auth.user && auth.token) {
|
||||||
await auth.fetchMe().catch(() => {});
|
await auth.fetchMe().catch(() => {});
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<div class="page">
|
<div class="page">
|
||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<h3>里程碑</h3>
|
<h3>伦理与启动管理</h3>
|
||||||
<PermissionAction action="milestone.create">
|
<PermissionAction action="milestone.create">
|
||||||
<el-button type="primary" @click="openCreate">新增里程碑</el-button>
|
<el-button type="primary" @click="openCreate">新建节点</el-button>
|
||||||
</PermissionAction>
|
</PermissionAction>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -12,10 +12,18 @@
|
|||||||
<el-card>
|
<el-card>
|
||||||
<el-table :data="milestones" v-loading="loading" style="width: 100%">
|
<el-table :data="milestones" v-loading="loading" style="width: 100%">
|
||||||
<el-table-column prop="name" label="名称" />
|
<el-table-column prop="name" label="名称" />
|
||||||
<el-table-column prop="type" label="类型" width="160" />
|
<el-table-column label="类型" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ typeLabel(scope.row.type) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="planned_date" label="计划日期" width="140" />
|
<el-table-column prop="planned_date" label="计划日期" width="140" />
|
||||||
<el-table-column prop="actual_date" label="实际日期" width="140" />
|
<el-table-column prop="actual_date" label="实际日期" width="140" />
|
||||||
<el-table-column prop="status" label="状态" width="140" />
|
<el-table-column label="状态" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ statusLabel(scope.row.status) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="owner_id" label="负责人" width="160" />
|
<el-table-column prop="owner_id" label="负责人" width="160" />
|
||||||
<el-table-column label="操作" width="120">
|
<el-table-column label="操作" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -74,6 +82,25 @@ const openEdit = (row: any) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadMilestones();
|
loadMilestones();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const typeLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
ETHICS_SUBMISSION: "伦理递交",
|
||||||
|
ETHICS_APPROVAL: "伦理批件",
|
||||||
|
SIV: "启动会",
|
||||||
|
FPI: "首例入组",
|
||||||
|
LPI: "末例入组",
|
||||||
|
DBL: "揭盲",
|
||||||
|
CSR: "总结报告",
|
||||||
|
}[v] || v);
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
NOT_STARTED: "未开始",
|
||||||
|
IN_PROGRESS: "进行中",
|
||||||
|
DONE: "已完成",
|
||||||
|
BLOCKED: "阻塞",
|
||||||
|
}[v] || v);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="study-home" v-if="study.currentStudy">
|
<div class="study-home" v-if="study.currentStudy">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div>
|
<div>
|
||||||
<h2>项目首页 / Dashboard</h2>
|
<h2>项目概览</h2>
|
||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
{{ study.currentStudy.name }}({{ study.currentStudy.code }})
|
{{ study.currentStudy.name }}({{ study.currentStudy.code }})
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<el-option v-for="s in sites" :key="s.id" :label="s.name || s.id" :value="s.id" />
|
<el-option v-for="s in sites" :key="s.id" :label="s.name || s.id" :value="s.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadSubjects">
|
<el-select v-model="filters.status" placeholder="状态" clearable @change="loadSubjects">
|
||||||
<el-option v-for="s in statuses" :key="s" :label="s" :value="s" />
|
<el-option v-for="s in statuses" :key="s" :label="statusLabel(s)" :value="s" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<el-button type="primary" v-if="canEdit" @click="showForm = true">新增受试者</el-button>
|
<el-button type="primary" v-if="canEdit" @click="showForm = true">新增受试者</el-button>
|
||||||
@@ -24,7 +24,11 @@
|
|||||||
<el-table :data="subjects" v-loading="loading" style="width: 100%" @row-click="goDetail">
|
<el-table :data="subjects" v-loading="loading" style="width: 100%" @row-click="goDetail">
|
||||||
<el-table-column prop="subject_no" label="受试者编号" />
|
<el-table-column prop="subject_no" label="受试者编号" />
|
||||||
<el-table-column prop="site_id" label="中心ID" />
|
<el-table-column prop="site_id" label="中心ID" />
|
||||||
<el-table-column prop="status" label="状态" width="120" />
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag>{{ statusLabel(scope.row.status) }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="screening_date" label="筛选日期" width="140" />
|
<el-table-column prop="screening_date" label="筛选日期" width="140" />
|
||||||
<el-table-column prop="enrollment_date" label="入组日期" width="140" />
|
<el-table-column prop="enrollment_date" label="入组日期" width="140" />
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -128,6 +132,14 @@ onMounted(async () => {
|
|||||||
await loadSites();
|
await loadSites();
|
||||||
loadSubjects();
|
loadSubjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({
|
||||||
|
SCREENING: "筛选中",
|
||||||
|
ENROLLED: "已入组",
|
||||||
|
COMPLETED: "已完成",
|
||||||
|
DROPPED: "已脱落",
|
||||||
|
}[v] || v);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
<el-select v-model="filters.milestone_id" placeholder="里程碑" clearable @change="loadTasks">
|
<el-select v-model="filters.milestone_id" placeholder="里程碑" clearable @change="loadTasks">
|
||||||
<el-option v-for="m in milestones" :key="m.id" :label="m.name" :value="m.id" />
|
<el-option v-for="m in milestones" :key="m.id" :label="m.name" :value="m.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-input v-model="filters.assignee_id" placeholder="负责人ID" style="width: 180px" @change="loadTasks" />
|
<el-input v-model="filters.assignee_id" placeholder="负责人" style="width: 180px" @change="loadTasks" />
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<PermissionAction action="task.create">
|
<PermissionAction action="task.create">
|
||||||
<el-button type="primary" @click="openCreate">新增任务</el-button>
|
<el-button type="primary" @click="openCreate">新建任务</el-button>
|
||||||
</PermissionAction>
|
</PermissionAction>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -19,10 +19,20 @@
|
|||||||
<el-card>
|
<el-card>
|
||||||
<el-table :data="tasks" v-loading="loading" style="width: 100%">
|
<el-table :data="tasks" v-loading="loading" style="width: 100%">
|
||||||
<el-table-column prop="title" label="标题" />
|
<el-table-column prop="title" label="标题" />
|
||||||
<el-table-column prop="milestone_id" label="里程碑" />
|
<el-table-column prop="milestone_id" label="节点/里程碑">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ milestoneName(scope.row.milestone_id) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="assignee_id" label="负责人" width="160" />
|
<el-table-column prop="assignee_id" label="负责人" width="160" />
|
||||||
<el-table-column prop="priority" label="优先级" width="100" />
|
<el-table-column prop="priority" label="优先级" width="100" />
|
||||||
<el-table-column prop="status" label="状态" width="120" />
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.status === 'DONE' ? 'success' : scope.row.status === 'BLOCKED' ? 'danger' : 'info'">
|
||||||
|
{{ statusLabel(scope.row.status) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="due_date" label="截止日期" width="140" />
|
<el-table-column prop="due_date" label="截止日期" width="140" />
|
||||||
<el-table-column label="操作" width="120">
|
<el-table-column label="操作" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -47,7 +57,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref, computed } from "vue";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { fetchTasks } from "../api/tasks";
|
import { fetchTasks } from "../api/tasks";
|
||||||
import { fetchMilestones } from "../api/milestones";
|
import { fetchMilestones } from "../api/milestones";
|
||||||
@@ -79,6 +89,12 @@ const showForm = ref(false);
|
|||||||
const editingTask = ref<any | null>(null);
|
const editingTask = ref<any | null>(null);
|
||||||
|
|
||||||
const { can } = usePermission();
|
const { can } = usePermission();
|
||||||
|
const milestoneMap = computed(() =>
|
||||||
|
milestones.value.reduce<Record<string, string>>((acc, cur) => {
|
||||||
|
acc[cur.id] = cur.name || cur.id;
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
|
||||||
const loadMilestones = async () => {
|
const loadMilestones = async () => {
|
||||||
if (!study.currentStudy) return;
|
if (!study.currentStudy) return;
|
||||||
@@ -142,8 +158,35 @@ const ensureUser = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filterKey = computed(() => (study.currentStudy ? `tasks_filter_${study.currentStudy.id}` : null));
|
||||||
|
const saveFilters = () => {
|
||||||
|
if (!filterKey.value) return;
|
||||||
|
localStorage.setItem(filterKey.value, JSON.stringify({ ...filters.value, page: page.value }));
|
||||||
|
};
|
||||||
|
const loadSavedFilters = () => {
|
||||||
|
if (!filterKey.value) return;
|
||||||
|
const raw = localStorage.getItem(filterKey.value);
|
||||||
|
if (raw) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
filters.value.status = parsed.status || "";
|
||||||
|
filters.value.milestone_id = parsed.milestone_id || "";
|
||||||
|
filters.value.assignee_id = parsed.assignee_id || "";
|
||||||
|
page.value = parsed.page || 1;
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusLabel = (v: string) =>
|
||||||
|
({ TODO: "待处理", DOING: "进行中", DONE: "已完成", BLOCKED: "阻塞" }[v] || v);
|
||||||
|
|
||||||
|
const milestoneName = (id: string) => milestoneMap.value[id] || id || "-";
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await ensureUser();
|
await ensureUser();
|
||||||
|
loadSavedFilters();
|
||||||
loadMilestones();
|
loadMilestones();
|
||||||
loadTasks();
|
loadTasks();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<div class="page">
|
<div class="page">
|
||||||
<el-card class="mb-12">
|
<el-card class="mb-12">
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<el-select v-model="filters.level" placeholder="类型" clearable @change="load">
|
<el-select v-model="filters.level" placeholder="核查层级" clearable @change="load">
|
||||||
<el-option label="SDV" value="SDV" />
|
<el-option label="SDV 核查" value="SDV" />
|
||||||
<el-option label="SDR" value="SDR" />
|
<el-option label="SDR 核查" value="SDR" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<SiteSelect
|
<SiteSelect
|
||||||
v-model="filters.site_id"
|
v-model="filters.site_id"
|
||||||
@@ -14,13 +14,13 @@
|
|||||||
@change="load"
|
@change="load"
|
||||||
/>
|
/>
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
<el-button v-if="canEdit" type="primary" @click="openCreate">新增进度</el-button>
|
<el-button v-if="canEdit" type="primary" @click="openCreate">新增核查进度</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<VerificationTable :verifications="verifications" :can-edit="canEdit" :loading="loading" @edit="openEdit" />
|
<VerificationTable :verifications="verifications" :can-edit="canEdit" :loading="loading" @edit="openEdit" />
|
||||||
|
|
||||||
<el-dialog :title="editForm.id ? '更新进度' : '新增进度'" v-model="showEdit" width="520px">
|
<el-dialog :title="editForm.id ? '更新核查进度' : '新增核查进度'" v-model="showEdit" width="520px">
|
||||||
<el-form :model="editForm" label-width="120px">
|
<el-form :model="editForm" label-width="120px">
|
||||||
<el-form-item label="受试者">
|
<el-form-item label="受试者">
|
||||||
<SubjectSelect
|
<SubjectSelect
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="类型">
|
<el-form-item label="类型">
|
||||||
<el-select v-model="editForm.level" placeholder="请选择">
|
<el-select v-model="editForm.level" placeholder="请选择">
|
||||||
<el-option label="SDV" value="SDV" />
|
<el-option label="SDV 核查" value="SDV" />
|
||||||
<el-option label="SDR" value="SDR" />
|
<el-option label="SDR 核查" value="SDR" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="完成度">
|
<el-form-item label="完成度">
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user