信息架构/菜单框架大重构-20260109
This commit is contained in:
@@ -59,7 +59,7 @@
|
||||
<div class="quick-entry-card">
|
||||
<div class="entry-header">
|
||||
<span class="entry-title">快捷入口</span>
|
||||
<el-button type="primary" link @click="goMore('/study/home')" class="entry-more">
|
||||
<el-button type="primary" link @click="goMore('/project/overview')" class="entry-more">
|
||||
进入项目 <el-icon class="el-icon--right"><Right /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -96,9 +96,8 @@ import { ElMessage } from "element-plus";
|
||||
import { useAuthStore } from "../../store/auth";
|
||||
import { useStudyStore } from "../../store/study";
|
||||
import { fetchAes } from "../../api/aes";
|
||||
import { fetchFinanceItems } from "../../api/finance";
|
||||
import { fetchImpTransactions } from "../../api/impTransactions";
|
||||
import { Right, Timer, UserFilled, Warning, Money, Collection, Management } from "@element-plus/icons-vue";
|
||||
import { listFinanceContracts } from "../../api/financeContracts";
|
||||
import { Right, Timer, UserFilled, Warning, Money, Collection } from "@element-plus/icons-vue";
|
||||
|
||||
interface WorkItem {
|
||||
title: string;
|
||||
@@ -132,26 +131,24 @@ const quickActions = computed(() => {
|
||||
if (!currentStudyId.value) return [];
|
||||
if (role.value === "CRA")
|
||||
return [
|
||||
{ label: "伦理启动", path: "/study/milestones", icon: Timer },
|
||||
{ label: "AE 列表", path: "/study/aes", icon: Warning },
|
||||
{ label: "立项与伦理", path: "/startup/feasibility-ethics", icon: Timer },
|
||||
{ label: "AE 列表", path: "/subjects", icon: Warning },
|
||||
];
|
||||
if (role.value === "PM")
|
||||
return [
|
||||
{ label: "伦理启动", path: "/study/milestones", icon: Timer },
|
||||
{ label: "费用审核", path: "/study/finance", icon: Money },
|
||||
{ label: "公告管理", path: "/study/faq", icon: Collection },
|
||||
{ label: "立项与伦理", path: "/startup/feasibility-ethics", icon: Timer },
|
||||
{ label: "合同费用", path: "/finance/contracts", icon: Money },
|
||||
{ label: "医学咨询", path: "/knowledge/medical-consult", icon: Collection },
|
||||
];
|
||||
if (role.value === "PV") return [{ label: "AE 列表", path: "/study/aes", icon: Warning }];
|
||||
if (role.value === "IMP") return [{ label: "药品台账", path: "/study/imp/transactions", icon: Management }];
|
||||
return [{ label: "伦理启动", path: "/study/milestones", icon: Timer }];
|
||||
if (role.value === "PV") return [{ label: "AE 列表", path: "/subjects", icon: Warning }];
|
||||
return [{ label: "立项与伦理", path: "/startup/feasibility-ethics", icon: Timer }];
|
||||
});
|
||||
|
||||
const todayMorePath = computed(() => (role.value === "IMP" ? "/study/imp/transactions" : "/study/aes"));
|
||||
const overdueMorePath = computed(() => (role.value === "IMP" ? "/study/imp/transactions" : "/study/aes"));
|
||||
const todayMorePath = computed(() => "/subjects");
|
||||
const overdueMorePath = computed(() => "/subjects");
|
||||
const actionMorePath = computed(() => {
|
||||
if (role.value === "IMP") return "/study/imp/transactions";
|
||||
if (role.value === "PM" || role.value === "ADMIN") return "/study/finance";
|
||||
return "/study/aes";
|
||||
if (role.value === "PM" || role.value === "ADMIN") return "/finance/contracts";
|
||||
return "/subjects";
|
||||
});
|
||||
|
||||
const isOverdue = (d?: string | null) => {
|
||||
@@ -164,23 +161,15 @@ const toAeItem = (ae: any): WorkItem => ({
|
||||
subtitle: study.currentStudy?.name || "",
|
||||
status: ae.status,
|
||||
overdue: isOverdue(ae.expected_resolution_date || ae.updated_at),
|
||||
path: `/study/aes/${ae.id}`,
|
||||
path: ae.subject_id ? `/subjects/${ae.subject_id}` : "/subjects",
|
||||
});
|
||||
|
||||
const toFinanceItem = (fi: any): WorkItem => ({
|
||||
title: fi.title || "费用",
|
||||
const toContractItem = (fi: any): WorkItem => ({
|
||||
title: fi.contract_no || "合同费用",
|
||||
subtitle: study.currentStudy?.name || "",
|
||||
status: fi.status,
|
||||
status: fi.site_name,
|
||||
overdue: false,
|
||||
path: `/study/finance/${fi.id}`,
|
||||
});
|
||||
|
||||
const toImpItem = (tx: any): WorkItem => ({
|
||||
title: tx.type || "药品记录",
|
||||
subtitle: study.currentStudy?.name || "",
|
||||
status: tx.status || "",
|
||||
overdue: false,
|
||||
path: "/study/imp/transactions",
|
||||
path: `/finance/contracts/${fi.id}`,
|
||||
});
|
||||
|
||||
const loadData = async () => {
|
||||
@@ -189,17 +178,13 @@ const loadData = async () => {
|
||||
try {
|
||||
const studyId = currentStudyId.value;
|
||||
const aesReq = fetchAes(studyId, { status: "NEW", limit: 50 });
|
||||
const financeReq = fetchFinanceItems(studyId, { status: "SUBMITTED", limit: 50 });
|
||||
const impReq = fetchImpTransactions ? fetchImpTransactions(studyId, { limit: 50 }) : Promise.resolve({ data: [] });
|
||||
|
||||
const [aesRes, financeRes, impRes] = await Promise.allSettled([aesReq, financeReq, impReq]);
|
||||
const [aesRes, financeRes] = await Promise.allSettled([aesReq, listFinanceContracts(studyId, { limit: 50 })]);
|
||||
const aes = aesRes.status === "fulfilled" ? (aesRes.value.data.items || aesRes.value.data || []) : [];
|
||||
const finances =
|
||||
financeRes.status === "fulfilled" ? (financeRes.value.data.items || financeRes.value.data || []) : [];
|
||||
const impData = impRes.status === "fulfilled" ? (impRes.value as any).data : [];
|
||||
const impTx = Array.isArray(impData) ? impData : (impData?.items || []);
|
||||
|
||||
buildSections(aes, finances, impTx);
|
||||
buildSections(aes, finances);
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || "工作台数据加载失败");
|
||||
} finally {
|
||||
@@ -207,13 +192,13 @@ const loadData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const buildSections = (aes: any[], finances: any[], impTx: any[]) => {
|
||||
const buildSections = (aes: any[], finances: any[]) => {
|
||||
todayList.value = [];
|
||||
overdueList.value = [];
|
||||
actionList.value = [];
|
||||
|
||||
const openAes = aes.filter((a) => a.status !== "CLOSED");
|
||||
const financePending = finances.filter((f) => f.status !== "PAID");
|
||||
const financePending = finances;
|
||||
const overdueAes = openAes.filter((a) => isOverdue(a.expected_resolution_date || a.updated_at));
|
||||
|
||||
if (role.value === "CRA") {
|
||||
@@ -223,17 +208,13 @@ const buildSections = (aes: any[], finances: any[], impTx: any[]) => {
|
||||
} else if (role.value === "PM" || role.value === "ADMIN") {
|
||||
todayList.value = openAes.slice(0, 5).map(toAeItem);
|
||||
overdueList.value = overdueAes.slice(0, 5).map(toAeItem);
|
||||
const financeTodo = financePending.slice(0, 3).map(toFinanceItem);
|
||||
const financeTodo = financePending.slice(0, 3).map(toContractItem);
|
||||
actionList.value = [...financeTodo, ...openAes.slice(0, 2).map(toAeItem)].slice(0, 5);
|
||||
} else if (role.value === "PV") {
|
||||
const aeOpen = aes.filter((a) => a.status !== "CLOSED");
|
||||
todayList.value = aeOpen.slice(0, 5).map(toAeItem);
|
||||
overdueList.value = aeOpen.filter((a) => isOverdue(a.updated_at)).slice(0, 5).map(toAeItem);
|
||||
actionList.value = aeOpen.slice(0, 5).map(toAeItem);
|
||||
} else if (role.value === "IMP") {
|
||||
actionList.value = impTx.slice(0, 5).map(toImpItem);
|
||||
todayList.value = [];
|
||||
overdueList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user