Compare commits

..

No commits in common. 'ca5c23059baf41c90a3449b28a40c85ae2551aa1' and '9502fa189079236e430e99b57bbb6f0725085865' have entirely different histories.

@ -1,11 +1,9 @@
<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"
@ -13,7 +11,6 @@
label-width="100px" label-width="100px"
@keyup.enter="onSubmit()" @keyup.enter="onSubmit()"
> >
<!-- 地区名称输入项 -->
<el-form-item <el-form-item
label="地区名称" label="地区名称"
prop="areaName" prop="areaName"
@ -25,7 +22,6 @@
show-word-limit show-word-limit
/> />
</el-form-item> </el-form-item>
<!-- 上级地区选择项 -->
<el-form-item <el-form-item
label="上级地区" label="上级地区"
prop="parentId" prop="parentId"
@ -41,7 +37,6 @@
/> />
</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
@ -64,12 +59,7 @@
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' },
@ -77,7 +67,6 @@ const dataRule = reactive({
] ]
}) })
//
const visible = ref(false) const visible = ref(false)
const areaList = ref([]) const areaList = ref([])
const dataForm = ref({ const dataForm = ref({
@ -92,76 +81,61 @@ 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 // ID dataForm.value.areaId = areaId || 0
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 }) => {
dataForm.value = data //
selectedOptions.value = dataForm.value.parentId //
// categoryTreePropsreactive
categoryTreeProps.areaId = dataForm.value.areaId
categoryTreeProps.areaName = dataForm.value.areaName
}) })
.then(({ data }) => {
dataForm.value = data
selectedOptions.value = dataForm.value.parentId
categoryTreeProps.areaId = dataForm.value.areaId
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 }) => {
areaList.value = treeDataTranslate(data, 'areaId', 'parentId')
}) })
.then(({ data }) => {
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)
} }
}) })
}) })
@ -169,9 +143,8 @@ 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,13 +1,10 @@
<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"
@ -16,20 +13,17 @@
新增 新增
</el-button> </el-button>
<!-- 树形控件展示地区层级结构 -->
<el-tree <el-tree
ref="tree2Ref" ref="tree2Ref"
:data="areaTreeData" :data="areaTreeData"
node-key="areaId" node-key="areaId"
:filter-node-method="filterNode" :filter-node-method="filterNode"
: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"
@ -37,7 +31,6 @@
> >
修改 修改
</el-button> </el-button>
<!-- 删除按钮点击时触发删除操作 -->
<el-button <el-button
type="text" type="text"
icon="el-icon-delete" icon="el-icon-delete"
@ -46,59 +39,48 @@
删除 删除
</el-button> </el-button>
</span> </span>
</template> </template>
</el-tree> </el-tree>
<!-- 添加或更新对话框组件 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@refresh-data-list="getDataList" @refresh-data-list="getDataList"
@close="addOrUpdateVisible=false" @close="addOrUpdateVisible=false"
/> />
</div> </div>
</template> </template>
<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.value, () => areaName,
(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'),
@ -108,46 +90,38 @@ 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 可选参数若提供则表示更新指定ID的地区信息 * @param 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 要删除的地区ID * @param areaId
*/ */
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',
@ -157,37 +131,35 @@ 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)
} }
// onDelete // eslint-disable-next-line no-unused-vars
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%; // 30% width: 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,111 +1,89 @@
<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" :rules="dataRule"
:rules="dataRule" label-width="80px"
label-width="80px" @keyup.enter="onSubmit()"
@keyup.enter="onSubmit()" >
> <el-form-item
<!-- 参数名输入项 --> label="参数名"
<el-form-item prop="paramKey"
label="参数名" >
prop="paramKey" <el-input
> v-model="dataForm.paramKey"
<el-input placeholder="参数名"
v-model="dataForm.paramKey" />
placeholder="参数名" </el-form-item>
/> <el-form-item
</el-form-item> label="参数值"
<!-- 参数值输入项 --> prop="paramValue"
<el-form-item >
label="参数值" <el-input
prop="paramValue" v-model="dataForm.paramValue"
> placeholder="参数值"
<el-input />
v-model="dataForm.paramValue" </el-form-item>
placeholder="参数值" <el-form-item
/> label="备注"
</el-form-item> prop="remark"
<!-- 备注输入项 --> >
<el-form-item <el-input
label="备注" v-model="dataForm.remark"
prop="remark" placeholder="备注"
> />
<el-input </el-form-item>
v-model="dataForm.remark" </el-form>
placeholder="备注" <template #footer>
/>
</el-form-item>
</el-form>
<!-- 对话框底部操作按钮 -->
<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 type="primary" @click="onSubmit()"></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 { 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, // ID0 id: 0,
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 // ID dataForm.id = id || 0
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
@ -113,21 +91,16 @@ 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,
@ -135,14 +108,13 @@ 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,164 +1,135 @@
<template> <template>
<!-- 配置管理模块 -->
<div class="mod-config"> <div class="mod-config">
<!-- 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"
@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" icon="el-icon-plus"
icon="el-icon-plus" @click.stop="onAddOrUpdate()"
@click.stop="onAddOrUpdate()" >
> 新增
新增 </el-button>
</el-button>
<el-button <el-button
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">
<!-- 自定义行内操作按钮 --> <el-button
<template #menu="scope"> type="primary"
<el-button icon="el-icon-edit"
type="primary" @click.stop="onAddOrUpdate(scope.row.id)"
icon="el-icon-edit" >
@click.stop="onAddOrUpdate(scope.row.id)" 编辑
> </el-button>
编辑 <el-button
</el-button> type="danger"
<el-button icon="el-icon-delete"
type="danger" @click.stop="onDelete(scope.row.id)"
icon="el-icon-delete" >
@click.stop="onDelete(scope.row.id)" 删除
> </el-button>
删除 </template>
</el-button>
</template>
</avue-crud> </avue-crud>
<!-- 添加或更新对话框组件 --> <!-- 弹窗, 新增 / 修改 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@refresh-data-list="getDataList" @refresh-data-list="getDataList"
/> />
</div> </div>
</template> </template>
<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'), // API url: http.adornUrl('/sys/config/page'),
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 => item.id) // ID const ids = id ? [id] : dataListSelections.value?.map(item => {
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',
@ -168,6 +139,6 @@ const onDelete = (id) => {
} }
}) })
}) })
}).catch(() => { /* 用户取消删除 */ }) }).catch(() => { })
} }
</script> </script>

@ -1,70 +1,57 @@
<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'), // API url: http.adornUrl('/sys/log/page'),
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,182 +1,162 @@
<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" :rules="dataRule"
:rules="dataRule" label-width="80px"
label-width="80px" @keyup.enter="onSubmit()"
@keyup.enter="onSubmit()" >
> <el-form-item
<!-- 类型选择项 --> label="类型"
<el-form-item prop="type"
label="类型"
prop="type"
>
<el-radio-group v-model="dataForm.type">
<el-radio
v-for="(type, index) in dataForm.typeList"
:key="index"
:label="index"
> >
{{ type }} <el-radio-group v-model="dataForm.type">
</el-radio> <el-radio
</el-radio-group> v-for="(type, index) in dataForm.typeList"
</el-form-item>
<!-- 动态标签根据类型改变 -->
<el-form-item
:label="dataForm.typeList[dataForm.type] + '名称'"
prop="name"
>
<el-input
v-model="dataForm.name"
:placeholder="dataForm.typeList[dataForm.type] + '名称'"
/>
</el-form-item>
<!-- 上级菜单选择 -->
<el-form-item label="上级菜单">
<el-cascader
v-model="selectedMenu"
expand-trigger="hover"
:options="menuList"
:props="menuListTreeProps"
change-on-select
:clearable="true"
@change="handleSelectMenuChange"
/>
</el-form-item>
<!-- 菜单路由输入仅当类型为1时显示 -->
<el-form-item
v-if="dataForm.type === 1"
label="菜单路由"
prop="url"
>
<el-input
v-model="dataForm.url"
placeholder="菜单路由"
/>
</el-form-item>
<!-- 授权标识输入除类型0外显示 -->
<el-form-item
v-if="dataForm.type !== 0"
label="授权标识"
prop="perms"
>
<el-input
v-model="dataForm.perms"
placeholder="多个用逗号分隔, 如: user:list,user:create"
/>
</el-form-item>
<!-- 排序号输入除类型2外显示 -->
<el-form-item
v-if="dataForm.type !== 2"
label="排序号"
prop="orderNum"
>
<el-input-number
v-model="dataForm.orderNum"
controls-position="right"
:min="0"
label="排序号"
/>
</el-form-item>
<!-- 菜单图标选择除类型2外显示 -->
<el-form-item
v-if="dataForm.type !== 2"
label="菜单图标"
prop="icon"
>
<el-row>
<el-col :span="22">
<el-input
ref="iconInputRef"
v-model="dataForm.icon"
:virtual-ref="iconListPopoverRef"
placeholder="菜单图标名称"
clearable
/>
<el-popover
ref="iconListPopoverRef"
style="width: 390px"
:virtual-ref="iconInputRef"
placement="bottom-start"
trigger="click"
:popper-style="iconPopoverClass"
virtual-triggering
>
<el-button
v-for="(item, index) in iconList"
:key="index" :key="index"
style="padding: 8px; margin: 8px 0 0 8px" :label="index"
:class="{ 'is-active': item === dataForm.icon }"
@click="iconActiveHandle(item)"
> >
<svg-icon {{ type }}
:icon-class="`${item}`" </el-radio>
/> </el-radio-group>
</el-button> </el-form-item>
</el-popover> <el-form-item
</el-col> :label="dataForm.typeList[dataForm.type] + '名称'"
<el-col prop="name"
:span="2"
class="icon-list__tips"
> >
<el-tooltip <el-input
placement="top" v-model="dataForm.name"
effect="light" :placeholder="dataForm.typeList[dataForm.type] + '名称'"
> />
<template #content> </el-form-item>
<div>全站推荐使用SVG Sprite, 详细请参考:icons/index.js 描述</div> <el-form-item label="上级菜单">
</template> <el-cascader
<i class="el-icon-warning" /> v-model="selectedMenu"
</el-tooltip> expand-trigger="hover"
</el-col> :options="menuList"
</el-row> :props="menuListTreeProps"
</el-form-item> change-on-select
</el-form> :clearable="true"
@change="handleSelectMenuChange"
<!-- 对话框底部操作按钮 --> />
<template #footer> </el-form-item>
<el-form-item
v-if="dataForm.type === 1"
label="菜单路由"
prop="url"
>
<el-input
v-model="dataForm.url"
placeholder="菜单路由"
/>
</el-form-item>
<el-form-item
v-if="dataForm.type !== 0"
label="授权标识"
prop="perms"
>
<el-input
v-model="dataForm.perms"
placeholder="多个用逗号分隔, 如: user:list,user:create"
/>
</el-form-item>
<el-form-item
v-if="dataForm.type !== 2"
label="排序号"
prop="orderNum"
>
<el-input-number
v-model="dataForm.orderNum"
controls-position="right"
:min="0"
label="排序号"
/>
</el-form-item>
<el-form-item
v-if="dataForm.type !== 2"
label="菜单图标"
prop="icon"
>
<el-row>
<el-col :span="22">
<el-input
ref="iconInputRef"
v-model="dataForm.icon"
:virtual-ref="iconListPopoverRef"
placeholder="菜单图标名称"
clearable
/>
<el-popover
ref="iconListPopoverRef"
style="width: 390px"
:virtual-ref="iconInputRef"
placement="bottom-start"
trigger="click"
:popper-style="iconPopoverClass"
virtual-triggering
>
<el-button
v-for="(item, index) in iconList"
:key="index"
style="padding: 8px; margin: 8px 0 0 8px"
:class="{ 'is-active': item === dataForm.icon }"
@click="iconActiveHandle(item)"
>
<svg-icon
:icon-class="`${item}`"
/>
</el-button>
</el-popover>
</el-col>
<el-col
:span="2"
class="icon-list__tips"
>
<el-tooltip
placement="top"
effect="light"
>
<template #content>
<div>全站推荐使用SVG Sprite, 详细请参考:icons/index.js 描述</div>
</template>
<i class="el-icon-warning" />
</el-tooltip>
</el-col>
</el-row>
</el-form-item>
</el-form>
<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 type="primary" @click="onSubmit()"></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 { 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 {
width: '396px'
}
})
//
const iconPopoverClass = computed(() => ({
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,
@ -189,19 +169,15 @@ 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
} }
// URL // eslint-disable-next-line no-unused-vars
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不能为空'))
@ -209,8 +185,6 @@ 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' },
@ -221,11 +195,10 @@ const dataRule = ref({
] ]
}) })
//
onMounted(() => { onMounted(() => {
onLoadIcons() onLoadIcons()
}) })
const iconList = []
/** /**
* 加载图标 * 加载图标
*/ */
@ -233,42 +206,35 @@ 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]
dataForm.iconList.push(iconName) 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 // ID dataForm.id = id || 0
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
@ -280,39 +246,31 @@ 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] // parentIdID dataForm.parentId = val[val.length - 1]
} }
/** /**
* 图标选中处理 * 图标选中
* @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,
@ -325,14 +283,13 @@ 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,211 +1,194 @@
<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" @click="onAddOrUpdate()"
@click="onAddOrUpdate()" >
> 新增
新增 </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" tree-key="menuId"
tree-key="menuId" width="150"
width="150" label="名称"
label="名称"
/>
<!-- 图标列 -->
<el-table-column
header-align="center"
align="center"
label="图标"
>
<template #default="scope"> <!-- 自定义列内容 -->
<svg-icon
:icon-class="`icon-${scope.row.icon}`"
/> />
</template> <el-table-column
</el-table-column> header-align="center"
align="center"
<!-- 类型列 --> label="图标"
<el-table-column >
prop="type" <template #default="scope">
header-align="center" <svg-icon
align="center" :icon-class="`icon-${scope.row.icon}`"
label="类型" />
> </template>
<template #default="scope"> <!-- 自定义列内容 --> </el-table-column>
<el-tag v-if="scope.row.type === 0"></el-tag> <!-- 根据类型动态渲染标签 --> <el-table-column
<el-tag v-else-if="scope.row.type === 1" type="success">菜单</el-tag> prop="type"
<el-tag v-else-if="scope.row.type === 2" type="info">按钮</el-tag> header-align="center"
</template> align="center"
</el-table-column> label="类型"
>
<!-- 排序号列 --> <template #default="scope">
<el-table-column <el-tag
prop="orderNum" v-if="scope.row.type === 0"
header-align="center" >
align="center" 目录
label="排序号" </el-tag>
/> <el-tag
v-else-if="scope.row.type === 1"
<!-- 菜单URL列 -->
<el-table-column type="success"
prop="url" >
header-align="center" 菜单
align="center" </el-tag>
width="150" <el-tag
:show-overflow-tooltip="true" v-else-if="scope.row.type === 2"
label="菜单URL"
> type="info"
<template #default="scope"> <!-- 自定义列内容 --> >
{{ scope.row.url || '-' }} <!-- 如果没有值则显示'-' --> 按钮
</template> </el-tag>
</el-table-column> </template>
</el-table-column>
<!-- 授权标识列 --> <el-table-column
<el-table-column prop="orderNum"
prop="perms" header-align="center"
header-align="center" align="center"
align="center" label="排序号"
width="150" />
:show-overflow-tooltip="true" <el-table-column
label="授权标识" prop="url"
> header-align="center"
<template #default="scope"> <!-- 自定义列内容 --> align="center"
{{ scope.row.perms || '-' }} <!-- 如果没有值则显示'-' --> width="150"
</template> :show-overflow-tooltip="true"
</el-table-column> label="菜单URL"
>
<!-- 操作列 --> <template #default="scope">
<el-table-column {{ scope.row.url || '-' }}
fixed="right" </template>
header-align="center" </el-table-column>
align="center" <el-table-column
width="150" prop="perms"
label="操作" header-align="center"
> align="center"
<template #default="scope"> <!-- 自定义列内容 --> width="150"
<!-- 修改按钮只有有权限时显示 --> :show-overflow-tooltip="true"
<el-button label="授权标识"
v-if="isAuth('sys:menu:update')"
type="text"
@click="onAddOrUpdate(scope.row.menuId)"
> >
修改 <template #default="scope">
</el-button> {{ scope.row.perms || '-' }}
<!-- 删除按钮只有有权限时显示 --> </template>
<el-button </el-table-column>
v-if="isAuth('sys:menu:delete')" <el-table-column
type="text" fixed="right"
@click="onDelete(scope.row.menuId)" header-align="center"
align="center"
width="150"
label="操作"
> >
删除 <template #default="scope">
</el-button> <el-button
</template> v-if="isAuth('sys:menu:update')"
</el-table-column> type="text"
@click="onAddOrUpdate(scope.row.menuId)"
>
修改
</el-button>
<el-button
v-if="isAuth('sys:menu:delete')"
type="text"
@click="onDelete(scope.row.menuId)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table> </el-table>
<!-- 弹窗, 新增 / 修改 --> <!-- 弹窗, 新增 / 修改 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@refresh-data-list="getDataList" @refresh-data-list="getDataList"
@close="addOrUpdateVisible=false" @close="addOrUpdateVisible=false"
/> />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, nextTick } from 'vue' import { treeDataTranslate, isAuth } from '@/utils'
import { treeDataTranslate, isAuth } from '@/utils' // 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' // /
//
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'), // API url: http.adornUrl('/sys/menu/table'),
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 菜单项ID可选如果没有传入则表示新增 * @param 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 * @param 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,180 +1,136 @@
<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" :rules="dataRule"
:rules="dataRule" label-width="80px"
label-width="80px" @keyup.enter="onSubmit()"
@keyup.enter="onSubmit()" >
> <el-form-item
<!-- 角色名称输入框 --> label="角色名称"
<el-form-item prop="roleName"
label="角色名称" >
prop="roleName" <el-input
> v-model="dataForm.roleName"
<el-input placeholder="角色名称"
v-model="dataForm.roleName" />
placeholder="角色名称" </el-form-item>
/> <el-form-item
</el-form-item> label="备注"
prop="remark"
<!-- 备注输入框 --> >
<el-form-item <el-input
label="备注" v-model="dataForm.remark"
prop="remark" placeholder="备注"
> />
<el-input </el-form-item>
v-model="dataForm.remark" <el-form-item label="授权">
placeholder="备注" <el-tree
/> ref="menuListTreeRef"
</el-form-item> :data="menuList"
:props="menuListTreeProps"
<!-- 授权菜单树 --> node-key="menuId"
<el-form-item label="授权"> show-checkbox
<el-tree />
ref="menuListTreeRef" </el-form-item>
:data="menuList" </el-form>
:props="menuListTreeProps" <template #footer>
node-key="menuId"
show-checkbox
/>
</el-form-item>
</el-form>
<!-- 对话框底部按钮组 -->
<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 type="primary" @click="onSubmit()"></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 { ref, reactive, nextTick } from 'vue' 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' //
//
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, // ID0 id: 0,
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 // id dataForm.id = id || 0
//
http({ http({
url: http.adornUrl('/sys/menu/table'), // API url: http.adornUrl('/sys/menu/table'),
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(() => {
visible.value = true //
return nextTick() // DOM
}) })
.then(() => { .then(() => {
dataFormRef.value?.resetFields() // visible.value = true
menuListTreeRef.value?.setCheckedKeys([]) // nextTick(() => {
dataFormRef.value?.resetFields()
menuListTreeRef.value?.setCheckedKeys([])
})
}) })
.then(() => { .then(() => {
if (dataForm.id) { // if (dataForm.id) {
http({ http({
url: http.adornUrl(`/sys/role/info/${dataForm.id}`), // API url: http.adornUrl(`/sys/role/info/${dataForm.id}`),
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'), // API url: http.adornUrl('/sys/role'),
method: dataForm.id ? 'put' : 'post', // id method: dataForm.id ? 'put' : 'post',
data: http.adornData({ data: http.adornData({
roleId: dataForm.id || undefined, // ID roleId: dataForm.id || undefined,
roleName: dataForm.roleName, // roleName: dataForm.roleName,
remark: dataForm.remark, // remark: dataForm.remark,
// ID menuIdList: [].concat(menuListTreeRef.value?.getCheckedKeys(), [tempKey], menuListTreeRef.value?.getHalfCheckedKeys())
menuIdList: [].concat(
menuListTreeRef.value?.getCheckedKeys(),
[tempKey],
menuListTreeRef.value?.getHalfCheckedKeys()
)
}) })
}) })
.then(() => { .then(() => {
@ -183,12 +139,13 @@ 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,186 +1,153 @@
<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"
:data="dataList" :data="dataList"
:option="tableOption" :option="tableOption"
@search-change="onSearch" @search-change="onSearch"
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<!-- 左侧菜单栏 --> <template #menu-left>
<template #menu-left> <el-button
<!-- 新增按钮只有有权限时显示 --> v-if="isAuth('sys:role:save')"
<el-button type="primary"
v-if="isAuth('sys:role:save')" icon="el-icon-plus"
type="primary" @click.stop="onAddOrUpdate()"
icon="el-icon-plus" >
@click.stop="onAddOrUpdate()" 新增
> </el-button>
新增
</el-button> <el-button
v-if="isAuth('sys:role:delete')"
<!-- 批量删除按钮只有有权限且选择了项目时显示 --> type="danger"
<el-button :disabled="dataListSelections.length <= 0"
v-if="isAuth('sys:role:delete')" @click="onDelete()"
type="danger" >
:disabled="dataListSelections.length <= 0" 批量删除
@click="onDelete()" </el-button>
> </template>
批量删除
</el-button> <template #menu="scope">
</template> <el-button
v-if="isAuth('sys:role:update')"
<!-- 行内菜单 --> type="primary"
<template #menu="scope"> <!-- 自定义行内菜单 --> icon="el-icon-edit"
<!-- 编辑按钮只有有权限时显示 --> @click.stop="onAddOrUpdate(scope.row.roleId)"
<el-button >
v-if="isAuth('sys:role:update')" 编辑
type="primary" </el-button>
icon="el-icon-edit"
@click.stop="onAddOrUpdate(scope.row.roleId)" <el-button
> v-if="isAuth('sys:role:delete')"
编辑 type="danger"
</el-button> icon="el-icon-delete"
@click.stop="onDelete(scope.row.roleId)"
<!-- 删除按钮只有有权限时显示 --> >
<el-button 删除
v-if="isAuth('sys:role:delete')" </el-button>
type="danger" </template>
icon="el-icon-delete"
@click.stop="onDelete(scope.row.roleId)"
>
删除
</el-button>
</template>
</avue-crud> </avue-crud>
<!-- 弹窗, 新增 / 修改 --> <!-- 弹窗, 新增 / 修改 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@refresh-data-list="getDataList" @refresh-data-list="getDataList"
/> />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive } from 'vue' import { isAuth } from '@/utils'
import { isAuth } from '@/utils' // import { ElMessage, ElMessageBox } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus' // import { tableOption } from '@/crud/sys/role.js'
import { tableOption } from '@/crud/sys/role.js' // import AddOrUpdate from './add-or-update.vue'
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'), // API url: http.adornUrl('/sys/role/page'),
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 => item.roleId) // ID const ids = id ? [id] : dataListSelections.value?.map(item => {
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) // ID data: http.adornData(ids, false)
}) })
.then(() => { .then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
getDataList() // getDataList()
} }
}) })
}) })
}).catch(() => { /* 用户取消删除操作 */ }) }).catch(() => { })
} }
</script> </script>

@ -1,264 +1,231 @@
<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" :rules="dataRule"
:rules="dataRule" label-width="80px"
label-width="80px" @keyup.enter="onSubmit()"
@keyup.enter="onSubmit()"
>
<!-- 用户名输入框 -->
<el-form-item
label="用户名"
prop="userName"
>
<el-input
v-model="dataForm.userName"
placeholder="登录帐号"
/>
</el-form-item>
<!-- 密码输入框 -->
<el-form-item
label="密码"
prop="password"
:class="{ 'is-required': !dataForm.id }"
>
<el-input
v-model="dataForm.password"
type="password"
placeholder="密码"
/>
</el-form-item>
<!-- 确认密码输入框 -->
<el-form-item
label="确认密码"
prop="comfirmPassword"
:class="{ 'is-required': !dataForm.id }"
>
<el-input
v-model="dataForm.comfirmPassword"
type="password"
placeholder="确认密码"
/>
</el-form-item>
<!-- 邮箱输入框 -->
<el-form-item
label="邮箱"
prop="email"
>
<el-input
v-model="dataForm.email"
placeholder="邮箱"
/>
</el-form-item>
<!-- 手机号输入框 -->
<el-form-item
label="手机号"
prop="mobile"
>
<el-input
v-model="dataForm.mobile"
maxlength="11"
placeholder="手机号"
/>
</el-form-item>
<!-- 角色选择 -->
<el-form-item
label="角色"
prop="roleIdList"
>
<el-checkbox-group v-model="dataForm.roleIdList"> <!-- ID -->
<el-checkbox
v-for="role in roleList"
:key="role.roleId"
:label="role.roleId"
> >
{{ role.roleName }} <!-- 显示角色名称 --> <el-form-item
</el-checkbox> label="用户名"
</el-checkbox-group> prop="userName"
</el-form-item> >
<el-input
<!-- 状态选择 --> v-model="dataForm.userName"
<el-form-item placeholder="登录帐号"
label="状态" />
prop="status" </el-form-item>
> <el-form-item
<el-radio-group v-model="dataForm.status"> <!-- --> label="密码"
<el-radio :label="0">禁用</el-radio> <!-- --> prop="password"
<el-radio :label="1">正常</el-radio> <!-- --> :class="{ 'is-required': !dataForm.id }"
</el-radio-group> >
</el-form-item> <el-input
</el-form> v-model="dataForm.password"
type="password"
<!-- 对话框底部按钮组 --> placeholder="密码"
<template #footer> />
</el-form-item>
<el-form-item
label="确认密码"
prop="comfirmPassword"
:class="{ 'is-required': !dataForm.id }"
>
<el-input
v-model="dataForm.comfirmPassword"
type="password"
placeholder="确认密码"
/>
</el-form-item>
<el-form-item
label="邮箱"
prop="email"
>
<el-input
v-model="dataForm.email"
placeholder="邮箱"
/>
</el-form-item>
<el-form-item
label="手机号"
prop="mobile"
>
<el-input
v-model="dataForm.mobile"
maxlength="11"
placeholder="手机号"
/>
</el-form-item>
<el-form-item
label="角色"
prop="roleIdList"
>
<el-checkbox-group v-model="dataForm.roleIdList">
<el-checkbox
v-for="role in roleList"
:key="role.roleId"
:label="role.roleId"
>
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item
label="状态"
prop="status"
>
<el-radio-group v-model="dataForm.status">
<el-radio :label="0">
禁用
</el-radio>
<el-radio :label="1">
正常
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<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 type="primary" @click="onSubmit()"></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 { ref, reactive, nextTick } from 'vue' import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus' // import { isEmail, isMobile } from '@/utils/validate'
import { isEmail, isMobile } from '@/utils/validate' // import { Debounce } from '@/utils/debounce'
import { Debounce } from '@/utils/debounce' // import { encrypt } from '@/utils/crypto'
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, // ID0 id: 0,
userName: '', // userName: '',
password: '', // password: '',
comfirmPassword: '', // comfirmPassword: '',
email: '', // email: '',
mobile: '', // mobile: '',
roleIdList: [], // ID roleIdList: [],
status: 1 // 1 status: 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 // id dataForm.id = id || 0
//
http({ http({
url: http.adornUrl('/sys/role/list'), // API url: http.adornUrl('/sys/role/list'),
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
return nextTick() // DOM nextTick(() => {
dataFormRef.value?.resetFields()
})
}).then(() => { }).then(() => {
dataFormRef.value?.resetFields() // if (dataForm.id) {
}).then(() => {
if (dataForm.id) { //
http({ http({
url: http.adornUrl(`/sys/user/info/${dataForm.id}`), // API url: http.adornUrl(`/sys/user/info/${dataForm.id}`),
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 // ID dataForm.roleIdList = data.roleIdList
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'), // API url: http.adornUrl('/sys/user'),
method: dataForm.id ? 'put' : 'post', // id method: dataForm.id ? 'put' : 'post',
data: http.adornData({ data: http.adornData({
userId: dataForm.id || undefined, // ID userId: dataForm.id || undefined,
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 // ID roleIdList: dataForm.roleIdList
}) })
}).then(() => { }).then(() => {
ElMessage({ ElMessage({
@ -266,12 +233,13 @@ 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,187 +1,155 @@
<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"
:data="dataList" :data="dataList"
:option="tableOption" :option="tableOption"
@search-change="onSearch" @search-change="onSearch"
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<!-- 左侧菜单栏 --> <template #menu-left>
<template #menu-left> <el-button
<!-- 新增按钮只有有权限时显示 --> v-if="isAuth('sys:user:save')"
<el-button type="primary"
v-if="isAuth('sys:user:save')" icon="el-icon-plus"
type="primary" @click.stop="onAddOrUpdate()"
icon="el-icon-plus" >
@click.stop="onAddOrUpdate()" 新增
</el-button>
<el-button
v-if="isAuth('sys:user:delete')"
type="danger"
:disabled="dataListSelections.length <= 0"
@click="onDelete()"
>
批量删除
</el-button>
</template>
<template
#menu="scope"
> >
新增 <el-button
</el-button> v-if="isAuth('sys:user:update')"
type="primary"
<!-- 批量删除按钮只有有权限且选择了项目时显示 --> icon="el-icon-edit"
<el-button @click.stop="onAddOrUpdate(scope.row.userId)"
v-if="isAuth('sys:user:delete')" >
type="danger" 编辑
:disabled="dataListSelections.length <= 0" </el-button>
@click="onDelete()"
> <el-button
批量删除 v-if="isAuth('sys:user:delete')"
</el-button> type="danger"
</template> icon="el-icon-delete"
@click.stop="onDelete(scope.row.userId)"
<!-- 行内菜单 --> >
<template #menu="scope"> <!-- 自定义行内菜单 --> 删除
<!-- 编辑按钮只有有权限时显示 --> </el-button>
<el-button </template>
v-if="isAuth('sys:user:update')"
type="primary"
icon="el-icon-edit"
@click.stop="onAddOrUpdate(scope.row.userId)"
>
编辑
</el-button>
<!-- 删除按钮只有有权限时显示 -->
<el-button
v-if="isAuth('sys:user:delete')"
type="danger"
icon="el-icon-delete"
@click.stop="onDelete(scope.row.userId)"
>
删除
</el-button>
</template>
</avue-crud> </avue-crud>
<!-- 弹窗, 新增 / 修改 --> <!-- 弹窗, 新增 / 修改 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@refresh-data-list="getDataList" @refresh-data-list="getDataList"
/> />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, nextTick } from 'vue' import { isAuth } from '@/utils'
import { isAuth } from '@/utils' // import { ElMessage, ElMessageBox } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus' // import { tableOption } from '@/crud/sys/user.js'
import { tableOption } from '@/crud/sys/user.js' // import AddOrUpdate from './add-or-update.vue'
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 // true dataListLoading.value = true
http({ http({
url: http.adornUrl('/sys/user/page'), // API url: http.adornUrl('/sys/user/page'),
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()
}) })
} }
/** /**
* 条件查询方法 * 条件查询
* @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 => item.userId) // ID const userIds = id ? [id] : dataListSelections.value?.map(item => {
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) // ID data: http.adornData(userIds, false)
}).then(() => { }).then(() => {
//
ElMessage({ ElMessage({
message: '操作成功', message: '操作成功',
type: 'success', type: 'success',
duration: 1500, duration: 1500,
onClose: () => { onClose: () => {
getDataList() // getDataList()
} }
}) })
}) })
}).catch(() => { /* 用户取消删除操作 */ }) }).catch(() => { })
} }
</script> </script>

@ -1,152 +1,139 @@
<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" :rules="dataRule"
:rules="dataRule" label-width="80px"
label-width="80px" @keyup.enter="onSubmit()"
@keyup.enter="onSubmit()" >
> <el-form-item
<!-- 用户头像展示 --> label="用户头像"
<el-form-item prop="pic"
label="用户头像" >
prop="pic" <img
> v-if="dataForm.pic"
<img :src="dataForm.pic"
v-if="dataForm.pic" class="image"
:src="dataForm.pic" alt=""
class="image" >
alt="" <div v-else>
/>
<div v-else></div> <!-- --> </div>
</el-form-item> </el-form-item>
<el-form-item
<!-- 用户昵称输入框 --> label="用户昵称"
<el-form-item prop="nickName"
label="用户昵称" >
prop="nickName" <el-input
> v-model="dataForm.nickName"
<el-input :disabled="true"
v-model="dataForm.nickName" placeholder="用户昵称"
:disabled="true" />
placeholder="用户昵称" </el-form-item>
/> <el-form-item
</el-form-item> label="状态"
prop="status"
<!-- 状态选择 --> >
<el-form-item <el-radio-group v-model="dataForm.status">
label="状态" <el-radio :label="0">
prop="status" 禁用
> </el-radio>
<el-radio-group v-model="dataForm.status"> <!-- --> <el-radio :label="1">
<el-radio :label="0">禁用</el-radio> <!-- --> 正常
<el-radio :label="1">正常</el-radio> <!-- --> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer>
<!-- 对话框底部按钮组 --> <span
<template #footer> class="dialog-footer"
<span class="dialog-footer"> >
<el-button @click="visible = false">取消</el-button> <!-- --> <el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit()"></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 { ref, reactive, nextTick } from 'vue' import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus' // import { Debounce } from '@/utils/debounce'
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, // ID0 userId: 0,
nickName: '', // nickName: '',
pic: '', // pic: '',
status: 1 // 1 status: 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 // id dataForm.value.userId = id || 0
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}`), // API url: http.adornUrl(`/admin/user/info/${dataForm.value.userId}`),
method: 'get', // method: 'get',
params: http.adornParams() // params: http.adornParams()
}).then(({ data }) => {
dataForm.value = data //
}) })
.then(({ 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'), // API url: http.adornUrl('/admin/user'),
method: dataForm.value.userId ? 'put' : 'post', // userId method: dataForm.value.userId ? 'put' : 'post',
data: http.adornData({ data: http.adornData({
userId: dataForm.value.userId || undefined, // ID userId: dataForm.value.userId || undefined,
nickName: dataForm.value.nickName, // nickName: dataForm.value.nickName,
status: dataForm.value.status // status: dataForm.value.status
})
}).then(() => {
ElMessage({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
visible.value = false //
emit('refreshDataList', page) //
}
}) })
}) })
.then(() => {
ElMessage({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
visible.value = false
emit('refreshDataList', page)
}
})
})
} }
}) })
}) })
</script> </script>

@ -1,139 +1,120 @@
<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"
:data="dataList" :data="dataList"
:option="tableOption" :option="tableOption"
@search-change="onSearch" @search-change="onSearch"
@selection-change="selectionChange" @selection-change="selectionChange"
@on-load="getDataList" @on-load="getDataList"
> >
<!-- 自定义列模板用户头像 --> <template #pic="scope">
<template #pic="scope"> <!-- 自定义用户头像列 --> <span
<span v-if="scope.row.pic" class="avue-crud__img"> v-if="scope.row.pic"
<el-icon><Document /></el-icon> <!-- --> class="avue-crud__img"
>
<el-icon><Document /></el-icon>
</span> </span>
<span v-else>-</span> <!-- "-" --> <span v-else>-</span>
</template> </template>
<!-- 自定义列模板状态 --> <template #status="scope">
<template #status="scope"> <!-- 自定义状态列 --> <el-tag
<el-tag v-if="scope.row.status === 0" type="danger"> v-if="scope.row.status === 0"
禁用 type="danger"
</el-tag> >
<el-tag v-else> 禁用
正常 </el-tag>
</el-tag> <el-tag v-else>
</template> 正常
</el-tag>
</template>
<!-- 自定义行内菜单 --> <template #menu="scope">
<template #menu="scope"> <!-- 自定义行内菜单 --> <el-button
<!-- 编辑按钮只有有权限时显示 --> v-if="isAuth('admin:user:update')"
<el-button type="primary"
v-if="isAuth('admin:user:update')" icon="el-icon-edit"
type="primary" @click.stop="onAddOrUpdate(scope.row.userId)"
icon="el-icon-edit" >
@click.stop="onAddOrUpdate(scope.row.userId)" 编辑
> </el-button>
编辑 </template>
</el-button>
</template>
</avue-crud> </avue-crud>
<!-- 弹窗, 新增 / 修改 --> <!-- 弹窗, 新增 / 修改 -->
<add-or-update <add-or-update
v-if="addOrUpdateVisible" v-if="addOrUpdateVisible"
ref="addOrUpdateRef" ref="addOrUpdateRef"
@refresh-data-list="getDataList" @refresh-data-list="getDataList"
/> />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, nextTick } from 'vue' import { isAuth } from '@/utils'
import { isAuth } from '@/utils' // import { tableOption } from '@/crud/user/user.js'
import { tableOption } from '@/crud/user/user.js' // import AddOrUpdate from './add-or-update.vue'
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 // true dataListLoading.value = true
http({ http({
url: http.adornUrl('/admin/user/page'), // API url: http.adornUrl('/admin/user/page'),
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 }) => {
dataList.value = data.records //
page.total = data.total //
dataListLoading.value = false // false
if (done) done() //
}) })
.then(({ data }) => {
dataList.value = data.records
page.total = data.total
dataListLoading.value = false
if (done) done()
})
} }
//
const addOrUpdateRef = ref(null) const addOrUpdateRef = ref(null)
/** /**
* 新增 / 修改用户信息 * 新增 / 修改
* @param id 用户ID可选如果没有传入则表示新增 * @param 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