275 lines
10 KiB
Vue
275 lines
10 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, reactive, ref } from "vue";
|
|
import { ElMessage } from "element-plus";
|
|
import {
|
|
adminApi,
|
|
type AdminAccessOverviewCard,
|
|
type AdminManagerItem,
|
|
type AdminManagerPayload,
|
|
type AdminPermissionItem,
|
|
type AdminRoleItem,
|
|
type AdminRolePayload,
|
|
} from "../../api/admin";
|
|
import OrderStatusTag from "../../components/OrderStatusTag.vue";
|
|
|
|
const loading = ref(false);
|
|
const cards = ref<AdminAccessOverviewCard[]>([]);
|
|
const admins = ref<AdminManagerItem[]>([]);
|
|
const roles = ref<AdminRoleItem[]>([]);
|
|
const permissions = ref<AdminPermissionItem[]>([]);
|
|
|
|
const adminDialogVisible = ref(false);
|
|
const roleDialogVisible = ref(false);
|
|
const adminSubmitting = ref(false);
|
|
const roleSubmitting = ref(false);
|
|
|
|
const adminForm = reactive<AdminManagerPayload>({
|
|
name: "",
|
|
mobile: "",
|
|
email: "",
|
|
password: "",
|
|
status: "enabled",
|
|
role_ids: [],
|
|
});
|
|
|
|
const roleForm = reactive<AdminRolePayload>({
|
|
name: "",
|
|
code: "",
|
|
status: "enabled",
|
|
permission_ids: [],
|
|
});
|
|
|
|
async function fetchAll() {
|
|
loading.value = true;
|
|
try {
|
|
const [overviewRes, adminsRes, rolesRes, permissionsRes] = await Promise.all([
|
|
adminApi.getAccessOverview(),
|
|
adminApi.getAdmins(),
|
|
adminApi.getRoles(),
|
|
adminApi.getPermissions(),
|
|
]);
|
|
|
|
cards.value = overviewRes.data.cards;
|
|
admins.value = adminsRes.data.list;
|
|
roles.value = rolesRes.data.list;
|
|
permissions.value = permissionsRes.data.list;
|
|
} catch (error) {
|
|
console.error(error);
|
|
ElMessage.error("权限中心数据加载失败");
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
function openAdminDialog(row?: AdminManagerItem) {
|
|
if (row) {
|
|
adminForm.id = row.id;
|
|
adminForm.name = row.name;
|
|
adminForm.mobile = row.mobile;
|
|
adminForm.email = row.email;
|
|
adminForm.password = "";
|
|
adminForm.status = row.status;
|
|
adminForm.role_ids = [...row.role_ids];
|
|
} else {
|
|
adminForm.id = undefined;
|
|
adminForm.name = "";
|
|
adminForm.mobile = "";
|
|
adminForm.email = "";
|
|
adminForm.password = "";
|
|
adminForm.status = "enabled";
|
|
adminForm.role_ids = roles.value.length ? [roles.value[0].id] : [];
|
|
}
|
|
adminDialogVisible.value = true;
|
|
}
|
|
|
|
async function submitAdmin() {
|
|
adminSubmitting.value = true;
|
|
try {
|
|
await adminApi.saveAdmin({ ...adminForm, role_ids: [...adminForm.role_ids] });
|
|
ElMessage.success(adminForm.id ? "管理员更新成功" : "管理员创建成功");
|
|
adminDialogVisible.value = false;
|
|
await fetchAll();
|
|
} catch (error) {
|
|
console.error(error);
|
|
ElMessage.error("管理员保存失败");
|
|
} finally {
|
|
adminSubmitting.value = false;
|
|
}
|
|
}
|
|
|
|
function openRoleDialog(row?: AdminRoleItem) {
|
|
if (row) {
|
|
roleForm.id = row.id;
|
|
roleForm.name = row.name;
|
|
roleForm.code = row.code;
|
|
roleForm.status = row.status;
|
|
roleForm.permission_ids = [...row.permission_ids];
|
|
} else {
|
|
roleForm.id = undefined;
|
|
roleForm.name = "";
|
|
roleForm.code = "";
|
|
roleForm.status = "enabled";
|
|
roleForm.permission_ids = permissions.value.map((item) => item.id);
|
|
}
|
|
roleDialogVisible.value = true;
|
|
}
|
|
|
|
async function submitRole() {
|
|
roleSubmitting.value = true;
|
|
try {
|
|
await adminApi.saveRole({ ...roleForm, permission_ids: [...roleForm.permission_ids] });
|
|
ElMessage.success(roleForm.id ? "角色更新成功" : "角色创建成功");
|
|
roleDialogVisible.value = false;
|
|
await fetchAll();
|
|
} catch (error) {
|
|
console.error(error);
|
|
ElMessage.error("角色保存失败");
|
|
} finally {
|
|
roleSubmitting.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(fetchAll);
|
|
</script>
|
|
|
|
<template>
|
|
<div v-loading="loading">
|
|
<div class="metric-grid" style="margin-bottom: 18px">
|
|
<div v-for="item in cards" :key="item.title" class="metric-card">
|
|
<div class="metric-card__label">{{ item.title }}</div>
|
|
<div class="metric-card__value">{{ item.value }}</div>
|
|
<div class="metric-card__desc">{{ item.desc }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<el-card class="panel-card" shadow="never">
|
|
<el-tabs>
|
|
<el-tab-pane label="管理员账号">
|
|
<div class="filters-row" style="margin-bottom: 16px">
|
|
<el-button type="primary" @click="openAdminDialog()">新增管理员</el-button>
|
|
</div>
|
|
<el-table :data="admins" stripe>
|
|
<el-table-column prop="name" label="姓名" min-width="140" />
|
|
<el-table-column prop="mobile" label="手机号" min-width="140" />
|
|
<el-table-column prop="email" label="邮箱" min-width="200" />
|
|
<el-table-column label="状态" min-width="100">
|
|
<template #default="{ row }">
|
|
<OrderStatusTag :status="row.status_text" />
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="角色" min-width="220">
|
|
<template #default="{ row }">
|
|
{{ row.role_names.join(" / ") || "未分配角色" }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="last_login_at" label="最近登录" min-width="170" />
|
|
<el-table-column label="操作" fixed="right" width="100">
|
|
<template #default="{ row }">
|
|
<el-button link type="primary" @click="openAdminDialog(row)">编辑</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane label="角色配置">
|
|
<div class="filters-row" style="margin-bottom: 16px">
|
|
<el-button type="primary" @click="openRoleDialog()">新增角色</el-button>
|
|
</div>
|
|
<el-table :data="roles" stripe>
|
|
<el-table-column prop="name" label="角色名称" min-width="140" />
|
|
<el-table-column prop="code" label="角色编码" min-width="160" />
|
|
<el-table-column label="状态" min-width="100">
|
|
<template #default="{ row }">
|
|
<OrderStatusTag :status="row.status_text" />
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="admin_count" label="管理员数" min-width="100" />
|
|
<el-table-column label="权限摘要" min-width="280">
|
|
<template #default="{ row }">
|
|
{{ row.permission_names.join(" / ") || "未分配权限" }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" fixed="right" width="100">
|
|
<template #default="{ row }">
|
|
<el-button link type="primary" @click="openRoleDialog(row)">编辑</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane label="权限点">
|
|
<el-table :data="permissions" stripe>
|
|
<el-table-column prop="name" label="权限名称" min-width="180" />
|
|
<el-table-column prop="code" label="权限编码" min-width="220" />
|
|
<el-table-column prop="module_text" label="所属模块" min-width="140" />
|
|
<el-table-column prop="action" label="动作" min-width="120" />
|
|
</el-table>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</el-card>
|
|
|
|
<el-dialog v-model="adminDialogVisible" :title="adminForm.id ? '编辑管理员' : '新增管理员'" width="560px">
|
|
<el-form label-position="top">
|
|
<el-form-item label="姓名">
|
|
<el-input v-model="adminForm.name" placeholder="请输入管理员姓名" />
|
|
</el-form-item>
|
|
<el-form-item label="手机号">
|
|
<el-input v-model="adminForm.mobile" placeholder="请输入管理员手机号" />
|
|
</el-form-item>
|
|
<el-form-item label="邮箱">
|
|
<el-input v-model="adminForm.email" placeholder="请输入管理员邮箱" />
|
|
</el-form-item>
|
|
<el-form-item :label="adminForm.id ? '登录密码(留空则不修改)' : '登录密码'">
|
|
<el-input v-model="adminForm.password" type="password" show-password placeholder="请输入管理员登录密码" />
|
|
</el-form-item>
|
|
<el-form-item label="账号状态">
|
|
<el-radio-group v-model="adminForm.status">
|
|
<el-radio value="enabled">启用</el-radio>
|
|
<el-radio value="disabled">停用</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
<el-form-item label="角色分配">
|
|
<el-select v-model="adminForm.role_ids" multiple style="width: 100%">
|
|
<el-option v-for="item in roles" :key="item.id" :label="item.name" :value="item.id" />
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="adminDialogVisible = false">取消</el-button>
|
|
<el-button type="primary" :loading="adminSubmitting" @click="submitAdmin">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
|
|
<el-dialog v-model="roleDialogVisible" :title="roleForm.id ? '编辑角色' : '新增角色'" width="640px">
|
|
<el-form label-position="top">
|
|
<el-form-item label="角色名称">
|
|
<el-input v-model="roleForm.name" placeholder="请输入角色名称" />
|
|
</el-form-item>
|
|
<el-form-item label="角色编码">
|
|
<el-input v-model="roleForm.code" placeholder="请输入角色编码,如 operations_manager" />
|
|
</el-form-item>
|
|
<el-form-item label="角色状态">
|
|
<el-radio-group v-model="roleForm.status">
|
|
<el-radio value="enabled">启用</el-radio>
|
|
<el-radio value="disabled">停用</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
<el-form-item label="权限分配">
|
|
<el-select v-model="roleForm.permission_ids" multiple style="width: 100%">
|
|
<el-option
|
|
v-for="item in permissions"
|
|
:key="item.id"
|
|
:label="`${item.module_text} / ${item.name}`"
|
|
:value="item.id"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="roleDialogVisible = false">取消</el-button>
|
|
<el-button type="primary" :loading="roleSubmitting" @click="submitRole">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|