Archived
forked from admin/userbase
init: UserBaseFront (frontend)
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div class="page-wrapper tree-wrapper">
|
||||
<Group class="tree-container" v-model:curTreeNode="selectedNode" :treeApi="treeApi" @on-change="onTreeChange"
|
||||
@on-tree-data="onTreeData" />
|
||||
<div class="main-container">
|
||||
<div class="search-wrap">
|
||||
<Button type="primary" @click="showAddUser">
|
||||
<Icon type="md-add" style="margin-right: 4px" />新增用户
|
||||
</Button>
|
||||
|
||||
<Input placeholder="输入用户名 / 真实姓名搜索" class="fr" search clearable suffix="ios-search" style="width: 220px"
|
||||
v-model="keyword" @on-search="onSearch" @on-clear="onSearch" />
|
||||
</div>
|
||||
|
||||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" :tableHeight="tableHeight" />
|
||||
|
||||
<!-- 容器组件:新增 / 编辑 -->
|
||||
<AddUserContainer ref="addRef" />
|
||||
<EditUserContainer ref="editRef" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from "vue";
|
||||
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import TablePageAlovaNew from '@/components/TablePageAlovaNew.vue';
|
||||
import { OperatorEnum } from '@/types';
|
||||
import Group from './group/index.vue'
|
||||
import AddUserContainer from './user/AddUserContainer.vue';
|
||||
import EditUserContainer from './user/EditUserContainer.vue';
|
||||
|
||||
defineOptions({ name: "GroupUser" });
|
||||
|
||||
const { $utils } = useCurrentInstance();
|
||||
|
||||
const treeApi = () => Apis.SysGroup.getTree();
|
||||
|
||||
/* ================= 组织树 ================= */
|
||||
const selectedNode = ref<any>({})
|
||||
const treeData = ref<any[]>([])
|
||||
|
||||
function onTreeChange(node: any) {
|
||||
selectedNode.value = node;
|
||||
dataParams.value.groupId = node?.id ?? null;
|
||||
tableRef.value?.refreshData();
|
||||
}
|
||||
function onTreeData(tree: any[]) {
|
||||
treeData.value = tree;
|
||||
}
|
||||
function onSearch() {
|
||||
dataParams.value.name = keyword.value.trim() || undefined;
|
||||
tableRef.value?.refreshData();
|
||||
}
|
||||
|
||||
/* ================= 所在组下拉(拍平组织树) ================= */
|
||||
const groupOptions = computed(() => {
|
||||
const flat: { id: number; name: string }[] = [];
|
||||
const walk = (list: any[], prefix = '') => {
|
||||
list.forEach(n => {
|
||||
flat.push({ id: n.id, name: prefix ? `${prefix} / ${n.name}` : n.name });
|
||||
if (n.children?.length) walk(n.children, prefix ? `${prefix} / ${n.name}` : n.name);
|
||||
});
|
||||
};
|
||||
walk(treeData.value);
|
||||
return flat;
|
||||
})
|
||||
|
||||
/* ================= 表格数据源 ================= */
|
||||
const tableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||
const keyword = ref('')
|
||||
const dataParams = ref<{
|
||||
name: string | undefined;
|
||||
groupId: number | null;
|
||||
}>({
|
||||
name: undefined,
|
||||
groupId: null,
|
||||
});
|
||||
|
||||
const tableApi = (params: { pageIndex: number; pageSize: number }) => {
|
||||
return Apis.SysUser.list({
|
||||
params: {
|
||||
name: dataParams.value.name,
|
||||
groupId: dataParams.value.groupId ?? undefined,
|
||||
// 选中组织时包含子组用户;未选中时不传
|
||||
withSub: dataParams.value.groupId != null ? 1 : undefined,
|
||||
pageIndex: params.pageIndex,
|
||||
pageSize: params.pageSize,
|
||||
},
|
||||
cacheFor: null,
|
||||
});
|
||||
};
|
||||
|
||||
const tableHeight = ref($utils.useTableHeight({ isOperat: false, isPage: true, isSearch: true }))
|
||||
|
||||
/* ================= 用户身份(roles[])展示 ================= */
|
||||
const userTypeMap: Record<number, string> = {
|
||||
1: '管理员', 2: '老师', 3: '校领导', 4: '局领导',
|
||||
5: '学生', 6: '家长', 7: '工作号',
|
||||
};
|
||||
const roleMap: Record<number, string> = {
|
||||
1: '超级管理员', 2: '学校管理员', 3: '普通用户',
|
||||
};
|
||||
function describeRoles(roles: any): string {
|
||||
if (!Array.isArray(roles) || roles.length === 0) return '-';
|
||||
const userTypes: string[] = [];
|
||||
const specificRoles: string[] = [];
|
||||
roles.forEach((r: any) => {
|
||||
const n = Number(r);
|
||||
if (userTypeMap[n]) userTypes.push(userTypeMap[n]);
|
||||
else if (roleMap[n]) specificRoles.push(roleMap[n]);
|
||||
});
|
||||
const parts: string[] = [];
|
||||
if (userTypes.length) parts.push(userTypes.join('/'));
|
||||
if (specificRoles.length) parts.push(specificRoles.join('/'));
|
||||
return parts.length ? parts.join(' · ') : '-';
|
||||
}
|
||||
|
||||
/* ================= 表格列 ================= */
|
||||
const columns = [
|
||||
{ type: 'index', title: '序号', width: 70, align: 'center' },
|
||||
{ title: '用户名', key: 'account', minWidth: 120 },
|
||||
{ title: '真实姓名', key: 'realName', minWidth: 120 },
|
||||
{ title: '手机号', key: 'phone', minWidth: 140 },
|
||||
{
|
||||
title: '用户身份', key: 'roles', minWidth: 180,
|
||||
render: (h: any, { row }: any) => h('span', describeRoles(row.roles)),
|
||||
},
|
||||
{
|
||||
title: '状态', key: 'disabled', width: 90, align: 'center',
|
||||
render: (h: any, { row }: any) =>
|
||||
h('Tag', { color: row.disabled ? 'default' : 'success' },
|
||||
row.disabled ? '已禁用' : '启用'),
|
||||
},
|
||||
{
|
||||
title: '操作', key: 'action', width: 220, align: 'center', fixed: 'right' as const,
|
||||
render: (h: any, { row }: any) => {
|
||||
const opList: any[] = [
|
||||
h('a', {
|
||||
style: { marginRight: '8px', color: '#577afb' },
|
||||
onClick: () => handleEdit(row),
|
||||
}, '编辑'),
|
||||
h('a', {
|
||||
style: { marginRight: '8px', color: '#ed4014' },
|
||||
onClick: () => handleDelete(row),
|
||||
}, '删除'),
|
||||
h('a', {
|
||||
style: { color: row.disabled ? '#19be6b' : '#ff9900' },
|
||||
onClick: () => handleToggleStatus(row),
|
||||
}, row.disabled ? '启用' : '禁用'),
|
||||
];
|
||||
return h('div', opList);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/* ================= 新增 ================= */
|
||||
const addRef = ref();
|
||||
function showAddUser() {
|
||||
const curGroupId = selectedNode.value?.id ?? null;
|
||||
addRef.value?.open(groupOptions.value, curGroupId, () => {
|
||||
tableRef.value?.reloadData(OperatorEnum.add);
|
||||
});
|
||||
}
|
||||
|
||||
/* ================= 编辑 ================= */
|
||||
const editRef = ref();
|
||||
function handleEdit(row: any) {
|
||||
editRef.value?.open(row, groupOptions.value, () => {
|
||||
tableRef.value?.reloadData(OperatorEnum.edit);
|
||||
});
|
||||
}
|
||||
|
||||
/* ================= 删除 ================= */
|
||||
async function handleDelete(row: any) {
|
||||
await MyConfirm({
|
||||
msg: `确定删除用户「${row.realName || row.account}」吗?`,
|
||||
info: '删除后不可恢复!',
|
||||
async onOk() {
|
||||
try {
|
||||
await Apis.SysUser.delete({ pathParams: { id: row.id } });
|
||||
Message.success('删除成功!');
|
||||
tableRef.value?.reloadData(OperatorEnum.del);
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || '删除失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/* ================= 禁用 / 启用 ================= */
|
||||
async function handleToggleStatus(row: any) {
|
||||
const isDisabled = !!row.disabled;
|
||||
await MyConfirm({
|
||||
msg: `确定要${isDisabled ? '启用' : '禁用'}用户「${row.realName || row.account}」吗?`,
|
||||
async onOk() {
|
||||
try {
|
||||
if (isDisabled) {
|
||||
await Apis.SysUser.enable({ pathParams: { id: row.id } });
|
||||
} else {
|
||||
await Apis.SysUser.disable({ pathParams: { id: row.id } });
|
||||
}
|
||||
Message.success(isDisabled ? '已启用!' : '已禁用!');
|
||||
tableRef.value?.reloadData(OperatorEnum.sel);
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || '操作失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
Reference in New Issue
Block a user