@@ -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,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,4 +1,4 @@ | |||
import { mockAxios as request } from '@/utils/http' | |||
import { defAxios as request } from '@/utils/http' | |||
export function userLogin(data = {}) { | |||
return request({ |
@@ -1,4 +1,4 @@ | |||
import { mockAxios as request } from '@/utils/http' | |||
import { defAxios as request } from '@/utils/http' | |||
export function getMenu() { | |||
return request({ |
@@ -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 | |||
} | |||
} | |||
} |
@@ -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,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> |
@@ -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> |
@@ -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> |
@@ -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) { |
@@ -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 } | |||
} | |||
/** |
@@ -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', |
@@ -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 { |
@@ -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' |
@@ -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> |
@@ -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 } | |||
} | |||
} | |||
@@ -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 } | |||
} | |||
} | |||
@@ -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 |