Compare commits

...

2 Commits

@ -1,9 +1,11 @@
<template> <template>
<!-- 对话框组件 -->
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="!dataForm.areaId ? '新增' : '修改'" :title="!dataForm.areaId ? '新增' : '修改'"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<!-- 表单组件 -->
<el-form <el-form
ref="dataFormRef" ref="dataFormRef"
:model="dataForm" :model="dataForm"
@ -11,6 +13,7 @@
label-width="100px" label-width="100px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 地区名称输入项 -->
<el-form-item <el-form-item
label="地区名称" label="地区名称"
prop="areaName" prop="areaName"
@ -22,6 +25,7 @@
show-word-limit show-word-limit
/> />
</el-form-item> </el-form-item>
<!-- 上级地区选择项 -->
<el-form-item <el-form-item
label="上级地区" label="上级地区"
prop="parentId" prop="parentId"
@ -37,6 +41,7 @@
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 对话框底部操作按钮 -->
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button <el-button
@ -59,7 +64,12 @@
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { treeDataTranslate } from '@/utils' import { treeDataTranslate } from '@/utils'
import { Debounce } from '@/utils/debounce' import { Debounce } from '@/utils/debounce'
import { ref, reactive, nextTick, defineEmits, defineExpose } from 'vue'
//
const emit = defineEmits(['refreshDataList']) const emit = defineEmits(['refreshDataList'])
//
const dataRule = reactive({ const dataRule = reactive({
areaName: [ areaName: [
{ required: true, message: '区域名称不能为空', trigger: 'blur' }, { required: true, message: '区域名称不能为空', trigger: 'blur' },
@ -67,6 +77,7 @@ const dataRule = reactive({
] ]
}) })
//
const visible = ref(false) const visible = ref(false)
const areaList = ref([]) const areaList = ref([])
const dataForm = ref({ const dataForm = ref({
@ -81,61 +92,76 @@ const categoryTreeProps = reactive({
checkStrictly: true checkStrictly: true
}) })
const selectedOptions = ref([]) const selectedOptions = ref([])
//
const dataFormRef = ref(null) const dataFormRef = ref(null)
// areaId
const init = (areaId) => { const init = (areaId) => {
dataForm.value.areaId = areaId || 0 dataForm.value.areaId = areaId || 0 // ID
visible.value = true visible.value = true //
selectedOptions.value = [] selectedOptions.value = [] //
// 使nextTickDOM
nextTick(() => { nextTick(() => {
dataFormRef.value?.resetFields() dataFormRef.value?.resetFields() //
if (dataForm.value.areaId) { if (dataForm.value.areaId) {
// areaId
http({ http({
url: http.adornUrl('/admin/area/info/' + dataForm.value.areaId), url: http.adornUrl('/admin/area/info/' + dataForm.value.areaId),
method: 'get', method: 'get',
params: http.adornParams() params: http.adornParams()
}) }).then(({ data }) => {
.then(({ data }) => { dataForm.value = data //
dataForm.value = data selectedOptions.value = dataForm.value.parentId //
selectedOptions.value = dataForm.value.parentId // categoryTreePropsreactive
categoryTreeProps.areaId = dataForm.value.areaId categoryTreeProps.areaId = dataForm.value.areaId
categoryTreeProps.areaName = dataForm.value.areaName categoryTreeProps.areaName = dataForm.value.areaName
}) })
} }
//
http({ http({
url: http.adornUrl('/admin/area/list'), url: http.adornUrl('/admin/area/list'),
method: 'get', method: 'get',
params: http.adornParams() params: http.adornParams()
}) }).then(({ data }) => {
.then(({ data }) => {
areaList.value = treeDataTranslate(data, 'areaId', 'parentId') areaList.value = treeDataTranslate(data, 'areaId', 'parentId')
}) })
}) })
} }
// init
defineExpose({ init }) defineExpose({ init })
//
const page = { const page = {
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 20 // pageSize: 20 //
} }
/** /**
* 表单提交 * 表单提交
*/ */
const onSubmit = Debounce(() => { const onSubmit = Debounce(() => {
//
dataFormRef.value?.validate((valid) => { dataFormRef.value?.validate((valid) => {
if (valid) { if (valid) {
// HTTP
http({ http({
url: http.adornUrl('/admin/area'), url: http.adornUrl('/admin/area'),
method: dataForm.value.areaId ? 'put' : 'post', method: dataForm.value.areaId ? 'put' : 'post', //
data: http.adornData(dataForm.value) data: http.adornData(dataForm.value)
}).then(() => { }).then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
visible.value = false visible.value = false //
emit('refreshDataList', page) emit('refreshDataList', page) //
} }
}) })
}) })
@ -143,8 +169,9 @@ const onSubmit = Debounce(() => {
}) })
}) })
//
const handleChange = (val) => { const handleChange = (val) => {
// parentIdID
dataForm.value.parentId = val[val.length - 1] dataForm.value.parentId = val[val.length - 1]
} }
</script> </script>

@ -1,10 +1,13 @@
<template> <template>
<!-- 地区管理模块 -->
<div class="mod-sys-area"> <div class="mod-sys-area">
<!-- 地区名称输入框用于过滤树状结构中的节点 -->
<el-input <el-input
v-model="areaName" v-model="areaName"
class="area-search-input" class="area-search-input"
placeholder="地区关键词" placeholder="地区关键词"
/> />
<!-- 新增按钮点击时触发新增或更新操作 -->
<el-button <el-button
type="primary" type="primary"
class="area-add-btn" class="area-add-btn"
@ -13,6 +16,7 @@
新增 新增
</el-button> </el-button>
<!-- 树形控件展示地区层级结构 -->
<el-tree <el-tree
ref="tree2Ref" ref="tree2Ref"
:data="areaTreeData" :data="areaTreeData"
@ -21,9 +25,11 @@
:props="props" :props="props"
:expand-on-click-node="false" :expand-on-click-node="false"
> >
<!-- 自定义节点内容模板 -->
<template #default="{ node, data }"> <template #default="{ node, data }">
<span class="addr-name">{{ node.label }}</span> <span class="addr-name">{{ node.label }}</span> <!-- 显示地区名称 -->
<span> <span>
<!-- 修改按钮点击时触发修改操作 -->
<el-button <el-button
type="text" type="text"
icon="el-icon-edit" icon="el-icon-edit"
@ -31,6 +37,7 @@
> >
修改 修改
</el-button> </el-button>
<!-- 删除按钮点击时触发删除操作 -->
<el-button <el-button
type="text" type="text"
icon="el-icon-delete" icon="el-icon-delete"
@ -42,6 +49,7 @@
</template> </template>
</el-tree> </el-tree>
<!-- 添加或更新对话框组件 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@ -53,34 +61,44 @@
<script setup> <script setup>
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import AddOrUpdate from './add-or-update.vue' import AddOrUpdate from './add-or-update.vue' //
import { treeDataTranslate } from '@/utils' import { treeDataTranslate } from '@/utils' //
import { ref, watch, onMounted, reactive, nextTick } from 'vue'
//
const areaName = ref('') const areaName = ref('')
//
const props = { const props = {
id: 'areaId', id: 'areaId',
label: 'areaName', label: 'areaName',
children: 'children' children: 'children'
} }
const tree2Ref = ref(null) //
watch( watch(
() => areaName, () => areaName.value,
(val) => { (val) => {
tree2Ref.value?.filter(val) tree2Ref.value?.filter(val)
} }
) )
//
onMounted(() => { onMounted(() => {
getDataList(page) getDataList(page)
}) })
//
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
//
const areaTreeData = ref(null) const areaTreeData = ref(null)
//
const getDataList = (pageParam, params) => { const getDataList = (pageParam, params) => {
http({ http({
url: http.adornUrl('/admin/area/list'), url: http.adornUrl('/admin/area/list'),
@ -90,38 +108,46 @@ const getDataList = (pageParam, params) => {
size: pageParam == null ? page.pageSize : pageParam.pageSize size: pageParam == null ? page.pageSize : pageParam.pageSize
}, params)) }, params))
}).then(({ data }) => { }).then(({ data }) => {
// areaTreeData
areaTreeData.value = treeDataTranslate(data, 'areaId', 'parentId') areaTreeData.value = treeDataTranslate(data, 'areaId', 'parentId')
}) })
} }
//
const addOrUpdateRef = ref(null) const addOrUpdateRef = ref(null)
//
const addOrUpdateVisible = ref(false) const addOrUpdateVisible = ref(false)
/** /**
* 新增 / 修改 * 触发新增或更新操作
* @param id * @param id 可选参数若提供则表示更新指定ID的地区信息
*/ */
const onAddOrUpdate = (id) => { const onAddOrUpdate = (id) => {
addOrUpdateVisible.value = true addOrUpdateVisible.value = true
nextTick(() => { nextTick(() => {
addOrUpdateRef.value?.init(id) addOrUpdateRef.value?.init(id) //
}) })
} }
/** /**
* 删除 * 执行删除操作
* @param areaId * @param areaId 要删除的地区ID
*/ */
const onDelete = (areaId) => { const onDelete = (areaId) => {
//
ElMessageBox.confirm('确定进行删除操作?', '提示', { ElMessageBox.confirm('确定进行删除操作?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
// HTTP
http({ http({
url: http.adornUrl('/admin/area/' + areaId), url: http.adornUrl('/admin/area/' + areaId),
method: 'delete', method: 'delete',
data: http.adornData({}) data: http.adornData({})
}).then(() => { }).then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
@ -131,35 +157,37 @@ const onDelete = (areaId) => {
} }
}) })
}) })
}).catch(() => { }) }).catch(() => { /* 用户取消删除 */ })
} }
// eslint-disable-next-line no-unused-vars
// onAddOrUpdate
const update = (node, data) => { const update = (node, data) => {
onAddOrUpdate(data.areaId) onAddOrUpdate(data.areaId)
} }
// eslint-disable-next-line no-unused-vars // onDelete
const remove = (node, data) => { const remove = (node, data) => {
onDelete(data.areaId) onDelete(data.areaId)
} }
//
const filterNode = (value, data) => { const filterNode = (value, data) => {
if (!value) return true if (!value) return true //
return data.areaName.indexOf(value) !== -1 return data.areaName.indexOf(value) !== -1 //
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mod-sys-area { .mod-sys-area {
.area-search-input { .area-search-input {
width: 30%; width: 30%; // 30%
} }
.area-add-btn { .area-add-btn {
float: right; float: right; //
} }
} }
/* 使用:deep选择器穿透样式作用于子组件 */
:deep(.el-tree-node) .addr-name { :deep(.el-tree-node) .addr-name {
width: 100%; width: 100%; //
} }
</style> </style>

@ -1,9 +1,11 @@
<template> <template>
<!-- 对话框组件 -->
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="!dataForm.id ? '新增' : '修改'" :title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<!-- 表单组件 -->
<el-form <el-form
ref="dataFormRef" ref="dataFormRef"
:model="dataForm" :model="dataForm"
@ -11,6 +13,7 @@
label-width="80px" label-width="80px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 参数名输入项 -->
<el-form-item <el-form-item
label="参数名" label="参数名"
prop="paramKey" prop="paramKey"
@ -20,6 +23,7 @@
placeholder="参数名" placeholder="参数名"
/> />
</el-form-item> </el-form-item>
<!-- 参数值输入项 -->
<el-form-item <el-form-item
label="参数值" label="参数值"
prop="paramValue" prop="paramValue"
@ -29,6 +33,7 @@
placeholder="参数值" placeholder="参数值"
/> />
</el-form-item> </el-form-item>
<!-- 备注输入项 -->
<el-form-item <el-form-item
label="备注" label="备注"
prop="remark" prop="remark"
@ -39,13 +44,12 @@
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 对话框底部操作按钮 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="visible = false">取消</el-button> <el-button @click="visible = false">取消</el-button> <!-- -->
<el-button <el-button type="primary" @click="onSubmit()"></el-button> <!-- 提交表单 -->
type="primary"
@click="onSubmit()"
>确定</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -54,36 +58,54 @@
<script setup> <script setup>
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Debounce } from '@/utils/debounce' import { Debounce } from '@/utils/debounce'
import { ref, reactive, nextTick, defineEmits, defineExpose } from 'vue'
//
const emit = defineEmits(['refreshDataList']) const emit = defineEmits(['refreshDataList'])
//
const visible = ref(false) const visible = ref(false)
// 使reactive
const dataForm = reactive({ const dataForm = reactive({
id: 0, id: 0, // ID0
paramKey: '', paramKey: '', //
paramValue: '', paramValue: '', //
remark: '' remark: '' //
}) })
//
const dataRule = { const dataRule = {
paramKey: [ paramKey: [
{ required: true, message: '参数名不能为空', trigger: 'blur' }, { required: true, message: '参数名不能为空', trigger: 'blur' }, //
{ pattern: /\s\S+|S+\s|\S/, message: '请输入正确的参数名', trigger: 'blur' } { pattern: /\s\S+|S+\s|\S/, message: '请输入正确的参数名', trigger: 'blur' } //
], ],
paramValue: [ paramValue: [
{ required: true, message: '参数值不能为空', trigger: 'blur' }, { required: true, message: '参数值不能为空', trigger: 'blur' }, //
{ pattern: /\s\S+|S+\s|\S/, message: '请输入正确的参数值', trigger: 'blur' } { pattern: /\s\S+|S+\s|\S/, message: '请输入正确的参数值', trigger: 'blur' } //
] ]
} }
//
const dataFormRef = ref(null) const dataFormRef = ref(null)
// id
const init = (id) => { const init = (id) => {
dataForm.id = id || 0 dataForm.id = id || 0 // ID
visible.value = true visible.value = true //
// 使nextTickDOM
nextTick(() => { nextTick(() => {
dataFormRef.value?.resetFields() dataFormRef.value?.resetFields() //
if (dataForm.id) { if (dataForm.id) {
// id
http({ http({
url: http.adornUrl(`/sys/config/info/${dataForm.id}`), url: http.adornUrl(`/sys/config/info/${dataForm.id}`),
method: 'get', method: 'get',
params: http.adornParams() params: http.adornParams()
}).then(({ data }) => { }).then(({ data }) => {
//
dataForm.paramKey = data.paramKey dataForm.paramKey = data.paramKey
dataForm.paramValue = data.paramValue dataForm.paramValue = data.paramValue
dataForm.remark = data.remark dataForm.remark = data.remark
@ -91,16 +113,21 @@ const init = (id) => {
} }
}) })
} }
// init
defineExpose({ init }) defineExpose({ init })
/** /**
* 表单提交 * 表单提交
*/ */
const onSubmit = Debounce(() => { const onSubmit = Debounce(() => {
//
dataFormRef.value?.validate((valid) => { dataFormRef.value?.validate((valid) => {
if (valid) { if (valid) {
// HTTP
http({ http({
url: http.adornUrl('/sys/config'), url: http.adornUrl('/sys/config'),
method: dataForm.id ? 'put' : 'post', method: dataForm.id ? 'put' : 'post', //
data: http.adornData({ data: http.adornData({
id: dataForm.id || undefined, id: dataForm.id || undefined,
paramKey: dataForm.paramKey, paramKey: dataForm.paramKey,
@ -108,13 +135,14 @@ const onSubmit = Debounce(() => {
remark: dataForm.remark remark: dataForm.remark
}) })
}).then(() => { }).then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
visible.value = false visible.value = false //
emit('refreshDataList') emit('refreshDataList') //
} }
}) })
}) })

@ -1,5 +1,7 @@
<template> <template>
<!-- 配置管理模块 -->
<div class="mod-config"> <div class="mod-config">
<!-- AvueCrud表格组件 -->
<avue-crud <avue-crud
ref="crudRef" ref="crudRef"
:page="page" :page="page"
@ -9,6 +11,7 @@
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<!-- 自定义左侧菜单按钮 -->
<template #menu-left> <template #menu-left>
<el-button <el-button
type="primary" type="primary"
@ -26,6 +29,8 @@
批量删除 批量删除
</el-button> </el-button>
</template> </template>
<!-- 自定义行内操作按钮 -->
<template #menu="scope"> <template #menu="scope">
<el-button <el-button
type="primary" type="primary"
@ -44,7 +49,7 @@
</template> </template>
</avue-crud> </avue-crud>
<!-- 弹窗, 新增 / 修改 --> <!-- 添加或更新对话框组件 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@ -55,81 +60,105 @@
<script setup> <script setup>
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { tableOption } from '@/crud/sys/config.js' import { tableOption } from '@/crud/sys/config.js' //
import { ref, reactive, nextTick, defineExpose } from 'vue'
//
const dataList = ref([]) const dataList = ref([])
//
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
/** /**
* 获取数据列表 * 获取数据列表方法
* @param pageParam 可选参数用于指定分页信息
* @param params 搜索条件参数
* @param done 分页加载完成回调函数
*/ */
const getDataList = (pageParam, params, done) => { const getDataList = (pageParam, params, done) => {
http({ http({
url: http.adornUrl('/sys/config/page'), url: http.adornUrl('/sys/config/page'), // API
method: 'get', method: 'get', //
params: http.adornParams( params: http.adornParams(
Object.assign( Object.assign(
{ {
current: pageParam == null ? page.currentPage : pageParam.currentPage, current: pageParam == null ? page.currentPage : pageParam.currentPage,
size: pageParam == null ? page.pageSize : pageParam.pageSize size: pageParam == null ? page.pageSize : pageParam.pageSize
}, },
params params //
) )
) )
}) })
.then(({ data }) => { .then(({ data }) => {
dataList.value = data.records dataList.value = data.records //
page.total = data.total page.total = data.total //
if (done) done() if (done) done() //
}) })
} }
/** /**
* 条件查询 * 条件查询方法
* @param params 搜索条件参数
* @param done 分页加载完成回调函数
*/ */
const onSearch = (params, done) => { const onSearch = (params, done) => {
getDataList(page, params, done) getDataList(page, params, done) //
} }
//
const dataListSelections = ref([]) const dataListSelections = ref([])
/** /**
* 多选变化 * 多选变化方法
* @param val 选中的数据项
*/ */
const selectionChange = (val) => { const selectionChange = (val) => {
dataListSelections.value = val dataListSelections.value = val //
} }
//
const addOrUpdateVisible = ref(false) const addOrUpdateVisible = ref(false)
//
const addOrUpdate = ref(null) const addOrUpdate = ref(null)
/** /**
* 新增 / 修改 * 触发新增或修改操作
* @param id 可选参数若提供则表示更新指定ID的配置信息
*/ */
const onAddOrUpdate = (id) => { const onAddOrUpdate = (id) => {
addOrUpdateVisible.value = true addOrUpdateVisible.value = true //
nextTick(() => { nextTick(() => {
addOrUpdate.value?.init(id) addOrUpdate.value?.init(id) //
}) })
} }
/** /**
* 删除 * 删除配置信息
* @param id 可选参数若提供则表示删除指定ID的配置信息
*/ */
const onDelete = (id) => { const onDelete = (id) => {
const ids = id ? [id] : dataListSelections.value?.map(item => { const ids = id ? [id] : dataListSelections.value?.map(item => item.id) // ID
return item.id
}) //
ElMessageBox.confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', { ElMessageBox.confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })
.then(() => { .then(() => {
// HTTP
http({ http({
url: http.adornUrl('/sys/config'), url: http.adornUrl('/sys/config'),
method: 'delete', method: 'delete',
data: http.adornData(ids, false) data: http.adornData(ids, false)
}) })
.then(() => { .then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
@ -139,6 +168,6 @@ const onDelete = (id) => {
} }
}) })
}) })
}).catch(() => { }) }).catch(() => { /* 用户取消删除 */ })
} }
</script> </script>

@ -1,57 +1,70 @@
<template> <template>
<!-- 日志管理模块 -->
<div class="mod-log"> <div class="mod-log">
<!-- AvueCrud表格组件用于展示日志数据 -->
<avue-crud <avue-crud
ref="crudRef" ref="crudRef" <!-- 引用表格实例 -->
:page="page" :page="page" <!-- 分页信息 -->
:data="dataList" :data="dataList" <!-- 表格数据 -->
:option="tableOption" :option="tableOption" <!-- 表格选项配置 -->
@search-change="onSearch" @search-change="onSearch" <!-- 搜索条件变化事件 -->
@on-load="getDataList" @on-load="getDataList" <!-- 加载数据事件 -->
/> />
</div> </div>
</template> </template>
<script setup> <script setup>
import { tableOption } from '@/crud/sys/log.js' import { tableOption } from '@/crud/sys/log.js' //
import { ref, reactive, onMounted } from 'vue'
//
const dataList = ref([]) const dataList = ref([])
//
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
//
onMounted(() => { onMounted(() => {
getDataList() getDataList()
}) })
/** /**
* 获取数据列表 * 获取数据列表方法
* @param pageParam 可选参数用于指定分页信息
* @param params 搜索条件参数
* @param done 分页加载完成回调函数
*/ */
const getDataList = (pageParam, params, done) => { const getDataList = (pageParam, params, done) => {
http({ http({
url: http.adornUrl('/sys/log/page'), url: http.adornUrl('/sys/log/page'), // API
method: 'get', method: 'get', //
params: http.adornParams( params: http.adornParams(
Object.assign( Object.assign(
{ {
current: pageParam == null ? page.currentPage : pageParam.currentPage, current: pageParam == null ? page.currentPage : pageParam.currentPage,
size: pageParam == null ? page.pageSize : pageParam.pageSize size: pageParam == null ? page.pageSize : pageParam.pageSize
}, },
params params //
) )
) )
}) })
.then(({ data }) => { .then(({ data }) => {
dataList.value = data.records dataList.value = data.records //
page.total = data.total page.total = data.total //
if (done) done() if (done) done() //
}) })
} }
/** /**
* 条件查询 * 条件查询方法
* @param params 搜索条件参数
* @param done 分页加载完成回调函数
*/ */
const onSearch = (params, done) => { const onSearch = (params, done) => {
getDataList(page, params, done) getDataList(page, params, done) //
} }
</script> </script>

@ -1,9 +1,11 @@
<template> <template>
<!-- 对话框组件 -->
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="!dataForm.id ? '新增' : '修改'" :title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<!-- 表单组件 -->
<el-form <el-form
ref="dataFormRef" ref="dataFormRef"
:model="dataForm" :model="dataForm"
@ -11,6 +13,7 @@
label-width="80px" label-width="80px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 类型选择项 -->
<el-form-item <el-form-item
label="类型" label="类型"
prop="type" prop="type"
@ -25,6 +28,8 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 动态标签根据类型改变 -->
<el-form-item <el-form-item
:label="dataForm.typeList[dataForm.type] + '名称'" :label="dataForm.typeList[dataForm.type] + '名称'"
prop="name" prop="name"
@ -34,6 +39,8 @@
:placeholder="dataForm.typeList[dataForm.type] + '名称'" :placeholder="dataForm.typeList[dataForm.type] + '名称'"
/> />
</el-form-item> </el-form-item>
<!-- 上级菜单选择 -->
<el-form-item label="上级菜单"> <el-form-item label="上级菜单">
<el-cascader <el-cascader
v-model="selectedMenu" v-model="selectedMenu"
@ -45,6 +52,8 @@
@change="handleSelectMenuChange" @change="handleSelectMenuChange"
/> />
</el-form-item> </el-form-item>
<!-- 菜单路由输入仅当类型为1时显示 -->
<el-form-item <el-form-item
v-if="dataForm.type === 1" v-if="dataForm.type === 1"
label="菜单路由" label="菜单路由"
@ -55,6 +64,8 @@
placeholder="菜单路由" placeholder="菜单路由"
/> />
</el-form-item> </el-form-item>
<!-- 授权标识输入除类型0外显示 -->
<el-form-item <el-form-item
v-if="dataForm.type !== 0" v-if="dataForm.type !== 0"
label="授权标识" label="授权标识"
@ -65,6 +76,8 @@
placeholder="多个用逗号分隔, 如: user:list,user:create" placeholder="多个用逗号分隔, 如: user:list,user:create"
/> />
</el-form-item> </el-form-item>
<!-- 排序号输入除类型2外显示 -->
<el-form-item <el-form-item
v-if="dataForm.type !== 2" v-if="dataForm.type !== 2"
label="排序号" label="排序号"
@ -77,6 +90,8 @@
label="排序号" label="排序号"
/> />
</el-form-item> </el-form-item>
<!-- 菜单图标选择除类型2外显示 -->
<el-form-item <el-form-item
v-if="dataForm.type !== 2" v-if="dataForm.type !== 2"
label="菜单图标" label="菜单图标"
@ -130,15 +145,12 @@
</el-row> </el-row>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 对话框底部操作按钮 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="visible = false">取消</el-button> <el-button @click="visible = false">取消</el-button> <!-- -->
<el-button <el-button type="primary" @click="onSubmit()"></el-button> <!-- 提交表单 -->
type="primary"
@click="onSubmit()"
>
确定
</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -147,16 +159,24 @@
<script setup> <script setup>
import { treeDataTranslate, idList } from '@/utils' import { treeDataTranslate, idList } from '@/utils'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { ref, reactive, computed, onMounted, nextTick, defineEmits, defineExpose } from 'vue'
//
const emit = defineEmits(['refreshDataList']) const emit = defineEmits(['refreshDataList'])
//
const iconInputRef = ref(null) const iconInputRef = ref(null)
const iconListPopoverRef = ref(null) const iconListPopoverRef = ref(null)
const iconPopoverClass = computed(() => {
return { //
const iconPopoverClass = computed(() => ({
width: '396px' width: '396px'
} }))
})
//
const visible = ref(false) const visible = ref(false)
// 使reactive
const dataForm = reactive({ const dataForm = reactive({
id: 0, id: 0,
type: 1, type: 1,
@ -169,15 +189,19 @@ const dataForm = reactive({
icon: '', icon: '',
iconList: [] iconList: []
}) })
//
const menuList = ref([]) const menuList = ref([])
const selectedMenu = ref([]) const selectedMenu = ref([])
//
const menuListTreeProps = { const menuListTreeProps = {
value: 'menuId', value: 'menuId',
label: 'name', label: 'name',
checkStrictly: true checkStrictly: true
} }
// eslint-disable-next-line no-unused-vars // URL
const validateUrl = (rule, value, callback) => { const validateUrl = (rule, value, callback) => {
if (dataForm.type === 1 && !/\S/.test(value)) { if (dataForm.type === 1 && !/\S/.test(value)) {
callback(new Error('菜单URL不能为空')) callback(new Error('菜单URL不能为空'))
@ -185,6 +209,8 @@ const validateUrl = (rule, value, callback) => {
callback() callback()
} }
} }
//
const dataRule = ref({ const dataRule = ref({
name: [ name: [
{ required: true, message: '菜单名称不能为空', trigger: 'blur' }, { required: true, message: '菜单名称不能为空', trigger: 'blur' },
@ -195,10 +221,11 @@ const dataRule = ref({
] ]
}) })
//
onMounted(() => { onMounted(() => {
onLoadIcons() onLoadIcons()
}) })
const iconList = []
/** /**
* 加载图标 * 加载图标
*/ */
@ -206,35 +233,42 @@ const onLoadIcons = () => {
const icons = import.meta.glob('@/icons/svg/*.svg') const icons = import.meta.glob('@/icons/svg/*.svg')
for (const icon in icons) { for (const icon in icons) {
const iconName = icon.split('/src/icons/svg/')[1].split('.svg')[0] const iconName = icon.split('/src/icons/svg/')[1].split('.svg')[0]
iconList.push(iconName) dataForm.iconList.push(iconName)
} }
} }
//
const dataFormRef = ref(null) const dataFormRef = ref(null)
/**
* 初始化方法接收id作为参数
* @param id 菜单项ID
*/
const init = (id) => { const init = (id) => {
dataForm.id = id || 0 dataForm.id = id || 0 // ID
http({ http({
url: http.adornUrl('/sys/menu/list'), url: http.adornUrl('/sys/menu/list'),
method: 'get', method: 'get',
params: http.adornParams() params: http.adornParams()
}) })
.then(({ data }) => { .then(({ data }) => {
menuList.value = treeDataTranslate(data, 'menuId') menuList.value = treeDataTranslate(data, 'menuId') //
}) })
.then(() => { .then(() => {
visible.value = true visible.value = true //
nextTick(() => { nextTick(() => {
dataFormRef.value?.resetFields() dataFormRef.value?.resetFields() //
}) })
}) })
.then(() => { .then(() => {
if (dataForm.id) { if (dataForm.id) {
// // id
http({ http({
url: http.adornUrl(`/sys/menu/info/${dataForm.id}`), url: http.adornUrl(`/sys/menu/info/${dataForm.id}`),
method: 'get', method: 'get',
params: http.adornParams() params: http.adornParams()
}).then(({ data }) => { }).then(({ data }) => {
//
dataForm.id = data.menuId dataForm.id = data.menuId
dataForm.type = data.type dataForm.type = data.type
dataForm.name = data.name dataForm.name = data.name
@ -246,31 +280,39 @@ const init = (id) => {
selectedMenu.value = idList(menuList.value, data.parentId, 'menuId', 'children').reverse() selectedMenu.value = idList(menuList.value, data.parentId, 'menuId', 'children').reverse()
}) })
} else { } else {
selectedMenu.value = [] selectedMenu.value = [] //
} }
}) })
} }
defineExpose({ init }) defineExpose({ init })
/**
* 上级菜单选择变化处理
* @param val 选中的菜单路径
*/
const handleSelectMenuChange = (val) => { const handleSelectMenuChange = (val) => {
dataForm.parentId = val[val.length - 1] dataForm.parentId = val[val.length - 1] // parentIdID
} }
/** /**
* 图标选中 * 图标选中处理
* @param iconName * @param iconName 选中的图标名称
*/ */
const iconActiveHandle = (iconName) => { const iconActiveHandle = (iconName) => {
dataForm.icon = iconName dataForm.icon = iconName //
} }
/** /**
* 表单提交 * 表单提交
*/ */
const onSubmit = Debounce(() => { const onSubmit = Debounce(() => {
//
dataFormRef.value?.validate((valid) => { dataFormRef.value?.validate((valid) => {
if (valid) { if (valid) {
// HTTP
http({ http({
url: http.adornUrl('/sys/menu'), url: http.adornUrl('/sys/menu'),
method: dataForm.id ? 'put' : 'post', method: dataForm.id ? 'put' : 'post', //
data: http.adornData({ data: http.adornData({
menuId: dataForm.id || undefined, menuId: dataForm.id || undefined,
type: dataForm.type, type: dataForm.type,
@ -283,13 +325,14 @@ const onSubmit = Debounce(() => {
}) })
}) })
.then(() => { .then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
visible.value = false visible.value = false //
emit('refreshDataList') emit('refreshDataList') //
} }
}) })
}) })

@ -1,10 +1,13 @@
<template> <template>
<!-- 菜单管理模块 -->
<div class="mod-menu"> <div class="mod-menu">
<!-- 搜索表单 -->
<el-form <el-form
:inline="true" :inline="true"
:model="dataForm" :model="dataForm"
> >
<el-form-item> <el-form-item>
<!-- 新增按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:menu:save')" v-if="isAuth('sys:menu:save')"
type="primary" type="primary"
@ -14,12 +17,15 @@
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 数据表格 -->
<el-table <el-table
:data="dataList" :data="dataList"
border border
style="width: 100%;" style="width: 100%;"
row-key="menuId" row-key="menuId"
> >
<!-- 名称列 -->
<el-table-column <el-table-column
prop="name" prop="name"
header-align="center" header-align="center"
@ -27,51 +33,43 @@
width="150" width="150"
label="名称" label="名称"
/> />
<!-- 图标列 -->
<el-table-column <el-table-column
header-align="center" header-align="center"
align="center" align="center"
label="图标" label="图标"
> >
<template #default="scope"> <template #default="scope"> <!-- 自定义列内容 -->
<svg-icon <svg-icon
:icon-class="`icon-${scope.row.icon}`" :icon-class="`icon-${scope.row.icon}`"
/> />
</template> </template>
</el-table-column> </el-table-column>
<!-- 类型列 -->
<el-table-column <el-table-column
prop="type" prop="type"
header-align="center" header-align="center"
align="center" align="center"
label="类型" label="类型"
> >
<template #default="scope"> <template #default="scope"> <!-- 自定义列内容 -->
<el-tag <el-tag v-if="scope.row.type === 0"></el-tag> <!-- 根据类型动态渲染标签 -->
v-if="scope.row.type === 0" <el-tag v-else-if="scope.row.type === 1" type="success">菜单</el-tag>
> <el-tag v-else-if="scope.row.type === 2" type="info">按钮</el-tag>
目录
</el-tag>
<el-tag
v-else-if="scope.row.type === 1"
type="success"
>
菜单
</el-tag>
<el-tag
v-else-if="scope.row.type === 2"
type="info"
>
按钮
</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<!-- 排序号列 -->
<el-table-column <el-table-column
prop="orderNum" prop="orderNum"
header-align="center" header-align="center"
align="center" align="center"
label="排序号" label="排序号"
/> />
<!-- 菜单URL列 -->
<el-table-column <el-table-column
prop="url" prop="url"
header-align="center" header-align="center"
@ -80,10 +78,12 @@
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
label="菜单URL" label="菜单URL"
> >
<template #default="scope"> <template #default="scope"> <!-- 自定义列内容 -->
{{ scope.row.url || '-' }} {{ scope.row.url || '-' }} <!-- 如果没有值则显示'-' -->
</template> </template>
</el-table-column> </el-table-column>
<!-- 授权标识列 -->
<el-table-column <el-table-column
prop="perms" prop="perms"
header-align="center" header-align="center"
@ -92,10 +92,12 @@
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
label="授权标识" label="授权标识"
> >
<template #default="scope"> <template #default="scope"> <!-- 自定义列内容 -->
{{ scope.row.perms || '-' }} {{ scope.row.perms || '-' }} <!-- 如果没有值则显示'-' -->
</template> </template>
</el-table-column> </el-table-column>
<!-- 操作列 -->
<el-table-column <el-table-column
fixed="right" fixed="right"
header-align="center" header-align="center"
@ -103,19 +105,19 @@
width="150" width="150"
label="操作" label="操作"
> >
<template #default="scope"> <template #default="scope"> <!-- 自定义列内容 -->
<!-- 修改按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:menu:update')" v-if="isAuth('sys:menu:update')"
type="text" type="text"
@click="onAddOrUpdate(scope.row.menuId)" @click="onAddOrUpdate(scope.row.menuId)"
> >
修改 修改
</el-button> </el-button>
<!-- 删除按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:menu:delete')" v-if="isAuth('sys:menu:delete')"
type="text" type="text"
@click="onDelete(scope.row.menuId)" @click="onDelete(scope.row.menuId)"
> >
删除 删除
@ -123,6 +125,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 弹窗, 新增 / 修改 --> <!-- 弹窗, 新增 / 修改 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
@ -134,61 +137,75 @@
</template> </template>
<script setup> <script setup>
import { treeDataTranslate, isAuth } from '@/utils' import { ref, onMounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { treeDataTranslate, isAuth } from '@/utils' //
import AddOrUpdate from './add-or-update.vue' import { ElMessage, ElMessageBox } from 'element-plus' //
import AddOrUpdate from './add-or-update.vue' // /
//
const dataForm = ref({}) const dataForm = ref({})
//
onMounted(() => { onMounted(() => {
getDataList() getDataList()
}) })
//
const dataList = ref([]) const dataList = ref([])
/** /**
* 获取数据列表 * 获取数据列表方法
*/ */
const getDataList = () => { const getDataList = () => {
http({ http({
url: http.adornUrl('/sys/menu/table'), url: http.adornUrl('/sys/menu/table'), // API
method: 'get', method: 'get', //
params: http.adornParams() params: http.adornParams() //
}).then(({ data }) => { }).then(({ data }) => {
dataList.value = treeDataTranslate(data, 'menuId') dataList.value = treeDataTranslate(data, 'menuId') //
}) })
} }
// /
const addOrUpdateRef = ref(null) const addOrUpdateRef = ref(null)
//
const addOrUpdateVisible = ref(false) const addOrUpdateVisible = ref(false)
/** /**
* 新增 / 修改 * 新增 / 修改菜单项
* @param id * @param id 菜单项ID可选如果没有传入则表示新增
*/ */
const onAddOrUpdate = (id) => { const onAddOrUpdate = (id) => {
addOrUpdateVisible.value = true addOrUpdateVisible.value = true //
nextTick(() => { nextTick(() => {
addOrUpdateRef.value?.init(id) addOrUpdateRef.value?.init(id) //
}) })
} }
/** /**
* 删除 * 删除菜单项
* @param id * @param id 菜单项ID
*/ */
const onDelete = (id) => { const onDelete = (id) => {
//
ElMessageBox.confirm(`确定对[id=${id}]进行[删除]操作?`, '提示', { ElMessageBox.confirm(`确定对[id=${id}]进行[删除]操作?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
// HTTP
http({ http({
url: http.adornUrl(`/sys/menu/${id}`), url: http.adornUrl(`/sys/menu/${id}`),
method: 'delete', method: 'delete',
data: http.adornData() data: http.adornData()
}).then(() => { }).then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
getDataList() getDataList() //
} }
}) })
}) })

@ -1,9 +1,11 @@
<template> <template>
<!-- 角色管理对话框 -->
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="!dataForm.id ? '新增' : '修改'" :title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<!-- 表单 -->
<el-form <el-form
ref="dataFormRef" ref="dataFormRef"
:model="dataForm" :model="dataForm"
@ -11,6 +13,7 @@
label-width="80px" label-width="80px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 角色名称输入框 -->
<el-form-item <el-form-item
label="角色名称" label="角色名称"
prop="roleName" prop="roleName"
@ -20,6 +23,8 @@
placeholder="角色名称" placeholder="角色名称"
/> />
</el-form-item> </el-form-item>
<!-- 备注输入框 -->
<el-form-item <el-form-item
label="备注" label="备注"
prop="remark" prop="remark"
@ -29,6 +34,8 @@
placeholder="备注" placeholder="备注"
/> />
</el-form-item> </el-form-item>
<!-- 授权菜单树 -->
<el-form-item label="授权"> <el-form-item label="授权">
<el-tree <el-tree
ref="menuListTreeRef" ref="menuListTreeRef"
@ -39,98 +46,135 @@
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 对话框底部按钮组 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="visible = false">取消</el-button> <el-button @click="visible = false">取消</el-button> <!-- -->
<el-button <el-button type="primary" @click="onSubmit()"></el-button> <!-- 确认按钮 -->
type="primary"
@click="onSubmit()"
>确定</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script setup>
import { ElMessage } from 'element-plus' import { ref, reactive, nextTick } from 'vue'
import { treeDataTranslate } from '@/utils' import { ElMessage } from 'element-plus' //
import { Debounce } from '@/utils/debounce' import { treeDataTranslate } from '@/utils' //
import { Debounce } from '@/utils/debounce' //
//
const emit = defineEmits(['refreshDataList']) const emit = defineEmits(['refreshDataList'])
const tempKey = -666666 // key) tree. #
// keytree
const tempKey = -666666
//
const visible = ref(false) const visible = ref(false)
//
const menuList = ref([]) const menuList = ref([])
//
const menuListTreeProps = { const menuListTreeProps = {
label: 'name', label: 'name', //
children: 'children' children: 'children' //
} }
// 使reactive使
const dataForm = reactive({ const dataForm = reactive({
id: 0, id: 0, // ID0
roleName: '', roleName: '', //
remark: '' remark: '' //
}) })
// 使reactive使
const dataRule = reactive({ const dataRule = reactive({
roleName: [ roleName: [ //
{ required: true, message: '角色名称不能为空', trigger: 'blur' }, { required: true, message: '角色名称不能为空', trigger: 'blur' }, //
{ pattern: /\s\S+|S+\s|\S/, message: '请输入正确的角色名称', trigger: 'blur' } { pattern: /\s\S+|\S+\s|\S/, message: '请输入正确的角色名称', trigger: 'blur' } //
], ],
remark: [ remark: [ //
{ required: false, pattern: /\s\S+|S+\s|\S/, message: '输入格式有误', trigger: 'blur' } { required: false, pattern: /\s\S+|\S+\s|\S/, message: '输入格式有误', trigger: 'blur' } //
] ]
}) })
//
const dataFormRef = ref(null) const dataFormRef = ref(null)
//
const menuListTreeRef = ref(null) const menuListTreeRef = ref(null)
/**
* 初始化方法接收可选的角色ID参数
* @param id 角色ID可选
*/
const init = (id) => { const init = (id) => {
dataForm.id = id || 0 dataForm.id = id || 0 // id
//
http({ http({
url: http.adornUrl('/sys/menu/table'), url: http.adornUrl('/sys/menu/table'), // API
method: 'get', method: 'get', //
params: http.adornParams() params: http.adornParams() //
}) })
.then(({ data }) => { .then(({ data }) => {
menuList.value = treeDataTranslate(data, 'menuId', 'parentId') menuList.value = treeDataTranslate(data, 'menuId', 'parentId') //
}) })
.then(() => { .then(() => {
visible.value = true visible.value = true //
nextTick(() => { return nextTick() // DOM
dataFormRef.value?.resetFields()
menuListTreeRef.value?.setCheckedKeys([])
}) })
.then(() => {
dataFormRef.value?.resetFields() //
menuListTreeRef.value?.setCheckedKeys([]) //
}) })
.then(() => { .then(() => {
if (dataForm.id) { if (dataForm.id) { //
http({ http({
url: http.adornUrl(`/sys/role/info/${dataForm.id}`), url: http.adornUrl(`/sys/role/info/${dataForm.id}`), // API
method: 'get', method: 'get', //
params: http.adornParams() params: http.adornParams() //
}) })
.then(({ data }) => { .then(({ data }) => {
dataForm.roleName = data.roleName dataForm.roleName = data.roleName //
dataForm.remark = data.remark dataForm.remark = data.remark //
// key
const idx = data.menuIdList.indexOf(tempKey) const idx = data.menuIdList.indexOf(tempKey)
if (idx !== -1) { if (idx !== -1) {
data.menuIdList.splice(idx, data.menuIdList.length - idx) data.menuIdList.splice(idx, data.menuIdList.length - idx)
} }
//
menuListTreeRef.value?.setCheckedKeys(data.menuIdList) menuListTreeRef.value?.setCheckedKeys(data.menuIdList)
}) })
} }
}) })
} }
// init便
defineExpose({ init }) defineExpose({ init })
/** /**
* 表单提交 * 提交表单方法
*/ */
const onSubmit = Debounce(() => { const onSubmit = Debounce(() => { // 使
dataFormRef.value?.validate((valid) => { dataFormRef.value?.validate((valid) => { //
if (valid) { if (valid) { //
http({ http({
url: http.adornUrl('/sys/role'), url: http.adornUrl('/sys/role'), // API
method: dataForm.id ? 'put' : 'post', method: dataForm.id ? 'put' : 'post', // id
data: http.adornData({ data: http.adornData({
roleId: dataForm.id || undefined, roleId: dataForm.id || undefined, // ID
roleName: dataForm.roleName, roleName: dataForm.roleName, //
remark: dataForm.remark, remark: dataForm.remark, //
menuIdList: [].concat(menuListTreeRef.value?.getCheckedKeys(), [tempKey], menuListTreeRef.value?.getHalfCheckedKeys()) // ID
menuIdList: [].concat(
menuListTreeRef.value?.getCheckedKeys(),
[tempKey],
menuListTreeRef.value?.getHalfCheckedKeys()
)
}) })
}) })
.then(() => { .then(() => {
@ -139,13 +183,12 @@ const onSubmit = Debounce(() => {
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
visible.value = false visible.value = false //
emit('refreshDataList') emit('refreshDataList') //
} }
}) })
}) })
} }
}) })
}) })
</script> </script>

@ -1,5 +1,7 @@
<template> <template>
<!-- 角色管理模块 -->
<div class="mod-role"> <div class="mod-role">
<!-- 使用avue-crud创建CRUD表格 -->
<avue-crud <avue-crud
ref="crudRef" ref="crudRef"
:page="page" :page="page"
@ -9,7 +11,9 @@
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<!-- 左侧菜单栏 -->
<template #menu-left> <template #menu-left>
<!-- 新增按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:role:save')" v-if="isAuth('sys:role:save')"
type="primary" type="primary"
@ -19,6 +23,7 @@
新增 新增
</el-button> </el-button>
<!-- 批量删除按钮只有有权限且选择了项目时显示 -->
<el-button <el-button
v-if="isAuth('sys:role:delete')" v-if="isAuth('sys:role:delete')"
type="danger" type="danger"
@ -29,7 +34,9 @@
</el-button> </el-button>
</template> </template>
<template #menu="scope"> <!-- 行内菜单 -->
<template #menu="scope"> <!-- 自定义行内菜单 -->
<!-- 编辑按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:role:update')" v-if="isAuth('sys:role:update')"
type="primary" type="primary"
@ -39,6 +46,7 @@
编辑 编辑
</el-button> </el-button>
<!-- 删除按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:role:delete')" v-if="isAuth('sys:role:delete')"
type="danger" type="danger"
@ -60,94 +68,119 @@
</template> </template>
<script setup> <script setup>
import { isAuth } from '@/utils' import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { isAuth } from '@/utils' //
import { tableOption } from '@/crud/sys/role.js' import { ElMessage, ElMessageBox } from 'element-plus' //
import AddOrUpdate from './add-or-update.vue' import { tableOption } from '@/crud/sys/role.js' //
import AddOrUpdate from './add-or-update.vue' // /
//
const dataList = ref([]) const dataList = ref([])
//
const dataListSelections = ref([]) const dataListSelections = ref([])
// 使reactive使
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
/** /**
* 获取数据列表 * 获取数据列表方法
* @param pageParam 分页参数可选
* @param params 搜索参数可选
* @param done 加载完成回调可选
*/ */
const getDataList = (pageParam, params, done) => { const getDataList = (pageParam, params, done) => {
http({ http({
url: http.adornUrl('/sys/role/page'), url: http.adornUrl('/sys/role/page'), // API
method: 'get', method: 'get', //
params: http.adornParams( params: http.adornParams(
Object.assign( Object.assign(
{ {
current: pageParam == null ? page.currentPage : pageParam.currentPage, current: pageParam == null ? page.currentPage : pageParam.currentPage, //
size: pageParam == null ? page.pageSize : pageParam.pageSize size: pageParam == null ? page.pageSize : pageParam.pageSize //
}, },
params params //
) )
) )
}) })
.then(({ data }) => { .then(({ data }) => {
dataList.value = data.records dataList.value = data.records //
page.total = data.total page.total = data.total //
if (done) { if (done) {
done() done() //
} }
}) })
} }
/** /**
* 条件查询 * 条件查询方法
* @param params 搜索参数
* @param done 加载完成回调可选
*/ */
const onSearch = (params, done) => { const onSearch = (params, done) => {
getDataList(page, params, done) getDataList(page, params, done)
} }
/** /**
* 多选变化 * 多选变化方法
* @param val 选择的数据项
*/ */
const selectionChange = (val) => { const selectionChange = (val) => {
dataListSelections.value = val dataListSelections.value = val //
} }
//
const addOrUpdateVisible = ref(false) const addOrUpdateVisible = ref(false)
//
const addOrUpdateRef = ref(null) const addOrUpdateRef = ref(null)
/** /**
* 新增 / 修改 * 新增 / 修改角色信息
* @param id 角色ID可选如果没有传入则表示新增
*/ */
const onAddOrUpdate = (id) => { const onAddOrUpdate = (id) => {
addOrUpdateVisible.value = true addOrUpdateVisible.value = true //
nextTick(() => { nextTick(() => {
addOrUpdateRef.value?.init(id) addOrUpdateRef.value?.init(id) //
}) })
} }
/** /**
* 删除 * 删除角色信息
* @param id 角色ID可选如果传入则为单个删除否则为批量删除
*/ */
const onDelete = (id) => { const onDelete = (id) => {
const ids = id ? [id] : dataListSelections.value?.map(item => { const ids = id ? [id] : dataListSelections.value?.map(item => item.roleId) // ID
return item.roleId
}) //
ElMessageBox.confirm(`确定进行[${id ? '删除' : '批量删除'}]操作?`, '提示', { ElMessageBox.confirm(`确定进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })
.then(() => { .then(() => {
// HTTP
http({ http({
url: http.adornUrl('/sys/role'), url: http.adornUrl('/sys/role'),
method: 'delete', method: 'delete',
data: http.adornData(ids, false) data: http.adornData(ids, false) // ID
}) })
.then(() => { .then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
getDataList() getDataList() //
} }
}) })
}) })
}).catch(() => { }) }).catch(() => { /* 用户取消删除操作 */ })
} }
</script> </script>

@ -1,9 +1,11 @@
<template> <template>
<!-- 用户管理对话框 -->
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="!dataForm.id ? '新增' : '修改'" :title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<!-- 表单 -->
<el-form <el-form
ref="dataFormRef" ref="dataFormRef"
:model="dataForm" :model="dataForm"
@ -11,6 +13,7 @@
label-width="80px" label-width="80px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 用户名输入框 -->
<el-form-item <el-form-item
label="用户名" label="用户名"
prop="userName" prop="userName"
@ -20,6 +23,8 @@
placeholder="登录帐号" placeholder="登录帐号"
/> />
</el-form-item> </el-form-item>
<!-- 密码输入框 -->
<el-form-item <el-form-item
label="密码" label="密码"
prop="password" prop="password"
@ -31,6 +36,8 @@
placeholder="密码" placeholder="密码"
/> />
</el-form-item> </el-form-item>
<!-- 确认密码输入框 -->
<el-form-item <el-form-item
label="确认密码" label="确认密码"
prop="comfirmPassword" prop="comfirmPassword"
@ -42,6 +49,8 @@
placeholder="确认密码" placeholder="确认密码"
/> />
</el-form-item> </el-form-item>
<!-- 邮箱输入框 -->
<el-form-item <el-form-item
label="邮箱" label="邮箱"
prop="email" prop="email"
@ -51,6 +60,8 @@
placeholder="邮箱" placeholder="邮箱"
/> />
</el-form-item> </el-form-item>
<!-- 手机号输入框 -->
<el-form-item <el-form-item
label="手机号" label="手机号"
prop="mobile" prop="mobile"
@ -61,171 +72,193 @@
placeholder="手机号" placeholder="手机号"
/> />
</el-form-item> </el-form-item>
<!-- 角色选择 -->
<el-form-item <el-form-item
label="角色" label="角色"
prop="roleIdList" prop="roleIdList"
> >
<el-checkbox-group v-model="dataForm.roleIdList"> <el-checkbox-group v-model="dataForm.roleIdList"> <!-- ID -->
<el-checkbox <el-checkbox
v-for="role in roleList" v-for="role in roleList"
:key="role.roleId" :key="role.roleId"
:label="role.roleId" :label="role.roleId"
> >
{{ role.roleName }} {{ role.roleName }} <!-- 显示角色名称 -->
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 状态选择 -->
<el-form-item <el-form-item
label="状态" label="状态"
prop="status" prop="status"
> >
<el-radio-group v-model="dataForm.status"> <el-radio-group v-model="dataForm.status"> <!-- -->
<el-radio :label="0"> <el-radio :label="0">禁用</el-radio> <!-- -->
禁用 <el-radio :label="1">正常</el-radio> <!-- -->
</el-radio>
<el-radio :label="1">
正常
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 对话框底部按钮组 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="visible = false">取消</el-button> <el-button @click="visible = false">取消</el-button> <!-- -->
<el-button <el-button type="primary" @click="onSubmit()"></el-button> <!-- 确认按钮 -->
type="primary"
@click="onSubmit()"
>确定</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script setup>
import { ElMessage } from 'element-plus' import { ref, reactive, nextTick } from 'vue'
import { isEmail, isMobile } from '@/utils/validate' import { ElMessage } from 'element-plus' //
import { Debounce } from '@/utils/debounce' import { isEmail, isMobile } from '@/utils/validate' //
import { encrypt } from '@/utils/crypto' import { Debounce } from '@/utils/debounce' //
import { encrypt } from '@/utils/crypto' //
//
const emit = defineEmits(['refreshDataList']) const emit = defineEmits(['refreshDataList'])
//
const visible = ref(false) const visible = ref(false)
// 使reactive使
const dataForm = reactive({ const dataForm = reactive({
id: 0, id: 0, // ID0
userName: '', userName: '', //
password: '', password: '', //
comfirmPassword: '', comfirmPassword: '', //
email: '', email: '', //
mobile: '', mobile: '', //
roleIdList: [], roleIdList: [], // ID
status: 1 status: 1 // 1
}) })
// eslint-disable-next-line no-unused-vars //
const validatePassword = (rule, value, callback) => { const validatePassword = (rule, value, callback) => {
if (!dataForm.id && !/\S/.test(value)) { if (!dataForm.id && !/\S/.test(value)) { //
callback(new Error('密码不能为空')) callback(new Error('密码不能为空'))
} else { } else {
callback() callback() //
} }
} }
// eslint-disable-next-line no-unused-vars
//
const validateComfirmPassword = (rule, value, callback) => { const validateComfirmPassword = (rule, value, callback) => {
if (!dataForm.id && !/\S/.test(value)) { if (!dataForm.id && !/\S/.test(value)) { //
dataForm.password = '' dataForm.password = ''
callback(new Error('确认密码不能为空')) callback(new Error('确认密码不能为空'))
} else if (dataForm.password !== value) { } else if (dataForm.password !== value) { //
callback(new Error('确认密码与密码输入不一致')) callback(new Error('确认密码与密码输入不一致'))
} else { } else {
callback() callback() //
} }
} }
// eslint-disable-next-line no-unused-vars
//
const validateEmail = (rule, value, callback) => { const validateEmail = (rule, value, callback) => {
if (!isEmail(value)) { if (!isEmail(value)) { //
callback(new Error('邮箱格式错误')) callback(new Error('邮箱格式错误'))
} else { } else {
callback() callback() //
} }
} }
// eslint-disable-next-line no-unused-vars
//
const validateMobile = (rule, value, callback) => { const validateMobile = (rule, value, callback) => {
if (!isMobile(value)) { if (!isMobile(value)) { //
callback(new Error('手机号格式错误')) callback(new Error('手机号格式错误'))
} else { } else {
callback() callback() //
} }
} }
const dataRule = {
// 使reactive使
const dataRule = reactive({
userName: [ userName: [
{ required: true, message: '用户名不能为空', trigger: 'blur' }, { required: true, message: '用户名不能为空', trigger: 'blur' }, //
{ pattern: /\s\S+|S+\s|\S/, message: '请输入正确的用户名', trigger: 'blur' } { pattern: /\s\S+|\S+\s|\S/, message: '请输入正确的用户名', trigger: 'blur' } //
], ],
password: [ password: [
{ validator: validatePassword, trigger: 'blur' } { validator: validatePassword, trigger: 'blur' } //
], ],
comfirmPassword: [ comfirmPassword: [
{ validator: validateComfirmPassword, trigger: 'blur' } { validator: validateComfirmPassword, trigger: 'blur' } //
], ],
email: [ email: [
{ required: true, message: '邮箱不能为空', trigger: 'blur' }, { required: true, message: '邮箱不能为空', trigger: 'blur' }, //
{ validator: validateEmail, trigger: 'blur' } { validator: validateEmail, trigger: 'blur' } //
], ],
mobile: [ mobile: [
{ required: true, message: '手机号不能为空', trigger: 'blur' }, { required: true, message: '手机号不能为空', trigger: 'blur' }, //
{ validator: validateMobile, trigger: 'blur' } { validator: validateMobile, trigger: 'blur' } //
] ]
} })
//
const roleList = ref([]) const roleList = ref([])
//
const dataFormRef = ref(null) const dataFormRef = ref(null)
/**
* 初始化方法接收可选的用户ID参数
* @param id 用户ID可选
*/
const init = (id) => { const init = (id) => {
dataForm.id = id || 0 dataForm.id = id || 0 // id
//
http({ http({
url: http.adornUrl('/sys/role/list'), url: http.adornUrl('/sys/role/list'), // API
method: 'get', method: 'get', //
params: http.adornParams() params: http.adornParams() //
}).then(({ data }) => { }).then(({ data }) => {
roleList.value = data roleList.value = data //
}).then(() => { }).then(() => {
visible.value = true visible.value = true //
nextTick(() => { return nextTick() // DOM
dataFormRef.value?.resetFields()
})
}).then(() => { }).then(() => {
if (dataForm.id) { dataFormRef.value?.resetFields() //
}).then(() => {
if (dataForm.id) { //
http({ http({
url: http.adornUrl(`/sys/user/info/${dataForm.id}`), url: http.adornUrl(`/sys/user/info/${dataForm.id}`), // API
method: 'get', method: 'get', //
params: http.adornParams() params: http.adornParams() //
}).then(({ data }) => { }).then(({ data }) => {
dataForm.userName = data.username dataForm.userName = data.username //
dataForm.email = data.email dataForm.email = data.email //
dataForm.mobile = data.mobile dataForm.mobile = data.mobile //
dataForm.roleIdList = data.roleIdList dataForm.roleIdList = data.roleIdList // ID
dataForm.status = data.status dataForm.status = data.status //
}) })
} }
}) })
} }
// init便
defineExpose({ init }) defineExpose({ init })
/** /**
* 表单提交 * 提交表单方法
*/ */
const onSubmit = Debounce(() => { const onSubmit = Debounce(() => { // 使
dataFormRef.value?.validate((valid) => { dataFormRef.value?.validate((valid) => { //
if (valid) { if (valid) { //
http({ http({
url: http.adornUrl('/sys/user'), url: http.adornUrl('/sys/user'), // API
method: dataForm.id ? 'put' : 'post', method: dataForm.id ? 'put' : 'post', // id
data: http.adornData({ data: http.adornData({
userId: dataForm.id || undefined, userId: dataForm.id || undefined, // ID
username: dataForm.userName, username: dataForm.userName, //
password: encrypt(dataForm.password), password: encrypt(dataForm.password), //
email: dataForm.email, email: dataForm.email, //
mobile: dataForm.mobile, mobile: dataForm.mobile, //
status: dataForm.status, status: dataForm.status, //
roleIdList: dataForm.roleIdList roleIdList: dataForm.roleIdList // ID
}) })
}).then(() => { }).then(() => {
ElMessage({ ElMessage({
@ -233,13 +266,12 @@ const onSubmit = Debounce(() => {
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
visible.value = false visible.value = false //
emit('refreshDataList') emit('refreshDataList') //
} }
}) })
}) })
} }
}) })
}) })
</script> </script>

@ -1,5 +1,7 @@
<template> <template>
<!-- 用户管理模块 -->
<div class="mod-user"> <div class="mod-user">
<!-- 使用avue-crud创建CRUD表格 -->
<avue-crud <avue-crud
ref="crudRef" ref="crudRef"
:page="page" :page="page"
@ -9,7 +11,9 @@
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<!-- 左侧菜单栏 -->
<template #menu-left> <template #menu-left>
<!-- 新增按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:user:save')" v-if="isAuth('sys:user:save')"
type="primary" type="primary"
@ -19,19 +23,20 @@
新增 新增
</el-button> </el-button>
<!-- 批量删除按钮只有有权限且选择了项目时显示 -->
<el-button <el-button
v-if="isAuth('sys:user:delete')" v-if="isAuth('sys:user:delete')"
type="danger" type="danger"
:disabled="dataListSelections.length <= 0" :disabled="dataListSelections.length <= 0"
@click="onDelete()" @click="onDelete()"
> >
批量删除 批量删除
</el-button> </el-button>
</template> </template>
<template
#menu="scope" <!-- 行内菜单 -->
> <template #menu="scope"> <!-- 自定义行内菜单 -->
<!-- 编辑按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:user:update')" v-if="isAuth('sys:user:update')"
type="primary" type="primary"
@ -41,6 +46,7 @@
编辑 编辑
</el-button> </el-button>
<!-- 删除按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('sys:user:delete')" v-if="isAuth('sys:user:delete')"
type="danger" type="danger"
@ -62,94 +68,120 @@
</template> </template>
<script setup> <script setup>
import { isAuth } from '@/utils' import { ref, reactive, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { isAuth } from '@/utils' //
import { tableOption } from '@/crud/sys/user.js' import { ElMessage, ElMessageBox } from 'element-plus' //
import AddOrUpdate from './add-or-update.vue' import { tableOption } from '@/crud/sys/user.js' //
import AddOrUpdate from './add-or-update.vue' // /
//
const dataList = ref([]) const dataList = ref([])
//
const dataListLoading = ref(false) const dataListLoading = ref(false)
//
const dataListSelections = ref([]) const dataListSelections = ref([])
//
const addOrUpdateVisible = ref(false) const addOrUpdateVisible = ref(false)
// 使reactive使
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
/** /**
* 获取数据列表 * 获取数据列表方法
* @param pageParam 分页参数可选
* @param params 搜索参数可选
* @param done 加载完成回调可选
*/ */
const getDataList = (pageParam, params, done) => { const getDataList = (pageParam, params, done) => {
dataListLoading.value = true dataListLoading.value = true // true
http({ http({
url: http.adornUrl('/sys/user/page'), url: http.adornUrl('/sys/user/page'), // API
method: 'get', method: 'get', //
params: http.adornParams( params: http.adornParams(
Object.assign( Object.assign(
{ {
current: pageParam == null ? page.currentPage : pageParam.currentPage, current: pageParam == null ? page.currentPage : pageParam.currentPage, //
size: pageParam == null ? page.pageSize : pageParam.pageSize size: pageParam == null ? page.pageSize : pageParam.pageSize //
}, },
params params //
) )
) )
}).then(({ data }) => { }).then(({ data }) => {
dataList.value = data.records dataList.value = data.records //
page.total = data.total page.total = data.total //
dataListLoading.value = false dataListLoading.value = false // false
if (done) done() if (done) done() //
}) })
} }
/** /**
* 条件查询 * 条件查询方法
* @param params 搜索参数
* @param done 加载完成回调可选
*/ */
const onSearch = (params, done) => { const onSearch = (params, done) => {
getDataList(page, params, done) getDataList(page, params, done)
} }
/** /**
* 多选变化 * 多选变化方法
* @param val 选择的数据项
*/ */
const selectionChange = (val) => { const selectionChange = (val) => {
dataListSelections.value = val dataListSelections.value = val //
} }
//
const addOrUpdateRef = ref(null) const addOrUpdateRef = ref(null)
/** /**
* 新增 / 修改 * 新增 / 修改用户信息
* @param id 用户ID可选如果没有传入则表示新增
*/ */
const onAddOrUpdate = (id) => { const onAddOrUpdate = (id) => {
addOrUpdateVisible.value = true addOrUpdateVisible.value = true //
nextTick(() => { nextTick(() => {
addOrUpdateRef.value?.init(id) addOrUpdateRef.value?.init(id) //
}) })
} }
/** /**
* 删除 * 删除用户信息
* @param id 用户ID可选如果传入则为单个删除否则为批量删除
*/ */
const onDelete = (id) => { const onDelete = (id) => {
const userIds = id ? [id] : dataListSelections.value?.map(item => { const userIds = id ? [id] : dataListSelections.value?.map(item => item.userId) // ID
return item.userId
}) //
ElMessageBox.confirm(`确定对[id=${userIds.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', { ElMessageBox.confirm(`确定对[id=${userIds.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
// HTTP
http({ http({
url: http.adornUrl('/sys/user'), url: http.adornUrl('/sys/user'),
method: 'delete', method: 'delete',
data: http.adornData(userIds, false) data: http.adornData(userIds, false) // ID
}).then(() => { }).then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
getDataList() getDataList() //
} }
}) })
}) })
}).catch(() => { }) }).catch(() => { /* 用户取消删除操作 */ })
} }
</script> </script>

@ -1,9 +1,11 @@
<template> <template>
<!-- 用户管理对话框 -->
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="!dataForm.userId ? '新增' : '修改'" :title="!dataForm.userId ? '新增' : '修改'"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<!-- 表单 -->
<el-form <el-form
ref="dataFormRef" ref="dataFormRef"
:model="dataForm" :model="dataForm"
@ -11,6 +13,7 @@
label-width="80px" label-width="80px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 用户头像展示 -->
<el-form-item <el-form-item
label="用户头像" label="用户头像"
prop="pic" prop="pic"
@ -20,11 +23,11 @@
:src="dataForm.pic" :src="dataForm.pic"
class="image" class="image"
alt="" alt=""
> />
<div v-else> <div v-else></div> <!-- -->
</div>
</el-form-item> </el-form-item>
<!-- 用户昵称输入框 -->
<el-form-item <el-form-item
label="用户昵称" label="用户昵称"
prop="nickName" prop="nickName"
@ -35,105 +38,115 @@
placeholder="用户昵称" placeholder="用户昵称"
/> />
</el-form-item> </el-form-item>
<!-- 状态选择 -->
<el-form-item <el-form-item
label="状态" label="状态"
prop="status" prop="status"
> >
<el-radio-group v-model="dataForm.status"> <el-radio-group v-model="dataForm.status"> <!-- -->
<el-radio :label="0"> <el-radio :label="0">禁用</el-radio> <!-- -->
禁用 <el-radio :label="1">正常</el-radio> <!-- -->
</el-radio>
<el-radio :label="1">
正常
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 对话框底部按钮组 -->
<template #footer> <template #footer>
<span <span class="dialog-footer">
class="dialog-footer" <el-button @click="visible = false">取消</el-button> <!-- -->
> <el-button type="primary" @click="onSubmit()"></el-button> <!-- 确认按钮 -->
<el-button @click="visible = false">取消</el-button>
<el-button
type="primary"
@click="onSubmit()"
>确定</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script setup>
import { ElMessage } from 'element-plus' import { ref, reactive, nextTick } from 'vue'
import { Debounce } from '@/utils/debounce' import { ElMessage } from 'element-plus' //
import { Debounce } from '@/utils/debounce' //
//
const emit = defineEmits(['refreshDataList']) const emit = defineEmits(['refreshDataList'])
//
const visible = ref(false) const visible = ref(false)
// 使ref使
const dataForm = ref({ const dataForm = ref({
userId: 0, userId: 0, // ID0
nickName: '', nickName: '', //
pic: '', pic: '', //
status: 1 status: 1 // 1
}) })
// 使reactive使
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
// 使
const dataRule = { const dataRule = {
nickName: [ nickName: [
{ required: true, message: '用户名不能为空', trigger: 'blur' } { required: true, message: '用户名不能为空', trigger: 'blur' } //
] ]
} }
//
const dataFormRef = ref(null) const dataFormRef = ref(null)
/**
* 初始化方法接收可选的用户ID参数
* @param id 用户ID可选
*/
const init = (id) => { const init = (id) => {
dataForm.value.userId = id || 0 dataForm.value.userId = id || 0 // id
visible.value = true visible.value = true //
nextTick(() => { nextTick(() => {
dataFormRef.value?.resetFields() dataFormRef.value?.resetFields() //
}) })
if (dataForm.value.userId) { if (dataForm.value.userId) { //
http({ http({
url: http.adornUrl(`/admin/user/info/${dataForm.value.userId}`), url: http.adornUrl(`/admin/user/info/${dataForm.value.userId}`), // API
method: 'get', method: 'get', //
params: http.adornParams() params: http.adornParams() //
}) }).then(({ data }) => {
.then(({ data }) => { dataForm.value = data //
dataForm.value = data
}) })
} }
} }
// init便
defineExpose({ init }) defineExpose({ init })
/** /**
* 表单提交 * 提交表单方法
*/ */
const onSubmit = Debounce(() => { const onSubmit = Debounce(() => { // 使
dataFormRef.value?.validate(valid => { dataFormRef.value?.validate((valid) => { //
if (valid) { if (valid) { //
http({ http({
url: http.adornUrl('/admin/user'), url: http.adornUrl('/admin/user'), // API
method: dataForm.value.userId ? 'put' : 'post', method: dataForm.value.userId ? 'put' : 'post', // userId
data: http.adornData({ data: http.adornData({
userId: dataForm.value.userId || undefined, userId: dataForm.value.userId || undefined, // ID
nickName: dataForm.value.nickName, nickName: dataForm.value.nickName, //
status: dataForm.value.status status: dataForm.value.status //
}) })
}) }).then(() => {
.then(() => {
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
visible.value = false visible.value = false //
emit('refreshDataList', page) emit('refreshDataList', page) //
} }
}) })
}) })
} }
}) })
}) })
</script> </script>

@ -1,5 +1,7 @@
<template> <template>
<!-- 用户管理模块 -->
<div class="mod-user"> <div class="mod-user">
<!-- 使用avue-crud创建CRUD表格 -->
<avue-crud <avue-crud
ref="crudRef" ref="crudRef"
:page="page" :page="page"
@ -9,21 +11,17 @@
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<template #pic="scope"> <!-- 自定义列模板用户头像 -->
<span <template #pic="scope"> <!-- 自定义用户头像列 -->
v-if="scope.row.pic" <span v-if="scope.row.pic" class="avue-crud__img">
class="avue-crud__img" <el-icon><Document /></el-icon> <!-- -->
>
<el-icon><Document /></el-icon>
</span> </span>
<span v-else>-</span> <span v-else>-</span> <!-- "-" -->
</template> </template>
<template #status="scope"> <!-- 自定义列模板状态 -->
<el-tag <template #status="scope"> <!-- 自定义状态列 -->
v-if="scope.row.status === 0" <el-tag v-if="scope.row.status === 0" type="danger">
type="danger"
>
禁用 禁用
</el-tag> </el-tag>
<el-tag v-else> <el-tag v-else>
@ -31,7 +29,9 @@
</el-tag> </el-tag>
</template> </template>
<template #menu="scope"> <!-- 自定义行内菜单 -->
<template #menu="scope"> <!-- 自定义行内菜单 -->
<!-- 编辑按钮只有有权限时显示 -->
<el-button <el-button
v-if="isAuth('admin:user:update')" v-if="isAuth('admin:user:update')"
type="primary" type="primary"
@ -53,68 +53,87 @@
</template> </template>
<script setup> <script setup>
import { isAuth } from '@/utils' import { ref, reactive, nextTick } from 'vue'
import { tableOption } from '@/crud/user/user.js' import { isAuth } from '@/utils' //
import AddOrUpdate from './add-or-update.vue' import { tableOption } from '@/crud/user/user.js' //
import AddOrUpdate from './add-or-update.vue' // /
//
const dataList = ref([]) const dataList = ref([])
//
const dataListLoading = ref(false) const dataListLoading = ref(false)
//
const dataListSelections = ref([]) const dataListSelections = ref([])
//
const addOrUpdateVisible = ref(false) const addOrUpdateVisible = ref(false)
// 使reactive使
const page = reactive({ const page = reactive({
total: 0, // total: 0, //
currentPage: 1, // currentPage: 1, //
pageSize: 10 // pageSize: 10 //
}) })
/** /**
* 获取数据列表 * 获取数据列表方法
* @param pageParam 分页参数可选
* @param params 搜索参数可选
* @param done 加载完成回调可选
*/ */
const getDataList = (pageParam, params, done) => { const getDataList = (pageParam, params, done) => {
dataListLoading.value = true dataListLoading.value = true // true
http({ http({
url: http.adornUrl('/admin/user/page'), url: http.adornUrl('/admin/user/page'), // API
method: 'get', method: 'get', //
params: http.adornParams( params: http.adornParams(
Object.assign( Object.assign(
{ {
current: pageParam == null ? page.currentPage : pageParam.currentPage, current: pageParam == null ? page.currentPage : pageParam.currentPage, //
size: pageParam == null ? page.pageSize : pageParam.pageSize size: pageParam == null ? page.pageSize : pageParam.pageSize //
}, },
params params //
) )
) )
}) }).then(({ data }) => {
.then(({ data }) => { dataList.value = data.records //
dataList.value = data.records page.total = data.total //
page.total = data.total dataListLoading.value = false // false
dataListLoading.value = false if (done) done() //
if (done) done()
}) })
} }
//
const addOrUpdateRef = ref(null) const addOrUpdateRef = ref(null)
/** /**
* 新增 / 修改 * 新增 / 修改用户信息
* @param id * @param id 用户ID可选如果没有传入则表示新增
*/ */
const onAddOrUpdate = (id) => { const onAddOrUpdate = (id) => {
addOrUpdateVisible.value = true addOrUpdateVisible.value = true //
nextTick(() => { nextTick(() => {
addOrUpdateRef.value?.init(id) addOrUpdateRef.value?.init(id) //
}) })
} }
/** /**
* 条件查询 * 条件查询方法
* @param params 搜索参数
* @param done 加载完成回调可选
*/ */
const onSearch = (params, done) => { const onSearch = (params, done) => {
getDataList(page, params, done) getDataList(page, params, done)
} }
/** /**
* 多选变化 * 多选变化方法
* @param val 选择的数据项
*/ */
const selectionChange = (val) => { const selectionChange = (val) => {
dataListSelections.value = val dataListSelections.value = val //
} }
</script> </script>

Loading…
Cancel
Save