🔱: [client] sync upgrade with 21 commits [trident-sync]

'admin-22.12.12:发布v2.4.21版本,具体更新内容查看CHANGELOG.md'
!42 修复 工作流无法添加新节点问题
Merge pull request !42 from beta/bugfix_workflow
修复 工作流无法添加新节点问题

1. 修复 工作流无法添加新节点问题
2. 修复 左侧导航无法隐藏问题
'admin-22.12.09:发布v2.4.2版本,具体更新内容查看CHANGELOG.md'
!41 修复get请求传递嵌套对象或数组时无法正常编码问题
Merge pull request !41 from 随心/master
!40 开启TagsView缓存后,刷新后所有的路由都变成组件缓存了
Merge pull request !40 from mrjimin/master
修复get请求传递嵌套对象或数组时无法正常编码问题
update src/layout/routerView/parent.vue.

Signed-off-by: mrjimin <z8888788@163.com>
update src/layout/routerView/parent.vue.
这里应该拿到的是已经设置开启组件缓存的路由,而不是全部,需要先判断item.meta.isKeepAlive

Signed-off-by: mrjimin <z8888788@163.com>
'admin-22.11.30:发布v2.4.1版本,具体更新内容查看CHANGELOG.md'
Merge branch 'master' of https://gitee.com/lyt-top/vue-next-admin
'admin-22.11.30:删除v2.4.0版本不需要的依赖'
update src/views/error/404.vue.

Signed-off-by: lyt-Top <1105290566@qq.com>
update src/components/table/index.vue.

Signed-off-by: lyt-Top <1105290566@qq.com>
'admin-22.11.30:修改v2.4.0文字说明'
'admin-22.11.30:修改v2.4.0文字说明'
'admin-22.11.29:发布v2.4.0版本,具体更新内容查看CHANGELOG.md'
'admin-22.11.19:修复v2.3.0版本动态路由事件调用关闭当前tagsview、普通路由刷新界面参数丢失问题'
'admin-22.11.18:优化v2.3.0版本tagsview风格5兼容火狐'
'admin-22.11.17:优化v2.3.0版本iframe右键菜单刷新问题'
...
This commit is contained in:
H0nGzA1
2023-02-13 00:17:30 +08:00
parent 8e5fba2532
commit 80323dd641
228 changed files with 35680 additions and 25 deletions

View File

@@ -0,0 +1,167 @@
<template>
<div class="system-dept-dialog-container">
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
<el-form ref="deptDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
<el-row :gutter="35">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="上级部门">
<el-cascader
:options="state.deptData"
:props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }"
placeholder="请选择部门"
clearable
class="w100"
v-model="state.ruleForm.deptLevel"
>
<template #default="{ node, data }">
<span>{{ data.deptName }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="部门名称">
<el-input v-model="state.ruleForm.deptName" placeholder="请输入部门名称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="负责人">
<el-input v-model="state.ruleForm.person" placeholder="请输入负责人" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="手机号">
<el-input v-model="state.ruleForm.phone" placeholder="请输入手机号" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="邮箱">
<el-input v-model="state.ruleForm.email" placeholder="请输入" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="排序">
<el-input-number v-model="state.ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="部门状态">
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="部门描述">
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入部门描述" maxlength="150"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel" size="default"> </el-button>
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="systemDeptDialog">
import { reactive, ref } from 'vue';
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
// 定义变量内容
const deptDialogFormRef = ref();
const state = reactive({
ruleForm: {
deptLevel: [] as string[], // 上级部门
deptName: '', // 部门名称
person: '', // 负责人
phone: '', // 手机号
email: '', // 邮箱
sort: 0, // 排序
status: true, // 部门状态
describe: '', // 部门描述
},
deptData: [] as DeptTreeType[], // 部门数据
dialog: {
isShowDialog: false,
type: '',
title: '',
submitTxt: '',
},
});
// 打开弹窗
const openDialog = (type: string, row: RowDeptType) => {
if (type === 'edit') {
row.deptLevel = ['vueNextAdmin'];
row.person = 'lyt';
row.phone = '12345678910';
row.email = 'vueNextAdmin@123.com';
state.ruleForm = row;
state.dialog.title = '修改部门';
state.dialog.submitTxt = '修 改';
} else {
state.dialog.title = '新增部门';
state.dialog.submitTxt = '新 增';
// 清空表单,此项需加表单验证才能使用
// nextTick(() => {
// deptDialogFormRef.value.resetFields();
// });
}
state.dialog.isShowDialog = true;
getMenuData();
};
// 关闭弹窗
const closeDialog = () => {
state.dialog.isShowDialog = false;
};
// 取消
const onCancel = () => {
closeDialog();
};
// 提交
const onSubmit = () => {
closeDialog();
emit('refresh');
// if (state.dialog.type === 'add') { }
};
// 初始化部门数据
const getMenuData = () => {
state.deptData.push({
deptName: 'vueNextAdmin',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '顶级部门',
id: Math.random(),
children: [
{
deptName: 'IT外包服务',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '总部',
id: Math.random(),
},
{
deptName: '资本控股',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '分部',
id: Math.random(),
},
],
});
};
// 暴露变量
defineExpose({
openDialog,
});
</script>

View File

@@ -0,0 +1,135 @@
<template>
<div class="system-dept-container layout-padding">
<el-card shadow="hover" class="layout-padding-auto">
<div class="system-dept-search mb15">
<el-input size="default" placeholder="请输入部门名称" style="max-width: 180px"> </el-input>
<el-button size="default" type="primary" class="ml10">
<el-icon>
<ele-Search />
</el-icon>
查询
</el-button>
<el-button size="default" type="success" class="ml10" @click="onOpenAddDept('add')">
<el-icon>
<ele-FolderAdd />
</el-icon>
新增部门
</el-button>
</div>
<el-table
:data="state.tableData.data"
v-loading="state.tableData.loading"
style="width: 100%"
row-key="id"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="deptName" label="部门名称" show-overflow-tooltip> </el-table-column>
<el-table-column label="排序" show-overflow-tooltip width="80">
<template #default="scope">
{{ scope.$index }}
</template>
</el-table-column>
<el-table-column prop="status" label="部门状态" show-overflow-tooltip>
<template #default="scope">
<el-tag type="success" v-if="scope.row.status">启用</el-tag>
<el-tag type="info" v-else>禁用</el-tag>
</template>
</el-table-column>
<el-table-column prop="describe" label="部门描述" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" show-overflow-tooltip width="140">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenAddDept('add')">新增</el-button>
<el-button size="small" text type="primary" @click="onOpenEditDept('edit', scope.row)">修改</el-button>
<el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<DeptDialog ref="deptDialogRef" @refresh="getTableData()" />
</div>
</template>
<script setup lang="ts" name="systemDept">
import { defineAsyncComponent, ref, reactive, onMounted } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
// 引入组件
const DeptDialog = defineAsyncComponent(() => import('/@/views/system/dept/dialog.vue'));
// 定义变量内容
const deptDialogRef = ref();
const state = reactive<SysDeptState>({
tableData: {
data: [],
total: 0,
loading: false,
param: {
pageNum: 1,
pageSize: 10,
},
},
});
// 初始化表格数据
const getTableData = () => {
state.tableData.loading = true;
state.tableData.data = [];
state.tableData.data.push({
deptName: 'vueNextAdmin',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '顶级部门',
id: Math.random(),
children: [
{
deptName: 'IT外包服务',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '总部',
id: Math.random(),
},
{
deptName: '资本控股',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '分部',
id: Math.random(),
},
],
});
state.tableData.total = state.tableData.data.length;
setTimeout(() => {
state.tableData.loading = false;
}, 500);
};
// 打开新增菜单弹窗
const onOpenAddDept = (type: string) => {
deptDialogRef.value.openDialog(type);
};
// 打开编辑菜单弹窗
const onOpenEditDept = (type: string, row: DeptTreeType) => {
deptDialogRef.value.openDialog(type, row);
};
// 删除当前行
const onTabelRowDel = (row: DeptTreeType) => {
ElMessageBox.confirm(`此操作将永久删除部门:${row.deptName}, 是否继续?`, '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
getTableData();
ElMessage.success('删除成功');
})
.catch(() => {});
};
// 页面加载时
onMounted(() => {
getTableData();
});
</script>

View File

@@ -0,0 +1,150 @@
<template>
<div class="system-dic-dialog-container">
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
<el-alert title="半成品,交互过于复杂,请自行扩展!" type="warning" :closable="false" class="mb20"> </el-alert>
<el-form ref="dicDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="字典名称">
<el-input v-model="state.ruleForm.dicName" placeholder="请输入字典名称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="字段名">
<el-input v-model="state.ruleForm.fieldName" placeholder="请输入字段名,拼接 ruleForm.list" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="字典状态">
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-row :gutter="35" v-for="(v, k) in state.ruleForm.list" :key="k">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item :prop="`list[${k}].label`">
<template #label>
<el-button type="primary" circle size="small" @click="onAddRow" v-if="k === 0">
<el-icon>
<ele-Plus />
</el-icon>
</el-button>
<el-button type="danger" circle size="small" @click="onDelRow(k)" v-else>
<el-icon>
<ele-Delete />
</el-icon>
</el-button>
<span class="ml10">字段</span>
</template>
<el-input v-model="v.label" style="width: 100%" placeholder="请输入字段名"> </el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="属性" :prop="`list[${k}].value`">
<el-input v-model="v.value" style="width: 100%" placeholder="请输入属性值"> </el-input>
</el-form-item>
</el-col>
</el-row>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="字典描述">
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入字典描述" maxlength="150"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel" size="default"> </el-button>
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="systemDicDialog">
import { reactive, ref } from 'vue';
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
// 定义变量内容
const dicDialogFormRef = ref();
const state = reactive({
ruleForm: {
dicName: '', // 字典名称
fieldName: '', // 字段名
status: true, // 字典状态
list: [] as ListType[], // 子集字段 + 属性值
describe: '', // 字典描述
},
dialog: {
isShowDialog: false,
type: '',
title: '',
submitTxt: '',
},
});
// 打开弹窗
const openDialog = (type: string, row: RowDicType) => {
if (type === 'edit') {
if (row.fieldName === 'SYS_UERINFO') {
row.list = [
{ id: Math.random(), label: 'sex', value: '1' },
{ id: Math.random(), label: 'sex', value: '0' },
];
} else {
row.list = [
{ id: Math.random(), label: 'role', value: 'admin' },
{ id: Math.random(), label: 'role', value: 'common' },
{ id: Math.random(), label: 'roleName', value: '超级管理员' },
{ id: Math.random(), label: 'roleName', value: '普通用户' },
];
}
state.ruleForm = row;
state.dialog.title = '修改字典';
state.dialog.submitTxt = '修 改';
} else {
state.dialog.title = '新增字典';
state.dialog.submitTxt = '新 增';
// 清空表单,此项需加表单验证才能使用
// nextTick(() => {
// dicDialogFormRef.value.resetFields();
// });
}
state.dialog.isShowDialog = true;
};
// 关闭弹窗
const closeDialog = () => {
state.dialog.isShowDialog = false;
};
// 取消
const onCancel = () => {
closeDialog();
};
// 提交
const onSubmit = () => {
closeDialog();
emit('refresh');
// if (state.dialog.type === 'add') { }
};
// 新增行
const onAddRow = () => {
state.ruleForm.list.push({
id: Math.random(),
label: '',
value: '',
});
};
// 删除行
const onDelRow = (k: number) => {
state.ruleForm.list.splice(k, 1);
};
// 暴露变量
defineExpose({
openDialog,
});
</script>

View File

@@ -0,0 +1,132 @@
<template>
<div class="system-dic-container layout-padding">
<el-card shadow="hover" class="layout-padding-auto">
<div class="system-user-search mb15">
<el-input size="default" placeholder="请输入字典名称" style="max-width: 180px"> </el-input>
<el-button size="default" type="primary" class="ml10">
<el-icon>
<ele-Search />
</el-icon>
查询
</el-button>
<el-button size="default" type="success" class="ml10" @click="onOpenAddDic('add')">
<el-icon>
<ele-FolderAdd />
</el-icon>
新增字典
</el-button>
</div>
<el-table :data="state.tableData.data" v-loading="state.tableData.loading" style="width: 100%">
<el-table-column type="index" label="序号" width="50" />
<el-table-column prop="dicName" label="字典名称" show-overflow-tooltip></el-table-column>
<el-table-column prop="fieldName" label="字段名" show-overflow-tooltip></el-table-column>
<el-table-column prop="status" label="字典状态" show-overflow-tooltip>
<template #default="scope">
<el-tag type="success" v-if="scope.row.status">启用</el-tag>
<el-tag type="info" v-else>禁用</el-tag>
</template>
</el-table-column>
<el-table-column prop="describe" label="字典描述" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenEditDic('edit', scope.row)">修改</el-button>
<el-button size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="onHandleSizeChange"
@current-change="onHandleCurrentChange"
class="mt15"
:pager-count="5"
:page-sizes="[10, 20, 30]"
v-model:current-page="state.tableData.param.pageNum"
background
v-model:page-size="state.tableData.param.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="state.tableData.total"
>
</el-pagination>
</el-card>
<DicDialog ref="dicDialogRef" @refresh="getTableData()" />
</div>
</template>
<script setup lang="ts" name="systemDic">
import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
// 引入组件
const DicDialog = defineAsyncComponent(() => import('/@/views/system/dic/dialog.vue'));
// 定义变量内容
const dicDialogRef = ref();
const state = reactive<SysDicState>({
tableData: {
data: [],
total: 0,
loading: false,
param: {
pageNum: 1,
pageSize: 10,
},
},
});
// 初始化表格数据
const getTableData = () => {
state.tableData.loading = true;
const data = [];
for (let i = 0; i < 2; i++) {
data.push({
dicName: i === 0 ? '角色标识' : '用户性别',
fieldName: i === 0 ? 'SYS_ROLE' : 'SYS_UERINFO',
describe: i === 0 ? '这是角色字典' : '这是用户性别字典',
status: true,
createTime: new Date().toLocaleString(),
list: [],
});
}
state.tableData.data = data;
state.tableData.total = state.tableData.data.length;
setTimeout(() => {
state.tableData.loading = false;
}, 500);
};
// 打开新增字典弹窗
const onOpenAddDic = (type: string) => {
dicDialogRef.value.openDialog(type);
};
// 打开修改字典弹窗
const onOpenEditDic = (type: string, row: RowDicType) => {
dicDialogRef.value.openDialog(type, row);
};
// 删除字典
const onRowDel = (row: RowDicType) => {
ElMessageBox.confirm(`此操作将永久删除字典名称:“${row.dicName}”,是否继续?`, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
getTableData();
ElMessage.success('删除成功');
})
.catch(() => {});
};
// 分页改变
const onHandleSizeChange = (val: number) => {
state.tableData.param.pageSize = val;
getTableData();
};
// 分页改变
const onHandleCurrentChange = (val: number) => {
state.tableData.param.pageNum = val;
getTableData();
};
// 页面加载时
onMounted(() => {
getTableData();
});
</script>

View File

@@ -0,0 +1,260 @@
<template>
<div class="system-menu-dialog-container">
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
<el-form ref="menuDialogFormRef" :model="state.ruleForm" size="default" label-width="80px">
<el-row :gutter="35">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="上级菜单">
<el-cascader
:options="state.menuData"
:props="{ checkStrictly: true, value: 'path', label: 'title' }"
placeholder="请选择上级菜单"
clearable
class="w100"
v-model="state.ruleForm.menuSuperior"
>
<template #default="{ node, data }">
<span>{{ data.title }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="菜单类型">
<el-radio-group v-model="state.ruleForm.menuType">
<el-radio label="menu">菜单</el-radio>
<el-radio label="btn">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="菜单名称">
<el-input v-model="state.ruleForm.meta.title" placeholder="格式message.router.xxx" clearable></el-input>
</el-form-item>
</el-col>
<template v-if="state.ruleForm.menuType === 'menu'">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="路由名称">
<el-input v-model="state.ruleForm.name" placeholder="路由中的 name 值" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="路由路径">
<el-input v-model="state.ruleForm.path" placeholder="路由中的 path 值" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="重定向">
<el-input v-model="state.ruleForm.redirect" placeholder="请输入路由重定向" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="菜单图标">
<IconSelector placeholder="请输入菜单图标" v-model="state.ruleForm.meta.icon" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="组件路径">
<el-input v-model="state.ruleForm.component" placeholder="组件路径" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="链接地址">
<el-input
v-model="state.ruleForm.meta.isLink"
placeholder="外链/内嵌时链接地址http:xxx.com"
clearable
:disabled="!state.ruleForm.isLink"
>
</el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="权限标识">
<el-select v-model="state.ruleForm.meta.roles" multiple placeholder="取角色管理" clearable class="w100">
<el-option label="admin" value="admin"></el-option>
<el-option label="common" value="common"></el-option>
</el-select>
</el-form-item>
</el-col>
</template>
<template v-if="state.ruleForm.menuType === 'btn'">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="权限标识">
<el-input v-model="state.ruleForm.btnPower" placeholder="请输入权限标识" clearable></el-input>
</el-form-item>
</el-col>
</template>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="菜单排序">
<el-input-number v-model="state.ruleForm.menuSort" controls-position="right" placeholder="请输入排序" class="w100" />
</el-form-item>
</el-col>
<template v-if="state.ruleForm.menuType === 'menu'">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="是否隐藏">
<el-radio-group v-model="state.ruleForm.meta.isHide">
<el-radio :label="true">隐藏</el-radio>
<el-radio :label="false">不隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="页面缓存">
<el-radio-group v-model="state.ruleForm.meta.isKeepAlive">
<el-radio :label="true">缓存</el-radio>
<el-radio :label="false">不缓存</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="是否固定">
<el-radio-group v-model="state.ruleForm.meta.isAffix">
<el-radio :label="true">固定</el-radio>
<el-radio :label="false">不固定</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="是否外链">
<el-radio-group v-model="state.ruleForm.isLink" :disabled="state.ruleForm.meta.isIframe">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="是否内嵌">
<el-radio-group v-model="state.ruleForm.meta.isIframe" @change="onSelectIframeChange">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel" size="default"> </el-button>
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="systemMenuDialog">
import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useRoutesList } from '/@/stores/routesList';
import { i18n } from '/@/i18n/index';
// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
// 引入组件
const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
// 定义变量内容
const menuDialogFormRef = ref();
const stores = useRoutesList();
const { routesList } = storeToRefs(stores);
const state = reactive({
// 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式
ruleForm: {
menuSuperior: [], // 上级菜单
menuType: 'menu', // 菜单类型
name: '', // 路由名称
component: '', // 组件路径
isLink: false, // 是否外链
menuSort: 0, // 菜单排序
path: '', // 路由路径
redirect: '', // 路由重定向,有子集 children 时
meta: {
title: '', // 菜单名称
icon: '', // 菜单图标
isHide: false, // 是否隐藏
isKeepAlive: true, // 是否缓存
isAffix: false, // 是否固定
isLink: '', // 外链/内嵌时链接地址http:xxx.com开启外链条件`1、isLink: 链接地址不为空`
isIframe: false, // 是否内嵌,开启条件,`1、isIframe:true 2、isLink链接地址不为空`
roles: '', // 权限标识,取角色管理
},
btnPower: '', // 菜单类型为按钮时,权限标识
},
menuData: [] as RouteItems, // 上级菜单数据
dialog: {
isShowDialog: false,
type: '',
title: '',
submitTxt: '',
},
});
// 获取 pinia 中的路由
const getMenuData = (routes: RouteItems) => {
const arr: RouteItems = [];
routes.map((val: RouteItem) => {
val['title'] = i18n.global.t(val.meta?.title as string);
arr.push({ ...val });
if (val.children) getMenuData(val.children);
});
return arr;
};
// 打开弹窗
const openDialog = (type: string, row?: any) => {
if (type === 'edit') {
// 模拟数据,实际请走接口
row.menuType = 'menu';
row.menuSort = Math.random();
row.component = `${row.component} `
.match(/\'(.+)\'/g)
?.join('')
.replace(/\'/g, '');
state.ruleForm = row;
state.dialog.title = '修改菜单';
state.dialog.submitTxt = '修 改';
} else {
state.dialog.title = '新增菜单';
state.dialog.submitTxt = '新 增';
// 清空表单,此项需加表单验证才能使用
// nextTick(() => {
// menuDialogFormRef.value.resetFields();
// });
}
state.dialog.type = type;
state.dialog.isShowDialog = true;
};
// 关闭弹窗
const closeDialog = () => {
state.dialog.isShowDialog = false;
};
// 是否内嵌下拉改变
const onSelectIframeChange = () => {
if (state.ruleForm.meta.isIframe) state.ruleForm.isLink = true;
else state.ruleForm.isLink = false;
};
// 取消
const onCancel = () => {
closeDialog();
};
// 提交
const onSubmit = () => {
closeDialog(); // 关闭弹窗
emit('refresh');
// if (state.dialog.type === 'add') { }
// setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试
};
// 页面加载时
onMounted(() => {
state.menuData = getMenuData(routesList.value);
});
// 暴露变量
defineExpose({
openDialog,
});
</script>

View File

@@ -0,0 +1,122 @@
<template>
<div class="system-menu-container layout-pd">
<el-card shadow="hover">
<div class="system-menu-search mb15">
<el-input size="default" placeholder="请输入菜单名称" style="max-width: 180px"> </el-input>
<el-button size="default" type="primary" class="ml10">
<el-icon>
<ele-Search />
</el-icon>
查询
</el-button>
<el-button size="default" type="success" class="ml10" @click="onOpenAddMenu">
<el-icon>
<ele-FolderAdd />
</el-icon>
新增菜单
</el-button>
</div>
<el-table
:data="state.tableData.data"
v-loading="state.tableData.loading"
style="width: 100%"
row-key="path"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column label="菜单名称" show-overflow-tooltip>
<template #default="scope">
<SvgIcon :name="scope.row.meta.icon" />
<span class="ml10">{{ $t(scope.row.meta.title) }}</span>
</template>
</el-table-column>
<el-table-column prop="path" label="路由路径" show-overflow-tooltip></el-table-column>
<el-table-column label="组件路径" show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row.component }}</span>
</template>
</el-table-column>
<el-table-column label="权限标识" show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row.meta.roles }}</span>
</template>
</el-table-column>
<el-table-column label="排序" show-overflow-tooltip width="80">
<template #default="scope">
{{ scope.$index }}
</template>
</el-table-column>
<el-table-column label="类型" show-overflow-tooltip width="80">
<template #default="scope">
<el-tag type="success" size="small">{{ scope.row.xx }}菜单</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" show-overflow-tooltip width="140">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenAddMenu('add')">新增</el-button>
<el-button size="small" text type="primary" @click="onOpenEditMenu('edit', scope.row)">修改</el-button>
<el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<MenuDialog ref="menuDialogRef" @refresh="getTableData()" />
</div>
</template>
<script setup lang="ts" name="systemMenu">
import { defineAsyncComponent, ref, onMounted, reactive } from 'vue';
import { RouteRecordRaw } from 'vue-router';
import { ElMessageBox, ElMessage } from 'element-plus';
import { storeToRefs } from 'pinia';
import { useRoutesList } from '/@/stores/routesList';
// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
// 引入组件
const MenuDialog = defineAsyncComponent(() => import('/@/views/system/menu/dialog.vue'));
// 定义变量内容
const stores = useRoutesList();
const { routesList } = storeToRefs(stores);
const menuDialogRef = ref();
const state = reactive({
tableData: {
data: [] as RouteRecordRaw[],
loading: true,
},
});
// 获取路由数据,真实请从接口获取
const getTableData = () => {
state.tableData.loading = true;
state.tableData.data = routesList.value;
setTimeout(() => {
state.tableData.loading = false;
}, 500);
};
// 打开新增菜单弹窗
const onOpenAddMenu = (type: string) => {
menuDialogRef.value.openDialog(type);
};
// 打开编辑菜单弹窗
const onOpenEditMenu = (type: string, row: RouteRecordRaw) => {
menuDialogRef.value.openDialog(type, row);
};
// 删除当前行
const onTabelRowDel = (row: RouteRecordRaw) => {
ElMessageBox.confirm(`此操作将永久删除路由:${row.path}, 是否继续?`, '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
ElMessage.success('删除成功');
getTableData();
//await setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试
})
.catch(() => {});
};
// 页面加载时
onMounted(() => {
getTableData();
});
</script>

View File

@@ -0,0 +1,236 @@
<template>
<div class="system-role-dialog-container">
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
<el-form ref="roleDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="角色名称">
<el-input v-model="state.ruleForm.roleName" placeholder="请输入角色名称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="角色标识">
<template #label>
<el-tooltip effect="dark" content="用于 `router/route.ts` meta.roles" placement="top-start">
<span>角色标识</span>
</el-tooltip>
</template>
<el-input v-model="state.ruleForm.roleSign" placeholder="请输入角色标识" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="排序">
<el-input-number v-model="state.ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="角色状态">
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="角色描述">
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入角色描述" maxlength="150"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="菜单权限">
<el-tree :data="state.menuData" :props="state.menuProps" show-checkbox class="menu-data-tree" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel" size="default"> </el-button>
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="systemRoleDialog">
import { reactive, ref } from 'vue';
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
// 定义变量内容
const roleDialogFormRef = ref();
const state = reactive({
ruleForm: {
roleName: '', // 角色名称
roleSign: '', // 角色标识
sort: 0, // 排序
status: true, // 角色状态
describe: '', // 角色描述
},
menuData: [] as TreeType[],
menuProps: {
children: 'children',
label: 'label',
},
dialog: {
isShowDialog: false,
type: '',
title: '',
submitTxt: '',
},
});
// 打开弹窗
const openDialog = (type: string, row: RowRoleType) => {
if (type === 'edit') {
state.ruleForm = row;
state.dialog.title = '修改角色';
state.dialog.submitTxt = '修 改';
} else {
state.dialog.title = '新增角色';
state.dialog.submitTxt = '新 增';
// 清空表单,此项需加表单验证才能使用
// nextTick(() => {
// roleDialogFormRef.value.resetFields();
// });
}
state.dialog.isShowDialog = true;
getMenuData();
};
// 关闭弹窗
const closeDialog = () => {
state.dialog.isShowDialog = false;
};
// 取消
const onCancel = () => {
closeDialog();
};
// 提交
const onSubmit = () => {
closeDialog();
emit('refresh');
// if (state.dialog.type === 'add') { }
};
// 获取菜单结构数据
const getMenuData = () => {
state.menuData = [
{
id: 1,
label: '系统管理',
children: [
{
id: 11,
label: '菜单管理',
children: [
{
id: 111,
label: '菜单新增',
},
{
id: 112,
label: '菜单修改',
},
{
id: 113,
label: '菜单删除',
},
{
id: 114,
label: '菜单查询',
},
],
},
{
id: 12,
label: '角色管理',
children: [
{
id: 121,
label: '角色新增',
},
{
id: 122,
label: '角色修改',
},
{
id: 123,
label: '角色删除',
},
{
id: 124,
label: '角色查询',
},
],
},
{
id: 13,
label: '用户管理',
children: [
{
id: 131,
label: '用户新增',
},
{
id: 132,
label: '用户修改',
},
{
id: 133,
label: '用户删除',
},
{
id: 134,
label: '用户查询',
},
],
},
],
},
{
id: 2,
label: '权限管理',
children: [
{
id: 21,
label: '前端控制',
children: [
{
id: 211,
label: '页面权限',
},
{
id: 212,
label: '页面权限',
},
],
},
{
id: 22,
label: '后端控制',
children: [
{
id: 221,
label: '页面权限',
},
],
},
],
},
];
};
// 暴露变量
defineExpose({
openDialog,
});
</script>
<style scoped lang="scss">
.system-role-dialog-container {
.menu-data-tree {
width: 100%;
border: 1px solid var(--el-border-color);
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
padding: 5px;
}
}
</style>

View File

@@ -0,0 +1,146 @@
<template>
<div class="system-role-container layout-padding">
<div class="system-role-padding layout-padding-auto layout-padding-view">
<div class="system-user-search mb15">
<el-input v-model="state.tableData.param.search" size="default" placeholder="请输入角色名称" style="max-width: 180px"> </el-input>
<el-button size="default" type="primary" class="ml10">
<el-icon>
<ele-Search />
</el-icon>
查询
</el-button>
<el-button size="default" type="success" class="ml10" @click="onOpenAddRole('add')">
<el-icon>
<ele-FolderAdd />
</el-icon>
新增角色
</el-button>
</div>
<el-table :data="state.tableData.data" v-loading="state.tableData.loading" style="width: 100%">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="roleName" label="角色名称" show-overflow-tooltip></el-table-column>
<el-table-column prop="roleSign" label="角色标识" show-overflow-tooltip></el-table-column>
<el-table-column prop="sort" label="排序" show-overflow-tooltip></el-table-column>
<el-table-column prop="status" label="角色状态" show-overflow-tooltip>
<template #default="scope">
<el-tag type="success" v-if="scope.row.status">启用</el-tag>
<el-tag type="info" v-else>禁用</el-tag>
</template>
</el-table-column>
<el-table-column prop="describe" label="角色描述" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onOpenEditRole('edit', scope.row)"
>修改</el-button
>
<el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="onHandleSizeChange"
@current-change="onHandleCurrentChange"
class="mt15"
:pager-count="5"
:page-sizes="[10, 20, 30]"
v-model:current-page="state.tableData.param.pageNum"
background
v-model:page-size="state.tableData.param.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="state.tableData.total"
>
</el-pagination>
</div>
<RoleDialog ref="roleDialogRef" @refresh="getTableData()" />
</div>
</template>
<script setup lang="ts" name="systemRole">
import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
// 引入组件
const RoleDialog = defineAsyncComponent(() => import('/@/views/system/role/dialog.vue'));
// 定义变量内容
const roleDialogRef = ref();
const state = reactive<SysRoleState>({
tableData: {
data: [],
total: 0,
loading: false,
param: {
search: '',
pageNum: 1,
pageSize: 10,
},
},
});
// 初始化表格数据
const getTableData = () => {
state.tableData.loading = true;
const data = [];
for (let i = 0; i < 20; i++) {
data.push({
roleName: i === 0 ? '超级管理员' : '普通用户',
roleSign: i === 0 ? 'admin' : 'common',
describe: `测试角色${i + 1}`,
sort: i,
status: true,
createTime: new Date().toLocaleString(),
});
}
state.tableData.data = data;
state.tableData.total = state.tableData.data.length;
setTimeout(() => {
state.tableData.loading = false;
}, 500);
};
// 打开新增角色弹窗
const onOpenAddRole = (type: string) => {
roleDialogRef.value.openDialog(type);
};
// 打开修改角色弹窗
const onOpenEditRole = (type: string, row: Object) => {
roleDialogRef.value.openDialog(type, row);
};
// 删除角色
const onRowDel = (row: RowRoleType) => {
ElMessageBox.confirm(`此操作将永久删除角色名称:“${row.roleName}”,是否继续?`, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
getTableData();
ElMessage.success('删除成功');
})
.catch(() => {});
};
// 分页改变
const onHandleSizeChange = (val: number) => {
state.tableData.param.pageSize = val;
getTableData();
};
// 分页改变
const onHandleCurrentChange = (val: number) => {
state.tableData.param.pageNum = val;
getTableData();
};
// 页面加载时
onMounted(() => {
getTableData();
});
</script>
<style scoped lang="scss">
.system-role-container {
.system-role-padding {
padding: 15px;
.el-table {
flex: 1;
}
}
}
</style>

View File

@@ -0,0 +1,187 @@
<template>
<div class="system-user-dialog-container">
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
<el-form ref="userDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="账户名称">
<el-input v-model="state.ruleForm.userName" placeholder="请输入账户名称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="用户昵称">
<el-input v-model="state.ruleForm.userNickname" placeholder="请输入用户昵称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="关联角色">
<el-select v-model="state.ruleForm.roleSign" placeholder="请选择" clearable class="w100">
<el-option label="超级管理员" value="admin"></el-option>
<el-option label="普通用户" value="common"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="部门">
<el-cascader
:options="state.deptData"
:props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }"
placeholder="请选择部门"
clearable
class="w100"
v-model="state.ruleForm.department"
>
<template #default="{ node, data }">
<span>{{ data.deptName }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="手机号">
<el-input v-model="state.ruleForm.phone" placeholder="请输入手机号" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="邮箱">
<el-input v-model="state.ruleForm.email" placeholder="请输入" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="性别">
<el-select v-model="state.ruleForm.sex" placeholder="请选择" clearable class="w100">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="账户密码">
<el-input v-model="state.ruleForm.password" placeholder="请输入" type="password" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="账户过期">
<el-date-picker v-model="state.ruleForm.overdueTime" type="date" placeholder="请选择" class="w100"> </el-date-picker>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="用户状态">
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="用户描述">
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入用户描述" maxlength="150"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel" size="default"> </el-button>
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="systemUserDialog">
import { reactive, ref } from 'vue';
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
// 定义变量内容
const userDialogFormRef = ref();
const state = reactive({
ruleForm: {
userName: '', // 账户名称
userNickname: '', // 用户昵称
roleSign: '', // 关联角色
department: [] as string[], // 部门
phone: '', // 手机号
email: '', // 邮箱
sex: '', // 性别
password: '', // 账户密码
overdueTime: '', // 账户过期
status: true, // 用户状态
describe: '', // 用户描述
},
deptData: [] as DeptTreeType[], // 部门数据
dialog: {
isShowDialog: false,
type: '',
title: '',
submitTxt: '',
},
});
// 打开弹窗
const openDialog = (type: string, row: RowUserType) => {
if (type === 'edit') {
state.ruleForm = row;
state.dialog.title = '修改用户';
state.dialog.submitTxt = '修 改';
} else {
state.dialog.title = '新增用户';
state.dialog.submitTxt = '新 增';
// 清空表单,此项需加表单验证才能使用
// nextTick(() => {
// userDialogFormRef.value.resetFields();
// });
}
state.dialog.isShowDialog = true;
getMenuData();
};
// 关闭弹窗
const closeDialog = () => {
state.dialog.isShowDialog = false;
};
// 取消
const onCancel = () => {
closeDialog();
};
// 提交
const onSubmit = () => {
closeDialog();
emit('refresh');
// if (state.dialog.type === 'add') { }
};
// 初始化部门数据
const getMenuData = () => {
state.deptData.push({
deptName: 'vueNextAdmin',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '顶级部门',
id: Math.random(),
children: [
{
deptName: 'IT外包服务',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '总部',
id: Math.random(),
},
{
deptName: '资本控股',
createTime: new Date().toLocaleString(),
status: true,
sort: Math.random(),
describe: '分部',
id: Math.random(),
},
],
});
};
// 暴露变量
defineExpose({
openDialog,
});
</script>

View File

@@ -0,0 +1,158 @@
<template>
<div class="system-user-container layout-padding">
<el-card shadow="hover" class="layout-padding-auto">
<div class="system-user-search mb15">
<el-input size="default" placeholder="请输入用户名称" style="max-width: 180px"> </el-input>
<el-button size="default" type="primary" class="ml10">
<el-icon>
<ele-Search />
</el-icon>
查询
</el-button>
<el-button size="default" type="success" class="ml10" @click="onOpenAddUser('add')">
<el-icon>
<ele-FolderAdd />
</el-icon>
新增用户
</el-button>
</div>
<el-table :data="state.tableData.data" v-loading="state.tableData.loading" style="width: 100%">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="userName" label="账户名称" show-overflow-tooltip></el-table-column>
<el-table-column prop="userNickname" label="用户昵称" show-overflow-tooltip></el-table-column>
<el-table-column prop="roleSign" label="关联角色" show-overflow-tooltip></el-table-column>
<el-table-column prop="department" label="部门" show-overflow-tooltip></el-table-column>
<el-table-column prop="phone" label="手机号" show-overflow-tooltip></el-table-column>
<el-table-column prop="email" label="邮箱" show-overflow-tooltip></el-table-column>
<el-table-column prop="status" label="用户状态" show-overflow-tooltip>
<template #default="scope">
<el-tag type="success" v-if="scope.row.status">启用</el-tag>
<el-tag type="info" v-else>禁用</el-tag>
</template>
</el-table-column>
<el-table-column prop="describe" label="用户描述" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onOpenEditUser('edit', scope.row)"
>修改</el-button
>
<el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="onHandleSizeChange"
@current-change="onHandleCurrentChange"
class="mt15"
:pager-count="5"
:page-sizes="[10, 20, 30]"
v-model:current-page="state.tableData.param.pageNum"
background
v-model:page-size="state.tableData.param.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="state.tableData.total"
>
</el-pagination>
</el-card>
<UserDialog ref="userDialogRef" @refresh="getTableData()" />
</div>
</template>
<script setup lang="ts" name="systemUser">
import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
// 引入组件
const UserDialog = defineAsyncComponent(() => import('/@/views/system/user/dialog.vue'));
// 定义变量内容
const userDialogRef = ref();
const state = reactive<SysUserState>({
tableData: {
data: [],
total: 0,
loading: false,
param: {
pageNum: 1,
pageSize: 10,
},
},
});
// 初始化表格数据
const getTableData = () => {
state.tableData.loading = true;
const data = [];
for (let i = 0; i < 2; i++) {
data.push({
userName: i === 0 ? 'admin' : 'test',
userNickname: i === 0 ? '我是管理员' : '我是普通用户',
roleSign: i === 0 ? 'admin' : 'common',
department: i === 0 ? ['vueNextAdmin', 'IT外包服务'] : ['vueNextAdmin', '资本控股'],
phone: '12345678910',
email: 'vueNextAdmin@123.com',
sex: '女',
password: '123456',
overdueTime: new Date(),
status: true,
describe: i === 0 ? '不可删除' : '测试用户',
createTime: new Date().toLocaleString(),
});
}
state.tableData.data = data;
state.tableData.total = state.tableData.data.length;
setTimeout(() => {
state.tableData.loading = false;
}, 500);
};
// 打开新增用户弹窗
const onOpenAddUser = (type: string) => {
userDialogRef.value.openDialog(type);
};
// 打开修改用户弹窗
const onOpenEditUser = (type: string, row: RowUserType) => {
userDialogRef.value.openDialog(type, row);
};
// 删除用户
const onRowDel = (row: RowUserType) => {
ElMessageBox.confirm(`此操作将永久删除账户名称:“${row.userName}”,是否继续?`, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
getTableData();
ElMessage.success('删除成功');
})
.catch(() => {});
};
// 分页改变
const onHandleSizeChange = (val: number) => {
state.tableData.param.pageSize = val;
getTableData();
};
// 分页改变
const onHandleCurrentChange = (val: number) => {
state.tableData.param.pageNum = val;
getTableData();
};
// 页面加载时
onMounted(() => {
getTableData();
});
</script>
<style scoped lang="scss">
.system-user-container {
:deep(.el-card__body) {
display: flex;
flex-direction: column;
flex: 1;
overflow: auto;
.el-table {
flex: 1;
}
}
}
</style>