Ver código fonte

mune change

master
zhangtao 2 anos atrás
pai
commit
d67c03dd84
18 arquivos alterados com 272 adições e 122 exclusões
  1. +1
    -1
      .env.localhost
  2. +3
    -3
      mock/system/router.js
  3. +1
    -1
      src/api/login/index.js
  4. +1
    -1
      src/api/system/index.js
  5. +3
    -2
      src/components/DataTable/index.vue
  6. +15
    -1
      src/components/DataTable/tools/useDataSource.js
  7. +1
    -47
      src/components/Dialog/index.vue
  8. +61
    -0
      src/components/Modal/index.vue
  9. +51
    -20
      src/components/Search/index.vue
  10. +6
    -4
      src/layout/components/Menu/index.vue
  11. +3
    -3
      src/layout/components/Tags/index.vue
  12. +6
    -6
      src/router/routes/index.js
  13. +22
    -9
      src/store/modules/permission.js
  14. +2
    -2
      src/views/login/index.vue
  15. +50
    -0
      src/views/system/menu/components/RoleModal.vue
  16. +11
    -4
      src/views/system/menu/index.vue
  17. +14
    -6
      src/views/system/role/index.vue
  18. +21
    -12
      src/views/system/role/info.js

+ 1
- 1
.env.localhost Ver arquivo

@@ -2,7 +2,7 @@
VITE_PUBLIC_PATH = '/'

# 是否启用MOCK
VITE_APP_USE_MOCK = true
VITE_APP_USE_MOCK = false

# proxy
VITE_PROXY = [["/api-local","http://127.0.0.1:8002/api"],["/api-mock","http://127.0.0.1:8003"]]

+ 3
- 3
mock/system/router.js Ver arquivo

@@ -3,7 +3,7 @@ const asyncRoutes = [
path: '/system',
component: 'Layout',
redirect: '/system/menu',
name: 'System',
title: 'System',
meta: {
title: '系统管理'
},
@@ -11,7 +11,7 @@ const asyncRoutes = [
{
path: 'menu',
component: 'views/system/menu/index',
name: 'SystemMenu',
title: 'SystemMenu',
meta: {
title: '菜单管理'
}
@@ -19,7 +19,7 @@ const asyncRoutes = [
{
path: 'user',
component: 'views/system/user/index',
name: 'SystemUser',
title: 'SystemUser',
meta: {
title: '用户管理'
}

+ 1
- 1
src/api/login/index.js Ver arquivo

@@ -1,4 +1,4 @@
import { mockAxios as request } from '@/utils/http'
import { defAxios as request } from '@/utils/http'

export function userLogin(data = {}) {
return request({

+ 1
- 1
src/api/system/index.js Ver arquivo

@@ -1,4 +1,4 @@
import { mockAxios as request } from '@/utils/http'
import { defAxios as request } from '@/utils/http'

export function getMenu() {
return request({

+ 3
- 2
src/components/DataTable/index.vue Ver arquivo

@@ -76,7 +76,7 @@ export default {

/* tableData-start */
const tableData = ref([])
const { getDataSourceRef, getRowKey, reload } = useDataSource(getProps, { getPaginationInfo, setPagination, tableData, setLoading }, emit)
const { getDataSourceRef, getRowKey, reload, reFetch } = useDataSource(getProps, { getPaginationInfo, setPagination, tableData, setLoading }, emit)
const isRequest = !!unref(getProps).request
const getBindProps = computed(() => {
return {
@@ -97,7 +97,8 @@ export default {
pagination,
updatePage,
updatePageSize,
reload
reload,
reFetch
}
}
}

+ 15
- 1
src/components/DataTable/tools/useDataSource.js Ver arquivo

@@ -99,6 +99,19 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
await fetch(opt)
}

async function reFetch(opt) {
console.log('opt', opt)
const { paginationSetting } = unref(propsRef)
const pageField = paginationSetting.pageField
const sizeField = paginationSetting.sizeField
const pageSize = paginationSetting.pageSize
setPagination({
[pageField]: 1,
[sizeField]: pageSize
})
await fetch(opt)
}

onMounted(() => {
setTimeout(() => {
fetch()
@@ -111,6 +124,7 @@ export function useDataSource(propsRef, { getPaginationInfo, setPagination, setL
getDataSource,
setTableData,
getRowKey,
reload
reload,
reFetch
}
}

+ 1
- 47
src/components/Dialog/index.vue Ver arquivo

@@ -1,52 +1,6 @@
<template />

<script setup>
import { isNullOrUndef } from '@/utils/is'
import { useDialog } from 'naive-ui'

const NDialog = useDialog()

class Dialog {
success(title, option) {
this.showDialog('success', { title, ...option })
}

warning(title, option) {
this.showDialog('warning', { title, ...option })
}

error(title, option) {
this.showDialog('error', { title, ...option })
}

showDialog(type = 'success', option) {
if (isNullOrUndef(option.title)) {
// ! 没有title的情况
option.showIcon = false
}
NDialog[type]({
positiveText: 'OK',
closable: false,
...option
})
}

confirm(option = {}) {
this.showDialog(option.type || 'error', {
positiveText: '确定',
negativeText: '取消',
onPositiveClick: option.confirm,
onNegativeClick: option.cancel,
onMaskClick: option.cancel,
...option
})
}
}

window['$dialog'] = new Dialog()
Object.freeze(window.$dialog)
Object.defineProperty(window, '$dialog', {
configurable: false,
writable: false
})
window['$dialog'] = useDialog()
</script>

+ 61
- 0
src/components/Modal/index.vue Ver arquivo

@@ -0,0 +1,61 @@
<template>
<n-modal v-model:show="getModalOptions" preset="dialog">
<n-card>
<slot name="Context" />
</n-card>
</n-modal>
</template>

<script>

import { defineComponent, computed } from 'vue'
export default defineComponent({
name: 'ModalModules',
props: {
/* 弹窗可见 */
visible: {
type: Boolean,
default: false
},
/* 弹窗标题 */
title: {
type: String,
default: ''
},
/* 确定按钮的loading */
confirmLoading: {
type: Boolean,
default: false
},
maskClosable: {
type: Boolean,
default: true
}
},
emits: {
click: null, // click事件没有检验
onClose: (value) => {
return value
}
},
setup(props, { emit }) {
const getModalOptions = computed(() => {
return props.visible
})
const handleClick = function() {
emit('click')
}
const handleCancel = function() {
emit('onClose', true)
}
return {
getModalOptions,
handleClick,
handleCancel
}
}
})
</script>

<style scoped lang='scss'>
</style>

+ 51
- 20
src/components/Search/index.vue Ver arquivo

@@ -2,13 +2,25 @@
<div>
<n-form ref="formRef" v-bind="getFormOptions">
<template v-for="(item, index) in getFormOptions.info" :key="`${index}-${item.label}`">
<n-form-item v-if="!item.options" :label="item.label">
<n-input v-model:value="getFormOptions.form[item.key]" :placeholder="item.placeholder" />
<n-form-item v-if="['input'].includes(item.type) || !item.type" :label="item.label">
<n-input v-model:value="getFormOptions.form[item.key]" v-bind="item.props" />
</n-form-item>
<n-form-item v-if="item.options" :label="item.label">
<n-select v-model:value="getFormOptions.form[item.key]" :options="item.options" />
<n-form-item v-if="['select'].includes(item.type) " :label="item.label">
<n-select v-model:value="getFormOptions.form[item.key]" v-bind="item.props" />
</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>
</template>
<n-form-item class="form__button">
<n-button @click="handleSearch">查询</n-button>
<n-button @click="handleReset">重置</n-button>
<n-button
v-if="showButton"
type="text"
@click="showMoreItem"
>{{ showItemNum === getFormOptions.info.length - 1 ? '收起' : '展开' }}</n-button>
</n-form-item>
</n-form>
</div>
</template>
@@ -25,36 +37,49 @@ export default {
default: () => []
}
},
emits: ['search'],
setup(props, { emit }) {
// const formOption = reactive({
// form: {

// }
// })
const getFormRef = computed(() => {
const { info } = unref(props)
const form = ref({})
info.forEach((item) => {
const showItemNum = ref(3)
const len = ref(props.info.length - 1)
const showButton = ref(!!(showItemNum.value < len.value))
/* 获取传递的props */
const data = reactive({
info: toRaw(props.info)
})
const form = ref({})
/* 初始化搜索表单信息 */
function initForm() {
data.info.forEach((item) => {
form.value[item.key] = ''
})
return unref(form)
})
console.log(getFormRef)
}

const getFormOptions = computed(() => {
return {
form: unref(getFormRef),
form: unref(form),
labelWidth: 'auto',
labelPlacement: 'left',
inline: true,
info: [...unref(props).info]
}
})
function getFormInfo() {
console.log(getFormOptions)
function handleSearch() {
emit('search', getFormOptions.value.form)
}
function handleReset() {
initForm()
emit('search', getFormOptions.value.form)
}
function showMoreItem() {
showItemNum.value = showItemNum.value === len.value ? 3 : len.value
}
return {
showItemNum,
showButton,
getFormOptions,
getFormInfo
handleSearch,
handleReset,
showMoreItem
}
}
}
@@ -71,5 +96,11 @@ export default {
.n-select{
width: 200px;
}
transition: all 10s;
}
.form__button{
button+button{
margin-left: 20px;
}
}
</style>

+ 6
- 4
src/layout/components/Menu/index.vue Ver arquivo

@@ -1,7 +1,7 @@
<template>
<n-menu
:mode="menuMode"
:value="(currentRoute.meta && currentRoute.meta.activeMenu) || currentRoute.name"
:value="(currentRoute.title && currentRoute.meta.activeMenu) || currentRoute.title"
:options="getMenuOptions"
@update:value="handleMenuSelect"
/>
@@ -29,6 +29,8 @@ const getMenuOptions = computed(() => {
return generateOptions(permissionStore.routes, '')
})

console.log('getMenuOptions', getMenuOptions)

function resolvePath(basePath, path) {
if (isExternal(path)) return path
return (
@@ -43,10 +45,10 @@ function resolvePath(basePath, path) {
function generateOptions(routes, basePath) {
const options = []
routes.forEach((route) => {
if (route.name && !route.isHidden) {
if (route.title && !route.isHidden) {
const curOption = {
label: (route.meta && route.meta.title) || route.name,
key: route.name,
label: (route.meta && route.meta.title) || route.title,
key: route.title,
path: resolvePath(basePath, route.path)
}
if (route.children && route.children.length) {

+ 3
- 3
src/layout/components/Tags/index.vue Ver arquivo

@@ -132,7 +132,7 @@ cacheRoutes.forEach((cacheRoute) => {
const findRoute = routes.find((route) => route.path === cacheRoute.path)
if (route) {
cacheRoute.meta = findRoute.meta || cacheRoute.meta
cacheRoute.name = (findRoute.name || cacheRoute.name)
cacheRoute.title = (findRoute.title || cacheRoute.title)
}
})

@@ -163,8 +163,8 @@ watch(
* @return { Object }
*/
function getSimpleRoute(route) {
const { fullPath, hash, meta, name, params, path, query } = route
return { fullPath, hash, meta, name, params, path, query }
const { fullPath, hash, meta, title, params, path, query } = route
return { fullPath, hash, meta, title, params, path, query }
}

/**

+ 6
- 6
src/router/routes/index.js Ver arquivo

@@ -4,7 +4,7 @@ import Home from '@/views/dashboard/index.vue'
export const basicRoutes = [
{
path: '/login',
name: 'Login',
title: 'Login',
component: () => import('@/views/login/index.vue'),
isHidden: true,
meta: {
@@ -13,16 +13,16 @@ export const basicRoutes = [
},
{
path: '/',
name: 'Dashboard',
title: '控制台',
component: Layout,
redirect: '/home',
meta: {
title: 'Dashboard'
title: '控制台'
},
children: [
{
path: 'home',
name: 'Home',
title: 'Home',
component: Home,
meta: {
title: '首页',
@@ -34,7 +34,7 @@ export const basicRoutes = [
]

export const NOT_FOUND_ROUTE = {
name: 'NOT_FOUND',
title: 'NOT_FOUND',
path: '/:pathMatch(.*)*',
redirect: '/404',
isHidden: true
@@ -42,7 +42,7 @@ export const NOT_FOUND_ROUTE = {

export const REDIRECT_ROUTE = {
path: '/redirect',
name: 'Redirect',
title: 'Redirect',
component: Layout,
meta: {
title: 'Redirect',

+ 22
- 9
src/store/modules/permission.js Ver arquivo

@@ -53,19 +53,31 @@ function dataArrayToRoutes(routes) {
const res = []
routes.forEach(item => {
const tmp = { ...item }
// 如果有component配置
if (tmp.component) {
// // 如果有component配置
// if (tmp.component) {
// // Layout引入
// if (tmp.component === 'Layout') {
// tmp.component = Layout
// } else {
// const sub_view = tmp.component.replace(/^\/*/g, '')
// const component = `../${sub_view}.vue`
// tmp.component = modules[component]
// }
// if (tmp.children) {
// tmp.children = dataArrayToRoutes(tmp.children)
// }
// }
// 如果pid为0
if (tmp.pid === 0) {
// Layout引入
if (tmp.component === 'Layout') {
tmp.component = Layout
} else {
const sub_view = tmp.component.replace(/^\/*/g, '')
const component = `../${sub_view}.vue`
tmp.component = modules[component]
}
tmp.component = Layout
if (tmp.children) {
tmp.children = dataArrayToRoutes(tmp.children)
}
} else {
const sub_view = tmp.component.replace(/^\/*/g, '')
const component = `../${sub_view}.vue`
tmp.component = modules[component]
}
res.push(tmp)
})
@@ -97,6 +109,7 @@ export const usePermissionStore = defineStore('permission', {
const res = await getMenu()
if (res.code === 0) {
const result = dataArrayToRoutes(res.data)
console.log(result)
this.accessRoutes = result
return Promise.resolve(result)
} else {

+ 2
- 2
src/views/login/index.vue Ver arquivo

@@ -13,8 +13,8 @@ export default {
async function handleLogin() {
try {
const params = {
captcha: '1',
key: '9132e06a-e2f0-4a9d-88da-b43ced72bb2e',
captcha: '520',
key: 'f2d40fb6-b946-4b99-969d-978c6d8a4ea2',
password: '123456',
remember: false,
username: 'admin'

+ 50
- 0
src/views/system/menu/components/RoleModal.vue Ver arquivo

@@ -0,0 +1,50 @@
<template>
<Modal :options="getModalOptions">
<template #Context>
111
</template>
</Modal>
</template>

<script>
import { defineComponent, reactive, computed } from 'vue'
import Modal from '@/components/Modal/index.vue'
export default defineComponent({
name: 'MenuModal',
components: { Modal },
props: {
visible: {
type: Boolean,
default: false
},
row: {
type: Object,
default: () => {}
}
},
emits: {
'update:visible': null,
onClose: null,
done: null
},
setup(props, { emit }) {
const getModalOptions = computed(() => {
return {
visible: props.visible
}
})

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

return {
getModalOptions
}
}
})
</script>
<style scoped lang='scss'>
</style>

+ 11
- 4
src/views/system/menu/index.vue Ver arquivo

@@ -3,24 +3,27 @@
<n-card>
<data-table :columns="data.columns" :pagination="false" :data="data.data" size="large">
<template #tableTitle>
<n-button type="primary">
<n-button type="primary" @click="handlleRoleAdd">
添加角色
</n-button>
</template>
</data-table>
</n-card>
</div>

<RoleModal :visible="data.modalShow" />
</template>

<script>
import dataTable from '@/components/DataTable/index.vue'
import RoleModal from './components/RoleModal.vue'
import Action from '@/components/DataTable/tools/Action.vue'
import { getMenuList } from '@/api/system/index.js'
import { h, onMounted } from 'vue'
import { reactive } from 'vue'
export default {
name: 'MenuPage',
components: { dataTable },
components: { dataTable, RoleModal },
setup() {
const data = reactive({
columns: [
@@ -118,7 +121,8 @@ export default {
],
data: [

]
],
modalShow: false
})

function play(row) {
@@ -133,12 +137,15 @@ export default {
const res = await getMenuList()
data.data = res.data
}
function handlleRoleAdd() {
data.modalShow = true
}

onMounted(() => {
fetchList()
})

return { data }
return { data, handlleRoleAdd }
}
}


+ 14
- 6
src/views/system/role/index.vue Ver arquivo

@@ -1,10 +1,10 @@
<template>
<div>
<n-card>

<headSearch :info="data.info" />
<headSearch :info="data.info" @search="handleSearch" />

<data-table
ref="tableRef"
:columns="data.columns"
:row-key="(row) => row.id"
:request="loadDataTable"
@@ -79,9 +79,17 @@ export default {
console.log(row)
}

const params = reactive({
name: 'xiaoMa'
})
const params = ref({})

const tableRef = ref()

function handleSearch(data) {
params.value = {
...data
}
console.log(params.value)
tableRef.value.reFetch({ ...unref(params) })
}

const loadDataTable = async(res) => {
const _params = {
@@ -91,7 +99,7 @@ export default {
return await getUserList(_params)
}

return { data, loadDataTable }
return { data, tableRef, loadDataTable, handleSearch }
}
}


+ 21
- 12
src/views/system/role/info.js Ver arquivo

@@ -2,19 +2,28 @@ const data = [
{
label: '角色名称',
key: 'name',
placeholder: '请输入角色名称'
},
{
label: '角色备注',
key: 'desc'
},
{
label: '角色类型',
key: 'op',
options: [{
label: 11, value: 1
}]
props: {
placeholder: '请输入角色名称'
}
}
// {
// label: '角色类型',
// type: 'select',
// key: 'op',
// props: {
// options: [{
// label: 11, value: 1
// }]
// }
// },
// {
// label: '角色类型',
// type: 'date',
// key: 'date',
// props: {
// type: 'date'
// }
// }
]

export default data

Carregando…
Cancelar
Salvar