update
This commit is contained in:
parent
61273892d8
commit
bfc7805172
|
|
@ -28,7 +28,11 @@
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
@update:page="updatePage"
|
@update:page="updatePage"
|
||||||
@update:page-size="updatePageSize"
|
@update:page-size="updatePageSize"
|
||||||
/>
|
>
|
||||||
|
<template #empty>
|
||||||
|
<slot name="empty" />
|
||||||
|
</template>
|
||||||
|
</n-data-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,10 @@ export default defineComponent({
|
||||||
const getActions = computed(() => {
|
const getActions = computed(() => {
|
||||||
return (toRaw(props.actions) || [])
|
return (toRaw(props.actions) || [])
|
||||||
.filter((action) => {
|
.filter((action) => {
|
||||||
return data.permissionList.includes(action.auth) || action.auth === ''
|
if (!Object.keys(action).includes('show')) {
|
||||||
|
action.show = Object.keys(action).includes('hidden') ? !action.hidden : true
|
||||||
|
}
|
||||||
|
return (data.permissionList.includes(action.auth) || action.auth === '') && action.show
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,10 @@ export default defineComponent({
|
||||||
const { filters } = unref(props)
|
const { filters } = unref(props)
|
||||||
function getFilter(value) {
|
function getFilter(value) {
|
||||||
const data = filters.find(item => {
|
const data = filters.find(item => {
|
||||||
return item.key === value
|
return item.value === value
|
||||||
})
|
})
|
||||||
return data || {
|
return data || {
|
||||||
key: value,
|
value: value,
|
||||||
label: value
|
label: value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ export const tableProps = {
|
||||||
pageField: 'page',
|
pageField: 'page',
|
||||||
// 每页数量字段名
|
// 每页数量字段名
|
||||||
sizeField: 'limit',
|
sizeField: 'limit',
|
||||||
|
// 接口返回的字段名
|
||||||
|
listPageField: 'current',
|
||||||
// 接口返回的数据字段名
|
// 接口返回的数据字段名
|
||||||
listField: 'records',
|
listField: 'records',
|
||||||
// 接口返回总页数字段名
|
// 接口返回总页数字段名
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { toTreeData } from './toTree'
|
||||||
|
|
||||||
export function useDataSource(propsRef, { getPaginationInfo, setPagination, setLoading, tableData }, emit) {
|
export function useDataSource(propsRef, { getPaginationInfo, setPagination, setLoading, tableData }, emit) {
|
||||||
const dataSourceRef = ref([])
|
const dataSourceRef = ref([])
|
||||||
|
const paginationPage = ref(1)
|
||||||
async function fetch(opt) {
|
async function fetch(opt) {
|
||||||
try {
|
try {
|
||||||
/* 设置loading */
|
/* 设置loading */
|
||||||
|
|
@ -14,6 +14,7 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
|
||||||
if (!request) return
|
if (!request) return
|
||||||
/* 获取分页信息 */
|
/* 获取分页信息 */
|
||||||
const pageField = paginationSetting.pageField
|
const pageField = paginationSetting.pageField
|
||||||
|
const listPageField = paginationSetting.listPageField
|
||||||
const sizeField = paginationSetting.sizeField
|
const sizeField = paginationSetting.sizeField
|
||||||
const totalField = paginationSetting.totalField
|
const totalField = paginationSetting.totalField
|
||||||
const listField = paginationSetting.listField
|
const listField = paginationSetting.listField
|
||||||
|
|
@ -25,6 +26,7 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
|
||||||
pageParams = {}
|
pageParams = {}
|
||||||
} else {
|
} else {
|
||||||
pageParams[pageField] = (opt && opt[pageField]) || page
|
pageParams[pageField] = (opt && opt[pageField]) || page
|
||||||
|
paginationPage.value = pageParams[pageField]
|
||||||
pageParams[sizeField] = pageSize
|
pageParams[sizeField] = pageSize
|
||||||
}
|
}
|
||||||
const params = {
|
const params = {
|
||||||
|
|
@ -33,7 +35,7 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
|
||||||
const response = await request(params)
|
const response = await request(params)
|
||||||
const res = noPagination ? response : response.data
|
const res = noPagination ? response : response.data
|
||||||
const resultTotal = res[totalField] || 0
|
const resultTotal = res[totalField] || 0
|
||||||
const currentPage = res[pageField]
|
const currentPage = res[listPageField]
|
||||||
// 如果数据异常,需获取正确的页码再次执行
|
// 如果数据异常,需获取正确的页码再次执行
|
||||||
if (resultTotal) {
|
if (resultTotal) {
|
||||||
if (page > Math.ceil(resultTotal / pageSize)) {
|
if (page > Math.ceil(resultTotal / pageSize)) {
|
||||||
|
|
@ -45,10 +47,11 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
|
||||||
}
|
}
|
||||||
// 处理数据结构
|
// 处理数据结构
|
||||||
const resultInfo = res[listField] ? res[listField] : res
|
const resultInfo = res[listField] ? res[listField] : res
|
||||||
dataSourceRef.value = dataType === 'tree' ? dealTree(resultInfo) : resultInfo
|
dataSourceRef.value = dataType === 'tree' ? dealTree(resultInfo.data) : resultInfo
|
||||||
setPagination({
|
setPagination({
|
||||||
[pageField]: currentPage,
|
[pageField]: currentPage,
|
||||||
[totalField]: Math.ceil(resultTotal / pageSize)
|
[totalField]: Math.ceil(resultTotal / pageSize),
|
||||||
|
itemCount: resultTotal
|
||||||
})
|
})
|
||||||
/* 更新页码数据 */
|
/* 更新页码数据 */
|
||||||
if (opt && opt[pageField]) {
|
if (opt && opt[pageField]) {
|
||||||
|
|
@ -105,13 +108,13 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
|
||||||
await fetch(opt)
|
await fetch(opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reFetch(opt) {
|
async function reFetch(opt, reload = true) {
|
||||||
const { paginationSetting } = unref(propsRef)
|
const { paginationSetting } = unref(propsRef)
|
||||||
const pageField = paginationSetting.pageField
|
const pageField = paginationSetting.pageField
|
||||||
const sizeField = paginationSetting.sizeField
|
const sizeField = paginationSetting.sizeField
|
||||||
const pageSize = paginationSetting.pageSize
|
const pageSize = paginationSetting.pageSize
|
||||||
setPagination({
|
setPagination({
|
||||||
[pageField]: 1,
|
[pageField]: reload ? 1 : paginationPage.value,
|
||||||
[sizeField]: pageSize
|
[sizeField]: pageSize
|
||||||
})
|
})
|
||||||
await fetch(opt)
|
await fetch(opt)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,10 @@ export function usePagination(refProps) {
|
||||||
showQuickJumper: paginationSetting.showQuickJumper,
|
showQuickJumper: paginationSetting.showQuickJumper,
|
||||||
...(isBoolean(pagination) ? {} : pagination),
|
...(isBoolean(pagination) ? {} : pagination),
|
||||||
...unref(configRef),
|
...unref(configRef),
|
||||||
pageCount: unref(configRef)[paginationSetting.totalField]
|
pageCount: unref(configRef)[paginationSetting.totalField],
|
||||||
|
prefix({ itemCount }) {
|
||||||
|
return `共 ${itemCount} 条`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<n-modal
|
<n-modal
|
||||||
|
ref="modalRef"
|
||||||
v-bind="getModalOptions"
|
v-bind="getModalOptions"
|
||||||
:style="`width:${getModalOptions.width}px`"
|
:style="`width:${getModalOptions.width}px`"
|
||||||
:title="options.title"
|
:title="options.title"
|
||||||
|
|
@ -12,7 +13,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { defineComponent, computed } from 'vue'
|
import { defineComponent, computed, ref } from 'vue'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CardDialogModal',
|
name: 'CardDialogModal',
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -28,6 +29,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
const modalRef = ref(null)
|
||||||
const getModalOptions = computed(() => {
|
const getModalOptions = computed(() => {
|
||||||
return {
|
return {
|
||||||
...props.options,
|
...props.options,
|
||||||
|
|
@ -43,7 +45,45 @@ export default defineComponent({
|
||||||
const handleClose = function() {
|
const handleClose = function() {
|
||||||
emit('onClose', true)
|
emit('onClose', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// const dialogHeaderEl = document.querySelector('.n-card-header')
|
||||||
|
// const dragDom = document.querySelector('.n-modal')
|
||||||
|
// dragDom.style.overflow = 'auto'
|
||||||
|
// dialogHeaderEl.style.cursor = 'move'
|
||||||
|
// const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
|
||||||
|
// const moveDown = (e) => {
|
||||||
|
// // 鼠标按下,计算当前元素距离可视区的距离
|
||||||
|
// const disX = e.clientX - dialogHeaderEl.offsetLeft
|
||||||
|
// const disY = e.clientY - dialogHeaderEl.offsetTop
|
||||||
|
// // 获取到的值带px 正则匹配替换
|
||||||
|
// let styL, styT
|
||||||
|
// // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
|
||||||
|
// if (sty.left.includes('%')) {
|
||||||
|
// styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
|
||||||
|
// styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
|
||||||
|
// } else {
|
||||||
|
// styL = +sty.left.replace(/\px/g, '')
|
||||||
|
// styT = +sty.top.replace(/\px/g, '')
|
||||||
|
// }
|
||||||
|
// document.onmousemove = function(e) {
|
||||||
|
// // 计算移动的距离
|
||||||
|
// const l = e.clientX - disX
|
||||||
|
// const t = e.clientY - disY
|
||||||
|
// // 移动当前元素
|
||||||
|
// dragDom.style.left = `${l + styL}px`
|
||||||
|
// dragDom.style.top = `${t + styT}px`
|
||||||
|
// }
|
||||||
|
// document.onmouseup = function(e) {
|
||||||
|
// document.onmousemove = null
|
||||||
|
// document.onmouseup = null
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// dialogHeaderEl.onmousedown = moveDown
|
||||||
|
// })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
modalRef,
|
||||||
getModalOptions,
|
getModalOptions,
|
||||||
handleConfirm,
|
handleConfirm,
|
||||||
handleClose
|
handleClose
|
||||||
|
|
@ -53,4 +93,9 @@ export default defineComponent({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang='scss'>
|
<style scoped lang='scss'>
|
||||||
|
::v-deep(.n-scrollbar-content){
|
||||||
|
&:first-child{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,15 @@
|
||||||
<div>
|
<div>
|
||||||
<n-form ref="formRef" v-bind="getFormOptions">
|
<n-form ref="formRef" v-bind="getFormOptions">
|
||||||
<template v-for="(item, index) in getFormOptions.info" :key="`${index}-${item.label}`">
|
<template v-for="(item, index) in getFormOptions.info" :key="`${index}-${item.label}`">
|
||||||
<n-form-item v-if="['input'].includes(item.type) || !item.type" :label="item.label">
|
<n-form-item :class="{'hidden-item': index > showItemNum}" :label="item.label">
|
||||||
<n-input v-model:value="getFormOptions.form[item.key]" v-bind="item.props" />
|
<n-input v-if="['input'].includes(item.type) || !item.type" v-model:value="getFormOptions.form[item.key]" v-bind="item.props" />
|
||||||
</n-form-item>
|
<n-select v-if="['select'].includes(item.type)" v-model:value="getFormOptions.form[item.key]" v-bind="item.props" />
|
||||||
<n-form-item v-if="['select'].includes(item.type) " :label="item.label">
|
<AreaCascader v-if="['area'].includes(item.type)" :ref="el=>{itemRefs[item.refIndex] = el}" v-model:value="getFormOptions.form[item.key]" v-bind="item.props" @selectd="handleSelect" />
|
||||||
<n-select v-model:value="getFormOptions.form[item.key]" v-bind="item.props" />
|
<n-date-picker v-if="['date'].includes(item.type)" v-model:formatted-value="getFormOptions.form[item.key]" v-bind="item.props" />
|
||||||
</n-form-item>
|
|
||||||
<n-form-item v-if="['area'].includes(item.type) " :label="item.label">
|
|
||||||
<AreaCascader :ref="el=>{itemRefs[item.refIndex] = el}" v-model:value="getFormOptions.form[item.key]" v-bind="item.props" @selectd="handleSelect" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item v-if="['date'].includes(item.type) " :label="item.label">
|
|
||||||
<n-date-picker v-model="getFormOptions.form[item.key]" v-bind="item.props" />
|
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</template>
|
</template>
|
||||||
<n-form-item class="form__button">
|
<n-form-item class="form__button">
|
||||||
<n-button @click="handleSearch">查询</n-button>
|
<n-button type="primary" @click="handleSearch">查询</n-button>
|
||||||
<n-button @click="handleReset">重置</n-button>
|
<n-button @click="handleReset">重置</n-button>
|
||||||
<n-button
|
<n-button
|
||||||
v-if="showButton"
|
v-if="showButton"
|
||||||
|
|
@ -29,7 +23,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, ref, unref } from 'vue'
|
import { computed, ref, unref, watch } from 'vue'
|
||||||
import { NForm } from 'naive-ui'
|
import { NForm } from 'naive-ui'
|
||||||
import AreaCascader from '@/components/AreaCascader/index.vue'
|
import AreaCascader from '@/components/AreaCascader/index.vue'
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -42,9 +36,9 @@ export default {
|
||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['search', 'reset'],
|
emits: ['search', 'change', 'reset'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const showItemNum = ref(3)
|
const showItemNum = ref(30)
|
||||||
const len = ref(props.info.length - 1)
|
const len = ref(props.info.length - 1)
|
||||||
const itemRefs = ref([])
|
const itemRefs = ref([])
|
||||||
const showButton = ref(!!(showItemNum.value < len.value))
|
const showButton = ref(!!(showItemNum.value < len.value))
|
||||||
|
|
@ -52,12 +46,14 @@ export default {
|
||||||
/* 初始化搜索表单信息 */
|
/* 初始化搜索表单信息 */
|
||||||
function initForm() {
|
function initForm() {
|
||||||
Object.keys(form.value).forEach((key) => {
|
Object.keys(form.value).forEach((key) => {
|
||||||
form.value[key] = null
|
const index = unref(props).info.findIndex((item) => item.key === key)
|
||||||
|
form.value[key] = (props).info[index].value || null
|
||||||
})
|
})
|
||||||
itemRefs.value.forEach((item) => {
|
itemRefs.value.forEach((item) => {
|
||||||
item.clearValue()
|
item.clearValue()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/* 地图选择事件 */
|
||||||
function handleSelect(data) {
|
function handleSelect(data) {
|
||||||
form.value = {
|
form.value = {
|
||||||
...form.value,
|
...form.value,
|
||||||
|
|
@ -65,21 +61,42 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getFormOptions = computed(() => {
|
const getFormOptions = computed(() => {
|
||||||
|
props.info.forEach((item) => {
|
||||||
|
// const hasInit = item.init || false
|
||||||
|
// const hasKey = Object.keys(form.value).includes(item.key)
|
||||||
|
// form.value[item.key] = hasInit ? (item.value || null) : hasKey ? form.value[item.key] : (item.value || null)
|
||||||
|
form.value[item.key] = item.value || null
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
form: unref(form),
|
form: unref(form),
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
labelPlacement: 'left',
|
labelPlacement: 'left',
|
||||||
inline: true,
|
inline: true,
|
||||||
info: [...unref(props).info]
|
info: [...props.info]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(getFormOptions.value.form,
|
||||||
|
(value) => {
|
||||||
|
emit('change', getFormOptions.value.form)
|
||||||
|
})
|
||||||
|
|
||||||
function handleSearch() {
|
function handleSearch() {
|
||||||
emit('search', getFormOptions.value.form)
|
emit('search', getFormOptions.value.form)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
initForm()
|
initForm()
|
||||||
emit('reset', getFormOptions.value.form)
|
emit('reset', getFormOptions.value.form)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setFormValue(params) {
|
||||||
|
Object.keys(params).forEach((key) => {
|
||||||
|
const index = unref(props).info.findIndex((item) => item.key === key)
|
||||||
|
form.value[key] = (props).info[index].value || null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function showMoreItem() {
|
function showMoreItem() {
|
||||||
showItemNum.value = showItemNum.value === len.value ? 3 : len.value
|
showItemNum.value = showItemNum.value === len.value ? 3 : len.value
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +106,7 @@ export default {
|
||||||
getFormOptions,
|
getFormOptions,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleReset,
|
handleReset,
|
||||||
|
setFormValue,
|
||||||
handleSelect,
|
handleSelect,
|
||||||
itemRefs,
|
itemRefs,
|
||||||
showMoreItem
|
showMoreItem
|
||||||
|
|
@ -111,6 +129,9 @@ export default {
|
||||||
.n-cascader{
|
.n-cascader{
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
&.hidden-item{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
transition: all 10s;
|
transition: all 10s;
|
||||||
}
|
}
|
||||||
.form__button{
|
.form__button{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="external" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-bind="$attrs" />
|
||||||
|
<svg v-else :class="svgClass" aria-hidden="true" v-bind="$attrs">
|
||||||
|
<use :xlink:href="iconName" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal } from '@/utils/is.js'
|
||||||
|
import { defineComponent, computed } from 'vue'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'SvgIcon',
|
||||||
|
props: {
|
||||||
|
prefix: {
|
||||||
|
type: String,
|
||||||
|
default: 'icon'
|
||||||
|
},
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const external = computed(() => {
|
||||||
|
return isExternal(props.iconClass)
|
||||||
|
})
|
||||||
|
|
||||||
|
const iconName = computed(() => {
|
||||||
|
return `#icon-${props.iconClass}`
|
||||||
|
})
|
||||||
|
|
||||||
|
const svgClass = computed(() => {
|
||||||
|
if (props.className) {
|
||||||
|
return 'svg-icon ' + props.className
|
||||||
|
} else {
|
||||||
|
return 'svg-icon'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const styleExternalIcon = computed(() => {
|
||||||
|
return {
|
||||||
|
mask: `url(${props.iconClass}) no-repeat 50% 50%`,
|
||||||
|
'-webkit-mask': `url(${props.iconClass}) no-repeat 50% 50%`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
external,
|
||||||
|
iconName,
|
||||||
|
svgClass,
|
||||||
|
styleExternalIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-external-icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
mask-size: cover!important;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="isFailed && useEmpty">
|
||||||
|
<slot name="empty" />
|
||||||
|
</div>
|
||||||
|
<div v-else :id="getPlayerId" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { defineComponent, reactive, ref, computed, toRefs, nextTick } from 'vue'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'VideoPlayer',
|
||||||
|
props: {
|
||||||
|
/* 播放器id */
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: () => 'palyer'
|
||||||
|
},
|
||||||
|
/* 是有填充空白 */
|
||||||
|
useEmpty: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['timeUpdate', 'video-status'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const videoPlayer = Symbol.for(props.id)
|
||||||
|
const data = reactive({
|
||||||
|
[videoPlayer]: null,
|
||||||
|
seekTime: null,
|
||||||
|
canSeek: true,
|
||||||
|
isSeek: false,
|
||||||
|
isFailed: true
|
||||||
|
})
|
||||||
|
/* 获取播放器的id */
|
||||||
|
const getPlayerId = computed(() => {
|
||||||
|
return props.id
|
||||||
|
})
|
||||||
|
|
||||||
|
/* 播放器组件 */
|
||||||
|
const toolComponent = Aliplayer.Component({
|
||||||
|
/* 时间更新事件 */
|
||||||
|
timeupdate(player, e) {
|
||||||
|
data.seekTime = player.getCurrentTime()
|
||||||
|
emit('video-status', data.isSeek ? 'skip' : 'playing')
|
||||||
|
},
|
||||||
|
ready(player, e) {
|
||||||
|
emit('video-status', 'ready')
|
||||||
|
},
|
||||||
|
pause(player, e) {
|
||||||
|
emit('video-status', 'pause')
|
||||||
|
},
|
||||||
|
play(player, e) {
|
||||||
|
emit('video-status', 'play')
|
||||||
|
},
|
||||||
|
ended(player, e) {
|
||||||
|
emit('video-status', 'ended')
|
||||||
|
},
|
||||||
|
error(player, e) {
|
||||||
|
data.isFailed = true
|
||||||
|
emit('video-status', 'error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/* 初始化播放器 */
|
||||||
|
function init(options) {
|
||||||
|
if (!options.source) {
|
||||||
|
data.isFailed = true
|
||||||
|
} else {
|
||||||
|
data.isFailed = false
|
||||||
|
nextTick(() => {
|
||||||
|
/* 实例化ali播放器 */
|
||||||
|
const player = new Aliplayer(
|
||||||
|
{
|
||||||
|
id: props.id,
|
||||||
|
width: '500px',
|
||||||
|
height: '260px',
|
||||||
|
autoplay: true,
|
||||||
|
...options,
|
||||||
|
components: [toolComponent]
|
||||||
|
},
|
||||||
|
function(player) { player.mute() }
|
||||||
|
)
|
||||||
|
/* 监听开始拖拽事件 */
|
||||||
|
player.on('startSeek', ({ paramData }) => {
|
||||||
|
/* 仅变更标识 */
|
||||||
|
data.isSeek = true
|
||||||
|
})
|
||||||
|
/* 监听完成拖拽事件 */
|
||||||
|
player.on('completeSeek', ({ paramData }) => {
|
||||||
|
/* 仅变更标识 */
|
||||||
|
data.isSeek = false
|
||||||
|
data.seekTime = paramData
|
||||||
|
/* 是否通知跳转 */
|
||||||
|
if (data.canSeek) {
|
||||||
|
emit('video-status', 'skip')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
data[videoPlayer] = player
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 获取当前播放器的时间 */
|
||||||
|
function getTime() {
|
||||||
|
let currentTime = 0
|
||||||
|
let duration = 0
|
||||||
|
const seekTime = data.seekTime
|
||||||
|
if (data[videoPlayer] && !data.isFailed) {
|
||||||
|
currentTime = data[videoPlayer]?.getCurrentTime()
|
||||||
|
duration = data[videoPlayer]?.getDuration()
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
currentTime,
|
||||||
|
duration,
|
||||||
|
seekTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 设定播放器播放时间 */
|
||||||
|
function seekTime(time) {
|
||||||
|
if (data[videoPlayer] && !data.isFailed) {
|
||||||
|
data.canSeek = false
|
||||||
|
data[videoPlayer]?.seek(time)
|
||||||
|
setTimeout(() => {
|
||||||
|
data.canSeek = true
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 设定播放器开始 */
|
||||||
|
function playVideo() {
|
||||||
|
if (data[videoPlayer] && !data.isFailed) {
|
||||||
|
data[videoPlayer]?.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 设定播放器暂停 */
|
||||||
|
function pauseVideo() {
|
||||||
|
if (data[videoPlayer] && !data.isFailed) {
|
||||||
|
data[videoPlayer]?.pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 销毁播放器 */
|
||||||
|
function disposeVideo() {
|
||||||
|
if (data[videoPlayer] && !data.isFailed) {
|
||||||
|
data[videoPlayer]?.dispose()
|
||||||
|
}
|
||||||
|
data.isFailed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
getPlayerId,
|
||||||
|
init,
|
||||||
|
getTime,
|
||||||
|
seekTime,
|
||||||
|
playVideo,
|
||||||
|
pauseVideo,
|
||||||
|
disposeVideo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.prism-player .prism-ErrorMessage .prism-error-operation{
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.prism-player .prism-ErrorMessage .prism-error-operation a.prism-button.prism-button-refresh{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.prism-player .prism-ErrorMessage .prism-error-operation a.prism-button.prism-button-orange{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* .prism-player .prism-ErrorMessage .prism-detect-info.prism-center{
|
||||||
|
display: none;
|
||||||
|
} */
|
||||||
|
</style>
|
||||||
|
|
@ -3,16 +3,45 @@ export default [
|
||||||
{
|
{
|
||||||
path: '/system',
|
path: '/system',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/system/menu',
|
redirect: '/system/user',
|
||||||
name: 'System',
|
name: 'System',
|
||||||
|
title: '系统管理',
|
||||||
meta: {
|
meta: {
|
||||||
title: '系统管理'
|
title: '系统管理'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
path: 'user',
|
||||||
|
component: () => import('@/views/system-manage/user-manage/index.vue'),
|
||||||
|
name: 'SystemUser',
|
||||||
|
title: '用户管理',
|
||||||
|
meta: {
|
||||||
|
title: '用户管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'role',
|
||||||
|
component: () => import('@/views/system-manage/role-manage/index.vue'),
|
||||||
|
name: 'SystemRole',
|
||||||
|
title: '角色管理',
|
||||||
|
meta: {
|
||||||
|
title: '角色管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'dept',
|
||||||
|
component: () => import('@/views/system-manage/department-manage/index.vue'),
|
||||||
|
name: 'SystemDept',
|
||||||
|
title: '部门管理',
|
||||||
|
meta: {
|
||||||
|
title: '部门管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'menu',
|
path: 'menu',
|
||||||
component: () => import('@/views/system/menu/index.vue'),
|
component: () => import('@/views/system-manage/menu-manage/index.vue'),
|
||||||
name: 'SystemMenu',
|
name: 'SystemMenu',
|
||||||
|
title: '菜单管理',
|
||||||
meta: {
|
meta: {
|
||||||
title: '菜单管理'
|
title: '菜单管理'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 调用store中的方法,登录以及存储token和用户信息 */
|
/* 调用store中的方法,登录以及存储token和用户信息 */
|
||||||
const res = await userStore.getLoginToken(this.loginForm)
|
const res = await userStore.getLoginToken(data.loginForm)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
const toPath = decodeURIComponent((route.query?.redirect || '/'))
|
const toPath = decodeURIComponent((route.query?.redirect || '/'))
|
||||||
route.name === '/login' ? router.replace('/') : router.replace(toPath)
|
route.name === '/login' ? router.replace('/') : router.replace(toPath)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
:options="getModalOptions"
|
||||||
|
:on-positive-click="handleConfirm"
|
||||||
|
:on-negative-click="handleClose"
|
||||||
|
:on-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #Context>
|
||||||
|
<n-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="departmentForm"
|
||||||
|
:rules="departmentRules"
|
||||||
|
:label-width="80"
|
||||||
|
label-placement="left"
|
||||||
|
require-mark-placement="left"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<template v-for="(item,index) in getFormOptions" :key="index">
|
||||||
|
<n-form-item :label="item.label" :path="item.key">
|
||||||
|
<n-input v-if="item.type === 'input'" v-model:value="departmentForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-select v-if="item.type === 'select'" v-model:value="departmentForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-input-number v-if="item.type === 'number'" v-model:value="departmentForm[item.key]" v-bind="item.props" />
|
||||||
|
</n-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</n-form>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { form, getDeptOptions } from '../tools/form.js'
|
||||||
|
import Modal from '@/components/Modal/index.vue'
|
||||||
|
import { addDept, editDept } from '@/api/system/dept/index.js'
|
||||||
|
import { defineComponent, ref, reactive, computed, toRefs } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'UserModal',
|
||||||
|
components: { Modal },
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'create'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: {
|
||||||
|
'update:visible': null,
|
||||||
|
'reload': null
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const MODAL_TYPE = {
|
||||||
|
'create': '新建部门',
|
||||||
|
'preview': '部门详情',
|
||||||
|
'update': '编辑部门'
|
||||||
|
}
|
||||||
|
getDeptOptions()
|
||||||
|
const { departmentForm, departmentRules } = form
|
||||||
|
const formRef = ref()
|
||||||
|
const data = reactive({
|
||||||
|
departmentForm: {
|
||||||
|
...departmentForm,
|
||||||
|
...props.data,
|
||||||
|
pid: props.data?.pid === 0 ? null : props.data?.pid
|
||||||
|
},
|
||||||
|
departmentRules: {
|
||||||
|
...departmentRules
|
||||||
|
},
|
||||||
|
disabled: props.type === 'preview'
|
||||||
|
})
|
||||||
|
const getModalOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
title: MODAL_TYPE[props.type],
|
||||||
|
show: props.visible,
|
||||||
|
negativeText: '取消',
|
||||||
|
positiveText: '确认'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getFormOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
...form.formItem
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
const params = { ...data.departmentForm }
|
||||||
|
if (params.id) {
|
||||||
|
editDept(params).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
addDept(params).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭弹窗 */
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('update:visible', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
formRef,
|
||||||
|
getModalOptions,
|
||||||
|
getFormOptions,
|
||||||
|
handleConfirm,
|
||||||
|
handleClose
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
.n-input-number{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<n-card>
|
||||||
|
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" />
|
||||||
|
<data-table
|
||||||
|
ref="tableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:request="loadDataTable"
|
||||||
|
:row-key="(row) => row.id"
|
||||||
|
:pagination="false"
|
||||||
|
data-type="tree"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
<template #tableTitle>
|
||||||
|
<n-button type="primary" @click="handleModal"> 新建 </n-button>
|
||||||
|
</template>
|
||||||
|
</data-table>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
<!-- 新增、编辑弹窗 -->
|
||||||
|
<DepartmentModal v-if="modalShow" v-model:visible="modalShow" :data="rowData" :type="modalType" @reload="handleSearch" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import search from './tools/search.js'
|
||||||
|
import table from './tools/table.js'
|
||||||
|
import headSearch from '@/components/Search/index.vue'
|
||||||
|
import dataTable from '@/components/DataTable/index.vue'
|
||||||
|
import DepartmentModal from './components/DepartmentModal.vue'
|
||||||
|
import { getDeptList } from '@/api/system/dept/index.js'
|
||||||
|
import { unref, toRefs, reactive, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MenuPage',
|
||||||
|
components: { dataTable, DepartmentModal, headSearch },
|
||||||
|
setup() {
|
||||||
|
const data = reactive({
|
||||||
|
...toRefs(table),
|
||||||
|
search
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadDataTable = async(res) => {
|
||||||
|
const _params = {
|
||||||
|
...unref(data.searchParams),
|
||||||
|
...res
|
||||||
|
}
|
||||||
|
return await getDeptList(_params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
function handleModal() {
|
||||||
|
data.rowData = null
|
||||||
|
data.modalType = 'create'
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
data.searchParams = null
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
loadDataTable,
|
||||||
|
handleModal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
.n-button + .n-button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { USER_STATUS } from '@/utils/dictionary.js'
|
||||||
|
import { getDeptAll } from '@/api/system/dept/index'
|
||||||
|
import { dataToSelect } from '@/utils/handleData.js'
|
||||||
|
const departmentOptions = ref()
|
||||||
|
|
||||||
|
export const form = reactive({
|
||||||
|
departmentForm: {
|
||||||
|
code: '',
|
||||||
|
name: '',
|
||||||
|
sort: null,
|
||||||
|
pid: null,
|
||||||
|
note: ''
|
||||||
|
},
|
||||||
|
departmentRules: {
|
||||||
|
code: [{ required: true, message: '请输入部门编号', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '请输入部门名称', type: 'string', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, type: 'number', message: '请输入排序号', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
formItem: [
|
||||||
|
{ type: 'input', key: 'code', label: '部门编号', props: { maxlength: '20', placeholder: '请输入部门编号', clearable: true }},
|
||||||
|
{ type: 'input', key: 'name', label: '部门名称', props: { maxlength: '20', placeholder: '请输入部门名称', clearable: true }},
|
||||||
|
{ type: 'select', key: 'pid', label: '所属部门', props: { options: departmentOptions, placeholder: '请选择所属部门' }},
|
||||||
|
{ type: 'number', key: 'sort', label: '排序号', props: { min: 0, placeholder: '请输入排序号', clearable: true }},
|
||||||
|
{ type: 'input', key: 'note', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDeptOptions = async function() {
|
||||||
|
const res = await getDeptAll()
|
||||||
|
departmentOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' })
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
const data = [
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
|
const data = reactive([
|
||||||
{
|
{
|
||||||
label: '部门名称',
|
label: '部门名称',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
|
@ -6,7 +8,7 @@ const data = [
|
||||||
placeholder: '请输入部门名称'
|
placeholder: '请输入部门名称'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
])
|
||||||
|
|
||||||
export default data
|
export default data
|
||||||
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { h, ref, reactive } from 'vue'
|
||||||
|
import TableAction from '@/components/DataTable/tools/Action.vue'
|
||||||
|
import { deleteDept } from '@/api/system/dept/index.js'
|
||||||
|
|
||||||
|
/* 注册table */
|
||||||
|
const tableRef = ref()
|
||||||
|
const searchParams = ref()
|
||||||
|
|
||||||
|
function handleSearch(params) {
|
||||||
|
searchParams.value = { ...params }
|
||||||
|
tableRef.value.reFetch({ searchParams })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取数据及操作
|
||||||
|
* @param {*} row 单行数据
|
||||||
|
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function getRowData(row, type) {
|
||||||
|
data.rowData = type === 'create' ? { pid: row.id } : row
|
||||||
|
data.modalType = type
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除方法
|
||||||
|
function deleteData(id) {
|
||||||
|
deleteDept(id)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
tableRef,
|
||||||
|
searchParams,
|
||||||
|
rowData: {},
|
||||||
|
modalType: 'create',
|
||||||
|
modalShow: false,
|
||||||
|
handleSearch,
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '部门编号',
|
||||||
|
key: 'code',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '部门名称',
|
||||||
|
key: 'name',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '排序',
|
||||||
|
key: 'sort',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
minWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '更新时间',
|
||||||
|
key: 'updateTime',
|
||||||
|
align: 'center',
|
||||||
|
minWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
fixed: 'right',
|
||||||
|
render(row) {
|
||||||
|
return h(TableAction, {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '添加',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
text: true,
|
||||||
|
onClick: getRowData.bind(null, row, 'create')
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '修改',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
text: true,
|
||||||
|
onClick: getRowData.bind(null, row, 'update')
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'popconfirm',
|
||||||
|
auth: 'basic_list',
|
||||||
|
tip: '确定删除这条数据吗?',
|
||||||
|
props: {
|
||||||
|
onPositiveClick: deleteData.bind(null, [row.id])
|
||||||
|
},
|
||||||
|
ButtonProps: {
|
||||||
|
text: true,
|
||||||
|
type: 'primary'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
align: 'center'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default data
|
||||||
|
|
@ -0,0 +1,161 @@
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
:options="getModalOptions"
|
||||||
|
:on-close="handleClose"
|
||||||
|
:on-positive-click="handleConfirm"
|
||||||
|
:on-negative-click="handleClose"
|
||||||
|
>
|
||||||
|
<template #Context>
|
||||||
|
<n-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="menuForm"
|
||||||
|
:rules="menuRules"
|
||||||
|
:label-width="80"
|
||||||
|
label-placement="left"
|
||||||
|
require-mark-placement="left"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<n-grid x-gap="12" :cols="2">
|
||||||
|
<template v-for="(item,index) in getFormOptions" :key="index">
|
||||||
|
<n-gi>
|
||||||
|
<n-form-item :label="item.label" :path="item.key">
|
||||||
|
<n-input v-if="item.type === 'input'" v-model:value="menuForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-select v-if="item.type === 'select'" v-model:value="menuForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-input-number v-if="item.type === 'number'" v-model:value="menuForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-radio-group v-if="item.type === 'radio'" v-model:value="menuForm[item.key]" :name="item.key">
|
||||||
|
<n-space>
|
||||||
|
<n-radio v-for="(cItem,cIndex) in item.options" :key="`${item.key}_${cIndex}`" :value="cItem.value"> {{ cItem.label }}</n-radio>
|
||||||
|
</n-space>
|
||||||
|
</n-radio-group>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
</template>
|
||||||
|
</n-grid>
|
||||||
|
|
||||||
|
</n-form>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { form, changeMenuType, getMenuOptions } from '../tools/form.js'
|
||||||
|
import { defineComponent, ref, reactive, computed, watch, toRefs } from 'vue'
|
||||||
|
import Modal from '@/components/Modal/index.vue'
|
||||||
|
import { addMenu, editMenu } from '@/api/system/menu/index.js'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MenuModal',
|
||||||
|
components: { Modal },
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'create'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: {
|
||||||
|
'update:visible': null,
|
||||||
|
'reload': null
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const MODAL_TYPE = {
|
||||||
|
'create': '新建菜单',
|
||||||
|
'preview': '菜单详情',
|
||||||
|
'update': '编辑菜单'
|
||||||
|
}
|
||||||
|
getMenuOptions()
|
||||||
|
const { menuForm, menuRules } = form
|
||||||
|
const formRef = ref()
|
||||||
|
const data = reactive({
|
||||||
|
menuForm: {
|
||||||
|
...menuForm,
|
||||||
|
...props.data,
|
||||||
|
pid: props.data?.pid === 0 ? null : props.data?.pid
|
||||||
|
},
|
||||||
|
menuRules: {
|
||||||
|
...menuRules
|
||||||
|
},
|
||||||
|
disabled: props.type === 'preview'
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => data.menuForm.type,
|
||||||
|
(val) => {
|
||||||
|
switch (val) {
|
||||||
|
case 0:
|
||||||
|
data.menuForm.permission = ''
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
data.menuForm.path = ''
|
||||||
|
data.menuForm.component = ''
|
||||||
|
break
|
||||||
|
}
|
||||||
|
changeMenuType(val)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getModalOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
title: MODAL_TYPE[props.type],
|
||||||
|
show: props.visible,
|
||||||
|
negativeText: '取消',
|
||||||
|
positiveText: '确认'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getFormOptions = computed(() => {
|
||||||
|
console.log('change')
|
||||||
|
return {
|
||||||
|
...form.formItem
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
const params = { ...data.menuForm }
|
||||||
|
if (params.id) {
|
||||||
|
editMenu(params).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
addMenu(params).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message.error('请完善必填信息')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭弹窗 */
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('update:visible', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
formRef,
|
||||||
|
getModalOptions,
|
||||||
|
getFormOptions,
|
||||||
|
handleConfirm,
|
||||||
|
handleClose
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<n-card>
|
||||||
|
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" />
|
||||||
|
<data-table
|
||||||
|
ref="tableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="false"
|
||||||
|
data-type="tree"
|
||||||
|
:request="loadDataTable"
|
||||||
|
:row-key="(row) => row.id"
|
||||||
|
>
|
||||||
|
<template #tableTitle>
|
||||||
|
<n-button type="primary" @click="handleModal"> 添加菜单 </n-button>
|
||||||
|
</template>
|
||||||
|
</data-table>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<MenuModal v-if="modalShow" v-model:visible="modalShow" :data="rowData" :type="modalType" @reload="handleSearch" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import search from './tools/search.js'
|
||||||
|
import table from './tools/table.js'
|
||||||
|
import headSearch from '@/components/Search/index.vue'
|
||||||
|
import dataTable from '@/components/DataTable/index.vue'
|
||||||
|
import MenuModal from './components/MenuModal.vue'
|
||||||
|
import { getMenuList } from '@/api/system/menu/index.js'
|
||||||
|
import { unref, reactive, toRefs, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MenuPage',
|
||||||
|
components: { dataTable, MenuModal, headSearch },
|
||||||
|
setup() {
|
||||||
|
const data = reactive({
|
||||||
|
...toRefs(table),
|
||||||
|
search
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadDataTable = async(res) => {
|
||||||
|
const _params = {
|
||||||
|
...unref(data.searchParams),
|
||||||
|
...res
|
||||||
|
}
|
||||||
|
return await getMenuList(_params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开新增弹框
|
||||||
|
function handleModal() {
|
||||||
|
data.rowData = null
|
||||||
|
data.modalType = 'create'
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
data.searchParams = null
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
loadDataTable,
|
||||||
|
handleModal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { ref, reactive, watch } from 'vue'
|
||||||
|
import { MENU_TYPE, MENU_OPEN, MENU_VISIBLE, MENU_STATUS } from '@/utils/dictionary.js'
|
||||||
|
import { getMenu } from '@/api/system/menu/index.js'
|
||||||
|
import { dataToSelect } from '@/utils/handleData.js'
|
||||||
|
const menuOptions = ref()
|
||||||
|
const menuType0 = ref(true)
|
||||||
|
const menuType1 = ref(false)
|
||||||
|
|
||||||
|
export const form = reactive({
|
||||||
|
menuForm: {
|
||||||
|
pid: null,
|
||||||
|
type: 0,
|
||||||
|
title: '',
|
||||||
|
target: '1',
|
||||||
|
icon: '',
|
||||||
|
permission: '',
|
||||||
|
path: '',
|
||||||
|
sort: null,
|
||||||
|
component: '',
|
||||||
|
hide: 0,
|
||||||
|
status: 1
|
||||||
|
},
|
||||||
|
menuRules: {
|
||||||
|
title: [{ required: true, message: '请输入菜单名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, type: 'number', message: '请输入排序号', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
formItem: [
|
||||||
|
{ type: 'select', key: 'pid', label: '上级菜单', props: { options: menuOptions, placeholder: '请选择上级菜单' }},
|
||||||
|
{ type: 'radio', key: 'type', label: '菜单类型', options: MENU_TYPE },
|
||||||
|
{ type: 'input', key: 'title', label: '菜单名称', props: { maxlength: '20', placeholder: '请输入菜单名称', clearable: true }},
|
||||||
|
{ type: 'radio', key: 'target', label: '打开方式', options: MENU_OPEN },
|
||||||
|
{ type: 'input', key: 'icon', label: '菜单图标', props: { maxlength: '20', placeholder: '请选择菜单图标', clearable: true }},
|
||||||
|
{ type: 'input', key: 'permission', label: '权限标识', props: { maxlength: '20', placeholder: '请输入部门名称', disabled: menuType0, clearable: true }},
|
||||||
|
{ type: 'input', key: 'path', label: '路由地址', props: { maxlength: '20', placeholder: '请输入部门名称', disabled: menuType1, clearable: true }},
|
||||||
|
{ type: 'number', key: 'sort', label: '排序号', props: { min: 0, placeholder: '请输入排序号', clearable: true }},
|
||||||
|
{ type: 'input', key: 'component', label: '组件路径', props: { maxlength: '20', placeholder: '请输入部门名称', disabled: menuType1, clearable: true }},
|
||||||
|
{ type: 'radio', key: 'hide', label: '是否可见', options: MENU_VISIBLE },
|
||||||
|
{ type: 'radio', key: 'status', label: '菜单状态', options: MENU_STATUS }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getMenuOptions = async function() {
|
||||||
|
const res = await getMenu()
|
||||||
|
setTimeout(() => {
|
||||||
|
menuOptions.value = dataToSelect(res.data, { label: 'title', value: 'id' })
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const changeMenuType = function(value) {
|
||||||
|
menuType0.value = !value
|
||||||
|
menuType1.value = !menuType0.value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
const data = reactive([
|
||||||
|
{
|
||||||
|
label: '菜单名称',
|
||||||
|
key: 'title',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入菜单名称'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
export default data
|
||||||
|
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { MENU_TYPE, MENU_STATUS, MENU_VISIBLE } from '@/utils/dictionary.js'
|
||||||
|
import { h, ref, reactive } from 'vue'
|
||||||
|
import TableTags from '@/components/DataTable/tools/Tags.vue'
|
||||||
|
import TableAction from '@/components/DataTable/tools/Action.vue'
|
||||||
|
import { deleteMenu } from '@/api/system/menu/index.js'
|
||||||
|
|
||||||
|
/* 注册table */
|
||||||
|
const tableRef = ref()
|
||||||
|
const searchParams = ref()
|
||||||
|
|
||||||
|
function handleSearch(params) {
|
||||||
|
searchParams.value = { ...params }
|
||||||
|
tableRef.value.reFetch({ searchParams })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取数据及操作
|
||||||
|
* @param {*} row 单行数据
|
||||||
|
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function getRowData(row, type) {
|
||||||
|
data.rowData = type === 'create' ? { pid: row.id } : row
|
||||||
|
data.modalType = type
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除方法
|
||||||
|
function deleteData(id) {
|
||||||
|
deleteMenu(id)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
tableRef,
|
||||||
|
searchParams,
|
||||||
|
rowData: {},
|
||||||
|
modalType: 'create',
|
||||||
|
modalShow: false,
|
||||||
|
handleSearch,
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '菜单标题',
|
||||||
|
key: 'title',
|
||||||
|
align: 'center',
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '菜单类型',
|
||||||
|
key: 'type',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
render(row) {
|
||||||
|
return h(TableTags, {
|
||||||
|
data: row.type,
|
||||||
|
filters: MENU_TYPE
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '路由地址',
|
||||||
|
key: 'path',
|
||||||
|
align: 'center',
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '组件路径',
|
||||||
|
key: 'component',
|
||||||
|
align: 'center',
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
render(row) {
|
||||||
|
return h(TableTags, {
|
||||||
|
data: row.status,
|
||||||
|
filters: MENU_STATUS
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '排序',
|
||||||
|
key: 'sort',
|
||||||
|
align: 'center',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '是否可见',
|
||||||
|
key: 'hide',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
render(row) {
|
||||||
|
return h(TableTags, {
|
||||||
|
data: row.hide,
|
||||||
|
filters: MENU_VISIBLE
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
fixed: 'right',
|
||||||
|
render(row) {
|
||||||
|
return h(TableAction, {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '添加',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
text: true,
|
||||||
|
onClick: getRowData.bind(null, row, 'create')
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '修改',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
text: true,
|
||||||
|
onClick: getRowData.bind(null, row, 'update')
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'popconfirm',
|
||||||
|
auth: 'basic_list',
|
||||||
|
tip: '确定删除这条数据吗?',
|
||||||
|
props: {
|
||||||
|
onPositiveClick: deleteData.bind(null, [row.id])
|
||||||
|
},
|
||||||
|
ButtonProps: {
|
||||||
|
text: true,
|
||||||
|
type: 'primary'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
align: 'center'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default data
|
||||||
|
|
@ -33,14 +33,14 @@ export default defineComponent({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
row: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: {
|
emits: {
|
||||||
'update:visible': null,
|
'update:visible': null,
|
||||||
'done': null
|
'reload': null
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
|
|
@ -62,7 +62,7 @@ export default defineComponent({
|
||||||
|
|
||||||
// 获取当前角色的权限菜单列表
|
// 获取当前角色的权限菜单列表
|
||||||
async function getMenuByRoleId() {
|
async function getMenuByRoleId() {
|
||||||
const res = await getRolePermission(props.row.id)
|
const res = await getRolePermission(props.data.id)
|
||||||
data.allTreeData = toTreeData(res.data, 'id', 'pid', 'children')
|
data.allTreeData = toTreeData(res.data, 'id', 'pid', 'children')
|
||||||
const checkedArr = res.data
|
const checkedArr = res.data
|
||||||
if (checkedArr.length) {
|
if (checkedArr.length) {
|
||||||
|
|
@ -80,6 +80,17 @@ export default defineComponent({
|
||||||
data.menuIds = keys
|
data.menuIds = keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
savePermission({ roleId: props.data.id, menuIds: data.menuIds }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/* 关闭弹窗 */
|
/* 关闭弹窗 */
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
emit('update:visible', false)
|
emit('update:visible', false)
|
||||||
|
|
@ -88,25 +99,9 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
...toRefs(data),
|
...toRefs(data),
|
||||||
getModalOptions,
|
getModalOptions,
|
||||||
handleClose,
|
handleCheckTree,
|
||||||
handleCheckTree
|
handleConfirm,
|
||||||
}
|
handleClose
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 提交
|
|
||||||
handleConfirm() {
|
|
||||||
console.log(this.menuIds, this.checkedTreeData)
|
|
||||||
savePermission({ roleId: this.row.id, menuIds: this.menuIds }).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
:options="getModalOptions"
|
||||||
|
:on-positive-click="handleConfirm"
|
||||||
|
:on-negative-click="handleClose"
|
||||||
|
:on-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #Context>
|
||||||
|
<n-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="roleForm"
|
||||||
|
:rules="roleRules"
|
||||||
|
:label-width="80"
|
||||||
|
label-placement="left"
|
||||||
|
require-mark-placement="left"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<template v-for="(item,index) in getFormOptions" :key="index">
|
||||||
|
<n-form-item :label="item.label" :path="item.key">
|
||||||
|
<n-input v-if="item.type === 'input'" v-model:value="roleForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-radio-group v-if="item.type === 'radio'" v-model:value="roleForm[item.key]" :name="item.key">
|
||||||
|
<n-space>
|
||||||
|
<n-radio v-for="(cItem,cIndex) in item.options" :key="`${item.key}_${cIndex}`" :value="cItem.value"> {{ cItem.label }}</n-radio>
|
||||||
|
</n-space>
|
||||||
|
</n-radio-group>
|
||||||
|
</n-form-item>
|
||||||
|
</template>
|
||||||
|
</n-form>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import form from '../tools/form.js'
|
||||||
|
import { defineComponent, ref, reactive, computed, toRefs } from 'vue'
|
||||||
|
import Modal from '@/components/Modal/index.vue'
|
||||||
|
import { addRole, editRole } from '@/api/system/role/index'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RoleModal',
|
||||||
|
components: { Modal },
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'create'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: {
|
||||||
|
'update:visible': null,
|
||||||
|
'reload': null
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const MODAL_TYPE = {
|
||||||
|
'create': '新建角色',
|
||||||
|
'preview': '角色详情',
|
||||||
|
'update': '编辑角色'
|
||||||
|
}
|
||||||
|
const { roleForm, roleRules } = form
|
||||||
|
const formRef = ref()
|
||||||
|
const data = reactive({
|
||||||
|
roleForm: {
|
||||||
|
...roleForm,
|
||||||
|
...props.data
|
||||||
|
},
|
||||||
|
roleRules: {
|
||||||
|
...roleRules
|
||||||
|
},
|
||||||
|
disabled: props.type === 'preview'
|
||||||
|
})
|
||||||
|
|
||||||
|
const getModalOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
title: MODAL_TYPE[props.type],
|
||||||
|
show: props.visible,
|
||||||
|
negativeText: '取消',
|
||||||
|
positiveText: '确认'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getFormOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
...form.formItem
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
formRef.value?.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
const params = { ...data.roleForm }
|
||||||
|
if (params.id) {
|
||||||
|
/* 编辑 */
|
||||||
|
editRole(params)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
/* 新增 */
|
||||||
|
addRole(params)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message.error('请完善必填信息')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭弹窗 */
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('update:visible', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
formRef,
|
||||||
|
getModalOptions,
|
||||||
|
getFormOptions,
|
||||||
|
handleConfirm,
|
||||||
|
handleClose
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<n-card>
|
||||||
|
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" />
|
||||||
|
<data-table
|
||||||
|
ref="tableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:row-key="(row) => row.id"
|
||||||
|
:request="loadDataTable"
|
||||||
|
size="large"
|
||||||
|
scroll-x="1200"
|
||||||
|
@update:checked-row-keys="handleCheck"
|
||||||
|
>
|
||||||
|
<template #tableTitle>
|
||||||
|
<n-button type="primary" @click="handleModal"> 新建 </n-button>
|
||||||
|
<n-popconfirm
|
||||||
|
negative-text="取消"
|
||||||
|
positive-text="确认"
|
||||||
|
@positive-click="deleteComplex"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<n-button type="primary">删除</n-button>
|
||||||
|
</template>
|
||||||
|
确定删除选中的数据吗?
|
||||||
|
</n-popconfirm>
|
||||||
|
</template>
|
||||||
|
</data-table>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
<!-- 新增、编辑弹窗 -->
|
||||||
|
<RoleModal v-if="modalShow" v-model:visible="modalShow" :data="rowData" :type="modalType" @reload="handleSearch" />
|
||||||
|
<!-- 分配权限 -->
|
||||||
|
<ConfigModal v-if="configModalShow" v-model:visible="configModalShow" :data="rowData" @reload="handleSearch" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import search from './tools/search.js'
|
||||||
|
import table from './tools/table.js'
|
||||||
|
import headSearch from '@/components/Search/index.vue'
|
||||||
|
import dataTable from '@/components/DataTable/index.vue'
|
||||||
|
import RoleModal from './components/RoleModal.vue'
|
||||||
|
import ConfigModal from './components/ConfigModal.vue'
|
||||||
|
import { getRoleList } from '@/api/system/role/index'
|
||||||
|
import { ref, unref, toRefs, reactive, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MenuPage',
|
||||||
|
components: { headSearch, dataTable, RoleModal, ConfigModal },
|
||||||
|
setup() {
|
||||||
|
const data = reactive({
|
||||||
|
...toRefs(table),
|
||||||
|
search
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadDataTable = async(res) => {
|
||||||
|
const _params = {
|
||||||
|
...unref(data.searchParams),
|
||||||
|
...res
|
||||||
|
}
|
||||||
|
return await getRoleList(_params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增用户
|
||||||
|
function handleModal() {
|
||||||
|
data.rowData = null
|
||||||
|
data.modalType = 'create'
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择表格数据
|
||||||
|
const selectedIds = ref([])
|
||||||
|
function handleCheck(rowKeys) {
|
||||||
|
selectedIds.value = rowKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除
|
||||||
|
function deleteComplex() {
|
||||||
|
if (selectedIds.value.length) {
|
||||||
|
data.deleteData(selectedIds.value)
|
||||||
|
} else {
|
||||||
|
$message.warning('请至少选中一条数据')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
data.searchParams = null
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
loadDataTable,
|
||||||
|
handleModal,
|
||||||
|
handleCheck,
|
||||||
|
selectedIds,
|
||||||
|
deleteComplex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
.n-button + .n-button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
import { USER_STATUS } from '@/utils/dictionary.js'
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
roleForm: {
|
||||||
|
code: '',
|
||||||
|
name: '',
|
||||||
|
status: 1,
|
||||||
|
note: ''
|
||||||
|
},
|
||||||
|
roleRules: {
|
||||||
|
code: [{ required: true, message: '请输入角色编号', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '请输入角色名称', type: 'string', trigger: 'blur' }],
|
||||||
|
status: [{ required: true, message: '请选择状态', type: 'number', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
formItem: [
|
||||||
|
{ type: 'input', key: 'code', label: '角色编号', props: { maxlength: '20', placeholder: '请输入角色编号', clearable: true }},
|
||||||
|
{ type: 'input', key: 'name', label: '角色名称', props: { maxlength: '20', placeholder: '请输入角色名称', clearable: true }},
|
||||||
|
{ type: 'radio', key: 'status', label: '状态', options: USER_STATUS },
|
||||||
|
{ type: 'input', key: 'note', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default data
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
const data = [
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
|
const data = reactive([
|
||||||
{
|
{
|
||||||
label: '角色名称',
|
label: '角色名称',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
|
@ -6,6 +8,6 @@ const data = [
|
||||||
placeholder: '请输入角色名称'
|
placeholder: '请输入角色名称'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
])
|
||||||
|
|
||||||
export default data
|
export default data
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { h, ref, reactive } from 'vue'
|
||||||
|
import TableSwitch from '@/components/DataTable/tools/Switch.vue'
|
||||||
|
import TableAction from '@/components/DataTable/tools/Action.vue'
|
||||||
|
import { deleteRole, setRoleStatus } from '@/api/system/role/index'
|
||||||
|
|
||||||
|
/* 注册table */
|
||||||
|
const tableRef = ref()
|
||||||
|
const searchParams = ref()
|
||||||
|
|
||||||
|
function handleSearch(params) {
|
||||||
|
searchParams.value = { ...params }
|
||||||
|
tableRef.value.reFetch({ searchParams })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取数据及操作
|
||||||
|
* @param {*} row 单行数据
|
||||||
|
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function getRowData(row, type) {
|
||||||
|
data.rowData = row
|
||||||
|
data.modalType = type
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 打开分配权限窗口
|
||||||
|
* @param {*} row 单行数据
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function configure(row) {
|
||||||
|
data.rowData = row
|
||||||
|
data.configModalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 改变状态
|
||||||
|
* @param {*} row 选中数据
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function handleStatusChange(row) {
|
||||||
|
setRoleStatus({ id: row.data.id, status: row.value })
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除接口
|
||||||
|
function deleteData(data) {
|
||||||
|
deleteRole(data)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
tableRef,
|
||||||
|
searchParams,
|
||||||
|
rowData: {},
|
||||||
|
modalType: 'create',
|
||||||
|
modalShow: false,
|
||||||
|
configModalShow: false,
|
||||||
|
handleSearch,
|
||||||
|
deleteData,
|
||||||
|
columns: [
|
||||||
|
{ type: 'selection' },
|
||||||
|
{
|
||||||
|
title: '角色编号',
|
||||||
|
key: 'code',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色名称',
|
||||||
|
key: 'name',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
Minwidth: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '更新时间',
|
||||||
|
key: 'updateTime',
|
||||||
|
align: 'center',
|
||||||
|
Minwidth: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
render(row) {
|
||||||
|
return h(TableSwitch, {
|
||||||
|
data: { id: row.id, status: row.status },
|
||||||
|
rowKey: 'status',
|
||||||
|
checkedValue: 1,
|
||||||
|
uncheckedValue: 2,
|
||||||
|
onChange: handleStatusChange.bind(row)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
fixed: 'right',
|
||||||
|
render(row) {
|
||||||
|
return h(TableAction, {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '修改',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
text: true,
|
||||||
|
onClick: getRowData.bind(null, row, 'update')
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '分配权限',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
ghost: true,
|
||||||
|
text: true,
|
||||||
|
onClick: configure.bind(null, row)
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'popconfirm',
|
||||||
|
auth: 'basic_list',
|
||||||
|
tip: '确定删除这条数据吗?',
|
||||||
|
props: {
|
||||||
|
onPositiveClick: deleteData.bind(null, [row.id])
|
||||||
|
},
|
||||||
|
ButtonProps: {
|
||||||
|
text: true,
|
||||||
|
type: 'primary'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
align: 'center'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default data
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
:options="getModalOptions"
|
||||||
|
:on-positive-click="handleConfirm"
|
||||||
|
:on-negative-click="handleClose"
|
||||||
|
:on-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #Context>
|
||||||
|
<n-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="userForm"
|
||||||
|
:rules="userRules"
|
||||||
|
:label-width="80"
|
||||||
|
label-placement="left"
|
||||||
|
require-mark-placement="left"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<template v-for="(item,index) in getFormOptions" :key="index">
|
||||||
|
<n-form-item :label="item.label" :path="item.key">
|
||||||
|
<UploadOss v-if="item.type === 'oss'" :ref="el=>{ossRefs[item.refIndex] = el}" :default-list="userForm[item.file]" @upload-status="handleUploadStatus" />
|
||||||
|
<n-input v-if="item.type === 'input'" v-model:value="userForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-select v-if="item.type === 'select'" v-model:value="userForm[item.key]" v-bind="item.props" />
|
||||||
|
<n-radio-group v-if="item.type === 'radio'" v-model:value="userForm[item.key]" :name="item.key">
|
||||||
|
<n-space>
|
||||||
|
<n-radio v-for="(cItem,cIndex) in item.options" :key="`${item.key}_${cIndex}`" :value="cItem.value"> {{ cItem.label }}</n-radio>
|
||||||
|
</n-space>
|
||||||
|
</n-radio-group>
|
||||||
|
</n-form-item>
|
||||||
|
</template>
|
||||||
|
</n-form>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { form, getDeptOptions, getRoleOptions } from '../tools/form.js'
|
||||||
|
import { defineComponent, ref, reactive, computed, toRefs } from 'vue'
|
||||||
|
import Modal from '@/components/Modal/index.vue'
|
||||||
|
import UploadOss from '@/components/UploadOss/index.vue'
|
||||||
|
import { addUser, editUser } from '@/api/system/user/index'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'UserModal',
|
||||||
|
components: { Modal, UploadOss },
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'create'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: {
|
||||||
|
'update:visible': null,
|
||||||
|
'reload': null
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const MODAL_TYPE = {
|
||||||
|
'create': '新建用户',
|
||||||
|
'preview': '用户详情',
|
||||||
|
'update': '编辑用户'
|
||||||
|
}
|
||||||
|
getDeptOptions()
|
||||||
|
getRoleOptions()
|
||||||
|
const { userForm, userRules } = form
|
||||||
|
const formRef = ref()
|
||||||
|
const ossRefs = ref([])
|
||||||
|
const data = reactive({
|
||||||
|
userForm: {
|
||||||
|
...userForm,
|
||||||
|
...props.data,
|
||||||
|
roleIds: props?.data?.roles.map((item) => { return item.id }) || []
|
||||||
|
},
|
||||||
|
userRules: {
|
||||||
|
...userRules
|
||||||
|
},
|
||||||
|
disabled: props.type === 'preview'
|
||||||
|
})
|
||||||
|
const getModalOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
show: props.visible,
|
||||||
|
title: MODAL_TYPE[props.type],
|
||||||
|
negativeText: '取消',
|
||||||
|
positiveText: '确认'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getFormOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
...form.formItem
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleUploadStatus(status) {
|
||||||
|
data.userForm.imageStatus = status
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
formRef.value?.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
const uploads = ossRefs.value.map((item, index) => {
|
||||||
|
return item.startUpload()
|
||||||
|
})
|
||||||
|
Promise.all(uploads)
|
||||||
|
.then(response => {
|
||||||
|
const isError = response.map((item) => {
|
||||||
|
return item.includes('error')
|
||||||
|
})
|
||||||
|
if (!isError.includes(true)) {
|
||||||
|
const imageStr = response.join()
|
||||||
|
const params = {
|
||||||
|
...data.userForm,
|
||||||
|
// avatar: imageStr
|
||||||
|
avatar: '/imagedir/2uim2hpl94u_1655380018696.png'
|
||||||
|
}
|
||||||
|
if (params.id) {
|
||||||
|
/* 编辑 */
|
||||||
|
editUser(params)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
/* 新增 */
|
||||||
|
addUser(params)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
emit('reload')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message.error('文件上传失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
$message.error('请完善必填信息')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭弹窗 */
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('update:visible', false)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
formRef,
|
||||||
|
ossRefs,
|
||||||
|
getModalOptions,
|
||||||
|
getFormOptions,
|
||||||
|
handleUploadStatus,
|
||||||
|
handleConfirm,
|
||||||
|
handleClose
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<n-card>
|
||||||
|
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" />
|
||||||
|
<data-table
|
||||||
|
ref="tableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:row-key="(row) => row.id"
|
||||||
|
:request="loadDataTable"
|
||||||
|
size="large"
|
||||||
|
@update:checked-row-keys="handleCheck"
|
||||||
|
>
|
||||||
|
<template #tableTitle>
|
||||||
|
<n-button type="primary" @click="handleModal"> 新建 </n-button>
|
||||||
|
<n-popconfirm
|
||||||
|
negative-text="取消"
|
||||||
|
positive-text="确认"
|
||||||
|
@positive-click="deleteComplex"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<n-button type="primary"> 删除 </n-button>
|
||||||
|
</template>
|
||||||
|
确认要删除选中数据吗?
|
||||||
|
</n-popconfirm>
|
||||||
|
</template>
|
||||||
|
</data-table>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新增、编辑弹窗 -->
|
||||||
|
<UserModal v-if="modalShow" v-model:visible="modalShow" :type="modalType" :data="rowData" @reload="handleSearch" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { search, fetchRolesOption } from './tools/search.js'
|
||||||
|
import table from './tools/table.js'
|
||||||
|
import headSearch from '@/components/Search/index.vue'
|
||||||
|
import dataTable from '@/components/DataTable/index.vue'
|
||||||
|
import UserModal from './components/UserModal.vue'
|
||||||
|
import { getUserList } from '@/api/system/user/index.js'
|
||||||
|
import { unref, ref, toRefs, reactive, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MenuPage',
|
||||||
|
components: { dataTable, UserModal, headSearch },
|
||||||
|
setup() {
|
||||||
|
fetchRolesOption()
|
||||||
|
const data = reactive({
|
||||||
|
...toRefs(table),
|
||||||
|
...toRefs(search)
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadDataTable = async(res) => {
|
||||||
|
const _params = {
|
||||||
|
...unref(data.searchParams),
|
||||||
|
...res
|
||||||
|
}
|
||||||
|
return await getUserList(_params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
function handleModal() {
|
||||||
|
data.rowData = null
|
||||||
|
data.modalType = 'create'
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择表格数据
|
||||||
|
const selectedIds = ref([])
|
||||||
|
function handleCheck(rowKeys) {
|
||||||
|
selectedIds.value = rowKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除
|
||||||
|
function deleteComplex() {
|
||||||
|
if (selectedIds.value.length) {
|
||||||
|
data.deleteData(selectedIds.value)
|
||||||
|
} else {
|
||||||
|
$message.warning('请至少选中一条数据')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
data.searchParams = null
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
loadDataTable,
|
||||||
|
handleModal,
|
||||||
|
selectedIds,
|
||||||
|
deleteComplex,
|
||||||
|
handleCheck
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
.n-button + .n-button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { USER_STATUS } from '@/utils/dictionary.js'
|
||||||
|
import { getDeptAll } from '@/api/system/dept/index'
|
||||||
|
import { getRoleAll } from '@/api/system/role/index'
|
||||||
|
import { dataToSelect } from '@/utils/handleData.js'
|
||||||
|
const departmentOptions = ref()
|
||||||
|
const rolesOptions = ref()
|
||||||
|
export const form = reactive({
|
||||||
|
userForm: {
|
||||||
|
avatar: '',
|
||||||
|
code: '',
|
||||||
|
deptId: null,
|
||||||
|
username: '',
|
||||||
|
realname: '',
|
||||||
|
password: '',
|
||||||
|
roleIds: [],
|
||||||
|
status: 1,
|
||||||
|
note: ''
|
||||||
|
},
|
||||||
|
userRules: {
|
||||||
|
imageStatus: [{ required: true, message: '请选择头像', type: 'string', trigger: 'blur' }],
|
||||||
|
code: [{ required: true, message: '请输入编号', trigger: 'blur' }],
|
||||||
|
realname: [{ required: true, message: '请输入用户姓名', type: 'string', trigger: 'blur' }],
|
||||||
|
deptId: [{ required: true, message: '请选择部门', type: 'number', trigger: 'blur' }],
|
||||||
|
status: [{ required: true, message: '请选择状态', type: 'number', trigger: 'blur' }],
|
||||||
|
roleIds: [{ required: true, message: '请选择角色', type: 'array', trigger: 'blur' }],
|
||||||
|
username: [{ required: true, message: '请输入用户账号', type: 'string', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
formItem: [
|
||||||
|
// { type: 'oss', key: 'imageStatus', label: '头像', file: 'avatar', refIndex: 0 },
|
||||||
|
{ type: 'oss', key: 'imageStatus', label: '头像', file: 'avatar' },
|
||||||
|
{ type: 'input', key: 'code', label: '用户编号', props: { maxlength: '20', placeholder: '请输入用户编号', clearable: true }},
|
||||||
|
{ type: 'input', key: 'username', label: '用户账号', props: { maxlength: '20', placeholder: '请输入用户账号', clearable: true }},
|
||||||
|
{ type: 'input', key: 'password', label: '登录密码', props: { type: 'password', maxlength: '20', placeholder: '请输入登录密码', clearable: true }},
|
||||||
|
{ type: 'input', key: 'realname', label: '用户姓名', props: { maxlength: '20', placeholder: '请输入用户姓名', clearable: true }},
|
||||||
|
{ type: 'select', key: 'deptId', label: '所属部门', props: { options: departmentOptions, placeholder: '请选择所属部门' }},
|
||||||
|
{ type: 'select', key: 'roleIds', label: '角色', props: { multiple: true, options: rolesOptions, placeholder: '请选择角色' }},
|
||||||
|
{ type: 'radio', key: 'status', label: '状态', options: USER_STATUS },
|
||||||
|
{ type: 'input', key: 'note', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDeptOptions = async function() {
|
||||||
|
const res = await getDeptAll()
|
||||||
|
departmentOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取角色列表
|
||||||
|
export const getRoleOptions = async function() {
|
||||||
|
const res = await getRoleAll()
|
||||||
|
rolesOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' })
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { getRoleAll } from '@/api/system/role/index'
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
const rolesOptions = ref([])
|
||||||
|
|
||||||
|
export const search = reactive({
|
||||||
|
search: [
|
||||||
|
{
|
||||||
|
label: '用户账号',
|
||||||
|
key: 'username',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入用户账号'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '用户姓名',
|
||||||
|
key: 'realname',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入用户姓名'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '用户角色',
|
||||||
|
type: 'select',
|
||||||
|
key: 'roleId',
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择用户角色',
|
||||||
|
options: rolesOptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export const fetchRolesOption = async function() {
|
||||||
|
const res = await getRoleAll()
|
||||||
|
rolesOptions.value = res.data.map((item) => { return { key: item.id, label: item.name } })
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
import { h, ref, reactive } from 'vue'
|
||||||
|
import TableImage from '@/components/DataTable/tools/Image.vue'
|
||||||
|
import TableTags from '@/components/DataTable/tools/Tags.vue'
|
||||||
|
import TableSwitch from '@/components/DataTable/tools/Switch.vue'
|
||||||
|
import TableAction from '@/components/DataTable/tools/Action.vue'
|
||||||
|
import { resetPassword, deleteUser, setUserStatus } from '@/api/system/user/index.js'
|
||||||
|
|
||||||
|
/* 注册table */
|
||||||
|
const tableRef = ref()
|
||||||
|
const searchParams = ref()
|
||||||
|
|
||||||
|
function handleSearch(params) {
|
||||||
|
searchParams.value = { ...params }
|
||||||
|
tableRef.value.reFetch({ searchParams })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取数据及操作
|
||||||
|
* @param {*} row 单行数据
|
||||||
|
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function getRowData(row, type) {
|
||||||
|
data.rowData = row
|
||||||
|
data.modalType = type
|
||||||
|
data.modalShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置状态
|
||||||
|
function setStatus(row) {
|
||||||
|
setUserStatus({ id: row.data.id, status: row.value }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
$message.success(res.msg)
|
||||||
|
} else {
|
||||||
|
$message.error(res.msg)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 重置密码
|
||||||
|
* @param {Number} id 选中数据id
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function handlePasswordReset(id) {
|
||||||
|
resetPassword({ id })
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 删除用户接口
|
||||||
|
* @param {Array} ids 用户id集合
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
function deleteData(ids) {
|
||||||
|
deleteUser(ids).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
tableRef,
|
||||||
|
searchParams,
|
||||||
|
rowData: {},
|
||||||
|
modalType: 'create',
|
||||||
|
modalShow: false,
|
||||||
|
handleSearch,
|
||||||
|
deleteData,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'selection'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户编号',
|
||||||
|
key: 'code',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '头像',
|
||||||
|
key: 'avatar',
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return h(TableImage, {
|
||||||
|
images: {
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
src: row.avatar
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户账号',
|
||||||
|
key: 'username',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户姓名',
|
||||||
|
key: 'realname',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色',
|
||||||
|
key: 'roleList',
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return h(TableTags, {
|
||||||
|
data: row.roles,
|
||||||
|
rowKey: 'name'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '部门',
|
||||||
|
key: 'deptName',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '更新时间',
|
||||||
|
key: 'updateTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
render(row) {
|
||||||
|
return h(TableSwitch, {
|
||||||
|
data: { id: row.id, status: row.status },
|
||||||
|
rowKey: 'status',
|
||||||
|
checkedValue: 1,
|
||||||
|
uncheckedValue: 2,
|
||||||
|
onChange: setStatus.bind(row)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
fixed: 'right',
|
||||||
|
render(row) {
|
||||||
|
return h(TableAction, {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '修改',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
text: true,
|
||||||
|
onClick: getRowData.bind(null, row, 'update')
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '重置密码',
|
||||||
|
type: 'popconfirm',
|
||||||
|
tip: '确定要重置为123456吗?',
|
||||||
|
props: {
|
||||||
|
onPositiveClick: handlePasswordReset.bind(null, row.id)
|
||||||
|
},
|
||||||
|
ButtonProps: {
|
||||||
|
text: true,
|
||||||
|
type: 'primary'
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'popconfirm',
|
||||||
|
auth: 'basic_list',
|
||||||
|
tip: '确定删除这条数据吗?',
|
||||||
|
props: {
|
||||||
|
onPositiveClick: deleteData.bind(null, [row.id])
|
||||||
|
},
|
||||||
|
ButtonProps: {
|
||||||
|
text: true,
|
||||||
|
type: 'primary'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
align: 'center'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default data
|
||||||
|
|
@ -1,187 +0,0 @@
|
||||||
<template>
|
|
||||||
<Modal
|
|
||||||
:options="getModalOptions"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
:on-close="handleClose"
|
|
||||||
>
|
|
||||||
<template #Context>
|
|
||||||
<n-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="form"
|
|
||||||
label-placement="left"
|
|
||||||
:rules="rules"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
>
|
|
||||||
<n-form-item label="部门编号:" path="code">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.code"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入部门编号"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="部门名称:" path="name">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.name"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入部门名称"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="所属部门:" path="pid">
|
|
||||||
<n-select
|
|
||||||
v-model:value="form.pid"
|
|
||||||
:options="getDeptList"
|
|
||||||
placeholder="请选择所属部门"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="排序号" path="sort">
|
|
||||||
<n-input-number v-model:value="form.sort" placeholder="请输入排序号" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item
|
|
||||||
label="备注:"
|
|
||||||
>
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.note"
|
|
||||||
type="textarea"
|
|
||||||
:rows="3"
|
|
||||||
:maxlength="200"
|
|
||||||
placeholder="请输入备注"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { defineComponent, computed, reactive, toRefs } from 'vue'
|
|
||||||
import Modal from '@/components/Modal/index.vue'
|
|
||||||
import { addDept, editDept } from '@/api/system/dept/index'
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'UserModal',
|
|
||||||
components: { Modal },
|
|
||||||
props: {
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {}
|
|
||||||
},
|
|
||||||
deptList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'update:visible': null,
|
|
||||||
'done': null
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const data = reactive({
|
|
||||||
form: {
|
|
||||||
avatar: '/images/user/20211011/20211011151447698.jpg',
|
|
||||||
code: '',
|
|
||||||
deptId: null,
|
|
||||||
username: '',
|
|
||||||
realname: '',
|
|
||||||
password: '',
|
|
||||||
roleIds: [],
|
|
||||||
status: 1,
|
|
||||||
note: ''
|
|
||||||
|
|
||||||
},
|
|
||||||
deptOptions: [],
|
|
||||||
rolesOptions: [],
|
|
||||||
rules: {
|
|
||||||
code: [
|
|
||||||
{ required: true, message: '请输入部门编号', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
name: [
|
|
||||||
{ required: true, message: '请输入部门名称', type: 'string', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
sort: [
|
|
||||||
{ required: true, type: 'number', message: '请输入排序号', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 获取部门选项
|
|
||||||
const getDeptList = computed(() => {
|
|
||||||
const list = props.deptList.map((item) => {
|
|
||||||
const menu = {
|
|
||||||
label: item.name,
|
|
||||||
value: item.id
|
|
||||||
}
|
|
||||||
return menu
|
|
||||||
})
|
|
||||||
return list
|
|
||||||
})
|
|
||||||
|
|
||||||
const getModalOptions = computed(() => {
|
|
||||||
const row = props.row
|
|
||||||
if (props.row.pid === 0) {
|
|
||||||
row.pid = null
|
|
||||||
}
|
|
||||||
console.log('====部门计算属性触发了====', row)
|
|
||||||
return {
|
|
||||||
title: props.row.name ? '修改部门' : '添加部门',
|
|
||||||
show: props.visible,
|
|
||||||
form: Object.assign(data.form, row),
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/* 关闭弹窗 */
|
|
||||||
const handleClose = () => {
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(data),
|
|
||||||
getDeptList,
|
|
||||||
getModalOptions,
|
|
||||||
handleClose
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 表单提交
|
|
||||||
handleConfirm() {
|
|
||||||
const type = this.row.name ? 'edit' : 'add'
|
|
||||||
this.$refs.formRef.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
if (type === 'add') {
|
|
||||||
addDept(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
} else if (type === 'edit') {
|
|
||||||
editDept(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,188 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<n-card>
|
|
||||||
<headSearch :info="info" @search="handleSearch" />
|
|
||||||
<data-table
|
|
||||||
ref="tableRef"
|
|
||||||
:columns="columns"
|
|
||||||
:request="loadDataTable"
|
|
||||||
:pagination="false"
|
|
||||||
data-type="tree"
|
|
||||||
size="large"
|
|
||||||
scroll-x="1200"
|
|
||||||
>
|
|
||||||
<template #tableTitle>
|
|
||||||
<n-button type="primary" @click="handleModal"> 新建 </n-button>
|
|
||||||
</template>
|
|
||||||
</data-table>
|
|
||||||
</n-card>
|
|
||||||
</div>
|
|
||||||
<!-- 新增、编辑弹窗 -->
|
|
||||||
<dept-modal
|
|
||||||
v-if="modalShow"
|
|
||||||
v-model:visible="modalShow"
|
|
||||||
:row="rowData"
|
|
||||||
:dept-list="deptList"
|
|
||||||
@done="handleSearch"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import headSearch from '@/components/Search/index.vue'
|
|
||||||
import dataTable from '@/components/DataTable/index.vue'
|
|
||||||
import TableAction from '@/components/DataTable/tools/Action.vue'
|
|
||||||
import {
|
|
||||||
getDeptList,
|
|
||||||
getDeptAll,
|
|
||||||
deleteDept
|
|
||||||
} from '@/api/system/dept/index.js'
|
|
||||||
import { h, unref, toRefs, ref, reactive, onMounted } from 'vue'
|
|
||||||
import DeptModal from './components/DeptModal.vue'
|
|
||||||
import info from './info.js'
|
|
||||||
import table from './table.js'
|
|
||||||
export default {
|
|
||||||
name: 'MenuPage',
|
|
||||||
components: { dataTable, DeptModal, headSearch },
|
|
||||||
setup() {
|
|
||||||
const data = reactive({
|
|
||||||
columns: [
|
|
||||||
...table.columns,
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
align: 'center',
|
|
||||||
width: 150,
|
|
||||||
fixed: 'right',
|
|
||||||
render(row) {
|
|
||||||
return h(TableAction, {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: '添加',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
onClick: add.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '修改',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
onClick: play.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
type: 'popconfirm',
|
|
||||||
auth: 'basic_list',
|
|
||||||
tip: '确定删除这条数据吗?',
|
|
||||||
props: {
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认',
|
|
||||||
onPositiveClick: deleteSingle.bind(null, row.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
align: 'center'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
info: ref(info),
|
|
||||||
modalShow: false,
|
|
||||||
rowData: {
|
|
||||||
status: 1,
|
|
||||||
type: 0,
|
|
||||||
hide: 0
|
|
||||||
},
|
|
||||||
deptList: []
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取全部菜单信息
|
|
||||||
async function getDept() {
|
|
||||||
const list = await getDeptAll()
|
|
||||||
data.deptList = list.data
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
getDept()
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* @description: 获取部门数据并做树形结构处理
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
const params = ref({})
|
|
||||||
|
|
||||||
const tableRef = ref()
|
|
||||||
|
|
||||||
function handleSearch(data) {
|
|
||||||
params.value = {
|
|
||||||
...data
|
|
||||||
}
|
|
||||||
tableRef.value.reFetch({ ...unref(params) })
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async(res) => {
|
|
||||||
const _params = {
|
|
||||||
...unref(params),
|
|
||||||
...res
|
|
||||||
}
|
|
||||||
return await getDeptList(_params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增
|
|
||||||
function handleModal() {
|
|
||||||
data.modalShow = true
|
|
||||||
data.rowData = {}
|
|
||||||
}
|
|
||||||
// 行内新增
|
|
||||||
function add(row) {
|
|
||||||
data.modalShow = true
|
|
||||||
data.rowData = {}
|
|
||||||
data.rowData.pid = row.id
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑
|
|
||||||
function play(row) {
|
|
||||||
data.rowData = row
|
|
||||||
data.modalShow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 单个删除数据
|
|
||||||
function deleteSingle(id) {
|
|
||||||
deleteData(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除方法
|
|
||||||
function deleteData(id) {
|
|
||||||
deleteDept(id)
|
|
||||||
.then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch({})
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(data),
|
|
||||||
tableRef,
|
|
||||||
loadDataTable,
|
|
||||||
handleSearch,
|
|
||||||
handleModal,
|
|
||||||
deleteSingle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
.n-button + .n-button {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
const table = {
|
|
||||||
columns: [{
|
|
||||||
title: '部门编号',
|
|
||||||
key: 'code',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '部门名称',
|
|
||||||
key: 'name',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '排序',
|
|
||||||
key: 'sort',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间',
|
|
||||||
key: 'createTime',
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '更新时间',
|
|
||||||
key: 'updateTime',
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
export default table
|
|
||||||
|
|
@ -1,238 +0,0 @@
|
||||||
<template>
|
|
||||||
<Modal
|
|
||||||
:options="getModalOptions"
|
|
||||||
:on-close="handleClose"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
>
|
|
||||||
<template #Context>
|
|
||||||
<n-form ref="formRef" :model="form" :rules="rules" require-mark-placement="left" :label-width="80" label-placement="left">
|
|
||||||
<n-grid x-gap="12" :cols="2">
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="上级菜单" path="pid">
|
|
||||||
<n-select
|
|
||||||
v-model:value="form.pid"
|
|
||||||
:options="getMenuList"
|
|
||||||
placeholder="请选择上级菜单"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="菜单类型" path="type">
|
|
||||||
<n-radio-group v-model:value="form.type" name="type">
|
|
||||||
<n-radio v-for="item in typeOptions" :key="item.key" :value="item.key">
|
|
||||||
{{ item.label }}
|
|
||||||
</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="菜单名称" path="title">
|
|
||||||
<n-input v-model:value="form.title" placeholder="请输入菜单名称" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="打开方式" path="target">
|
|
||||||
<n-radio-group v-model:value="form.target" name="target">
|
|
||||||
<n-radio v-for="item in openOptions" :key="item.key" :value="item.key">
|
|
||||||
{{ item.label }}
|
|
||||||
</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="菜单图标" path="icon">
|
|
||||||
<n-input v-model:value="form.icon" :disabled="form.type === 1" placeholder="请选择菜单图标" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="权限标识" path="permission">
|
|
||||||
<n-input v-model:value="form.permission" :disabled="form.type === 0" placeholder="请输入权限标识" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="路由地址" path="path">
|
|
||||||
<n-input v-model:value="form.path" :disabled="form.type === 1" placeholder="请输入路由地址" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="排序号" path="sort">
|
|
||||||
<n-input-number v-model:value="form.sort" placeholder="请输入排序号" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="组件路径" path="component">
|
|
||||||
<n-input v-model:value="form.component" :disabled="form.type === 1" placeholder="请输入组件路径" />
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="是否可见" path="hide">
|
|
||||||
<n-radio-group v-model:value="form.hide" name="hide">
|
|
||||||
<n-radio v-for="item in visibleOptions" :key="item.key" :value="item.key">
|
|
||||||
{{ item.label }}
|
|
||||||
</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<n-form-item label="菜单状态" path="status">
|
|
||||||
<n-radio-group v-model:value="form.status" name="status">
|
|
||||||
<n-radio v-for="item in statusOptions" :key="item.key" :value="item.key">
|
|
||||||
{{ item.label }}
|
|
||||||
</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
</n-gi>
|
|
||||||
|
|
||||||
</n-grid>
|
|
||||||
</n-form>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { defineComponent, computed, reactive, toRefs } from 'vue'
|
|
||||||
import Modal from '@/components/Modal/index.vue'
|
|
||||||
import { addMenu, editMenu } from '@/api/system/menu/index.js'
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'MenuModal',
|
|
||||||
components: { Modal },
|
|
||||||
props: {
|
|
||||||
/* 可见 */
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
/* 选中的数据 */
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {}
|
|
||||||
},
|
|
||||||
menuList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'update:visible': null,
|
|
||||||
'done': null
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const data = reactive({
|
|
||||||
form: {
|
|
||||||
title: '',
|
|
||||||
icon: '',
|
|
||||||
permission: '',
|
|
||||||
path: '',
|
|
||||||
component: '',
|
|
||||||
hide: 0,
|
|
||||||
status: 1
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
title: [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入菜单名称',
|
|
||||||
trigger: 'blur'
|
|
||||||
}],
|
|
||||||
sort: [{
|
|
||||||
required: true,
|
|
||||||
type: 'number',
|
|
||||||
message: '请输入排序号',
|
|
||||||
trigger: 'blur'
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
typeOptions: [
|
|
||||||
{ key: 0, label: '菜单' },
|
|
||||||
{ key: 1, label: '按钮' }
|
|
||||||
],
|
|
||||||
openOptions: [
|
|
||||||
{ key: '1', label: '内部' },
|
|
||||||
{ key: '2', label: '外部' }
|
|
||||||
],
|
|
||||||
visibleOptions: [
|
|
||||||
{ key: 0, label: '可见' },
|
|
||||||
{ key: 1, label: '不可见' }
|
|
||||||
],
|
|
||||||
statusOptions: [
|
|
||||||
{ key: 1, label: '在用' },
|
|
||||||
{ key: 2, label: '停用' }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const getMenuList = computed(() => {
|
|
||||||
const list = props.menuList.map((item) => {
|
|
||||||
const menu = {
|
|
||||||
label: item.title,
|
|
||||||
value: item.id
|
|
||||||
}
|
|
||||||
return menu
|
|
||||||
})
|
|
||||||
return list
|
|
||||||
})
|
|
||||||
|
|
||||||
const getModalOptions = computed(() => {
|
|
||||||
const row = props.data
|
|
||||||
if (props.data.pid === 0) {
|
|
||||||
row.pid = null
|
|
||||||
}
|
|
||||||
console.log('菜单页面计算属性触发:', row)
|
|
||||||
return {
|
|
||||||
title: props.data.title ? '修改菜单' : '添加菜单',
|
|
||||||
show: props.visible,
|
|
||||||
form: Object.assign(data.form, row),
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/* 关闭弹窗 */
|
|
||||||
const handleClose = () => {
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(data),
|
|
||||||
getMenuList,
|
|
||||||
getModalOptions,
|
|
||||||
handleClose
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 表单提交
|
|
||||||
handleConfirm() {
|
|
||||||
const type = this.data.title ? 'edit' : 'add'
|
|
||||||
this.$refs.formRef.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
if (type === 'add') {
|
|
||||||
addMenu(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
} else if (type === 'edit') {
|
|
||||||
editMenu(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$message.error('请完善必填信息')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<n-card>
|
|
||||||
<headSearch :info="info" />
|
|
||||||
<!-- <data-table
|
|
||||||
ref="tableRef"
|
|
||||||
:columns="columns"
|
|
||||||
:pagination="false"
|
|
||||||
data-type="tree"
|
|
||||||
:request="loadDataTable"
|
|
||||||
>
|
|
||||||
<template #tableTitle>
|
|
||||||
<n-button type="primary" @click="handleModal"> 添加菜单 </n-button>
|
|
||||||
</template>
|
|
||||||
</data-table> -->
|
|
||||||
</n-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<MenuModal
|
|
||||||
v-if="modalShow"
|
|
||||||
v-model:visible="modalShow"
|
|
||||||
:data="rowData"
|
|
||||||
:menu-list="menuList"
|
|
||||||
@done="handleSearch"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import headSearch from '@/components/Search/index.vue'
|
|
||||||
import dataTable from '@/components/DataTable/index.vue'
|
|
||||||
import MenuModal from './components/MenuModal.vue'
|
|
||||||
import Action from '@/components/DataTable/tools/Action.vue'
|
|
||||||
import { getMenu, getMenuList, deleteMenu } from '@/api/system/menu/index.js'
|
|
||||||
import { h, ref, unref, reactive, toRefs, onMounted } from 'vue'
|
|
||||||
import info from './info.js'
|
|
||||||
import table from './table.js'
|
|
||||||
export default {
|
|
||||||
name: 'MenuPage',
|
|
||||||
components: { dataTable, MenuModal, headSearch },
|
|
||||||
setup() {
|
|
||||||
const data = reactive({
|
|
||||||
columns: [
|
|
||||||
...table.columns,
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
align: 'center',
|
|
||||||
width: 150,
|
|
||||||
fixed: 'right',
|
|
||||||
render(row) {
|
|
||||||
return h(Action, {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: '添加',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
onClick: add.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '修改',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
onClick: play.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
type: 'popconfirm',
|
|
||||||
auth: 'basic_list',
|
|
||||||
tip: '确定删除这条数据吗?',
|
|
||||||
props: {
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认',
|
|
||||||
onPositiveClick: deleteSingle.bind(null, row.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
align: 'center'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
info: ref(info),
|
|
||||||
modalShow: false,
|
|
||||||
menuList: [],
|
|
||||||
rowData: {
|
|
||||||
status: 1,
|
|
||||||
type: 0,
|
|
||||||
hide: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取全部菜单信息
|
|
||||||
async function getMenuAll() {
|
|
||||||
const list = await getMenu()
|
|
||||||
data.menuList = list.data
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
getMenuAll()
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 获取菜单数据
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
const params = ref({})
|
|
||||||
const tableRef = ref()
|
|
||||||
|
|
||||||
function handleSearch(data) {
|
|
||||||
params.value = {
|
|
||||||
...data
|
|
||||||
}
|
|
||||||
tableRef.value.reFetch({ ...unref(params) })
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async(res) => {
|
|
||||||
const _params = {
|
|
||||||
...unref(params),
|
|
||||||
...res
|
|
||||||
}
|
|
||||||
return await getMenuList(_params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开新增弹框
|
|
||||||
function handleModal() {
|
|
||||||
data.modalShow = true
|
|
||||||
data.rowData = {}
|
|
||||||
}
|
|
||||||
// 行内新增
|
|
||||||
function add(row) {
|
|
||||||
data.modalShow = true
|
|
||||||
data.rowData = {}
|
|
||||||
data.rowData.pid = row.id
|
|
||||||
}
|
|
||||||
// 编辑
|
|
||||||
function play(row) {
|
|
||||||
data.rowData = row
|
|
||||||
data.modalShow = true
|
|
||||||
}
|
|
||||||
// 单个删除数据
|
|
||||||
function deleteSingle(id) {
|
|
||||||
deleteData(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除方法
|
|
||||||
function deleteData(id) {
|
|
||||||
deleteMenu(id)
|
|
||||||
.then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch({})
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(data),
|
|
||||||
tableRef,
|
|
||||||
loadDataTable,
|
|
||||||
handleSearch,
|
|
||||||
handleModal,
|
|
||||||
deleteSingle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
label: '菜单名称',
|
|
||||||
type: 'area',
|
|
||||||
key: 'name',
|
|
||||||
refIndex: 0,
|
|
||||||
props: {
|
|
||||||
placeholder: '请输入菜单名称',
|
|
||||||
options: [{ label: 1, value: 1, children: [{ label: '1-1', value: '1-1' }] }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export default data
|
|
||||||
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
import { h } from 'vue'
|
|
||||||
import TableTags from '@/components/DataTable/tools/Tags.vue'
|
|
||||||
const table = {
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: '菜单标题',
|
|
||||||
key: 'title',
|
|
||||||
align: 'center',
|
|
||||||
width: 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '菜单类型',
|
|
||||||
key: 'type',
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render(row) {
|
|
||||||
return h(TableTags, {
|
|
||||||
data: row.type,
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
key: 0,
|
|
||||||
label: '菜单'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 1,
|
|
||||||
label: '节点'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '路由地址',
|
|
||||||
key: 'path',
|
|
||||||
align: 'center',
|
|
||||||
width: 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '组件路径',
|
|
||||||
key: 'component',
|
|
||||||
align: 'center',
|
|
||||||
width: 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
key: 'status',
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render(row) {
|
|
||||||
return h(TableTags, {
|
|
||||||
data: row.status,
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
key: 1,
|
|
||||||
label: '在用'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 2,
|
|
||||||
label: '停用'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '排序',
|
|
||||||
key: 'sort',
|
|
||||||
align: 'center',
|
|
||||||
width: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '是否可见',
|
|
||||||
key: 'hide',
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render(row) {
|
|
||||||
return h(TableTags, {
|
|
||||||
data: row.hide,
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
key: 1,
|
|
||||||
label: '可见'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 2,
|
|
||||||
label: '不可见'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间',
|
|
||||||
key: 'createTime',
|
|
||||||
align: 'center',
|
|
||||||
width: 160
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default table
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
<template>
|
|
||||||
<Modal
|
|
||||||
:options="getModalOptions"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
:on-close="handleClose"
|
|
||||||
>
|
|
||||||
<template #Context>
|
|
||||||
<n-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="form"
|
|
||||||
label-placement="left"
|
|
||||||
:rules="rules"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
>
|
|
||||||
<n-form-item label="角色编号:" path="code">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.code"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入角色编号"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="角色名称:" path="name">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.name"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入角色名称"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="状态" path="status">
|
|
||||||
<n-radio-group
|
|
||||||
v-model:value="form.status"
|
|
||||||
>
|
|
||||||
<n-radio :value="1">正常</n-radio>
|
|
||||||
<n-radio :value="2">禁用</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item
|
|
||||||
label="备注:"
|
|
||||||
>
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.note"
|
|
||||||
type="textarea"
|
|
||||||
:rows="3"
|
|
||||||
:maxlength="200"
|
|
||||||
placeholder="请输入备注"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { defineComponent, computed, reactive, toRefs } from 'vue'
|
|
||||||
import Modal from '@/components/Modal/index.vue'
|
|
||||||
import { addRole, editRole } from '@/api/system/role/index'
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'RoleModal',
|
|
||||||
components: { Modal },
|
|
||||||
props: {
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'update:visible': null,
|
|
||||||
'done': null
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const data = reactive({
|
|
||||||
form: {
|
|
||||||
code: '',
|
|
||||||
name: '',
|
|
||||||
status: 1,
|
|
||||||
note: ''
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
code: [
|
|
||||||
{ required: true, message: '请输入角色编号', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
name: [
|
|
||||||
{ required: true, message: '请输入角色名称', type: 'string', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
status: [
|
|
||||||
{ required: true, message: '请选择状态', type: 'number', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const getModalOptions = computed(() => {
|
|
||||||
return {
|
|
||||||
title: Object.keys(props.row).length === 0 ? '添加角色' : '编辑角色',
|
|
||||||
show: props.visible,
|
|
||||||
form: Object.assign(data.form, props.row),
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/* 关闭弹窗 */
|
|
||||||
const handleClose = () => {
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
getModalOptions,
|
|
||||||
handleClose,
|
|
||||||
...toRefs(data),
|
|
||||||
rules: reactive({
|
|
||||||
code: [
|
|
||||||
{ required: true, message: '请输入角色编号', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
name: [
|
|
||||||
{ required: true, message: '请输入角色名称', type: 'string', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
status: [
|
|
||||||
{ required: true, message: '请选择状态', type: 'number', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 表单提交
|
|
||||||
handleConfirm() {
|
|
||||||
const type = Object.keys(this.row).length === 0 ? 'add' : 'edit'
|
|
||||||
this.$refs.formRef.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
if (type === 'add') {
|
|
||||||
addRole(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
} else if (type === 'edit') {
|
|
||||||
editRole(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,239 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<n-card>
|
|
||||||
<headSearch :info="info" @search="handleSearch" />
|
|
||||||
<data-table
|
|
||||||
ref="tableRef"
|
|
||||||
:columns="columns"
|
|
||||||
:row-key="(row) => row.id"
|
|
||||||
:request="loadDataTable"
|
|
||||||
size="large"
|
|
||||||
scroll-x="1200"
|
|
||||||
@update:checked-row-keys="handleCheck"
|
|
||||||
>
|
|
||||||
<template #tableTitle>
|
|
||||||
<n-button type="primary" @click="handleModal"> 新建 </n-button>
|
|
||||||
<n-popconfirm
|
|
||||||
negative-text="取消"
|
|
||||||
positive-text="确认"
|
|
||||||
@positive-click="deleteComplex"
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<n-button type="primary">删除</n-button>
|
|
||||||
</template>
|
|
||||||
确定删除选中的数据吗?
|
|
||||||
</n-popconfirm>
|
|
||||||
</template>
|
|
||||||
</data-table>
|
|
||||||
</n-card>
|
|
||||||
</div>
|
|
||||||
<!-- 新增、编辑弹窗 -->
|
|
||||||
<role-modal
|
|
||||||
v-if="modalShow"
|
|
||||||
v-model:visible="modalShow"
|
|
||||||
:row="rowData"
|
|
||||||
@done="handleSearch"
|
|
||||||
/>
|
|
||||||
<!-- 分配权限 -->
|
|
||||||
<config-modal
|
|
||||||
v-if="configModalShow"
|
|
||||||
v-model:visible="configModalShow"
|
|
||||||
:row="rowData"
|
|
||||||
@done="handleSearch"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import headSearch from '@/components/Search/index.vue'
|
|
||||||
import dataTable from '@/components/DataTable/index.vue'
|
|
||||||
import TableAction from '@/components/DataTable/tools/Action.vue'
|
|
||||||
import TableSwitch from '@/components/DataTable/tools/Switch.vue'
|
|
||||||
import {
|
|
||||||
getRoleList,
|
|
||||||
deleteRole,
|
|
||||||
setRoleStatus
|
|
||||||
} from '@/api/system/role/index'
|
|
||||||
import { h, ref, unref, toRefs, reactive } from 'vue'
|
|
||||||
import table from './table.js'
|
|
||||||
import info from './info.js'
|
|
||||||
import RoleModal from './components/RoleModal.vue'
|
|
||||||
import ConfigModal from './components/ConfigModal.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'MenuPage',
|
|
||||||
components: { headSearch, dataTable, RoleModal, ConfigModal },
|
|
||||||
setup() {
|
|
||||||
const data = reactive({
|
|
||||||
columns: [
|
|
||||||
...table.columns,
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
key: 'status',
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render(row) {
|
|
||||||
return h(TableSwitch, {
|
|
||||||
data: { id: row.id, status: row.status },
|
|
||||||
rowKey: 'status',
|
|
||||||
checkedValue: 1,
|
|
||||||
uncheckedValue: 2,
|
|
||||||
onChange: setStatus.bind(row)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
align: 'center',
|
|
||||||
width: 150,
|
|
||||||
fixed: 'right',
|
|
||||||
render(row) {
|
|
||||||
return h(TableAction, {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: '修改',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
onClick: play.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '分配权限',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
ghost: true,
|
|
||||||
onClick: configure.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
type: 'popconfirm',
|
|
||||||
auth: 'basic_list',
|
|
||||||
tip: '确定删除这条数据吗?',
|
|
||||||
props: {
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认',
|
|
||||||
onPositiveClick: deleteSingle.bind(null, row.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
align: 'center'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
info: ref(info),
|
|
||||||
modalShow: false,
|
|
||||||
configModalShow: false,
|
|
||||||
rowData: {}
|
|
||||||
})
|
|
||||||
// 编辑
|
|
||||||
function play(row) {
|
|
||||||
data.rowData = row
|
|
||||||
data.modalShow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置权限
|
|
||||||
function configure(row) {
|
|
||||||
data.rowData = row
|
|
||||||
data.configModalShow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = ref({})
|
|
||||||
const tableRef = ref()
|
|
||||||
function handleSearch(data) {
|
|
||||||
params.value = {
|
|
||||||
...data
|
|
||||||
}
|
|
||||||
tableRef.value.reFetch({ ...unref(params) })
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async(res) => {
|
|
||||||
const _params = {
|
|
||||||
...unref(params),
|
|
||||||
...res
|
|
||||||
}
|
|
||||||
return await getRoleList(_params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增用户
|
|
||||||
function handleModal() {
|
|
||||||
data.rowData = {}
|
|
||||||
data.modalShow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择表格数据
|
|
||||||
const selectedIds = ref([])
|
|
||||||
function handleCheck(rowKeys) {
|
|
||||||
selectedIds.value = rowKeys
|
|
||||||
}
|
|
||||||
// 批量删除
|
|
||||||
function deleteComplex() {
|
|
||||||
if (selectedIds.value.length) {
|
|
||||||
deleteData(selectedIds.value)
|
|
||||||
} else {
|
|
||||||
$message.warning('请至少选中一条数据')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 单个删除数据
|
|
||||||
function deleteSingle(id) {
|
|
||||||
deleteData([id])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除接口
|
|
||||||
function deleteData(data) {
|
|
||||||
deleteRole(data)
|
|
||||||
.then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch()
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置状态
|
|
||||||
function setStatus(row) {
|
|
||||||
console.log(row)
|
|
||||||
setRoleStatus({ id: row.data.id, status: row.value })
|
|
||||||
.then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch()
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(data),
|
|
||||||
tableRef,
|
|
||||||
loadDataTable,
|
|
||||||
handleSearch,
|
|
||||||
handleModal,
|
|
||||||
handleCheck,
|
|
||||||
selectedIds,
|
|
||||||
deleteSingle,
|
|
||||||
deleteComplex,
|
|
||||||
deleteData,
|
|
||||||
setStatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
.n-button + .n-button {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
const data = {
|
|
||||||
columns: [
|
|
||||||
{ type: 'selection' },
|
|
||||||
{
|
|
||||||
title: '角色编号',
|
|
||||||
key: 'code',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '角色名称',
|
|
||||||
key: 'name',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间',
|
|
||||||
key: 'createTime',
|
|
||||||
align: 'center',
|
|
||||||
Minwidth: 160
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '更新时间',
|
|
||||||
key: 'updateTime',
|
|
||||||
align: 'center',
|
|
||||||
Minwidth: 160
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default data
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
<template>
|
|
||||||
<Modal
|
|
||||||
:options="getModalOptions"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
:on-close="handleClose"
|
|
||||||
>
|
|
||||||
<template #Context>
|
|
||||||
<n-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="form"
|
|
||||||
label-placement="left"
|
|
||||||
:rules="rules"
|
|
||||||
:on-positive-click="handleConfirm"
|
|
||||||
:on-negative-click="handleClose"
|
|
||||||
>
|
|
||||||
<n-form-item
|
|
||||||
label="头像:"
|
|
||||||
path="avatar"
|
|
||||||
>
|
|
||||||
<uploadImage
|
|
||||||
:options="{
|
|
||||||
max:1,
|
|
||||||
action: '/upload/uploadImage/demo',
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="用户编号:" path="code">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.code"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入用户编号"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="用户账号:" path="username">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.username"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入用户账号"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item
|
|
||||||
label="登录密码:"
|
|
||||||
path="password"
|
|
||||||
>
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.password"
|
|
||||||
type="password"
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入登录密码"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="用户姓名:" path="realname">
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.realname"
|
|
||||||
clearable
|
|
||||||
:maxlength="20"
|
|
||||||
placeholder="请输入用户姓名"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="所属部门:" path="deptId">
|
|
||||||
<n-select
|
|
||||||
v-model:value="form.deptId"
|
|
||||||
:options="deptOptions"
|
|
||||||
placeholder="请选择所属部门"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="角色:" path="roleIds">
|
|
||||||
<n-select
|
|
||||||
v-model:value="form.roleIds"
|
|
||||||
clearable
|
|
||||||
:multiple="true"
|
|
||||||
:options="rolesOptions"
|
|
||||||
placeholder="请选择角色"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="状态" path="status">
|
|
||||||
<n-radio-group
|
|
||||||
v-model:value="form.status"
|
|
||||||
>
|
|
||||||
<n-radio :value="1">正常</n-radio>
|
|
||||||
<n-radio :value="2">禁用</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item
|
|
||||||
label="备注:"
|
|
||||||
>
|
|
||||||
<n-input
|
|
||||||
v-model:value="form.note"
|
|
||||||
type="textarea"
|
|
||||||
:rows="3"
|
|
||||||
:maxlength="200"
|
|
||||||
placeholder="请输入备注"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { defineComponent, computed, onMounted, reactive, toRefs } from 'vue'
|
|
||||||
import Modal from '@/components/Modal/index.vue'
|
|
||||||
import uploadImage from '@/components/ImgUpload/index.vue'
|
|
||||||
import { getDeptAll } from '@/api/system/dept/index'
|
|
||||||
import { getRoleAll } from '@/api/system/role/index'
|
|
||||||
import { addUser, editUser } from '@/api/system/user/index'
|
|
||||||
import { dataToSelect } from '@/utils/handleData.js'
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'UserModal',
|
|
||||||
components: { Modal, uploadImage },
|
|
||||||
props: {
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
'update:visible': null,
|
|
||||||
'done': null
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const data = reactive({
|
|
||||||
form: {
|
|
||||||
avatar: '/images/user/20211011/20211011151447698.jpg',
|
|
||||||
code: '',
|
|
||||||
deptId: null,
|
|
||||||
username: '',
|
|
||||||
realname: '',
|
|
||||||
password: '',
|
|
||||||
roleIds: [],
|
|
||||||
status: 1,
|
|
||||||
note: ''
|
|
||||||
|
|
||||||
},
|
|
||||||
deptOptions: [],
|
|
||||||
rolesOptions: [],
|
|
||||||
rules: {
|
|
||||||
avatar: [
|
|
||||||
{ required: true, message: '请选择头像', type: 'string', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
code: [
|
|
||||||
{ required: true, message: '请输入编号', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
realname: [
|
|
||||||
{ required: true, message: '请输入用户姓名', type: 'string', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
deptId: [
|
|
||||||
{ required: true, message: '请选择部门', type: 'number', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
status: [
|
|
||||||
{ required: true, message: '请选择状态', type: 'number', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
roleIds: [
|
|
||||||
{ required: true, message: '请选择角色', type: 'array', trigger: 'blur' }
|
|
||||||
],
|
|
||||||
username: [
|
|
||||||
{ required: true, message: '请输入用户账号', type: 'string', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const getModalOptions = computed(() => {
|
|
||||||
return {
|
|
||||||
title: Object.keys(props.row).length === 0 ? '添加用户' : '编辑用户',
|
|
||||||
show: props.visible,
|
|
||||||
form: Object.assign(data.form, props.row),
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/* 关闭弹窗 */
|
|
||||||
const handleClose = () => {
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取部门列表
|
|
||||||
async function getDeptOptions() {
|
|
||||||
const res = await getDeptAll()
|
|
||||||
data.deptOptions = dataToSelect(res.data, { label: 'name', value: 'id' })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取角色列表
|
|
||||||
async function getRoleOptions() {
|
|
||||||
const res = await getRoleAll()
|
|
||||||
data.rolesOptions = dataToSelect(res.data, { label: 'name', value: 'id' })
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getDeptOptions()
|
|
||||||
getRoleOptions()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 上传文件
|
|
||||||
const handleUpload = ({ file }) => {
|
|
||||||
console.log(file)
|
|
||||||
// data.form.avatar = file.url
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(data),
|
|
||||||
getModalOptions,
|
|
||||||
handleClose,
|
|
||||||
handleUpload
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 表单提交
|
|
||||||
handleConfirm() {
|
|
||||||
const type = Object.keys(this.row).length === 0 ? 'add' : 'edit'
|
|
||||||
this.$refs.formRef.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
if (type === 'add') {
|
|
||||||
addUser(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
} else if (type === 'edit') {
|
|
||||||
editUser(this.form).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
this.handleClose()
|
|
||||||
this.$emit('done')
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$message.error('请完善必填信息')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,233 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<n-card>
|
|
||||||
<headSearch :info="info" @search="handleSearch" />
|
|
||||||
<data-table
|
|
||||||
ref="tableRef"
|
|
||||||
:columns="columns"
|
|
||||||
:row-key="(row) => row.id"
|
|
||||||
:request="loadDataTable"
|
|
||||||
size="large"
|
|
||||||
@update:checked-row-keys="handleCheck"
|
|
||||||
>
|
|
||||||
<template #tableTitle>
|
|
||||||
<n-button type="primary" @click="handleModal"> 新建 </n-button>
|
|
||||||
<n-popconfirm
|
|
||||||
negative-text="取消"
|
|
||||||
positive-text="确认"
|
|
||||||
@positive-click="deleteComplex"
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<n-button type="primary"> 删除 </n-button>
|
|
||||||
</template>
|
|
||||||
确认要删除选中数据吗?
|
|
||||||
</n-popconfirm>
|
|
||||||
</template>
|
|
||||||
</data-table>
|
|
||||||
</n-card>
|
|
||||||
</div>
|
|
||||||
<!-- 新增、编辑弹窗 -->
|
|
||||||
<user-modal
|
|
||||||
v-if="modalShow"
|
|
||||||
v-model:visible="modalShow"
|
|
||||||
:row="rowData"
|
|
||||||
@done="handleSearch"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import headSearch from '@/components/Search/index.vue'
|
|
||||||
import dataTable from '@/components/DataTable/index.vue'
|
|
||||||
import TableSwitch from '@/components/DataTable/tools/Switch.vue'
|
|
||||||
import TableAction from '@/components/DataTable/tools/Action.vue'
|
|
||||||
import { getUserList, resetPassword, deleteUser, setUserStatus } from '@/api/system/user/index.js'
|
|
||||||
import { h, unref, ref, toRefs, reactive } from 'vue'
|
|
||||||
import UserModal from './components/UserModal.vue'
|
|
||||||
import info from './info.js'
|
|
||||||
import table from './table.js'
|
|
||||||
export default {
|
|
||||||
name: 'MenuPage',
|
|
||||||
components: { dataTable, UserModal, headSearch },
|
|
||||||
setup() {
|
|
||||||
const data = reactive({
|
|
||||||
columns: [
|
|
||||||
...table.columns,
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
key: 'status',
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render(row) {
|
|
||||||
return h(TableSwitch, {
|
|
||||||
data: { id: row.id, status: row.status },
|
|
||||||
rowKey: 'status',
|
|
||||||
checkedValue: 1,
|
|
||||||
uncheckedValue: 2,
|
|
||||||
onChange: setStatus.bind(row)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
align: 'center',
|
|
||||||
width: 150,
|
|
||||||
fixed: 'right',
|
|
||||||
render(row) {
|
|
||||||
return h(TableAction, {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: '修改',
|
|
||||||
type: 'button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
onClick: play.bind(null, row)
|
|
||||||
},
|
|
||||||
auth: 'basic_list'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '重置密码',
|
|
||||||
type: 'popconfirm',
|
|
||||||
auth: 'basic_list',
|
|
||||||
tip: '确定要重置为123456吗?',
|
|
||||||
props: {
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认',
|
|
||||||
onPositiveClick: resetPsw.bind(null, row.id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
type: 'popconfirm',
|
|
||||||
auth: 'basic_list',
|
|
||||||
tip: '确定删除这条数据吗?',
|
|
||||||
props: {
|
|
||||||
negativeText: '取消',
|
|
||||||
positiveText: '确认',
|
|
||||||
onPositiveClick: deleteSingle.bind(null, row.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
align: 'center'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
info: ref(info),
|
|
||||||
modalShow: false,
|
|
||||||
rowData: {}
|
|
||||||
})
|
|
||||||
// 打开编辑弹窗
|
|
||||||
function play(row) {
|
|
||||||
data.rowData = row
|
|
||||||
data.modalShow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = ref({})
|
|
||||||
|
|
||||||
const tableRef = ref()
|
|
||||||
|
|
||||||
function handleSearch(data) {
|
|
||||||
params.value = {
|
|
||||||
...data
|
|
||||||
}
|
|
||||||
tableRef.value.reFetch({ ...unref(params) })
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async(res) => {
|
|
||||||
const _params = {
|
|
||||||
...unref(params),
|
|
||||||
...res
|
|
||||||
}
|
|
||||||
return await getUserList(_params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增
|
|
||||||
function handleModal() {
|
|
||||||
data.rowData = {}
|
|
||||||
data.modalShow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择表格数据
|
|
||||||
const selectedIds = ref([])
|
|
||||||
function handleCheck(rowKeys) {
|
|
||||||
selectedIds.value = rowKeys
|
|
||||||
}
|
|
||||||
// 批量删除
|
|
||||||
function deleteComplex() {
|
|
||||||
if (selectedIds.value.length) {
|
|
||||||
deleteData(selectedIds.value)
|
|
||||||
} else {
|
|
||||||
$message.warning('请至少选中一条数据')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 单个删除数据
|
|
||||||
function deleteSingle(id) {
|
|
||||||
deleteData([id])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除用户接口
|
|
||||||
function deleteData(data) {
|
|
||||||
deleteUser(data).then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch()
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置密码
|
|
||||||
function resetPsw(id) {
|
|
||||||
resetPassword({ id }).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch()
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置状态
|
|
||||||
function setStatus(row) {
|
|
||||||
setUserStatus({ id: row.data.id, status: row.value }).then(res => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
handleSearch()
|
|
||||||
$message.success(res.msg)
|
|
||||||
} else {
|
|
||||||
$message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
loadDataTable,
|
|
||||||
handleModal,
|
|
||||||
...toRefs(data),
|
|
||||||
tableRef,
|
|
||||||
handleSearch,
|
|
||||||
selectedIds,
|
|
||||||
deleteComplex,
|
|
||||||
handleCheck,
|
|
||||||
deleteData,
|
|
||||||
resetPsw,
|
|
||||||
setStatus
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped lang='scss'>
|
|
||||||
.n-button + .n-button {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import { getRoleAll } from '@/api/system/role/index'
|
|
||||||
import { dataToSelect } from '@/utils/handleData.js'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
const rolesOptions = ref([])
|
|
||||||
const getRolesOption = async function() {
|
|
||||||
const res = await getRoleAll()
|
|
||||||
rolesOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' })
|
|
||||||
}
|
|
||||||
// getRolesOption()
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
label: '用户账号',
|
|
||||||
key: 'username',
|
|
||||||
props: {
|
|
||||||
placeholder: '请输入用户账号'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '用户姓名',
|
|
||||||
key: 'realname',
|
|
||||||
props: {
|
|
||||||
placeholder: '请输入用户姓名'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '用户角色',
|
|
||||||
type: 'select',
|
|
||||||
key: 'roleId',
|
|
||||||
props: {
|
|
||||||
placeholder: '请选择用户角色',
|
|
||||||
options: rolesOptions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// {
|
|
||||||
// label: '角色类型',
|
|
||||||
// type: 'date',
|
|
||||||
// key: 'date',
|
|
||||||
// props: {
|
|
||||||
// type: 'date'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
]
|
|
||||||
|
|
||||||
export default data
|
|
||||||
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import { h } from 'vue'
|
|
||||||
import TableImage from '@/components/DataTable/tools/Image.vue'
|
|
||||||
import TableTags from '@/components/DataTable/tools/Tags.vue'
|
|
||||||
|
|
||||||
const table = {
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
type: 'selection'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用户编号',
|
|
||||||
key: 'code',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '头像',
|
|
||||||
key: 'avatar',
|
|
||||||
align: 'center',
|
|
||||||
render(row) {
|
|
||||||
return h(TableImage, {
|
|
||||||
images: {
|
|
||||||
width: 36,
|
|
||||||
height: 36,
|
|
||||||
src: row.avatar
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用户账号',
|
|
||||||
key: 'username',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用户姓名',
|
|
||||||
key: 'realname',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '角色',
|
|
||||||
key: 'roleList',
|
|
||||||
align: 'center',
|
|
||||||
render(row) {
|
|
||||||
return h(TableTags, {
|
|
||||||
data: row.roleList,
|
|
||||||
rowKey: 'name'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '部门',
|
|
||||||
key: 'deptName',
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间',
|
|
||||||
key: 'createTime',
|
|
||||||
align: 'center',
|
|
||||||
width: 160
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '更新时间',
|
|
||||||
key: 'updateTime',
|
|
||||||
align: 'center',
|
|
||||||
width: 160
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
export default table
|
|
||||||
Loading…
Reference in New Issue