- 新增全局主题美化样式文件 theme.css 并在 bootstrap.ts 中引入 - 实现工作台页面重构,包含渐变英雄头、统计卡片和快捷入口宫格 - 开发楼盘地图功能,在 dashboard 中集成腾讯地图 GL JS 散点显示 - 添加成交记录列表页面,支持关键词和区域筛选查询 - 新增新房预售许可证管理页面,包含预售证号、楼盘名等信息展示 - 扩展 house API 接口,增加交易记录和预售许可相关数据模型 - 优化数据明细页面,将占位内容替换为实际的成交记录表格 - 添加招聘数据看板和爬虫管理页面,支持数据源管理和抓取触发功能
232 lines
5.7 KiB
Vue
232 lines
5.7 KiB
Vue
<script lang="ts" setup>
|
|
import type { MenuNode, RoleItem } from '#/api/system';
|
|
|
|
import { onMounted, reactive, ref } from 'vue';
|
|
|
|
import { useAccess } from '@vben/access';
|
|
import { Page } from '@vben/common-ui';
|
|
|
|
import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
|
|
|
|
import {
|
|
createRole,
|
|
deleteRole,
|
|
getMenuTree,
|
|
getRoleList,
|
|
updateRole,
|
|
} from '#/api/system';
|
|
|
|
const { hasAccessByCodes } = useAccess();
|
|
|
|
const loading = ref(false);
|
|
const list = ref<RoleItem[]>([]);
|
|
const menuTree = ref<any[]>([]);
|
|
const dialogOpen = ref(false);
|
|
const editing = ref<null | RoleItem>(null);
|
|
|
|
const query = reactive({ page: 1, size: 10, keyword: '' });
|
|
const pagination = reactive({ current: 1, pageSize: 10, total: 0 });
|
|
const form = reactive({
|
|
code: '',
|
|
name: '',
|
|
status: 1,
|
|
menuIds: [] as number[],
|
|
});
|
|
|
|
function toTree(nodes: MenuNode[]): any[] {
|
|
return (nodes ?? []).map((n) => ({
|
|
label: n.name,
|
|
value: n.id,
|
|
children: n.children?.length ? toTree(n.children) : undefined,
|
|
}));
|
|
}
|
|
|
|
async function load() {
|
|
loading.value = true;
|
|
try {
|
|
const data = await getRoleList(query);
|
|
list.value = data.list ?? [];
|
|
pagination.total = data.total ?? 0;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function loadMenus() {
|
|
const data = await getMenuTree();
|
|
menuTree.value = toTree(data.tree ?? []);
|
|
}
|
|
|
|
function openCreate() {
|
|
editing.value = null;
|
|
Object.assign(form, { code: '', name: '', status: 1, menuIds: [] });
|
|
dialogOpen.value = true;
|
|
}
|
|
|
|
function openEdit(row: RoleItem) {
|
|
editing.value = row;
|
|
Object.assign(form, {
|
|
code: row.code,
|
|
name: row.name,
|
|
status: row.status,
|
|
menuIds: row.menuIds ?? [],
|
|
});
|
|
dialogOpen.value = true;
|
|
}
|
|
|
|
async function submit() {
|
|
if (editing.value) {
|
|
await updateRole(editing.value.id, {
|
|
name: form.name,
|
|
status: form.status,
|
|
menuIds: form.menuIds,
|
|
});
|
|
} else {
|
|
await createRole({
|
|
code: form.code,
|
|
name: form.name,
|
|
status: form.status,
|
|
menuIds: form.menuIds,
|
|
});
|
|
}
|
|
MessagePlugin.success('保存成功');
|
|
dialogOpen.value = false;
|
|
load();
|
|
}
|
|
|
|
function onDelete(row: RoleItem) {
|
|
const d = DialogPlugin.confirm({
|
|
header: `确认删除角色「${row.name}」?`,
|
|
onConfirm: async () => {
|
|
await deleteRole(row.id);
|
|
MessagePlugin.success('删除成功');
|
|
load();
|
|
d.destroy();
|
|
},
|
|
});
|
|
}
|
|
|
|
const columns = [
|
|
{ colKey: 'id', title: 'ID', width: 70 },
|
|
{ colKey: 'code', title: '角色编码' },
|
|
{ colKey: 'name', title: '角色名称' },
|
|
{ colKey: 'statusText', title: '状态', width: 90 },
|
|
{ colKey: 'createdAt', title: '创建时间', width: 170 },
|
|
{ colKey: 'op', title: '操作', width: 150 },
|
|
];
|
|
|
|
function onPageChange(p: { current: number; pageSize: number }) {
|
|
query.page = p.current;
|
|
query.size = p.pageSize;
|
|
pagination.current = p.current;
|
|
pagination.pageSize = p.pageSize;
|
|
load();
|
|
}
|
|
|
|
onMounted(() => {
|
|
load();
|
|
loadMenus();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Page auto-content-height>
|
|
<div class="wb-page-head">
|
|
<h2 class="wb-page-title">角色管理</h2>
|
|
<p class="wb-page-sub">维护角色及其菜单权限</p>
|
|
</div>
|
|
|
|
<t-card :bordered="false" class="wb-filter-card">
|
|
<div class="mb-3 flex items-center justify-between">
|
|
<div class="flex items-center gap-2">
|
|
<t-input
|
|
v-model="query.keyword"
|
|
clearable
|
|
placeholder="角色编码/名称"
|
|
style="width: 220px"
|
|
@enter="load"
|
|
/>
|
|
<t-button theme="primary" @click="load">查询</t-button>
|
|
</div>
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:role:create'])"
|
|
theme="primary"
|
|
@click="openCreate"
|
|
>
|
|
新增角色
|
|
</t-button>
|
|
</div>
|
|
</t-card>
|
|
|
|
<t-card :bordered="false" class="wb-table-card">
|
|
<t-table
|
|
row-key="id"
|
|
:data="list"
|
|
:columns="columns"
|
|
:loading="loading"
|
|
:pagination="pagination"
|
|
@page-change="onPageChange"
|
|
>
|
|
<template #statusText="{ row }">
|
|
{{
|
|
row.status === 1 ? '启用' : '禁用'
|
|
}}
|
|
</template>
|
|
<template #op="{ row }">
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:role:update'])"
|
|
size="small"
|
|
theme="primary"
|
|
variant="text"
|
|
@click="openEdit(row)"
|
|
>
|
|
编辑
|
|
</t-button>
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:role:delete'])"
|
|
size="small"
|
|
theme="danger"
|
|
variant="text"
|
|
@click="onDelete(row)"
|
|
>
|
|
删除
|
|
</t-button>
|
|
</template>
|
|
</t-table>
|
|
</t-card>
|
|
|
|
<t-dialog
|
|
v-model:visible="dialogOpen"
|
|
:header="editing ? '编辑角色' : '新增角色'"
|
|
width="560px"
|
|
:on-confirm="submit"
|
|
>
|
|
<t-form label-align="right" label-width="80px">
|
|
<t-form-item label="角色编码" required>
|
|
<t-input
|
|
v-model="form.code"
|
|
:disabled="!!editing"
|
|
placeholder="如 super_admin"
|
|
/>
|
|
</t-form-item>
|
|
<t-form-item label="角色名称" required>
|
|
<t-input v-model="form.name" placeholder="显示名称" />
|
|
</t-form-item>
|
|
<t-form-item label="状态">
|
|
<t-switch v-model="form.status" :custom-value="[1, 0]" />
|
|
</t-form-item>
|
|
<t-form-item label="菜单权限">
|
|
<t-tree
|
|
v-model="form.menuIds"
|
|
:data="menuTree"
|
|
checkable
|
|
:expand-all="true"
|
|
value-mode="all"
|
|
:keys="{ value: 'value', label: 'label', children: 'children' }"
|
|
/>
|
|
</t-form-item>
|
|
</t-form>
|
|
</t-dialog>
|
|
</Page>
|
|
</template>
|