帐号治理-帐号管理--更新

This commit is contained in:
Cheng Zhou
2025-12-18 19:14:38 +08:00
parent f6b89cb8c4
commit eed83cec5a
23 changed files with 233 additions and 30 deletions
+52 -21
View File
@@ -12,17 +12,25 @@
<el-table-column prop="name" label="中心名称" min-width="180" />
<el-table-column prop="city" label="城市" width="140" />
<el-table-column prop="pi_name" label="PI" width="160" />
<el-table-column prop="contact" label="CRA 联系人" min-width="180" />
<el-table-column label="电话" width="160">
<template #default="scope">
{{ phoneText(scope.row) }}
</template>
</el-table-column>
<el-table-column prop="contact" label="负责人" min-width="180">
<template #default="scope">
{{ contactLabel(scope.row) }}
</template>
</el-table-column>
<el-table-column label="状态" width="120">
<template #default="scope">
<el-tag type="success" v-if="scope.row.is_active">启用</el-tag>
<el-tag type="danger" v-else>停用</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="280" fixed="right">
<el-table-column label="操作" width="220" fixed="right">
<template #default="scope">
<el-button link type="primary" size="small" @click="openEdit(scope.row)">编辑</el-button>
<el-button link type="primary" size="small" @click="openBind(scope.row)">绑定 CRA</el-button>
<el-button
link
:type="scope.row.is_active ? 'danger' : 'primary'"
@@ -40,14 +48,8 @@
v-model:visible="formVisible"
:study-id="projectId"
:site="editingSite"
@saved="loadSites"
/>
<SiteCraBinding
v-if="projectId"
v-model:visible="bindVisible"
:study-id="projectId"
:site="bindingSite"
:cra-users="craUsers"
:members="members"
:users="users"
@saved="loadSites"
/>
</div>
@@ -60,8 +62,8 @@ import { ElMessage, ElMessageBox } from "element-plus";
import { fetchStudyDetail } from "../../api/studies";
import { fetchSites, updateSite } from "../../api/sites";
import { fetchUsers } from "../../api/users";
import { listMembers } from "../../api/members";
import SiteForm from "./SiteForm.vue";
import SiteCraBinding from "./SiteCraBinding.vue";
import type { Site, Study, UserInfo } from "../../types/api";
import { useAuthStore } from "../../store/auth";
import { evaluateAction } from "../../guards/actionGuard";
@@ -74,11 +76,10 @@ const auth = useAuthStore();
const project = ref<Study | null>(null);
const sites = ref<Site[]>([]);
const users = ref<UserInfo[]>([]);
const members = ref<any[]>([]);
const loading = ref(false);
const formVisible = ref(false);
const editingSite = ref<Site | null>(null);
const bindVisible = ref(false);
const bindingSite = ref<Site | null>(null);
const loadProject = async () => {
if (!projectId.value) return;
@@ -112,23 +113,53 @@ const loadUsers = async () => {
}
};
const craUsers = computed(() => users.value.filter((u) => u.role === "CRA" && u.is_active));
const loadMembers = async () => {
if (!projectId.value) return;
try {
const { data } = await listMembers(projectId.value, { limit: 500 });
members.value = Array.isArray(data) ? data : data.items || [];
} catch {
members.value = [];
}
};
const memberNameMap = computed(() => {
const map: Record<string, string> = {};
users.value.forEach((u) => {
map[u.id] = u.username || u.id;
});
members.value.forEach((m) => {
if (m.user_id && !map[m.user_id]) map[m.user_id] = m.username || m.user_id;
});
return map;
});
const contactLabel = (row: any) => {
if (!row?.contact) return "—";
return String(row.contact)
.split(",")
.map((c) => c.trim())
.filter(Boolean)
.map((c) => memberNameMap.value[c] || c)
.join("、") || "—";
};
const phoneText = (row: any) => row?.phone || row?.contact_phone || "—";
const openCreate = () => {
loadUsers();
loadMembers();
editingSite.value = null;
formVisible.value = true;
};
const openEdit = (row: Site) => {
loadUsers();
loadMembers();
editingSite.value = row;
formVisible.value = true;
};
const openBind = (row: Site) => {
bindingSite.value = row;
bindVisible.value = true;
};
const toggleSite = async (row: Site) => {
if (!projectId.value) return;
const decision = evaluateAction({
@@ -178,7 +209,7 @@ const toggleSite = async (row: Site) => {
};
onMounted(async () => {
await Promise.all([loadProject(), loadUsers()]);
await Promise.all([loadProject(), loadUsers(), loadMembers()]);
loadSites();
});
</script>