增加admin管理帐号和项目的界面--初步实现
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card>
|
||||
<div class="header">
|
||||
<div>
|
||||
<h3>中心管理</h3>
|
||||
<div class="sub" v-if="project">项目:{{ project.code }} - {{ project.name }}</div>
|
||||
</div>
|
||||
<el-button type="primary" @click="openCreate">新建中心</el-button>
|
||||
</div>
|
||||
<el-table :data="sites" v-loading="loading" stripe>
|
||||
<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="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">
|
||||
<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'"
|
||||
size="small"
|
||||
@click="toggleSite(scope.row)"
|
||||
>
|
||||
{{ scope.row.is_active ? "停用" : "启用" }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<SiteForm
|
||||
v-if="projectId"
|
||||
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"
|
||||
@saved="loadSites"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { fetchStudyDetail } from "../../api/studies";
|
||||
import { fetchSites, updateSite } from "../../api/sites";
|
||||
import { fetchUsers } from "../../api/users";
|
||||
import SiteForm from "./SiteForm.vue";
|
||||
import SiteCraBinding from "./SiteCraBinding.vue";
|
||||
import type { Site, Study, UserInfo } from "../../types/api";
|
||||
|
||||
const route = useRoute();
|
||||
const projectId = computed(() => route.params.projectId as string);
|
||||
|
||||
const project = ref<Study | null>(null);
|
||||
const sites = ref<Site[]>([]);
|
||||
const users = ref<UserInfo[]>([]);
|
||||
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;
|
||||
try {
|
||||
const { data } = await fetchStudyDetail(projectId.value);
|
||||
project.value = data;
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
|
||||
const loadSites = async () => {
|
||||
if (!projectId.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data } = await fetchSites(projectId.value);
|
||||
sites.value = Array.isArray(data) ? data : (data as any).items || [];
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || "中心列表加载失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadUsers = async () => {
|
||||
try {
|
||||
const { data } = await fetchUsers({ limit: 500 });
|
||||
users.value = (data as any).items || [];
|
||||
} catch {
|
||||
users.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const craUsers = computed(() => users.value.filter((u) => u.role === "CRA" && u.is_active));
|
||||
|
||||
const openCreate = () => {
|
||||
editingSite.value = null;
|
||||
formVisible.value = true;
|
||||
};
|
||||
|
||||
const openEdit = (row: Site) => {
|
||||
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;
|
||||
if (row.is_active) {
|
||||
const ok = await ElMessageBox.confirm("该操作将影响中心数据,请确认是否继续", "停用中心", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确认",
|
||||
}).catch(() => null);
|
||||
if (!ok) return;
|
||||
}
|
||||
try {
|
||||
await updateSite(projectId.value, row.id, { is_active: !row.is_active });
|
||||
ElMessage.success(row.is_active ? "已停用" : "已启用");
|
||||
loadSites();
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || "操作失败");
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([loadProject(), loadUsers()]);
|
||||
loadSites();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
padding: 16px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.sub {
|
||||
color: #666;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user