Browse Source

Merge branch 'develop' of gitadmin/tuoheng_pilot_web into release

pull/114/head
zhangtao 1 year ago
parent
commit
421afaaaa3
39 changed files with 1372 additions and 931 deletions
  1. +4
    -1
      .env
  2. +3
    -2
      .env.localhost
  3. +13
    -0
      src/api/auth/index.js
  4. +71
    -2
      src/api/system/menu/index.js
  5. +25
    -3
      src/api/system/role/index.js
  6. +11
    -3
      src/components/DataTable/tools/Action.vue
  7. +3
    -4
      src/layout/components/Header/index.vue
  8. +19
    -4
      src/layout/components/Menu/index.vue
  9. +6
    -5
      src/router/guard/permission-guard.js
  10. +55
    -7
      src/store/modules/permission.js
  11. +13
    -0
      src/utils/dictionary.js
  12. +10
    -1
      src/views/system-manage/department-manage/tools/table.js
  13. +60
    -40
      src/views/system-manage/menu-manage/components/MenuModal.vue
  14. +30
    -23
      src/views/system-manage/menu-manage/index.vue
  15. +32
    -35
      src/views/system-manage/menu-manage/tools/form.js
  16. +2
    -1
      src/views/system-manage/menu-manage/tools/search.js
  17. +86
    -38
      src/views/system-manage/menu-manage/tools/table.js
  18. +180
    -0
      src/views/system-manage/mpmenu-manage/components/MenuModal.vue
  19. +72
    -0
      src/views/system-manage/mpmenu-manage/index.vue
  20. +47
    -0
      src/views/system-manage/mpmenu-manage/tools/form.js
  21. +14
    -0
      src/views/system-manage/mpmenu-manage/tools/search.js
  22. +186
    -0
      src/views/system-manage/mpmenu-manage/tools/table.js
  23. +204
    -0
      src/views/system-manage/role-manage/components/AuthModal.vue
  24. +71
    -47
      src/views/system-manage/role-manage/components/RoleModal.vue
  25. +15
    -41
      src/views/system-manage/role-manage/index.vue
  26. +15
    -18
      src/views/system-manage/role-manage/tools/form.js
  27. +2
    -1
      src/views/system-manage/role-manage/tools/search.js
  28. +61
    -52
      src/views/system-manage/role-manage/tools/table.js
  29. +0
    -168
      src/views/system-manage/user-manage/components/UserModal.vue
  30. +0
    -105
      src/views/system-manage/user-manage/index.vue
  31. +0
    -52
      src/views/system-manage/user-manage/tools/form.js
  32. +0
    -36
      src/views/system-manage/user-manage/tools/search.js
  33. +0
    -210
      src/views/system-manage/user-manage/tools/table.js
  34. +5
    -2
      src/views/task-manage/index.vue
  35. +6
    -10
      src/views/task-manage/tools/table.js
  36. +2
    -1
      src/views/user-manage/components/UserModal.vue
  37. +8
    -4
      src/views/user-manage/index.vue
  38. +16
    -5
      src/views/user-manage/tools/form.js
  39. +25
    -10
      src/views/user-manage/tools/table.js

+ 4
- 1
.env View File

@@ -6,4 +6,7 @@ VITE_PORT = 3050

VITE_SERVER = "/pilot/admin"

VITE_PLATFORM = "tuoheng-pilot-admin"
VITE_PLATFORM = "tuoheng-pilot-admin"

VITE_CLIENT_ID = 'tuoheng-pilot-admin'
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='

+ 3
- 2
.env.localhost View File

@@ -13,6 +13,7 @@ VITE_APP_GLOB_BASE_API = '/api-local'
# mock base api
VITE_APP_GLOB_BASE_API_MOCK = '/api-mock'

VITE_AUTHORITY = 'https://login-test.t-aaron.com'
VITE_AUTHORITY = 'http://192.168.11.11:8090'
VITE_CLIENT_ID = 'tuoheng-pilot-admin'
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='
VITE_REDIRECT_URI = 'http://192.168.12.6:3050/login'

+ 13
- 0
src/api/auth/index.js View File

@@ -21,3 +21,16 @@ export function getMenu() {
method: 'GET'
})
}

/**
* @description: 获取menu和permission
* @param {String} roleId 角色Id
* @return {*}
*/
export const fetchPermission = (params) => {
return request({
url: `/permission/getRolePermission`,
method: 'GET',
params
})
}

+ 71
- 2
src/api/system/menu/index.js View File

@@ -27,7 +27,7 @@ export function getMenu(params) {
* 添加菜单
* params
*/
export function addMenu(data) {
export function menuCreate(data) {
return request({
url: '/menu/add',
method: 'POST',
@@ -39,7 +39,30 @@ export function addMenu(data) {
* 编辑菜单
* params
*/
export function editMenu(data) {
export function menuUpdate(data) {
return request({
url: '/menu/edit',
method: 'PUT',
data
})
}
/**
* 添加按钮
* params
*/
export function permissionCreate(data) {
return request({
url: '/menu/add',
method: 'POST',
data
})
}

/**
* 编辑按钮
* params
*/
export function permissionUpdate(data) {
return request({
url: '/menu/edit',
method: 'PUT',
@@ -57,3 +80,49 @@ export function deleteMenu(id) {
method: 'DELETE'
})
}

/**
* 添加按钮
* params
*/
export function mpMenuCreate(data) {
return request({
url: '/menu/add',
method: 'POST',
data
})
}

/**
* 编辑菜单
* params
*/
export function mpMenuUpdate(data) {
return request({
url: '/menu/edit',
method: 'PUT',
data
})
}

/**
* 删除菜单
* params
*/
export function deleteMpMenu(id) {
return request({
url: `/menu/delete/${id}`,
method: 'DELETE'
})
}

/**
* 删除按钮
* params
*/
export function deletePermission(ids) {
return request({
url: `/menu/delete/${ids}`,
method: 'DELETE'
})
}

+ 25
- 3
src/api/system/role/index.js View File

@@ -27,7 +27,7 @@ export function getRoleAll(params) {
* 添加角色
* params
*/
export function addRole(data) {
export function roleCreate(data) {
return request({
url: '/role/add',
method: 'POST',
@@ -39,7 +39,7 @@ export function addRole(data) {
* 编辑角色
* params
*/
export function editRole(data) {
export function roleUpdate(data) {
return request({
url: '/role/edit',
method: 'PUT',
@@ -63,12 +63,34 @@ export function setRoleStatus(data) {
* 删除角色
* params
*/
export function deleteRole(data) {
export function roleDelete(data) {
return request({
url: `/role/delete/${data}`,
method: 'DELETE'
})
}
/**
* 获取角色菜单
* params
*/
export function getRoleMenu(params) {
return request({
url: `/role/getMenuList`,
method: 'GET',
params
})
}
/**
* 保存角色选中的菜单
* params
*/
export function saveRoleMenu(data) {
return request({
url: `/role/savePermission`,
method: 'POST',
data
})
}

/**
* 获取角色权限数据

+ 11
- 3
src/components/DataTable/tools/Action.vue View File

@@ -21,6 +21,7 @@

<script>
import { defineComponent, computed, toRaw, reactive } from 'vue'
import { usePermissionStore } from '@/store/modules/permission'
export default defineComponent({
name: 'TableAction',
props: {
@@ -42,17 +43,24 @@ export default defineComponent({
}
},
setup(props, { emit }) {
const permissionStore = usePermissionStore()
const data = reactive({
permissionList: [
'basic_list'
]
permissionList: permissionStore.accessPermissionCodes
})

const getPermissionLabel = (code) => {
return permissionStore.accessPermissions.find((item) => {
return item.code === code
})?.name || ''
}

const getActions = computed(() => {
return (toRaw(props.actions) || [])
.filter((action) => {
if (!Object.keys(action).includes('show')) {
action.show = Object.keys(action).includes('hidden') ? !action.hidden : true
}
action.label = action.label || getPermissionLabel(action.auth)
return (data.permissionList.includes(action.auth) || action.auth === '') && action.show
})
})

+ 3
- 4
src/layout/components/Header/index.vue View File

@@ -5,17 +5,16 @@
<span class="sp">欢迎回来, {{ getUserInfo.realname }}</span>
</div>

<n-dropdown v-if="getUserInfo.hasLogin" trigger="hover" :options="options" @select="handleSelect">
<n-dropdown trigger="hover" :options="options" @select="handleSelect">
<div class="user_msg">
<!-- <n-image
<n-image
class="user_avatar"
:src="getUserInfo.avatar"
preview-disabled
/> -->
/>
<span class="user_name">{{ getUserInfo.realname }}</span>
</div>
</n-dropdown>
<div v-if="!getUserInfo.hasLogin" class="header__login" @click="handleLogin">登录</div>
</n-layout-header>
</template>


+ 19
- 4
src/layout/components/Menu/index.vue View File

@@ -1,15 +1,17 @@
<template>
<n-menu
:mode="menuMode"
:value="(currentRoute.title && currentRoute.meta.activeMenu) || currentRoute.title"
:value="currentRoute.title ?? currentRoute.meta.title"
:options="getMenuOptions"
:default-expanded-keys="defaultExpandedKeys"
:watch-props="['defaultExpandedKeys']"
@update:value="handleMenuSelect"
/>
</template>

<script setup>
import { useRouter } from 'vue-router'
import { computed, defineProps, toRaw } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { computed, defineProps, toRaw, ref } from 'vue'
import { isExternal } from '@/utils/is.js'
import { usePermissionStore } from '@/store/modules/permission'

@@ -20,6 +22,18 @@ const props = defineProps({
}
})

// 刷新展开相应路由
const route = useRoute()
const defaultExpandedKeys = ref([])
const menuInstRef = ref(null)
setTimeout(() => {
if (route.meta.isHidden) { // 没有菜单的路由
defaultExpandedKeys.value = [route.matched[0]?.meta?.title] // 展开 父级菜单
} else { // 有菜单的路由
menuInstRef.value?.showOption(route.meta?.title) // 选中该菜单
}
})

const menuMode = toRaw(props.menuMode)

const router = useRouter()
@@ -47,7 +61,8 @@ function generateOptions(routes, basePath) {
const curOption = {
label: (route.meta && route.meta.title) || route.title,
key: route.title,
path: resolvePath(basePath, route.path)
path: resolvePath(basePath, route.path),
icons: route.icons ?? ''
}
if (route.children && route.children.length && !route.meta?.hideChild) {
curOption.children = generateOptions(route.children, resolvePath(basePath, route.path))

+ 6
- 5
src/router/guard/permission-guard.js View File

@@ -14,11 +14,12 @@ export function createPermissionGuard(router) {
next()
} else {
try {
// const { role } = oidcUser.profile
// const roles = role.includes('admin') ? 'admin' : 'flyer'
const userRole = await userStore.getUserInfos() || 1
const roleList = { 1: 'admin', 2: 'flyer' }
const routes = await permissionStore.generateRoutesMock([roleList[userRole]])
const { VITE_CLIENT_ID } = import.meta.env
const { clientRoleList } = oidcUser.profile
const { roleId } = clientRoleList.find((item) => {
return item.clientId === VITE_CLIENT_ID
})
const routes = await permissionStore.generateRoutes(roleId)
routes.forEach((item) => {
router.addRoute(item)
})

+ 55
- 7
src/store/modules/permission.js View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { asyncRoutes, basicRoutes } from '@/router/routes'
import { getMenu } from '@/api/auth/index'
import { fetchPermission } from '@/api/auth/index'
import Layout from '@/layout/index.vue'
import modules from '@/utils/module.js'

@@ -89,10 +89,44 @@ function dataArrayToRoutes(routes) {
return res
}

function dealRoutes(routes) {
const res = []
routes.forEach(item => {
const tmp = { ...item }
if (tmp.parentId === 0) {
tmp.component = Layout
if (tmp.children) {
tmp.redirect = tmp.path === '/' ? `/${tmp.children[0].path}` : `${tmp.path}/${tmp.children[0].path}`
tmp.children = dealRoutes(tmp.children)
}
} else {
const sub_view = tmp.component.replace(/^\/*/g, '')
const component = `../${sub_view}.vue`
tmp.component = modules[component]
}
tmp.title = tmp.name
tmp.meta = {
...tmp?.meta,
title: tmp.name
}
res.push(tmp)
})
return res
}

function dealPermissions(permissionsList) {
const res = permissionsList.map((tmp) => {
return tmp.code
})
return res
}

export const usePermissionStore = defineStore('permission', {
state() {
return {
accessRoutes: []
accessRoutes: [],
accessPermissions: [],
accessPermissionCodes: []
}
},
getters: {
@@ -101,6 +135,12 @@ export const usePermissionStore = defineStore('permission', {
},
permissionRoutes() {
return this.accessRoutes
},
validatePermission() {
return this.accessPermissions
},
validatePermissionCode() {
return this.accessPermissionCodes
}
},
actions: {
@@ -109,13 +149,21 @@ export const usePermissionStore = defineStore('permission', {
this.accessRoutes = accessRoutes
return accessRoutes
},
async generateRoutes() {
async generateRoutes(roleId) {
try {
const res = await getMenu()
const res = await fetchPermission({ roleId, clientId: 'tuoheng-pilot-admin' })
// const res = await fetchPermission(3)
if (res.code === 0) {
const result = dataArrayToRoutes(res.data)
this.accessRoutes = result
return Promise.resolve(result)
const { opMenusList, permissionsList } = res.data
const menus = dealRoutes(opMenusList)
const permissionCodes = dealPermissions(permissionsList)
this.accessRoutes = menus
this.accessPermissions = permissionsList
this.accessPermissionCodes = permissionCodes
return Promise.resolve(menus)
// const accessRoutes = filterAsyncRoutes(asyncRoutes)
// this.accessRoutes = accessRoutes
// return Promise.resolve(accessRoutes)
} else {
return Promise.reject(res.message)
}

+ 13
- 0
src/utils/dictionary.js View File

@@ -60,6 +60,19 @@ export const FILE_TYPE = [
{ label: '御2', value: 2 },
{ label: '御3E', value: 3 }
]
/**
* 角色状态
*/
export const ROLE_STATUS = [
{
label: '正常',
value: 1
},
{
label: '禁用',
value: 0
}
]

/**
* 状态

+ 10
- 1
src/views/system-manage/department-manage/tools/table.js View File

@@ -45,10 +45,19 @@ const data = reactive({
handleSearch,

columns: [
{
title: '序号',
key: 'key',
render: (_, index) => {
return `${index + 1}`
},
align: 'center'
},
{
title: '部门编号',
key: 'code',
align: 'center'
align: 'center',
width: 200
},
{
title: '部门名称',

+ 60
- 40
src/views/system-manage/menu-manage/components/MenuModal.vue View File

@@ -1,9 +1,9 @@
<template>
<Modal
:options="getModalOptions"
:on-close="handleClose"
:on-positive-click="handleConfirm"
:on-negative-click="handleClose"
:on-close="handleClose"
>
<template #Context>
<n-form
@@ -19,31 +19,32 @@
<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-tree-select v-if="item.type === 'tree-select'" 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-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-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 { form, setMenuOptions, changeMenuType } from '../tools/form.js'
import Modal from '@/components/Modal/index.vue'
import { addMenu, editMenu } from '@/api/system/menu/index.js'
import { menuCreate, menuUpdate, permissionCreate, permissionUpdate } from '@/api/system/menu/index.js'
import { defineComponent, ref, reactive, computed, toRefs, watch } from 'vue'

export default defineComponent({
name: 'MenuModal',
name: 'UserModal',
components: { Modal },
props: {
visible: {
@@ -57,6 +58,10 @@ export default defineComponent({
data: {
type: Object,
default: () => {}
},
source: {
type: Array,
default: () => []
}
},
emits: {
@@ -69,9 +74,9 @@ export default defineComponent({
'preview': '菜单详情',
'update': '编辑菜单'
}
getMenuOptions()
const { menuForm, menuRules } = form
const formRef = ref()
setMenuOptions(props.source)
const data = reactive({
menuForm: {
...menuForm,
@@ -83,24 +88,15 @@ export default defineComponent({
},
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)
})
changeMenuType(data.menuForm.type)
watch(() => data.menuForm.type, (value) => {
changeMenuType(value)
})

const getModalOptions = computed(() => {
return {
title: MODAL_TYPE[props.type],
width: 800,
show: props.visible,
negativeText: '取消',
positiveText: '确认'
@@ -118,24 +114,44 @@ export default defineComponent({
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)
})
if (params.type === 0) {
menuUpdate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
}).catch(e => {
console.log(e)
})
} else {
permissionUpdate(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()
}
})
if (params.type === 0) {
params.parentId = params.parentId || 0
menuCreate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
})
} else {
params.menuId = params.parentId || 0
permissionCreate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
})
}
}
} else {
$message.error('请完善必填信息')
}
})
}
@@ -156,5 +172,9 @@ export default defineComponent({
}
})
</script>

<style scoped lang='scss'>
.n-input-number{
width: 100%;
}
</style>

+ 30
- 23
src/views/system-manage/menu-manage/index.vue View File

@@ -1,49 +1,53 @@
<template>
<div>
<n-card>
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" />
<data-table
<HeadSearch :info="search" @search="handleSearch" @reset="handleSearch" />
<DataTable
ref="tableRef"
:columns="columns"
:pagination="false"
data-type="tree"
:request="loadDataTable"
:data="tableData"
:row-key="(row) => row.id"
>
<template #tableTitle>
<n-button type="primary" @click="handleModal"> 添加菜单 </n-button>
<n-button
v-if="permissionList.includes('system:menu:create')"
type="primary"
@click="handleModal"
><n-icon size="18"><AddOutline /></n-icon> {{ getPermissionLabel('system:menu:create') }} </n-button>
</template>
</data-table>
</DataTable>
</n-card>
</div>
<MenuModal v-if="modalShow" v-model:visible="modalShow" :data="rowData" :type="modalType" @reload="handleSearch" />
<!-- 新增、编辑弹窗 -->
<MenuModal v-if="modalShow" v-model:visible="modalShow" :source="menuSource" :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 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'
import { toRefs, reactive, onUnmounted } from 'vue'
import { usePermissionStore } from '@/store/modules/permission'

export default {
name: 'MenuPage',
components: { dataTable, MenuModal, headSearch },
components: { DataTable, MenuModal, HeadSearch },
setup() {
const permissionStore = usePermissionStore()
const data = reactive({
...toRefs(table),
search
search,
permissionList: permissionStore.accessPermissionCodes
})
table.fetchList()

const loadDataTable = async(res) => {
const _params = {
...unref(data.searchParams),
...res
}
return await getMenuList(_params)
const getPermissionLabel = (code) => {
return permissionStore.accessPermissions.find((item) => {
return item.code === code
})?.name || ''
}

// 打开新增弹框
@@ -54,16 +58,19 @@ export default {
}

onUnmounted(() => {
data.searchParams = null
data.searchParams = { }
})

return {
...toRefs(data),
loadDataTable,
handleModal
handleModal,
getPermissionLabel
}
}
}
</script>
<style scoped lang='scss'>
.n-button + .n-button {
margin-left: 10px;
}
</style>

+ 32
- 35
src/views/system-manage/menu-manage/tools/form.js View File

@@ -1,53 +1,50 @@
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'
import { ref, reactive } from 'vue'
import { MENU_TYPE, MENU_STATUS, MENU_VISIBLE } from '@/utils/dictionary.js'
const menuOptions = ref()
const menuType0 = ref(true)
const menuType1 = ref(false)
const disCode = ref(true)
const disMenu = ref(false)

export const form = reactive({
menuForm: {
pid: null,
parentId: null,
type: 0,
title: '',
target: '1',
icon: '',
permission: '',
path: '',
sort: null,
component: '',
hide: 0,
status: 1
name: null,
code: null,
path: null,
component: null,
isHidden: 0,
status: 1,
clientId: 'tuoheng-pilot-admin'
},
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: 'tree-select', key: 'parentId', label: '上级菜单', props: { options: menuOptions, labelField: 'name', keyField: 'id', placeholder: '请选择上级菜单', clearable: true }},
{ 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: 'input', key: 'name', label: '菜单名称', props: { maxlength: '20', placeholder: '请输入菜单名称', clearable: true }},
{ type: 'input', key: 'code', label: '权限标识', props: { maxlength: '200', disabled: disCode, placeholder: '请输入权限标识', clearable: true }},
{ type: 'input', key: 'path', label: '路由地址', props: { maxlength: '200', disabled: disMenu, placeholder: '请输入路由地址', clearable: true }},
{ type: 'input', key: 'component', label: '组件路径', props: { maxlength: '200', disabled: disMenu, placeholder: '请输入组件路径', clearable: true }},
{ type: 'number', key: 'sort', label: '排序号', props: { min: 0, placeholder: '请输入排序号', showButton: false, clearable: true }},
{ type: 'radio', key: 'isHidden', 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 setMenuOptions = async function(value) {
menuOptions.value = value
}

export const changeMenuType = function(value) {
menuType0.value = !value
menuType1.value = !menuType0.value
export const changeMenuType = async function(value) {
switch (value) {
case 0:
disCode.value = true
disMenu.value = false
break
case 1:
disCode.value = false
disMenu.value = true
break
}
}


+ 2
- 1
src/views/system-manage/menu-manage/tools/search.js View File

@@ -1,8 +1,9 @@
import { reactive } from 'vue'

const data = reactive([
{
label: '菜单名称',
key: 'title',
key: 'name',
props: {
placeholder: '请输入菜单名称'
}

+ 86
- 38
src/views/system-manage/menu-manage/tools/table.js View File

@@ -1,16 +1,32 @@
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 { h, ref, unref, reactive } from 'vue'
import TableAction from '@/components/DataTable/tools/Action.vue'
import { deleteMenu } from '@/api/system/menu/index.js'
import TableTags from '@/components/DataTable/tools/Tags.vue'
import { MENU_TYPE, MENU_STATUS, MENU_VISIBLE } from '@/utils/dictionary.js'
import { getMenuList, deleteMenu, deletePermission } from '@/api/system/menu/index.js'
import { toTreeData } from '@/utils/handleData.js'

/* 注册table */
const tableRef = ref()
const searchParams = ref()

async function fetchList() {
const params = {
...unref(data.searchParams),
menuType: 1
}
const res = await getMenuList(params)
const { menuListVoList, permissionList } = res.data
menuListVoList.forEach((item) => { item.type = 0; item.value = item.id })
const sourecData = [...menuListVoList]
permissionList.forEach((item) => { item.type = 1; item.value = `${item.menuId}_${item.id}`; item.parentId = item.menuId })
const tableData = [...menuListVoList.concat(permissionList)]
data.menuSource = toTreeData(sourecData, 'value', 'parentId', 'children')
data.tableData = toTreeData(tableData, 'value', 'parentId', 'children')
}

function handleSearch(params) {
searchParams.value = { ...params }
tableRef.value.reFetch({ searchParams })
fetchList()
}

/**
@@ -20,38 +36,61 @@ function handleSearch(params) {
* @return {*}
*/
function getRowData(row, type) {
data.rowData = type === 'create' ? { pid: row.id } : row
data.rowData = type === 'create' ? { parentId: row.id } : row
data.modalType = type
data.modalShow = true
}

// 删除方法
function deleteData(id) {
deleteMenu(id)
.then((res) => {
function deleteData({ type, id }) {
if (type === 0) {
deleteMenu(id).then((res) => {
if (res.code === 0) {
handleSearch()
}
})
.catch((e) => {
console.log(e)
})
.catch((e) => {
console.log(e)
})
} else {
deletePermission(id)
.then((res) => {
if (res.code === 0) {
handleSearch()
}
})
.catch((e) => {
console.log(e)
})
}
}

const data = reactive({
tableRef,
searchParams,
rowData: {},
menuSource: [],
tableData: [],
modalType: 'create',
modalShow: false,
handleSearch,
fetchList,

columns: [
{
title: '编号',
key: 'key',
render: (_, index) => {
return `${index + 1}`
},
align: 'center',
width: 100
},
{
title: '菜单标题',
key: 'title',
key: 'name',
align: 'center',
width: 200
width: 150
},
{
title: '菜单类型',
@@ -61,7 +100,10 @@ const data = reactive({
render(row) {
return h(TableTags, {
data: row.type,
filters: MENU_TYPE
filters: MENU_TYPE,
tags: {
bordered: true
}
})
}
},
@@ -69,13 +111,19 @@ const data = reactive({
title: '路由地址',
key: 'path',
align: 'center',
width: 200
minWidth: 200
},
{
title: '组件路径',
key: 'component',
align: 'center',
width: 200
minWidth: 300
},
{
title: '权限标识',
key: 'code',
align: 'center',
minWidth: 200
},
{
title: '状态',
@@ -83,35 +131,38 @@ const data = reactive({
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.status,
filters: MENU_STATUS
})
if (row.status) {
return h(TableTags, {
data: row.status,
filters: MENU_STATUS
})
}
}
},
{
title: '排序',
key: 'sort',
align: 'center',
width: 100
align: 'center'
},
{
title: '是否可见',
key: 'hide',
title: '可见',
key: 'isHidden',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.hide,
filters: MENU_VISIBLE
})
if (row.isHidden) {
return h(TableTags, {
data: row.isHidden,
filters: MENU_VISIBLE
})
}
}
},
{
title: '创建时间',
key: 'createTime',
align: 'center',
width: 160
minWidth: 200
},
{
title: '操作',
@@ -122,37 +173,34 @@ const data = reactive({
return h(TableAction, {
actions: [
{
label: '添加',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'create')
},
auth: 'basic_list'
auth: 'system:menu:add'
},
{
label: '修改',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'update')
},
auth: 'basic_list'
auth: 'system:menu:edit'
},
{
label: '删除',
type: 'popconfirm',
auth: 'basic_list',
tip: '确定删除这条数据吗?',
props: {
onPositiveClick: deleteData.bind(null, [row.id])
onPositiveClick: deleteData.bind(null, { type: row.type, id: [row.id] })
},
ButtonProps: {
text: true,
type: 'primary'
}
},
auth: 'system:menu:delete'
}
],
align: 'center'

+ 180
- 0
src/views/system-manage/mpmenu-manage/components/MenuModal.vue View File

@@ -0,0 +1,180 @@
<template>
<Modal
:options="getModalOptions"
:on-positive-click="handleConfirm"
:on-negative-click="handleClose"
:on-close="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-tree-select v-if="item.type === 'tree-select'" 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-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-form-item>
</n-gi>
</template>
</n-grid>
</n-form>
</template>
</Modal>
</template>

<script>
import { form, setMenuOptions, changeMenuType } from '../tools/form.js'
import Modal from '@/components/Modal/index.vue'
import { mpMenuCreate, mpMenuUpdate, permissionCreate, permissionUpdate } from '@/api/system/menu/index.js'
import { defineComponent, ref, reactive, computed, toRefs, watch } from 'vue'

export default defineComponent({
name: 'UserModal',
components: { Modal },
props: {
visible: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'create'
},
data: {
type: Object,
default: () => {}
},
source: {
type: Array,
default: () => []
}
},
emits: {
'update:visible': null,
'reload': null
},
setup(props, { emit }) {
const MODAL_TYPE = {
'create': '新建菜单',
'preview': '菜单详情',
'update': '编辑菜单'
}
const { menuForm, menuRules } = form
const formRef = ref()
setMenuOptions(props.source)
const data = reactive({
menuForm: {
...menuForm,
...props.data,
pid: props.data?.pid === 0 ? null : props.data?.pid
},
menuRules: {
...menuRules
},
disabled: props.type === 'preview'
})
changeMenuType(data.menuForm.type)
watch(() => data.menuForm.type, (value) => {
changeMenuType(value)
})

const getModalOptions = computed(() => {
return {
title: MODAL_TYPE[props.type],
width: 800,
show: props.visible,
negativeText: '取消',
positiveText: '确认'
}
})

const getFormOptions = computed(() => {
return {
...form.formItem
}
})

function handleConfirm() {
formRef.value.validate((errors) => {
if (!errors) {
const params = { ...data.menuForm }
if (params.id) {
if (params.type === 0) {
mpMenuUpdate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
}).catch(e => {
console.log(e)
})
} else {
permissionUpdate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
}).catch(e => {
console.log(e)
})
}
} else {
if (params.type === 0) {
params.parentId = params.parentId || 0
mpMenuCreate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
})
} else {
params.menuId = params.parentId || 0
permissionCreate(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>

+ 72
- 0
src/views/system-manage/mpmenu-manage/index.vue View File

@@ -0,0 +1,72 @@
<template>
<div>
<n-card>
<headSearch :info="search" @search="loadDataTable" @reset="loadDataTable" />
<data-table
ref="tableRef"
:columns="columns"
:row-key="(row) => row.id"
:data="tableData"
:pagination="false"
size="large"
>
<template #tableTitle>
<n-button v-if="permissionList.includes('system:mpmenu:create')" type="primary" @click="handleModal"> {{ getPermissionLabel('system:mpmenu:create') }} </n-button>
</template>
</data-table>
</n-card>
</div>
<!-- 新增、编辑弹窗 -->
<MenuModal v-if="modalShow" v-model:visible="modalShow" :source="menuSource" :data="rowData" :type="modalType" @reload="loadDataTable" />
</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 { toRefs, reactive, onUnmounted } from 'vue'
import { usePermissionStore } from '@/store/modules/permission'
export default {
name: 'MenuPage',
components: { dataTable, MenuModal, headSearch },
setup() {
const permissionStore = usePermissionStore()
const data = reactive({
...toRefs(table),
search,
permissionList: permissionStore.accessPermissionCodes
})

table.fetchList()

const getPermissionLabel = (code) => {
return permissionStore.accessPermissions.find((item) => {
return item.code === code
})?.name || ''
}
// 新增
function handleModal() {
data.rowData = null
data.modalType = 'create'
data.modalShow = true
}

onUnmounted(() => {
data.searchParams = { menuType: 2 }
})

return {
...toRefs(data),
handleModal,
getPermissionLabel
}
}
}
</script>
<style scoped lang='scss'>
.n-button + .n-button {
margin-left: 10px;
}
</style>

+ 47
- 0
src/views/system-manage/mpmenu-manage/tools/form.js View File

@@ -0,0 +1,47 @@
import { ref, reactive } from 'vue'
import { MENU_TYPE, MENU_STATUS, MENU_VISIBLE } from '@/utils/dictionary.js'
const menuOptions = ref()
const disCode = ref(true)
const disMenu = ref(false)

export const form = reactive({
menuForm: {
parentId: null,
type: 0,
name: null,
path: null,
component: null,
code: null,
apiUrl: null,
clientId: 'tuoheng-pilot-mp'
},
menuRules: {
name: [{ required: true, message: '请输入菜单名称', trigger: 'blur' }]
},
formItem: [
{ type: 'tree-select', key: 'parentId', label: '上级菜单', props: { options: menuOptions, labelField: 'name', keyField: 'id', placeholder: '请选择上级菜单', clearable: true }},
{ type: 'radio', key: 'type', label: '菜单类型', options: MENU_TYPE },
{ type: 'input', key: 'name', label: '菜单名称', props: { maxlength: '20', placeholder: '请输入菜单名称', clearable: true }},
{ type: 'input', key: 'path', label: '路由地址', props: { maxlength: '200', disabled: disMenu, placeholder: '请输入路由地址', clearable: true }},
{ type: 'input', key: 'component', label: '组件路径', props: { maxlength: '200', disabled: disMenu, placeholder: '请输入组件路径', clearable: true }},
{ type: 'input', key: 'code', label: '权限标识', props: { maxlength: '200', disabled: disCode, placeholder: '请输入权限标识', clearable: true }},
{ type: 'input', key: 'apiUrl', label: '接口地址', props: { maxlength: '200', disabled: disCode, placeholder: '请输入接口地址', clearable: true }}
]
})

export const setMenuOptions = async function(value) {
menuOptions.value = value
}

export const changeMenuType = async function(value) {
switch (value) {
case 0:
disCode.value = true
disMenu.value = false
break
case 1:
disCode.value = false
disMenu.value = true
break
}
}

+ 14
- 0
src/views/system-manage/mpmenu-manage/tools/search.js View File

@@ -0,0 +1,14 @@
import { reactive } from 'vue'

const data = reactive([
{
label: '菜单名称',
key: 'name',
props: {
placeholder: '请输入菜单名称'
}
}
])

export default data


+ 186
- 0
src/views/system-manage/mpmenu-manage/tools/table.js View File

@@ -0,0 +1,186 @@
import { h, ref, reactive, unref } from 'vue'
import TableAction from '@/components/DataTable/tools/Action.vue'
import TableTags from '@/components/DataTable/tools/Tags.vue'
import { MENU_TYPE } from '@/utils/dictionary.js'
import { deleteMpMenu, deletePermission, getMenuList } from '@/api/system/menu/index.js'
import { toTreeData } from '@/utils/handleData.js'

/* 注册table */
const tableRef = ref()
const searchParams = ref({ menuType: 2 })

async function fetchList() {
const params = {
...unref(data.searchParams),
menuType: 1
}
const res = await getMenuList(params)
const { menuListVoList, permissionList } = res.data
menuListVoList.forEach((item) => { item.type = 0; item.value = item.id })
const sourecData = [...menuListVoList]
permissionList.forEach((item) => { item.type = 1; item.value = `${item.menuId}_${item.id}`; item.parentId = item.menuId })
const tableData = [...menuListVoList.concat(permissionList)]
data.menuSource = toTreeData(sourecData, 'value', 'parentId', 'children')
data.tableData = toTreeData(tableData, 'value', 'parentId', 'children')
}

function handleSearch(params) {
searchParams.value = { ...params }
fetchList()
}

/**
* @description: 获取数据及操作
* @param {*} row 单行数据
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
* @return {*}
*/
function getRowData(row, type) {
data.rowData = type === 'create' ? { parentId: row.id } : row
data.modalType = type
data.modalShow = true
}

// 删除方法
function deleteData({ type, id }) {
if (type === 0) {
deleteMpMenu(id).then((res) => {
if (res.code === 0) {
handleSearch()
}
})
.catch((e) => {
console.log(e)
})
} else {
deletePermission(id)
.then((res) => {
if (res.code === 0) {
handleSearch()
}
})
.catch((e) => {
console.log(e)
})
}
}

const data = reactive({
tableRef,
searchParams,
rowData: {},
menuSource: [],
tableData: [],
modalType: 'create',
modalShow: false,
refetch: false,
handleSearch,
fetchList,
columns: [
{
title: '编号',
key: 'key',
render: (_, index) => {
return `${index + 1}`
},
align: 'center',
width: 100
},
{
title: '菜单标题',
key: 'name',
align: 'center',
width: 150
},
{
title: '菜单类型',
key: 'type',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.type,
filters: MENU_TYPE,
tags: {
bordered: true
}
})
}
},
{
title: '路由地址',
key: 'path',
align: 'center',
minWidth: 200
},
{
title: '组件路径',
key: 'component',
align: 'center',
minWidth: 300
},
{
title: '权限标识',
key: 'code',
align: 'center',
minWidth: 200
},
{
title: '接口地址',
key: 'apiUrl',
align: 'center',
minWidth: 200
},
{
title: '创建时间',
key: 'createTime',
align: 'center',
minWidth: 200
},
{
title: '操作',
align: 'center',
width: 150,
fixed: 'right',
render(row) {
return h(TableAction, {
actions: [
{
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'create')
},
auth: 'system:mpmenu:add'
},
{
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'update')
},
auth: 'system:mpmenu:edit'
},
{
type: 'popconfirm',
auth: 'system:mpmenu:delete',
tip: '确定删除这条数据吗?',
props: {
onPositiveClick: deleteData.bind(null, { type: row.type, id: [row.id] })
},
ButtonProps: {
text: true,
type: 'primary'
}
}
],
align: 'center'
})
}
}
]
})

export default data

+ 204
- 0
src/views/system-manage/role-manage/components/AuthModal.vue View File

@@ -0,0 +1,204 @@
<template>
<Modal
:options="getModalOptions"
:on-positive-click="handleConfirm"
:on-negative-click="handleClose"
:on-close="handleClose"
>
<template #Context>
<n-tabs type="line" animated>
<n-tab-pane display-directive="show" name="pc" tab="管理端菜单">
<n-tree
v-if="tabsTreeVisible"
ref="adminTreeRef"
block-line
cascade
checkable
default-expand-all
virtual-scroll
label-field="name"
:data="adminData"
:default-checked-keys="adminKeys"
style="height: 400px"
/>
</n-tab-pane>
<n-tab-pane display-directive="show" name="mp" tab="小程序菜单">
<n-tree
v-if="tabsTreeVisible"
ref="miniTreeRef"
block-line
cascade
checkable
default-expand-all
virtual-scroll
label-field="name"
:data="miniData"
:default-checked-keys="miniKeys"
style="height: 400px"
/>
</n-tab-pane>
</n-tabs>
</template>
</Modal>
</template>

<script>
import Modal from '@/components/Modal/index.vue'
import { getRoleMenu, saveRoleMenu } from '@/api/system/role/index.js'
import { toTreeData } from '@/utils/handleData.js'
import { defineComponent, ref, reactive, computed, toRefs, onBeforeMount, nextTick } 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 = { 'relate': '分配权限' }
const adminTreeRef = ref()
const miniTreeRef = ref()
const data = reactive({
tabsTreeVisible: false,
adminData: [],
adminKeys: [],
miniData: [],
miniKeys: []
})
const getModalOptions = computed(() => {
return {
title: MODAL_TYPE[props.type],
width: 600,
show: props.visible,
trapFocus: false,
negativeText: '取消',
positiveText: '确认'
}
})

function handleConfirm() {
const adminCheckedData = adminTreeRef.value.getCheckedData()
const adminIndeterminateData = adminTreeRef.value.getIndeterminateData()
const miniCheckedData = miniTreeRef.value.getCheckedData()
const miniIndeterminateData = miniTreeRef.value.getIndeterminateData()
const adminKeys = adminCheckedData.keys.concat(adminIndeterminateData.keys)
const miniKeys = miniCheckedData.keys.concat(miniIndeterminateData.keys)
const params = { roleId: props.data.id, ids: adminKeys.concat(miniKeys) }
saveRoleMenu(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
}).catch(e => {
console.log(e)
})
}

/* 关闭弹窗 */
const handleClose = () => {
emit('update:visible', false)
}

const querySelectedKeys = (data, list) => {
data.forEach((item) => {
if (item.children && item.children.length) {
querySelectedKeys(item.children, list)
} else {
if (item.checked) {
list.push(item.key)
}
}
})
}

onBeforeMount(async() => {
const res = await getRoleMenu({ roleId: props.data.id })
if (res.code === 0) {
const { opMenusList, permissionsList } = res.data
const adminMenus = opMenusList.filter((item) => {
item.title = item.name
item.key = item.identificationId
return item.clientId === 'tuoheng-pilot-admin'
})
const adminPermissions = permissionsList.filter((item) => {
item.title = item.name
item.parentId = item.menuId
item.key = item.identificationId
return item.clientId === 'tuoheng-pilot-admin'
})
const mpMenus = opMenusList.filter((item) => {
item.title = item.name
item.key = item.identificationId
return item.clientId === 'tuoheng-waterway-mp'
})
const mpPermissions = permissionsList.filter((item) => {
item.title = item.name
item.parentId = item.menuId
item.key = item.identificationId
return item.clientId === 'tuoheng-waterway-mp'
})
const adminData = adminMenus.concat(adminPermissions)
const adminTreeData = toTreeData(adminData, 'id', 'parentId', 'children')
data.adminKeys = []
querySelectedKeys(adminTreeData, data.adminKeys)
const miniData = mpMenus.concat(mpPermissions)
const miniTreeData = toTreeData(miniData, 'id', 'parentId', 'children')
data.miniKeys = []
querySelectedKeys(miniTreeData, data.miniKeys)

nextTick(() => {
data.tabsTreeVisible = true
data.adminData = adminTreeData
data.miniData = miniTreeData
})
}
})

return {
...toRefs(data),
adminTreeRef,
miniTreeRef,
getModalOptions,
handleConfirm,
handleClose
}
}
})
</script>

<style scoped lang='scss'>
.n-input-number{
width: 100%;
}

.flex__body{
display: flex;
width: 100%;
flex-wrap: wrap;
.n-form-item{
width: 100%;
}
// .flex__item{
// width: 50%;
// }
}

.n-date-picker{
width: 100%;
}
</style>

+ 71
- 47
src/views/system-manage/role-manage/components/RoleModal.vue View File

@@ -8,35 +8,39 @@
<template #Context>
<n-form
ref="formRef"
:model="roleForm"
:rules="roleRules"
:label-width="80"
:model="userForm"
:rules="userRules"
:label-width="100"
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>
<div class="flex__body">
<template v-for="(item,index) in getFormOptions" :key="index">
<n-form-item :label="item.label" :path="item.key" :class="{ 'flex__item': !['oss','editor'].includes(item.type) }">
<n-input v-if="item.type === 'input'" 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>
</div>

</n-form>
</template>
</Modal>
</template>

<script>
import form from '../tools/form.js'
import { defineComponent, ref, reactive, computed, toRefs } from 'vue'
import { form } from '../tools/form.js'
import Modal from '@/components/Modal/index.vue'
import { addRole, editRole } from '@/api/system/role/index'
import { roleCreate, roleUpdate } from '@/api/system/role/index.js'
import { defineComponent, ref, reactive, computed, toRefs } from 'vue'

export default defineComponent({
name: 'RoleModal',
name: 'UserModal',
components: { Modal },
props: {
visible: {
@@ -58,27 +62,28 @@ export default defineComponent({
},
setup(props, { emit }) {
const MODAL_TYPE = {
'create': '新建角色',
'preview': '角色详情',
'update': '编辑角色'
'create': '新增用户',
'preview': '用户详情',
'update': '编辑用户'
}
const { roleForm, roleRules } = form
const { userForm, userRules } = form
const formRef = ref()
const data = reactive({
roleForm: {
...roleForm,
userForm: {
...userForm,
...props.data
},
roleRules: {
...roleRules
userRules: {
...userRules
},
disabled: props.type === 'preview'
})

const getModalOptions = computed(() => {
return {
title: MODAL_TYPE[props.type],
width: 600,
show: props.visible,
trapFocus: false,
negativeText: '取消',
positiveText: '确认'
}
@@ -91,30 +96,29 @@ export default defineComponent({
})

function handleConfirm() {
formRef.value?.validate((errors) => {
formRef.value.validate((errors) => {
if (!errors) {
const params = { ...data.roleForm }
if (params.id) {
/* 编辑 */
editRole(params)
.then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
})
const params = { ...data.userForm }
if (props.type === 'preview') {
emit('reload')
handleClose()
} else if (params.id) {
roleUpdate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
}).catch(e => {
console.log(e)
})
} else {
/* 新增 */
addRole(params)
.then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
})
roleCreate(params).then(res => {
if (res.code === 0) {
emit('reload')
handleClose()
}
})
}
} else {
$message.error('请完善必填信息')
}
})
}
@@ -135,5 +139,25 @@ export default defineComponent({
}
})
</script>

<style scoped lang='scss'>
.n-input-number{
width: 100%;
}

.flex__body{
display: flex;
width: 100%;
flex-wrap: wrap;
.n-form-item{
width: 100%;
}
// .flex__item{
// width: 50%;
// }
}

.n-date-picker{
width: 100%;
}
</style>

+ 15
- 41
src/views/system-manage/role-manage/index.vue View File

@@ -5,32 +5,21 @@
<data-table
ref="tableRef"
:columns="columns"
:row-key="(row) => row.id"
:request="loadDataTable"
:row-key="(row) => row.id"
:scroll-x="1200"
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>
<n-button v-if="permissionStore.includes('system:role:create')" type="primary" @click="handleModal"> 新建 </n-button>
</template>
</data-table>
</n-card>
</div>
{{ permissionStore.getToken }}
<!-- 新增、编辑弹窗 -->
<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" />
<AuthModal v-if="relateShow" v-model:visible="relateShow" :data="rowData" :type="modalType" @reload="handleSearch" />
</template>

<script>
@@ -39,19 +28,20 @@ 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'
import AuthModal from './components/AuthModal.vue'
import { getRoleList } from '@/api/system/role/index.js'
import { unref, toRefs, reactive, onUnmounted } from 'vue'
import { usePermissionStore } from '@/store/modules/permission'

export default {
name: 'MenuPage',
components: { headSearch, dataTable, RoleModal, ConfigModal },
name: 'UserManage',
components: { dataTable, headSearch, RoleModal, AuthModal },
setup() {
const data = reactive({
...toRefs(table),
search
})
const permissionStore = usePermissionStore().accessPermissionCodes // 按钮权限
const loadDataTable = async(res) => {
const _params = {
...unref(data.searchParams),
@@ -60,39 +50,23 @@ export default {
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
data.modalShow = false
})

return {
...toRefs(data),
loadDataTable,
handleModal,
handleCheck,
selectedIds,
deleteComplex
permissionStore
}
}
}

+ 15
- 18
src/views/system-manage/role-manage/tools/form.js View File

@@ -1,24 +1,21 @@
import { reactive } from 'vue'
import { USER_STATUS } from '@/utils/dictionary.js'
import { ref, reactive } from 'vue'
import { ROLE_STATUS } from '@/utils/dictionary.js'

const data = reactive({
roleForm: {
code: '',
name: '',
status: 1,
note: ''
export const form = reactive({
userForm: {
roleName: null,
remark: null,
roleCode: null,
status: 1
},
roleRules: {
code: [{ required: true, message: '请输入角色编号', trigger: 'blur' }],
name: [{ required: true, message: '请输入角色名称', type: 'string', trigger: 'blur' }],
status: [{ required: true, message: '请选择状态', type: 'number', trigger: 'blur' }]
userRules: {
roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
roleCode: [{ required: true, 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: 'radio', key: 'status', label: '状态', options: USER_STATUS },
{ type: 'input', key: 'note', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}}
{ type: 'input', key: 'roleName', label: '角色名称', props: { maxlength: '20', placeholder: '请输入角色名称', clearable: true }},
{ type: 'input', key: 'roleCode', label: '角色编码', props: { maxlength: '20', placeholder: '请输入角色名称', clearable: true }},
{ type: 'radio', key: 'status', label: '角色状态', options: ROLE_STATUS },
{ type: 'input', key: 'remark', label: '备注', props: { type: 'textarea', maxlength: '140', autosize: { minRows: 3, maxRows: 3 }, placeholder: '请输入备注', clearable: true }}
]
})

export default data

+ 2
- 1
src/views/system-manage/role-manage/tools/search.js View File

@@ -3,7 +3,7 @@ import { reactive } from 'vue'
const data = reactive([
{
label: '角色名称',
key: 'name',
key: 'roleName',
props: {
placeholder: '请输入角色名称'
}
@@ -11,3 +11,4 @@ const data = reactive([
])

export default data


+ 61
- 52
src/views/system-manage/role-manage/tools/table.js View File

@@ -1,7 +1,7 @@
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'
import TableSwitch from '@/components/DataTable/tools/Switch.vue'
import { setRoleStatus, roleDelete } from '@/api/system/role/index.js'

/* 注册table */
const tableRef = ref()
@@ -12,28 +12,6 @@ function handleSearch(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 选中数据
@@ -51,9 +29,8 @@ function handleStatusChange(row) {
})
}

// 删除接口
function deleteData(data) {
deleteRole(data)
function deleteData(id) {
roleDelete(id)
.then((res) => {
if (res.code === 0) {
handleSearch()
@@ -63,6 +40,21 @@ function deleteData(data) {
console.log(e)
})
}
/**
* @description: 获取数据及操作
* @param {*} row 单行数据
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
* @return {*}
*/
function getRowData(row, type) {
data.rowData = row || {}
data.modalType = type
if (type === 'relate') {
data.relateShow = true
} else {
data.modalShow = true
}
}

const data = reactive({
tableRef,
@@ -70,32 +62,30 @@ const data = reactive({
rowData: {},
modalType: 'create',
modalShow: false,
configModalShow: false,
relateShow: false,
handleSearch,
deleteData,
columns: [
{ type: 'selection' },
{
title: '角色编号',
key: 'code',
align: 'center'
title: '编号',
key: 'key',
render: (_, index) => {
return `${index + 1}`
},
align: 'center',
width: 50
},
{
title: '角色名称',
key: 'name',
align: 'center'
},
{
title: '创建时间',
key: 'createTime',
key: 'roleName',
align: 'center',
Minwidth: 160
width: 200
},
{
title: '更新时间',
key: 'updateTime',
title: '角色编码',
key: 'roleCode',
align: 'center',
Minwidth: 160
width: 200
},
{
title: '状态',
@@ -107,45 +97,63 @@ const data = reactive({
data: { id: row.id, status: row.status },
rowKey: 'status',
checkedValue: 1,
uncheckedValue: 2,
uncheckedValue: 0,
onChange: handleStatusChange.bind(row)
})
}
},
{
title: '描述',
key: 'remark',
align: 'center',
ellipsis: {
tooltip: true
},
width: 400
},
{
title: '操作',
align: 'center',
width: 150,
width: 200,
fixed: 'right',
render(row) {
return h(TableAction, {
actions: [
{
label: '修改',
label: '详情',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'preview')
},
auth: 'system:role:preview'
},
{
label: '编辑',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'update')
},
auth: 'basic_list'
auth: 'system:role:edit'
},
{
label: '分配权限',
type: 'button',
props: {
type: 'primary',
ghost: true,
text: true,
onClick: configure.bind(null, row)
onClick: getRowData.bind(null, row, 'relate')
},
auth: 'basic_list'
auth: 'system:role:dispatch'
},
{
label: '删除',
type: 'popconfirm',
auth: 'basic_list',
tip: '确定删除这条数据吗?',
auth: 'system:role:delete',
tip: '确定删除这个角色吗?',
props: {
onPositiveClick: deleteData.bind(null, [row.id])
},
@@ -154,6 +162,7 @@ const data = reactive({
type: 'primary'
}
}

],
align: 'center'
})

+ 0
- 168
src/views/system-manage/user-manage/components/UserModal.vue View File

@@ -1,168 +0,0 @@
<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
- 105
src/views/system-manage/user-manage/index.vue View File

@@ -1,105 +0,0 @@
<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
- 52
src/views/system-manage/user-manage/tools/form.js View File

@@ -1,52 +0,0 @@
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
- 36
src/views/system-manage/user-manage/tools/search.js View File

@@ -1,36 +0,0 @@
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
- 210
src/views/system-manage/user-manage/tools/table.js View File

@@ -1,210 +0,0 @@
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

+ 5
- 2
src/views/task-manage/index.vue View File

@@ -13,8 +13,8 @@
size="large"
@update:checked-row-keys="handleCheck"
>
<template v-if="roleType === 1" #tableTitle>
<n-button type="primary" @click="handleModal"> 新建 </n-button>
<template #tableTitle>
<n-button v-if="permissionStore.includes('task:all:create')" type="primary" @click="handleModal"> 新建 </n-button>
</template>
</data-table>
</n-card>
@@ -42,6 +42,7 @@ import UserModal from './components/UserModal.vue'
import { getTaskList } from '@/api/task/index'
import { unref, ref, toRefs, reactive, onUnmounted } from 'vue'
import { useUserStore } from '@/store/modules/user'
import { usePermissionStore } from '@/store/modules/permission'

export default {
name: 'TaskManage',
@@ -52,6 +53,7 @@ export default {
...toRefs(table),
...toRefs(search)
})
const permissionStore = usePermissionStore().accessPermissionCodes // 按钮权限
const status = ['任务待分配', '任务已分配', '飞手已接单', '任务飞行中', '任务已完成']
const loadDataTable = async(res) => {
const _params = {
@@ -99,6 +101,7 @@ export default {
handleModal,
selectedIds,
// deleteComplex,
permissionStore,
handleCheck,
roleType
}

+ 6
- 10
src/views/task-manage/tools/table.js View File

@@ -132,27 +132,23 @@ const data = reactive({
props: {
type: 'primary',
text: true,
onClick: editHandle.bind(null, row, 'update'),
style: {
display: row.status > 10 || row.inspectionType !== 1 || roleType.value !== 1 ? 'none' : ''
}
onClick: editHandle.bind(null, row, 'update')
},
auth: 'basic_list'
show: row.status > 10 || row.inspectionType !== 1,
auth: 'task:all:edit'
},
{
label: '删除',
type: 'popconfirm',
auth: 'basic_list',
tip: '确定删除这条数据吗?',
props: {
onPositiveClick: deleteData.bind(null, row.id)
},
auth: 'task:all:delete',
show: row.status > 15 || row.inspectionType !== 1,
ButtonProps: {
text: true,
type: 'primary',
style: {
display: row.status > 15 || row.inspectionType !== 1 || roleType.value !== 1 ? 'none' : ''
}
type: 'primary'
}
}
],

+ 2
- 1
src/views/user-manage/components/UserModal.vue View File

@@ -27,7 +27,7 @@
</template>

<script>
import { form } from '../tools/form.js'
import { form, getRoleOptions } from '../tools/form.js'
import { defineComponent, ref, reactive, computed, toRefs } from 'vue'
import { userCreate, userUpdate } from '@/api/system/user.js'
import Modal from '@/components/Modal/index.vue'
@@ -58,6 +58,7 @@ export default defineComponent({
'preview': '人员详情',
'update': '编辑人员信息'
}
getRoleOptions()
const { userForm, userRules } = form
const formRef = ref()
const data = reactive({

+ 8
- 4
src/views/user-manage/index.vue View File

@@ -10,7 +10,7 @@
size="large"
>
<template #tableTitle>
<n-button type="primary" @click="handleModal"> 新建 </n-button>
<n-button v-if="permissionStore.includes('user:menber:create')" type="primary" @click="handleModal"> 新建 </n-button>
</template>
</data-table>
</n-card>
@@ -21,21 +21,24 @@

<script>
import search from './tools/search.js'
import table from './tools/table.js'
import { tableData, getRoleOptions } 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 { unref, toRefs, reactive, onUnmounted } from 'vue'
import { userPage } from '@/api/system/user.js'
import { usePermissionStore } from '@/store/modules/permission'

export default {
name: 'UserManage',
components: { dataTable, UserModal, headSearch },
setup() {
const data = reactive({
...toRefs(table),
...toRefs(tableData),
search
})
const permissionStore = usePermissionStore().accessPermissionCodes // 按钮权限
getRoleOptions()

const loadDataTable = async(res) => {
const _params = {
@@ -59,7 +62,8 @@ export default {
return {
...toRefs(data),
loadDataTable,
handleModal
handleModal,
permissionStore
}
}
}

+ 16
- 5
src/views/user-manage/tools/form.js View File

@@ -1,12 +1,13 @@
import { reactive } from 'vue'
import { ROLE_TYPE } from '@/utils/dictionary.js'
import { reactive, ref } from 'vue'
import { isPhone } from '@/utils/is.js'
import { getRoleAll } from '@/api/system/role'
const roleOptions = ref([])

export const form = reactive({
userForm: {
realname: null,
mobile: null,
type: null,
roleId: null,
username: null,
password: null
},
@@ -16,15 +17,25 @@ export const form = reactive({
// { required: true, message: '请输入联系电话', type: 'string', trigger: 'blur' },
{ required: true, message: '请输入正确的联系电话', pattern: /^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/, trigger: 'blur' }
],
type: [{ required: true, type: 'number', message: '请选择身份', trigger: 'blur' }],
roleId: [{ required: true, type: 'number', message: '请选择身份', trigger: 'blur' }],
username: [{ required: true, message: '账号为英文和数字', pattern: /^[a-zA-Z0-9]+$/, trigger: 'blur' }],
password: [{ required: true, message: '密码为6到20位的大小写英文和数字组成的', pattern: /^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$)([^\u4e00-\u9fa5\s]){6,20}$/, trigger: 'blur' }]
},
formItem: [
{ type: 'input', key: 'realname', label: '姓名', props: { maxlength: '5', placeholder: '请输入姓名', clearable: true }},
{ type: 'input', key: 'mobile', label: '联系电话', props: { maxlength: '20', placeholder: '请输入联系电话', clearable: true }},
{ type: 'select', key: 'type', label: '身份选择', props: { options: ROLE_TYPE, clearable: true }},
{ type: 'select', key: 'roleId', label: '身份选择', props: { options: roleOptions, clearable: true }},
{ type: 'input', key: 'username', label: '帐号', props: { maxlength: '20', placeholder: '请输入帐号', clearable: true }},
{ type: 'input', key: 'password', label: '初始密码', props: { maxlength: '20', placeholder: '请输入初始密码', clearable: true }}
]
})
export const getRoleOptions = async function() {
const res = await getRoleAll()
if (res.code === 0) {
roleOptions.value = res.data.map(it => ({
...it,
label: it.roleName,
value: it.id
}))
}
}

+ 25
- 10
src/views/user-manage/tools/table.js View File

@@ -2,9 +2,20 @@ import { h, ref, reactive } from '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 { ROLE_TYPE } from '@/utils/dictionary.js'
import { userUpdate } from '@/api/system/user.js'
import { getRoleAll } from '@/api/system/role'

const roleOptions = ref([])
export const getRoleOptions = async function() {
const res = await getRoleAll()
if (res.code === 0) {
roleOptions.value = res.data.map(it => ({
...it,
label: it.roleName,
value: it.id
}))
}
}
/* 注册table */
const tableRef = ref()
const searchParams = ref()
@@ -21,9 +32,9 @@ function handleSearch(params) {
* @return {*}
*/
function getRowData(row, type) {
data.rowData = row
data.modalType = type
data.modalShow = true
tableData.rowData = row
tableData.modalType = type
tableData.modalShow = true
}

// 设置状态
@@ -37,7 +48,7 @@ function changeStatus(row) {
})
}

const data = reactive({
export const tableData = reactive({
tableRef,
searchParams,
rowData: {},
@@ -55,14 +66,19 @@ const data = reactive({
align: 'center',
width: 100
},
{
title: '账号',
key: 'username',
align: 'center'
},
{
title: '角色',
key: 'type',
key: 'roleId',
align: 'center',
render(row) {
return h(TableTags, {
data: row.type,
filters: ROLE_TYPE
data: row.roleId,
filters: roleOptions.value
})
}
},
@@ -119,7 +135,7 @@ const data = reactive({
text: true,
onClick: getRowData.bind(null, row, 'update')
},
auth: 'basic_list'
auth: 'user:menber:edit'
}
],
align: 'center'
@@ -129,4 +145,3 @@ const data = reactive({
]
})

export default data

Loading…
Cancel
Save