mirror of
https://gitee.com/lyt-top/vue-next-admin
synced 2026-07-03 20:01:09 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2d83fd70b | |||
| 56139e72a7 | |||
| 07e0f742d8 | |||
| c09b154a3f | |||
| 6e59014357 | |||
| 02e7c49750 | |||
| 7b26cb21dd | |||
| bfecc6f6d2 | |||
| 14981044b9 | |||
| 8ed7986a96 | |||
| 852075ccfb | |||
| ba80b9bc76 | |||
| 4f8f13a722 |
23
CHANGELOG.md
23
CHANGELOG.md
@ -2,6 +2,29 @@
|
|||||||
|
|
||||||
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支)
|
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支)
|
||||||
|
|
||||||
|
## 2.4.2
|
||||||
|
|
||||||
|
`2022.12.09`
|
||||||
|
|
||||||
|
- 🌟 更新 依赖更新最新版本
|
||||||
|
- 🎉 新增 国际化自动导入文件功能,只需在 `/src/i18n/pages` 下新建文件夹定义即可
|
||||||
|
- 🎉 新增 `/make/tableDemo` 中 [搜索框展开,收缩功能,高级筛选组件 有计划做吗](https://gitee.com/lyt-top/vue-next-admin/issues/I6511L)
|
||||||
|
- 🐞 修复 [!40 开启 TagsView 缓存后,刷新后所有的路由都变成组件缓存了](https://gitee.com/lyt-top/vue-next-admin/pulls/40),感谢[@mrjimin](https://gitee.com/mrjimin)
|
||||||
|
- 🐞 修复 [!41 修复 get 请求传递嵌套对象或数组时无法正常编码问题](https://gitee.com/lyt-top/vue-next-admin/pulls/41),感谢[@随心](https://gitee.com/jiangqiang1996)
|
||||||
|
- 🐞 修复 组件 wangEditor 回显值的问题
|
||||||
|
- 🐞 修复 `/fun/echartsMap`(地理坐标/地图)、`visualizingDemo2`(数据可视化演示 2) 演示报错问题
|
||||||
|
- 🎯 优化 版本升级提示
|
||||||
|
- 🎯 优化 无权限登录时增加提示信息,[BUG:因前端加载路由(initFrontEndControlRoutes)中当前用户角色为一个陌生角色, 导致 router.beforeEach 会死循环 浏览器崩溃](https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO),感谢[@canroc](https://gitee.com/canroc)、[@随心](https://gitee.com/jiangqiang1996)
|
||||||
|
- 🌈 重构 `/views/system` 新增修改组件合并。[可以把新增修改组件合并成一个吧](https://gitee.com/lyt-top/vue-next-admin/issues/I64WES)
|
||||||
|
- 🌈 重构 图标选择器,[图标选择器没办法筛选,只能筛选 ali 的](https://gitee.com/lyt-top/vue-next-admin/issues/I64HZD),感谢[@随心](https://gitee.com/jiangqiang1996)
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
|
||||||
|
`2022.11.30`
|
||||||
|
|
||||||
|
- 🎉 新增 版本升级提示
|
||||||
|
- 🐞 修复 [先打开 F12 再登录进去,然后改变浏览器大小 js 报错](https://gitee.com/lyt-top/vue-next-admin/issues/I63ZZT),感谢[@Quber](https://gitee.com/quber)
|
||||||
|
|
||||||
## 2.4.0
|
## 2.4.0
|
||||||
|
|
||||||
`2022.11.29`
|
`2022.11.29`
|
||||||
|
|||||||
@ -43,13 +43,15 @@
|
|||||||
|
|
||||||
| Edge | Firefox | Chrome | Safari |
|
| Edge | Firefox | Chrome | Safari |
|
||||||
| --------- | ------------ | ----------- | ----------- |
|
| --------- | ------------ | ----------- | ----------- |
|
||||||
| Edge ≥ 79 | Firefox ≥ 78 | Chrome ≥ 72 | Safari ≥ 12 |
|
| Edge ≥ 88 | Firefox ≥ 78 | Chrome ≥ 87 | Safari ≥ 13 |
|
||||||
|
|
||||||
> 由于 Vue3 不再支持 IE11,故而 ElementPlus 也不支持 IE11 及之前版本。
|
> 由于 Vue3 不再支持 IE11,故而 ElementPlus 也不支持 IE11 及之前版本。
|
||||||
|
|
||||||
#### ⚡ 使用说明
|
#### ⚡ 使用说明
|
||||||
|
|
||||||
建议使用 cnpm,因为 yarn 有时会报错。<a href="http://nodejs.cn/" target="_blank">node 版本 > 12xx.xx.x</a>
|
建议使用 cnpm,因为 yarn 有时会报错。<a href="http://nodejs.cn/" target="_blank">node 版本 > 14.18+/16+</a>
|
||||||
|
|
||||||
|
> Vite 不再支持 Node 12 / 13 / 15,因为上述版本已经进入了 EOL 阶段。现在你必须使用 Node 14.18+ / 16+ 版本。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 克隆项目
|
# 克隆项目
|
||||||
|
|||||||
2952
package-lock.json
generated
2952
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-next-admin",
|
"name": "vue-next-admin",
|
||||||
"version": "2.4.0",
|
"version": "2.4.2",
|
||||||
"description": "vue3 vite next admin template",
|
"description": "vue3 vite next admin template",
|
||||||
"author": "lyt_20201208",
|
"author": "lyt_20201208",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -13,21 +13,22 @@
|
|||||||
"@element-plus/icons-vue": "^2.0.10",
|
"@element-plus/icons-vue": "^2.0.10",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"axios": "^1.2.0",
|
"axios": "^1.2.1",
|
||||||
"countup.js": "^2.3.2",
|
"countup.js": "^2.3.2",
|
||||||
"cropperjs": "^1.5.13",
|
"cropperjs": "^1.5.13",
|
||||||
"echarts": "^5.4.0",
|
"echarts": "^5.4.0",
|
||||||
"echarts-gl": "^2.0.9",
|
"echarts-gl": "^2.0.9",
|
||||||
"echarts-wordcloud": "^2.1.0",
|
"echarts-wordcloud": "^2.1.0",
|
||||||
"element-plus": "^2.2.25",
|
"element-plus": "^2.2.26",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"js-table2excel": "^1.0.3",
|
"js-table2excel": "^1.0.3",
|
||||||
"jsplumb": "^2.15.6",
|
"jsplumb": "^2.15.6",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.27",
|
"pinia": "^2.0.28",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"qrcodejs2-fixes": "^0.0.2",
|
"qrcodejs2-fixes": "^0.0.2",
|
||||||
|
"qs": "^6.11.0",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"splitpanes": "^3.1.5",
|
"splitpanes": "^3.1.5",
|
||||||
@ -38,21 +39,19 @@
|
|||||||
"vue-router": "^4.1.6"
|
"vue-router": "^4.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.11.9",
|
"@types/node": "^18.11.12",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/sortablejs": "^1.15.0",
|
"@types/sortablejs": "^1.15.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.46.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.46.0",
|
||||||
"@vitejs/plugin-vue": "^3.2.0",
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
"@vue/compiler-sfc": "^3.2.45",
|
"@vue/compiler-sfc": "^3.2.45",
|
||||||
"dotenv": "^16.0.3",
|
"eslint": "^8.29.0",
|
||||||
"eslint": "^8.28.0",
|
|
||||||
"eslint-plugin-vue": "^9.8.0",
|
"eslint-plugin-vue": "^9.8.0",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^2.8.1",
|
||||||
"sass": "^1.56.1",
|
"sass": "^1.56.2",
|
||||||
"sass-loader": "^13.2.0",
|
"typescript": "^4.9.4",
|
||||||
"typescript": "^4.9.3",
|
"vite": "^4.0.0",
|
||||||
"vite": "^3.2.4",
|
|
||||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||||
"vue-eslint-parser": "^9.1.0"
|
"vue-eslint-parser": "^9.1.0"
|
||||||
},
|
},
|
||||||
@ -65,8 +64,8 @@
|
|||||||
"url": "https://gitee.com/lyt-top/vue-next-admin/issues"
|
"url": "https://gitee.com/lyt-top/vue-next-admin/issues"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0",
|
"node": ">=16.0.0",
|
||||||
"npm": ">= 6.0.0"
|
"npm": ">= 7.0.0"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"vue",
|
"vue",
|
||||||
|
|||||||
11
src/App.vue
11
src/App.vue
@ -4,6 +4,7 @@
|
|||||||
<LockScreen v-if="themeConfig.isLockScreen" />
|
<LockScreen v-if="themeConfig.isLockScreen" />
|
||||||
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
|
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
|
||||||
<CloseFull v-if="!themeConfig.isLockScreen" />
|
<CloseFull v-if="!themeConfig.isLockScreen" />
|
||||||
|
<Upgrade v-if="getVersion" />
|
||||||
</el-config-provider>
|
</el-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ import setIntroduction from '/@/utils/setIconfont';
|
|||||||
const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
|
const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
|
||||||
const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
|
const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
|
||||||
const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
|
const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
|
||||||
|
const Upgrade = defineAsyncComponent(() => import('/@/layout/upgrade/index.vue'));
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const { messages, locale } = useI18n();
|
const { messages, locale } = useI18n();
|
||||||
@ -32,6 +34,15 @@ const stores = useTagsViewRoutes();
|
|||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
|
|
||||||
|
// 获取版本号
|
||||||
|
const getVersion = computed(() => {
|
||||||
|
let isVersion = false;
|
||||||
|
if (route.path !== '/login') {
|
||||||
|
// @ts-ignore
|
||||||
|
if ((Local.get('version') && Local.get('version') !== __VERSION__) || !Local.get('version')) isVersion = true;
|
||||||
|
}
|
||||||
|
return isVersion;
|
||||||
|
});
|
||||||
// 获取全局组件大小
|
// 获取全局组件大小
|
||||||
const getGlobalComponentSize = computed(() => {
|
const getGlobalComponentSize = computed(() => {
|
||||||
return other.globalComponentSize();
|
return other.globalComponentSize();
|
||||||
|
|||||||
@ -1,17 +1,27 @@
|
|||||||
import request from '/@/utils/request';
|
import request from '/@/utils/request';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
|
||||||
|
*
|
||||||
* 登录api接口集合
|
* 登录api接口集合
|
||||||
* @method signIn 用户登录
|
* @method signIn 用户登录
|
||||||
* @method signOut 用户退出登录
|
* @method signOut 用户退出登录
|
||||||
*/
|
*/
|
||||||
export function useLoginApi() {
|
export function useLoginApi() {
|
||||||
return {
|
return {
|
||||||
signIn: (params: object) => {
|
signIn: (data: object) => {
|
||||||
return request.post('/user/signIn', params);
|
return request({
|
||||||
|
url: '/user/signIn',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
signOut: (params: object) => {
|
signOut: (data: object) => {
|
||||||
return request.post('/user/signOut', params);
|
return request({
|
||||||
|
url: '/user/signOut',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import request from '/@/utils/request';
|
|||||||
/**
|
/**
|
||||||
* 以下为模拟接口地址,gitee 的不通,就换自己的真实接口地址
|
* 以下为模拟接口地址,gitee 的不通,就换自己的真实接口地址
|
||||||
*
|
*
|
||||||
|
* (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
|
||||||
|
*
|
||||||
* 后端控制菜单模拟json,路径在 https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu
|
* 后端控制菜单模拟json,路径在 https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu
|
||||||
* 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
* 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||||
* @method getAdminMenu 获取后端动态路由菜单(admin)
|
* @method getAdminMenu 获取后端动态路由菜单(admin)
|
||||||
@ -11,10 +13,18 @@ import request from '/@/utils/request';
|
|||||||
export function useMenuApi() {
|
export function useMenuApi() {
|
||||||
return {
|
return {
|
||||||
getAdminMenu: (params?: object) => {
|
getAdminMenu: (params?: object) => {
|
||||||
return request.get('/gitee/lyt-top/vue-next-admin-images/raw/master/menu/adminMenu.json', params);
|
return request({
|
||||||
|
url: '/gitee/lyt-top/vue-next-admin-images/raw/master/menu/adminMenu.json',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getTestMenu: (params?: object) => {
|
getTestMenu: (params?: object) => {
|
||||||
return request.get('/gitee/lyt-top/vue-next-admin-images/raw/master/menu/testMenu.json', params);
|
return request({
|
||||||
|
url: '/gitee/lyt-top/vue-next-admin-images/raw/master/menu/testMenu.json',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,4 +88,14 @@ watch(
|
|||||||
deep: true,
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// 监听双向绑定值改变,用于回显
|
||||||
|
watch(
|
||||||
|
() => props.getHtml,
|
||||||
|
(val) => {
|
||||||
|
state.editorVal = val;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,67 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="icon-selector w100 h100">
|
<div class="icon-selector w100 h100">
|
||||||
|
<el-input
|
||||||
|
v-model="state.fontIconSearch"
|
||||||
|
:placeholder="state.fontIconPlaceholder"
|
||||||
|
:clearable="clearable"
|
||||||
|
:disabled="disabled"
|
||||||
|
:size="size"
|
||||||
|
ref="inputWidthRef"
|
||||||
|
@clear="onClearFontIcon"
|
||||||
|
@focus="onIconFocus"
|
||||||
|
@blur="onIconBlur"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<SvgIcon
|
||||||
|
:name="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix"
|
||||||
|
class="font14"
|
||||||
|
v-if="state.fontIconPrefix === '' ? prepend?.indexOf('ele-') > -1 : state.fontIconPrefix?.indexOf('ele-') > -1"
|
||||||
|
/>
|
||||||
|
<i v-else :class="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix" class="font14"></i>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
<el-popover
|
<el-popover
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
:width="state.fontIconWidth"
|
:width="state.fontIconWidth"
|
||||||
trigger="click"
|
|
||||||
transition="el-zoom-in-top"
|
transition="el-zoom-in-top"
|
||||||
popper-class="icon-selector-popper"
|
popper-class="icon-selector-popper"
|
||||||
@show="onPopoverShow"
|
trigger="click"
|
||||||
|
:virtual-ref="inputWidthRef"
|
||||||
|
virtual-triggering
|
||||||
>
|
>
|
||||||
<template #reference>
|
|
||||||
<el-input
|
|
||||||
v-model="state.fontIconSearch"
|
|
||||||
:placeholder="state.fontIconPlaceholder"
|
|
||||||
:clearable="clearable"
|
|
||||||
:disabled="disabled"
|
|
||||||
:size="size"
|
|
||||||
ref="inputWidthRef"
|
|
||||||
@clear="onClearFontIcon"
|
|
||||||
@focus="onIconFocus"
|
|
||||||
@blur="onIconBlur"
|
|
||||||
>
|
|
||||||
<template #prepend>
|
|
||||||
<SvgIcon
|
|
||||||
:name="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix"
|
|
||||||
class="font14"
|
|
||||||
v-if="state.fontIconPrefix === '' ? prepend?.indexOf('ele-') > -1 : state.fontIconPrefix?.indexOf('ele-') > -1"
|
|
||||||
/>
|
|
||||||
<i v-else :class="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix" class="font14"></i>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="icon-selector-warp">
|
<div class="icon-selector-warp">
|
||||||
<div class="icon-selector-warp-title flex">
|
<div class="icon-selector-warp-title">{{ title }}</div>
|
||||||
<div class="flex-auto">{{ title }}</div>
|
<el-tabs v-model="state.fontIconTabActive" @tab-click="onIconClick">
|
||||||
<div class="icon-selector-warp-title-tab" v-if="type === 'all'">
|
<el-tab-pane lazy label="ali" name="ali">
|
||||||
<span :class="{ 'span-active': state.fontIconType === 'ali' }" @click="onIconChange('ali')" class="ml10" title="iconfont 图标">
|
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
|
||||||
ali
|
</el-tab-pane>
|
||||||
</span>
|
<el-tab-pane lazy label="ele" name="ele">
|
||||||
<span :class="{ 'span-active': state.fontIconType === 'ele' }" @click="onIconChange('ele')" class="ml10" title="elementPlus 图标">
|
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
|
||||||
ele
|
</el-tab-pane>
|
||||||
</span>
|
<el-tab-pane lazy label="awe" name="awe">
|
||||||
<span :class="{ 'span-active': state.fontIconType === 'awe' }" @click="onIconChange('awe')" class="ml10" title="fontawesome 图标">
|
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
|
||||||
awe
|
</el-tab-pane>
|
||||||
</span>
|
</el-tabs>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="icon-selector-warp-row">
|
|
||||||
<el-scrollbar ref="selectorScrollbarRef">
|
|
||||||
<el-row :gutter="10" v-if="fontIconSheetsFilterList.length > 0">
|
|
||||||
<el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" @click="onColClick(v)" v-for="(v, k) in fontIconSheetsFilterList" :key="k">
|
|
||||||
<div class="icon-selector-warp-item" :class="{ 'icon-selector-active': state.fontIconPrefix === v }">
|
|
||||||
<div class="flex-margin">
|
|
||||||
<div class="icon-selector-warp-item-value">
|
|
||||||
<SvgIcon :name="v" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0" :description="emptyDescription"></el-empty>
|
|
||||||
</el-scrollbar>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
@ -69,8 +50,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="iconSelector">
|
<script setup lang="ts" name="iconSelector">
|
||||||
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
import { defineAsyncComponent, ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
||||||
|
import type { TabsPaneContext } from 'element-plus';
|
||||||
import initIconfont from '/@/utils/getStyleSheets';
|
import initIconfont from '/@/utils/getStyleSheets';
|
||||||
|
import '/@/theme/iconSelector.scss';
|
||||||
|
|
||||||
// 定义父组件传过来的值
|
// 定义父组件传过来的值
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -94,11 +77,6 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: () => '请选择图标',
|
default: () => '请选择图标',
|
||||||
},
|
},
|
||||||
// icon 图标类型
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: () => 'ele',
|
|
||||||
},
|
|
||||||
// 禁用
|
// 禁用
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -123,18 +101,22 @@ const props = defineProps({
|
|||||||
// 定义子组件向父组件传值/事件
|
// 定义子组件向父组件传值/事件
|
||||||
const emit = defineEmits(['update:modelValue', 'get', 'clear']);
|
const emit = defineEmits(['update:modelValue', 'get', 'clear']);
|
||||||
|
|
||||||
|
// 引入组件
|
||||||
|
const IconList = defineAsyncComponent(() => import('/@/components/iconSelector/list.vue'));
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const inputWidthRef = ref();
|
const inputWidthRef = ref();
|
||||||
const selectorScrollbarRef = ref();
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
fontIconPrefix: '',
|
fontIconPrefix: '',
|
||||||
fontIconWidth: 0,
|
fontIconWidth: 0,
|
||||||
fontIconSearch: '',
|
fontIconSearch: '',
|
||||||
fontIconTabsIndex: 0,
|
|
||||||
fontIconSheetsList: [],
|
|
||||||
fontIconPlaceholder: '',
|
fontIconPlaceholder: '',
|
||||||
fontIconType: 'ali',
|
fontIconTabActive: 'ali',
|
||||||
fontIconShow: true,
|
fontIconList: {
|
||||||
|
ali: [],
|
||||||
|
ele: [],
|
||||||
|
awe: [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理 input 获取焦点时,modelValue 有值时,改变 input 的 placeholder 值
|
// 处理 input 获取焦点时,modelValue 有值时,改变 input 的 placeholder 值
|
||||||
@ -145,32 +127,91 @@ const onIconFocus = () => {
|
|||||||
};
|
};
|
||||||
// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
|
// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
|
||||||
const onIconBlur = () => {
|
const onIconBlur = () => {
|
||||||
|
const list = fontIconTabNameList();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const icon = state.fontIconSheetsList.filter((icon: string) => icon === state.fontIconSearch);
|
const icon = list.filter((icon: string) => icon === state.fontIconSearch);
|
||||||
if (icon.length <= 0) state.fontIconSearch = '';
|
if (icon.length <= 0) state.fontIconSearch = '';
|
||||||
}, 300);
|
}, 300);
|
||||||
};
|
};
|
||||||
|
// 图标搜索及图标数据显示
|
||||||
|
const fontIconSheetsFilterList = computed(() => {
|
||||||
|
const list = fontIconTabNameList();
|
||||||
|
if (!state.fontIconSearch) return list;
|
||||||
|
let search = state.fontIconSearch.trim().toLowerCase();
|
||||||
|
return list.filter((item: string) => {
|
||||||
|
if (item.toLowerCase().indexOf(search) !== -1) return item;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 根据 tab name 类型设置图标
|
||||||
|
const fontIconTabNameList = () => {
|
||||||
|
let iconList: any = [];
|
||||||
|
if (state.fontIconTabActive === 'ali') iconList = state.fontIconList.ali;
|
||||||
|
else if (state.fontIconTabActive === 'ele') iconList = state.fontIconList.ele;
|
||||||
|
else if (state.fontIconTabActive === 'awe') iconList = state.fontIconList.awe;
|
||||||
|
return iconList;
|
||||||
|
};
|
||||||
// 处理 icon 双向绑定数值回显
|
// 处理 icon 双向绑定数值回显
|
||||||
const initModeValueEcho = () => {
|
const initModeValueEcho = () => {
|
||||||
if (props.modelValue === '') return ((<string | undefined>state.fontIconPlaceholder) = props.placeholder);
|
if (props.modelValue === '') return ((<string | undefined>state.fontIconPlaceholder) = props.placeholder);
|
||||||
(<string | undefined>state.fontIconPlaceholder) = props.modelValue;
|
(<string | undefined>state.fontIconPlaceholder) = props.modelValue;
|
||||||
(<string | undefined>state.fontIconPrefix) = props.modelValue;
|
(<string | undefined>state.fontIconPrefix) = props.modelValue;
|
||||||
};
|
};
|
||||||
// 处理 icon type 类型为 all 时,类型 ali、ele、awe 回显问题
|
// 处理 icon 类型,用于回显时,tab 高亮与初始化数据
|
||||||
const initFontIconTypeEcho = () => {
|
const initFontIconName = () => {
|
||||||
if (props.modelValue!.indexOf('iconfont') > -1) onIconChange('ali');
|
let name = 'ali';
|
||||||
else if (props.modelValue!.indexOf('ele-') > -1) onIconChange('ele');
|
if (props.modelValue!.indexOf('iconfont') > -1) name = 'ali';
|
||||||
else if (props.modelValue!.indexOf('fa') > -1) onIconChange('awe');
|
else if (props.modelValue!.indexOf('ele-') > -1) name = 'ele';
|
||||||
else onIconChange('ali');
|
else if (props.modelValue!.indexOf('fa') > -1) name = 'awe';
|
||||||
|
// 初始化 tab 高亮回显
|
||||||
|
state.fontIconTabActive = name;
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
// 初始化数据
|
||||||
|
const initFontIconData = async (name: string) => {
|
||||||
|
if (name === 'ali') {
|
||||||
|
// 阿里字体图标使用 `iconfont xxx`
|
||||||
|
if (state.fontIconList.ali.length > 0) return;
|
||||||
|
await initIconfont.ali().then((res: any) => {
|
||||||
|
state.fontIconList.ali = res.map((i: string) => `iconfont ${i}`);
|
||||||
|
});
|
||||||
|
} else if (name === 'ele') {
|
||||||
|
// element plus 图标
|
||||||
|
if (state.fontIconList.ele.length > 0) return;
|
||||||
|
await initIconfont.ele().then((res: any) => {
|
||||||
|
state.fontIconList.ele = res;
|
||||||
|
});
|
||||||
|
} else if (name === 'awe') {
|
||||||
|
// fontawesome字体图标使用 `fa xxx`
|
||||||
|
if (state.fontIconList.awe.length > 0) return;
|
||||||
|
await initIconfont.awe().then((res: any) => {
|
||||||
|
state.fontIconList.awe = res.map((i: string) => `fa ${i}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 初始化 input 的 placeholder
|
||||||
|
// 参考(单项数据流):https://cn.vuejs.org/v2/guide/components-props.html?#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81
|
||||||
|
state.fontIconPlaceholder = props.placeholder;
|
||||||
|
// 初始化双向绑定回显
|
||||||
|
initModeValueEcho();
|
||||||
|
};
|
||||||
|
// 图标点击切换
|
||||||
|
const onIconClick = (pane: TabsPaneContext) => {
|
||||||
|
initFontIconData(pane.paneName as string);
|
||||||
|
inputWidthRef.value.focus();
|
||||||
|
};
|
||||||
|
// 获取当前点击的 icon 图标
|
||||||
|
const onColClick = (v: string) => {
|
||||||
|
state.fontIconPlaceholder = v;
|
||||||
|
state.fontIconPrefix = v;
|
||||||
|
emit('get', state.fontIconPrefix);
|
||||||
|
emit('update:modelValue', state.fontIconPrefix);
|
||||||
|
inputWidthRef.value.focus();
|
||||||
|
};
|
||||||
|
// 清空当前点击的 icon 图标
|
||||||
|
const onClearFontIcon = () => {
|
||||||
|
state.fontIconPrefix = '';
|
||||||
|
emit('clear', state.fontIconPrefix);
|
||||||
|
emit('update:modelValue', state.fontIconPrefix);
|
||||||
};
|
};
|
||||||
// 图标搜索及图标数据显示
|
|
||||||
const fontIconSheetsFilterList = computed(() => {
|
|
||||||
if (!state.fontIconSearch) return state.fontIconSheetsList;
|
|
||||||
let search = state.fontIconSearch.trim().toLowerCase();
|
|
||||||
return state.fontIconSheetsList.filter((item: string) => {
|
|
||||||
if (item.toLowerCase().indexOf(search) !== -1) return item;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// 获取 input 的宽度
|
// 获取 input 的宽度
|
||||||
const getInputWidth = () => {
|
const getInputWidth = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -183,56 +224,9 @@ const initResize = () => {
|
|||||||
getInputWidth();
|
getInputWidth();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 初始化数据
|
|
||||||
const initFontIconData = async (type: string) => {
|
|
||||||
state.fontIconSheetsList = [];
|
|
||||||
if (type === 'ali') {
|
|
||||||
await initIconfont.ali().then((res: any) => {
|
|
||||||
// 阿里字体图标使用 `iconfont xxx`
|
|
||||||
state.fontIconSheetsList = res.map((i: string) => `iconfont ${i}`);
|
|
||||||
});
|
|
||||||
} else if (type === 'ele') {
|
|
||||||
await initIconfont.ele().then((res: any) => {
|
|
||||||
state.fontIconSheetsList = res;
|
|
||||||
});
|
|
||||||
} else if (type === 'awe') {
|
|
||||||
await initIconfont.awe().then((res: any) => {
|
|
||||||
// fontawesome字体图标使用 `fa xxx`
|
|
||||||
state.fontIconSheetsList = res.map((i: string) => `fa ${i}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 初始化 input 的 placeholder
|
|
||||||
// 参考(单项数据流):https://cn.vuejs.org/v2/guide/components-props.html?#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81
|
|
||||||
state.fontIconPlaceholder = props.placeholder;
|
|
||||||
// 初始化双向绑定回显
|
|
||||||
initModeValueEcho();
|
|
||||||
};
|
|
||||||
// 图标点击切换
|
|
||||||
const onIconChange = (type: string) => {
|
|
||||||
state.fontIconType = type;
|
|
||||||
initFontIconData(type);
|
|
||||||
};
|
|
||||||
// 获取当前点击的 icon 图标
|
|
||||||
const onColClick = (v: string) => {
|
|
||||||
state.fontIconPlaceholder = v;
|
|
||||||
state.fontIconPrefix = v;
|
|
||||||
emit('get', state.fontIconPrefix);
|
|
||||||
emit('update:modelValue', state.fontIconPrefix);
|
|
||||||
};
|
|
||||||
// 清空当前点击的 icon 图标
|
|
||||||
const onClearFontIcon = () => {
|
|
||||||
state.fontIconPrefix = '';
|
|
||||||
emit('clear', state.fontIconPrefix);
|
|
||||||
emit('update:modelValue', state.fontIconPrefix);
|
|
||||||
};
|
|
||||||
// 监听 Popover 打开,用于双向绑定值回显
|
|
||||||
const onPopoverShow = () => {
|
|
||||||
initModeValueEcho();
|
|
||||||
initFontIconTypeEcho();
|
|
||||||
};
|
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initModeValueEcho();
|
initFontIconData(initFontIconName());
|
||||||
initResize();
|
initResize();
|
||||||
getInputWidth();
|
getInputWidth();
|
||||||
});
|
});
|
||||||
@ -241,6 +235,7 @@ watch(
|
|||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
() => {
|
() => {
|
||||||
initModeValueEcho();
|
initModeValueEcho();
|
||||||
|
initFontIconName();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
84
src/components/iconSelector/list.vue
Normal file
84
src/components/iconSelector/list.vue
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<div class="icon-selector-warp-row">
|
||||||
|
<el-scrollbar ref="selectorScrollbarRef">
|
||||||
|
<el-row :gutter="10" v-if="props.list.length > 0">
|
||||||
|
<el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" v-for="(v, k) in list" :key="k" @click="onColClick(v)">
|
||||||
|
<div class="icon-selector-warp-item" :class="{ 'icon-selector-active': prefix === v }">
|
||||||
|
<SvgIcon :name="v" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-empty :image-size="100" v-if="list.length <= 0" :description="empty"></el-empty>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="iconSelectorList">
|
||||||
|
// 定义父组件传过来的值
|
||||||
|
const props = defineProps({
|
||||||
|
// 图标列表数据
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
// 自定义空状态描述文字
|
||||||
|
empty: {
|
||||||
|
type: String,
|
||||||
|
default: () => '无相关图标',
|
||||||
|
},
|
||||||
|
// 高亮当前选中图标
|
||||||
|
prefix: {
|
||||||
|
type: String,
|
||||||
|
default: () => '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['get-icon']);
|
||||||
|
|
||||||
|
// 当前 icon 图标点击时
|
||||||
|
const onColClick = (v: unknown | string) => {
|
||||||
|
emit('get-icon', v);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.icon-selector-warp-row {
|
||||||
|
height: 230px;
|
||||||
|
overflow: hidden;
|
||||||
|
.el-row {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
.el-scrollbar__bar.is-horizontal {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.icon-selector-warp-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
height: 30px;
|
||||||
|
i {
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--el-color-primary-light-9);
|
||||||
|
border: 1px solid var(--el-color-primary-light-5);
|
||||||
|
i {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon-selector-active {
|
||||||
|
background-color: var(--el-color-primary-light-9);
|
||||||
|
border: 1px solid var(--el-color-primary-light-5);
|
||||||
|
i {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -21,7 +21,7 @@
|
|||||||
:label="item.title"
|
:label="item.title"
|
||||||
>
|
>
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<template v-if="item.key === 'image'">
|
<template v-if="item.type === 'image'">
|
||||||
<img :src="scope.row[item.key]" :width="item.width" :height="item.height" />
|
<img :src="scope.row[item.key]" :width="item.width" :height="item.height" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@ -119,11 +119,6 @@ const props = defineProps({
|
|||||||
type: Array<EmptyObjectType>,
|
type: Array<EmptyObjectType>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
// 搜索参数
|
|
||||||
param: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
// 配置项
|
// 配置项
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -161,7 +156,7 @@ const setHeader = computed(() => {
|
|||||||
return props.header.filter((v) => v.isCheck);
|
return props.header.filter((v) => v.isCheck);
|
||||||
});
|
});
|
||||||
// tool 列显示全选改变时
|
// tool 列显示全选改变时
|
||||||
const onCheckAllChange = (val: boolean) => {
|
const onCheckAllChange = <T>(val: T) => {
|
||||||
if (val) props.header.forEach((v) => (v.isCheck = true));
|
if (val) props.header.forEach((v) => (v.isCheck = true));
|
||||||
else props.header.forEach((v) => (v.isCheck = false));
|
else props.header.forEach((v) => (v.isCheck = false));
|
||||||
state.checkListIndeterminate = false;
|
state.checkListIndeterminate = false;
|
||||||
|
|||||||
@ -2,53 +2,53 @@ import { createI18n } from 'vue-i18n';
|
|||||||
import pinia from '/@/stores/index';
|
import pinia from '/@/stores/index';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import zhcnLocale from 'element-plus/lib/locale/lang/zh-cn';
|
|
||||||
import enLocale from 'element-plus/lib/locale/lang/en';
|
|
||||||
import zhtwLocale from 'element-plus/lib/locale/lang/zh-tw';
|
|
||||||
|
|
||||||
import nextZhcn from '/@/i18n/lang/zh-cn';
|
|
||||||
import nextEn from '/@/i18n/lang/en';
|
|
||||||
import nextZhtw from '/@/i18n/lang/zh-tw';
|
|
||||||
|
|
||||||
import pagesLoginZhcn from '/@/i18n/pages/login/zh-cn';
|
|
||||||
import pagesLoginEn from '/@/i18n/pages/login/en';
|
|
||||||
import pagesLoginZhtw from '/@/i18n/pages/login/zh-tw';
|
|
||||||
import pagesFormI18nZhcn from '/@/i18n/pages/formI18n/zh-cn';
|
|
||||||
import pagesFormI18nEn from '/@/i18n/pages/formI18n/en';
|
|
||||||
import pagesFormI18nZhtw from '/@/i18n/pages/formI18n/zh-tw';
|
|
||||||
|
|
||||||
// 定义语言国际化内容
|
// 定义语言国际化内容
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 说明:
|
* 说明:
|
||||||
* /src/i18n/lang 下的 ts 为框架的国际化内容
|
* 须在 pages 下新建文件夹(建议 `要国际化界面目录` 与 `i18 目录` 相同,方便查找),
|
||||||
* /src/i18n/pages 下的 ts 为各界面的国际化内容
|
* 注意国际化定义的字段,不要与原有的定义字段相同。
|
||||||
|
* 1、/src/i18n/lang 下的 ts 为框架的国际化内容
|
||||||
|
* 2、/src/i18n/pages 下的 ts 为各界面的国际化内容
|
||||||
*/
|
*/
|
||||||
const messages = {
|
|
||||||
[zhcnLocale.name]: {
|
// element plus 自带国际化
|
||||||
...zhcnLocale,
|
import enLocale from 'element-plus/lib/locale/lang/en';
|
||||||
message: {
|
import zhcnLocale from 'element-plus/lib/locale/lang/zh-cn';
|
||||||
...nextZhcn,
|
import zhtwLocale from 'element-plus/lib/locale/lang/zh-tw';
|
||||||
...pagesLoginZhcn,
|
|
||||||
...pagesFormI18nZhcn,
|
// 定义变量内容
|
||||||
},
|
const messages = {};
|
||||||
},
|
const element = { en: enLocale, 'zh-cn': zhcnLocale, 'zh-tw': zhtwLocale };
|
||||||
[enLocale.name]: {
|
const itemize = { en: [], 'zh-cn': [], 'zh-tw': [] };
|
||||||
...enLocale,
|
const modules: Record<string, any> = import.meta.glob('./**/*.ts', { eager: true });
|
||||||
message: {
|
|
||||||
...nextEn,
|
// 对自动引入的 modules 进行分类 en、zh-cn、zh-tw
|
||||||
...pagesLoginEn,
|
// https://vitejs.cn/vite3-cn/guide/features.html#glob-import
|
||||||
...pagesFormI18nEn,
|
for (const path in modules) {
|
||||||
},
|
const key = path.match(/(\S+)\/(\S+).ts/);
|
||||||
},
|
if (itemize[key![2]]) itemize[key![2]].push(modules[path].default);
|
||||||
[zhtwLocale.name]: {
|
else itemize[key![2]] = modules[path];
|
||||||
...zhtwLocale,
|
}
|
||||||
message: {
|
|
||||||
...nextZhtw,
|
// 合并数组对象(非标准数组对象,数组中对象的每项 key、value 都不同)
|
||||||
...pagesLoginZhtw,
|
function mergeArrObj<T>(list: T, key: string) {
|
||||||
...pagesFormI18nZhtw,
|
let obj = {};
|
||||||
},
|
list[key].forEach((i: EmptyObjectType) => {
|
||||||
},
|
obj = Object.assign({}, obj, i);
|
||||||
};
|
});
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理最终格式
|
||||||
|
for (const key in itemize) {
|
||||||
|
messages[key] = {
|
||||||
|
name: key,
|
||||||
|
el: element[key].el,
|
||||||
|
message: mergeArrObj(itemize, key),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 读取 pinia 默认语言
|
// 读取 pinia 默认语言
|
||||||
const stores = useThemeConfig(pinia);
|
const stores = useThemeConfig(pinia);
|
||||||
|
|||||||
@ -180,4 +180,12 @@ export default {
|
|||||||
copyTextSuccess: 'Copy succeeded!',
|
copyTextSuccess: 'Copy succeeded!',
|
||||||
copyTextError: 'Copy failed!',
|
copyTextError: 'Copy failed!',
|
||||||
},
|
},
|
||||||
|
upgrade: {
|
||||||
|
title: 'New version',
|
||||||
|
msg: 'The new version is available, please update it now! Dont worry, the update is fast!',
|
||||||
|
desc: 'Prompt: Update will restore the default configuration',
|
||||||
|
btnOne: 'Cruel refusal',
|
||||||
|
btnTwo: 'Update now',
|
||||||
|
btnTwoLoading: 'Updating',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -180,4 +180,12 @@ export default {
|
|||||||
copyTextSuccess: '复制成功!',
|
copyTextSuccess: '复制成功!',
|
||||||
copyTextError: '复制失败!',
|
copyTextError: '复制失败!',
|
||||||
},
|
},
|
||||||
|
upgrade: {
|
||||||
|
title: '新版本升级',
|
||||||
|
msg: '新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!',
|
||||||
|
desc: '提示:更新会还原默认配置',
|
||||||
|
btnOne: '残忍拒绝',
|
||||||
|
btnTwo: '马上更新',
|
||||||
|
btnTwoLoading: '更新中',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -180,4 +180,12 @@ export default {
|
|||||||
copyTextSuccess: '複製成功!',
|
copyTextSuccess: '複製成功!',
|
||||||
copyTextError: '複製失敗!',
|
copyTextError: '複製失敗!',
|
||||||
},
|
},
|
||||||
|
upgrade: {
|
||||||
|
title: '新版本陞級',
|
||||||
|
msg: '新版本來啦,馬上更新嘗鮮吧! 不用擔心,更新很快的哦!',
|
||||||
|
desc: '提示:更新會還原默認配寘',
|
||||||
|
btnOne: '殘忍拒絕',
|
||||||
|
btnTwo: '馬上更新',
|
||||||
|
btnTwoLoading: '更新中',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -619,6 +619,8 @@ const onCopyConfigClick = () => {
|
|||||||
const onResetConfigClick = () => {
|
const onResetConfigClick = () => {
|
||||||
Local.clear();
|
Local.clear();
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
// @ts-ignore
|
||||||
|
Local.set('version', __VERSION__);
|
||||||
};
|
};
|
||||||
// 初始化菜单样式等
|
// 初始化菜单样式等
|
||||||
const initSetStyle = () => {
|
const initSetStyle = () => {
|
||||||
|
|||||||
@ -80,9 +80,13 @@ onMounted(() => {
|
|||||||
getIframeListRoutes();
|
getIframeListRoutes();
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I58U75
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I58U75
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK
|
||||||
|
// https://gitee.com/lyt-top/vue-next-admin/pulls/40
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (themeConfig.value.isCacheTagsView) cachedViews.value = Session.get('tagsViewList')?.map((item: RouteItem) => item.name);
|
if (themeConfig.value.isCacheTagsView) {
|
||||||
|
let tagsViewArr: RouteItem[] = Session.get('tagsViewList') || [];
|
||||||
|
cachedViews.value = tagsViewArr.filter((item) => item.meta?.isKeepAlive).map((item) => item.name as string);
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
151
src/layout/upgrade/index.vue
Normal file
151
src/layout/upgrade/index.vue
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<template>
|
||||||
|
<div class="upgrade-dialog">
|
||||||
|
<el-dialog
|
||||||
|
v-model="state.isUpgrade"
|
||||||
|
width="300px"
|
||||||
|
destroy-on-close
|
||||||
|
:show-close="false"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
|
<div class="upgrade-title">
|
||||||
|
<div class="upgrade-title-warp">
|
||||||
|
<span class="upgrade-title-warp-txt">{{ $t('message.upgrade.title') }}</span>
|
||||||
|
<span class="upgrade-title-warp-version">v{{ state.version }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="upgrade-content">
|
||||||
|
{{ getThemeConfig.globalTitle }} {{ $t('message.upgrade.msg') }}
|
||||||
|
<div class="mt5">
|
||||||
|
<el-link type="primary" class="font12" href="https://gitee.com/lyt-top/vue-next-admin/blob/master/CHANGELOG.md" target="_black">
|
||||||
|
CHANGELOG.md
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
|
<div class="upgrade-content-desc mt5">{{ $t('message.upgrade.desc') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="upgrade-btn">
|
||||||
|
<el-button round size="default" type="info" text @click="onCancel">{{ $t('message.upgrade.btnOne') }}</el-button>
|
||||||
|
<el-button type="primary" round size="default" @click="onUpgrade" :loading="state.isLoading">{{ state.btnTxt }}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="layoutUpgrade">
|
||||||
|
import { reactive, computed, onMounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
|
import { Local } from '/@/utils/storage';
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
|
const { t } = useI18n();
|
||||||
|
const storesThemeConfig = useThemeConfig();
|
||||||
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
|
const state = reactive({
|
||||||
|
isUpgrade: false,
|
||||||
|
// @ts-ignore
|
||||||
|
version: __VERSION__,
|
||||||
|
isLoading: false,
|
||||||
|
btnTxt: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取布局配置信息
|
||||||
|
const getThemeConfig = computed(() => {
|
||||||
|
return themeConfig.value;
|
||||||
|
});
|
||||||
|
// 残忍拒绝
|
||||||
|
const onCancel = () => {
|
||||||
|
state.isUpgrade = false;
|
||||||
|
};
|
||||||
|
// 马上更新
|
||||||
|
const onUpgrade = () => {
|
||||||
|
state.isLoading = true;
|
||||||
|
state.btnTxt = t('message.upgrade.btnTwoLoading');
|
||||||
|
setTimeout(() => {
|
||||||
|
Local.clear();
|
||||||
|
window.location.reload();
|
||||||
|
Local.set('version', state.version);
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
// 延迟显示,防止刷新时界面显示太快
|
||||||
|
const delayShow = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
state.isUpgrade = true;
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
delayShow();
|
||||||
|
setTimeout(() => {
|
||||||
|
state.btnTxt = t('message.upgrade.btnTwo');
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.upgrade-dialog {
|
||||||
|
:deep(.el-dialog) {
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.el-dialog__header {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.upgrade-title {
|
||||||
|
text-align: center;
|
||||||
|
height: 130px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--el-color-primary-light-1);
|
||||||
|
width: 130%;
|
||||||
|
height: 130px;
|
||||||
|
border-bottom-left-radius: 100%;
|
||||||
|
border-bottom-right-radius: 100%;
|
||||||
|
}
|
||||||
|
.upgrade-title-warp {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
.upgrade-title-warp-txt {
|
||||||
|
color: var(--next-color-white);
|
||||||
|
font-size: 22px;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
}
|
||||||
|
.upgrade-title-warp-version {
|
||||||
|
color: var(--next-color-white);
|
||||||
|
background-color: var(--el-color-primary-light-4);
|
||||||
|
font-size: 12px;
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
top: -2px;
|
||||||
|
right: -50px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.upgrade-content {
|
||||||
|
padding: 20px;
|
||||||
|
line-height: 22px;
|
||||||
|
.upgrade-content-desc {
|
||||||
|
color: var(--el-color-info-light-5);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.upgrade-btn {
|
||||||
|
border-top: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 15px 20px;
|
||||||
|
.el-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -43,6 +43,9 @@ export async function initBackEndControlRoutes() {
|
|||||||
await useUserInfo().setUserInfos();
|
await useUserInfo().setUserInfos();
|
||||||
// 获取路由菜单数据
|
// 获取路由菜单数据
|
||||||
const res = await getBackEndControlRoutes();
|
const res = await getBackEndControlRoutes();
|
||||||
|
// 无登录权限时,添加判断
|
||||||
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
|
||||||
|
if (res.data.length <= 0) return Promise.resolve(true);
|
||||||
// 存储接口原始路由(未处理component),根据需求选择使用
|
// 存储接口原始路由(未处理component),根据需求选择使用
|
||||||
useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data)));
|
useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data)));
|
||||||
// 处理路由(component),替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
|
// 处理路由(component),替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
|
||||||
@ -58,7 +61,7 @@ export async function initBackEndControlRoutes() {
|
|||||||
* @description 用于左侧菜单、横向菜单的显示
|
* @description 用于左侧菜单、横向菜单的显示
|
||||||
* @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
|
* @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
|
||||||
*/
|
*/
|
||||||
export function setFilterMenuAndCacheTagsViewRoutes() {
|
export async function setFilterMenuAndCacheTagsViewRoutes() {
|
||||||
const storesRoutesList = useRoutesList(pinia);
|
const storesRoutesList = useRoutesList(pinia);
|
||||||
storesRoutesList.setRoutesList(dynamicRoutes[0].children as any);
|
storesRoutesList.setRoutesList(dynamicRoutes[0].children as any);
|
||||||
setCacheTagsViewRoutes();
|
setCacheTagsViewRoutes();
|
||||||
@ -119,8 +122,8 @@ export function getBackEndControlRoutes() {
|
|||||||
* @description 用于菜单管理界面刷新菜单(未进行测试)
|
* @description 用于菜单管理界面刷新菜单(未进行测试)
|
||||||
* @description 路径:/src/views/system/menu/component/addMenu.vue
|
* @description 路径:/src/views/system/menu/component/addMenu.vue
|
||||||
*/
|
*/
|
||||||
export function setBackEndControlRefreshRoutes() {
|
export async function setBackEndControlRefreshRoutes() {
|
||||||
getBackEndControlRoutes();
|
await getBackEndControlRoutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -26,6 +26,9 @@ export async function initFrontEndControlRoutes() {
|
|||||||
// 触发初始化用户信息 pinia
|
// 触发初始化用户信息 pinia
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
||||||
await useUserInfo(pinia).setUserInfos();
|
await useUserInfo(pinia).setUserInfos();
|
||||||
|
// 无登录权限时,添加判断
|
||||||
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
|
||||||
|
if (useUserInfo().userInfos.roles.length <= 0) return Promise.resolve(true);
|
||||||
// 添加动态路由
|
// 添加动态路由
|
||||||
await setAddRoute();
|
await setAddRoute();
|
||||||
// 设置递归过滤有权限的路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
|
// 设置递归过滤有权限的路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
|
||||||
|
|||||||
@ -856,7 +856,7 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
|||||||
isAffix: false,
|
isAffix: false,
|
||||||
isIframe: false,
|
isIframe: false,
|
||||||
roles: ['admin'],
|
roles: ['admin'],
|
||||||
icon: 'iconfont icon-diannao',
|
icon: 'iconfont icon-wenducanshu-05',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -89,7 +89,7 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
// 是否开启 TagsView 共用
|
// 是否开启 TagsView 共用
|
||||||
isShareTagsView: false,
|
isShareTagsView: false,
|
||||||
// 是否开启 Footer 底部版权信息
|
// 是否开启 Footer 底部版权信息
|
||||||
isFooter: true,
|
isFooter: false,
|
||||||
// 是否开启灰色模式
|
// 是否开启灰色模式
|
||||||
isGrayscale: false,
|
isGrayscale: false,
|
||||||
// 是否开启色弱模式
|
// 是否开启色弱模式
|
||||||
|
|||||||
@ -19,9 +19,6 @@
|
|||||||
|
|
||||||
/* Input 输入框、InputNumber 计数器
|
/* Input 输入框、InputNumber 计数器
|
||||||
------------------------------- */
|
------------------------------- */
|
||||||
.el-input {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
// 菜单搜索
|
// 菜单搜索
|
||||||
.el-autocomplete-suggestion__wrap {
|
.el-autocomplete-suggestion__wrap {
|
||||||
max-height: 280px !important;
|
max-height: 280px !important;
|
||||||
|
|||||||
@ -5,64 +5,25 @@
|
|||||||
.icon-selector-warp {
|
.icon-selector-warp {
|
||||||
height: 260px;
|
height: 260px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
.icon-selector-warp-title {
|
.icon-selector-warp-title {
|
||||||
|
position: absolute;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
padding: 0 15px;
|
left: 15px;
|
||||||
.icon-selector-warp-title-tab {
|
|
||||||
span {
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.span-active {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.icon-selector-warp-row {
|
.el-tabs__header {
|
||||||
height: 230px;
|
display: flex;
|
||||||
overflow: hidden;
|
justify-content: flex-end;
|
||||||
border-top: 1px solid var(--el-border-color);
|
padding: 0 15px;
|
||||||
.el-row {
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
padding: 15px;
|
margin: 0 !important;
|
||||||
}
|
.el-tabs__nav-wrap {
|
||||||
.el-scrollbar__bar.is-horizontal {
|
&::after {
|
||||||
display: none;
|
height: 0 !important;
|
||||||
}
|
|
||||||
.icon-selector-warp-item {
|
|
||||||
display: flex;
|
|
||||||
border: 1px solid var(--el-border-color);
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
.icon-selector-warp-item-value {
|
|
||||||
i {
|
|
||||||
font-size: 20px;
|
|
||||||
color: var(--el-text-color-regular);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&:hover {
|
.el-tabs__item {
|
||||||
cursor: pointer;
|
padding: 0 5px !important;
|
||||||
background-color: var(--el-color-primary-light-9);
|
|
||||||
border: 1px solid var(--el-color-primary-light-5);
|
|
||||||
.icon-selector-warp-item-value {
|
|
||||||
i {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.icon-selector-active {
|
|
||||||
background-color: var(--el-color-primary-light-9);
|
|
||||||
border: 1px solid var(--el-color-primary-light-5);
|
|
||||||
.icon-selector-warp-item-value {
|
|
||||||
i {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
@import 'common/transition.scss';
|
@import 'common/transition.scss';
|
||||||
@import './other.scss';
|
@import './other.scss';
|
||||||
@import './element.scss';
|
@import './element.scss';
|
||||||
@import './iconSelector.scss';
|
|
||||||
@import './media/media.scss';
|
@import './media/media.scss';
|
||||||
@import './waves.scss';
|
@import './waves.scss';
|
||||||
@import './dark.scss';
|
@import './dark.scss';
|
||||||
|
|||||||
@ -16,4 +16,16 @@
|
|||||||
// 响应式表单时,登录页需要重新处理
|
// 响应式表单时,登录页需要重新处理
|
||||||
display: unset !important;
|
display: unset !important;
|
||||||
}
|
}
|
||||||
|
// 表格演示中的表单筛选
|
||||||
|
.table-form-btn {
|
||||||
|
display: flex !important;
|
||||||
|
.el-form-item__label {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 表格演示中的表单筛选最大高度,适配移动端
|
||||||
|
.table-search-container {
|
||||||
|
max-height: 160px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/types/global.d.ts
vendored
1
src/types/global.d.ts
vendored
@ -5,6 +5,7 @@ declare module 'splitpanes';
|
|||||||
declare module 'js-cookie';
|
declare module 'js-cookie';
|
||||||
declare module '@wangeditor/editor-for-vue';
|
declare module '@wangeditor/editor-for-vue';
|
||||||
declare module 'js-table2excel';
|
declare module 'js-table2excel';
|
||||||
|
declare module 'qs';
|
||||||
|
|
||||||
// 声明一个模块,防止引入文件时报错
|
// 声明一个模块,防止引入文件时报错
|
||||||
declare module '*.json';
|
declare module '*.json';
|
||||||
|
|||||||
13
src/types/views.d.ts
vendored
13
src/types/views.d.ts
vendored
@ -43,7 +43,6 @@ declare type Demo2State<T = any> = {
|
|||||||
earth3DBtnList: T[];
|
earth3DBtnList: T[];
|
||||||
chartData4List: T[];
|
chartData4List: T[];
|
||||||
myCharts: T[];
|
myCharts: T[];
|
||||||
the3DEarth: HTMLDivElement | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,11 +304,19 @@ declare type TableHeaderType = {
|
|||||||
isCheck: boolean;
|
isCheck: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare type TableSearchType = {
|
||||||
|
label: string;
|
||||||
|
prop: string;
|
||||||
|
placeholder: string;
|
||||||
|
required: boolean;
|
||||||
|
type: string;
|
||||||
|
options?: SelectOptionType[];
|
||||||
|
};
|
||||||
|
|
||||||
declare type TableDemoState = {
|
declare type TableDemoState = {
|
||||||
tableData: {
|
tableData: {
|
||||||
data: EmptyObjectType[];
|
data: EmptyObjectType[];
|
||||||
header: TableHeaderType[];
|
header: TableHeaderType[];
|
||||||
param: EmptyObjectType;
|
|
||||||
config: {
|
config: {
|
||||||
total: number;
|
total: number;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -318,5 +325,7 @@ declare type TableDemoState = {
|
|||||||
isSerialNo: boolean;
|
isSerialNo: boolean;
|
||||||
isOperate: boolean;
|
isOperate: boolean;
|
||||||
};
|
};
|
||||||
|
search: TableSearchType[];
|
||||||
|
param: EmptyObjectType;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,18 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
|
import qs from 'qs';
|
||||||
|
|
||||||
// 配置新建一个 axios 实例
|
// 配置新建一个 axios 实例
|
||||||
const service: AxiosInstance = axios.create({
|
const service: AxiosInstance = axios.create({
|
||||||
baseURL: import.meta.env.VITE_API_URL,
|
baseURL: import.meta.env.VITE_API_URL,
|
||||||
timeout: 50000,
|
timeout: 50000,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
paramsSerializer: {
|
||||||
|
serialize(params) {
|
||||||
|
return qs.stringify(params, { allowDots: true });
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加请求拦截器
|
// 添加请求拦截器
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import { useRouter } from 'vue-router';
|
|||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
// 返回首页
|
||||||
const onGoHome = () => {
|
const onGoHome = () => {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<div ref="echartsMap" style="height: 100%"></div>
|
<div ref="echartsMapRef" style="height: 100%"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="funEchartsMap">
|
<script setup lang="ts" name="funEchartsMap">
|
||||||
import { reactive, onMounted } from 'vue';
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import 'echarts/extension/bmap/bmap';
|
import 'echarts/extension/bmap/bmap';
|
||||||
import { echartsMapList, echartsMapData } from './mock';
|
import { echartsMapList, echartsMapData } from './mock';
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
|
const echartsMapRef = ref<RefType>('');
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
echartsMap: '' as unknown,
|
echartsMap: '' as unknown,
|
||||||
echartsMapList,
|
echartsMapList,
|
||||||
@ -35,7 +36,7 @@ const convertData = (data: EmptyObjectType[]) => {
|
|||||||
};
|
};
|
||||||
// 初始化 echartsMap
|
// 初始化 echartsMap
|
||||||
const initEchartsMap = () => {
|
const initEchartsMap = () => {
|
||||||
const myChart = echarts.init(<HTMLElement>state.echartsMap);
|
const myChart = echarts.init(echartsMapRef.value);
|
||||||
const option = {
|
const option = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
|
|||||||
@ -66,7 +66,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="home">
|
<script setup lang="ts" name="home">
|
||||||
import { reactive, onMounted, ref, watch, nextTick, onActivated } from 'vue';
|
import { reactive, onMounted, ref, watch, nextTick, onActivated, markRaw } from 'vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
@ -192,7 +192,7 @@ const state = reactive({
|
|||||||
// 折线图
|
// 折线图
|
||||||
const initLineChart = () => {
|
const initLineChart = () => {
|
||||||
if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) state.global.homeChartOne.dispose();
|
if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) state.global.homeChartOne.dispose();
|
||||||
state.global.homeChartOne = echarts.init(homeLineRef.value, state.charts.theme);
|
state.global.homeChartOne = markRaw(echarts.init(homeLineRef.value, state.charts.theme));
|
||||||
const option = {
|
const option = {
|
||||||
backgroundColor: state.charts.bgColor,
|
backgroundColor: state.charts.bgColor,
|
||||||
title: {
|
title: {
|
||||||
@ -274,7 +274,7 @@ const initLineChart = () => {
|
|||||||
// 饼图
|
// 饼图
|
||||||
const initPieChart = () => {
|
const initPieChart = () => {
|
||||||
if (!state.global.dispose.some((b: any) => b === state.global.homeChartTwo)) state.global.homeChartTwo.dispose();
|
if (!state.global.dispose.some((b: any) => b === state.global.homeChartTwo)) state.global.homeChartTwo.dispose();
|
||||||
state.global.homeChartTwo = echarts.init(homePieRef.value, state.charts.theme);
|
state.global.homeChartTwo = markRaw(echarts.init(homePieRef.value, state.charts.theme));
|
||||||
var getname = ['房屋及结构物', '专用设备', '通用设备', '文物和陈列品', '图书、档案'];
|
var getname = ['房屋及结构物', '专用设备', '通用设备', '文物和陈列品', '图书、档案'];
|
||||||
var getvalue = [34.2, 38.87, 17.88, 9.05, 2.05];
|
var getvalue = [34.2, 38.87, 17.88, 9.05, 2.05];
|
||||||
var data = [];
|
var data = [];
|
||||||
@ -359,7 +359,7 @@ const initPieChart = () => {
|
|||||||
// 柱状图
|
// 柱状图
|
||||||
const initBarChart = () => {
|
const initBarChart = () => {
|
||||||
if (!state.global.dispose.some((b: any) => b === state.global.homeCharThree)) state.global.homeCharThree.dispose();
|
if (!state.global.dispose.some((b: any) => b === state.global.homeCharThree)) state.global.homeCharThree.dispose();
|
||||||
state.global.homeCharThree = echarts.init(homeBarRef.value, state.charts.theme);
|
state.global.homeCharThree = markRaw(echarts.init(homeBarRef.value, state.charts.theme));
|
||||||
const option = {
|
const option = {
|
||||||
backgroundColor: state.charts.bgColor,
|
backgroundColor: state.charts.bgColor,
|
||||||
title: {
|
title: {
|
||||||
|
|||||||
@ -100,37 +100,41 @@ const onSignIn = async () => {
|
|||||||
Cookies.set('userName', state.ruleForm.userName);
|
Cookies.set('userName', state.ruleForm.userName);
|
||||||
if (!themeConfig.value.isRequestRoutes) {
|
if (!themeConfig.value.isRequestRoutes) {
|
||||||
// 前端控制路由,2、请注意执行顺序
|
// 前端控制路由,2、请注意执行顺序
|
||||||
await initFrontEndControlRoutes();
|
const isNoPower = await initFrontEndControlRoutes();
|
||||||
signInSuccess();
|
signInSuccess(isNoPower);
|
||||||
} else {
|
} else {
|
||||||
// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||||
// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
|
// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
|
||||||
await initBackEndControlRoutes();
|
const isNoPower = await initBackEndControlRoutes();
|
||||||
// 执行完 initBackEndControlRoutes,再执行 signInSuccess
|
// 执行完 initBackEndControlRoutes,再执行 signInSuccess
|
||||||
signInSuccess();
|
signInSuccess(isNoPower);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 登录成功后的跳转
|
// 登录成功后的跳转
|
||||||
const signInSuccess = () => {
|
const signInSuccess = (isNoPower: boolean | undefined) => {
|
||||||
// 初始化登录成功时间问候语
|
if (isNoPower) {
|
||||||
let currentTimeInfo = currentTime.value;
|
ElMessage.warning('抱歉,您没有登录权限');
|
||||||
// 登录成功,跳到转首页
|
Session.clear();
|
||||||
// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
|
|
||||||
if (route.query?.redirect) {
|
|
||||||
router.push({
|
|
||||||
path: <string>route.query?.redirect,
|
|
||||||
query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
router.push('/');
|
// 初始化登录成功时间问候语
|
||||||
|
let currentTimeInfo = currentTime.value;
|
||||||
|
// 登录成功,跳到转首页
|
||||||
|
// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
|
||||||
|
if (route.query?.redirect) {
|
||||||
|
router.push({
|
||||||
|
path: <string>route.query?.redirect,
|
||||||
|
query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
router.push('/');
|
||||||
|
}
|
||||||
|
// 登录成功提示
|
||||||
|
const signInText = t('message.signInText');
|
||||||
|
ElMessage.success(`${currentTimeInfo},${signInText}`);
|
||||||
|
// 添加 loading,防止第一次进入界面时出现短暂空白
|
||||||
|
NextLoading.start();
|
||||||
}
|
}
|
||||||
// 登录成功提示
|
state.loading.signIn = false;
|
||||||
// 关闭 loading
|
|
||||||
state.loading.signIn = true;
|
|
||||||
const signInText = t('message.signInText');
|
|
||||||
ElMessage.success(`${currentTimeInfo},${signInText}`);
|
|
||||||
// 添加 loading,防止第一次进入界面时出现短暂空白
|
|
||||||
NextLoading.start();
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,13 @@ const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelect
|
|||||||
const state = reactive({
|
const state = reactive({
|
||||||
modelIcon: '',
|
modelIcon: '',
|
||||||
tableData: [
|
tableData: [
|
||||||
|
{
|
||||||
|
a1: 'v-model',
|
||||||
|
a2: '双向绑定值',
|
||||||
|
a3: 'string',
|
||||||
|
a4: '',
|
||||||
|
a5: '',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
a1: 'prepend',
|
a1: 'prepend',
|
||||||
a2: '输入框前置内容,只能字体图标',
|
a2: '输入框前置内容,只能字体图标',
|
||||||
@ -63,13 +70,6 @@ const state = reactive({
|
|||||||
a4: '',
|
a4: '',
|
||||||
a5: '请选择图标',
|
a5: '请选择图标',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
a1: 'type',
|
|
||||||
a2: 'icon 图标类型',
|
|
||||||
a3: 'string',
|
|
||||||
a4: 'ali / ele / awe / all',
|
|
||||||
a5: 'ele',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
a1: 'disabled',
|
a1: 'disabled',
|
||||||
a2: '禁用',
|
a2: '禁用',
|
||||||
|
|||||||
@ -1,15 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="table-demo-container layout-padding">
|
<div class="table-demo-container layout-padding">
|
||||||
<div class="table-demo-padding layout-padding-view layout-padding-auto">
|
<div class="table-demo-padding layout-padding-view layout-padding-auto">
|
||||||
<div class="system-user-search mb15">
|
<TableSearch :search="state.tableData.search" @search="onSearch" />
|
||||||
<el-input v-model="state.tableData.param.search" size="default" placeholder="请输入核酸采样点名称" style="max-width: 180px" />
|
|
||||||
<el-button size="default" type="primary" class="ml10" @click="onSearch">
|
|
||||||
<el-icon>
|
|
||||||
<ele-Search />
|
|
||||||
</el-icon>
|
|
||||||
查询
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<Table
|
<Table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
v-bind="state.tableData"
|
v-bind="state.tableData"
|
||||||
@ -28,6 +20,7 @@ import { ElMessage } from 'element-plus';
|
|||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'));
|
const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'));
|
||||||
|
const TableSearch = defineAsyncComponent(() => import('/@/views/make/tableDemo/search.vue'));
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const tableRef = ref<RefType>();
|
const tableRef = ref<RefType>();
|
||||||
@ -44,10 +37,6 @@ const state = reactive<TableDemoState>({
|
|||||||
{ key: 'isSupport', colWidth: '', title: '是否支持24小时核酸检测', type: 'text', isCheck: true },
|
{ key: 'isSupport', colWidth: '', title: '是否支持24小时核酸检测', type: 'text', isCheck: true },
|
||||||
{ key: 'image', colWidth: '', width: '70', height: '40', title: '图片描述', type: 'image', isCheck: true },
|
{ key: 'image', colWidth: '', width: '70', height: '40', title: '图片描述', type: 'image', isCheck: true },
|
||||||
],
|
],
|
||||||
// 搜索参数(可选)
|
|
||||||
param: {
|
|
||||||
search: '',
|
|
||||||
},
|
|
||||||
// 配置项(必传)
|
// 配置项(必传)
|
||||||
config: {
|
config: {
|
||||||
total: 0, // 列表总数
|
total: 0, // 列表总数
|
||||||
@ -57,6 +46,31 @@ const state = reactive<TableDemoState>({
|
|||||||
isSelection: true, // 是否显示表格多选
|
isSelection: true, // 是否显示表格多选
|
||||||
isOperate: true, // 是否显示表格操作栏
|
isOperate: true, // 是否显示表格操作栏
|
||||||
},
|
},
|
||||||
|
// 搜索表单,动态生成(传空数组时,将不显示搜索,注意格式)
|
||||||
|
search: [
|
||||||
|
{ label: '采样点名称', prop: 'name', placeholder: '请输入应检尽检核酸采样点名称', required: true, type: 'input' },
|
||||||
|
{ label: '详细地址', prop: 'address', placeholder: '请输入详细地址', required: false, type: 'input' },
|
||||||
|
{ label: '联系电话', prop: 'phone', placeholder: '请输入采样点联系电话', required: false, type: 'input' },
|
||||||
|
{ label: '开放时间', prop: 'time', placeholder: '请选择', required: false, type: 'date' },
|
||||||
|
{
|
||||||
|
label: '支持24小时',
|
||||||
|
prop: 'isSupport',
|
||||||
|
placeholder: '请选择',
|
||||||
|
required: false,
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '是', value: 1 },
|
||||||
|
{ label: '否', value: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ label: '图片描述', prop: 'image', placeholder: '请输入图片描述', required: false, type: 'input' },
|
||||||
|
{ label: '核酸机构', prop: 'mechanism', placeholder: '请输入核酸机构', required: false, type: 'input' },
|
||||||
|
],
|
||||||
|
// 搜索参数(不用传,用于分页、搜索时传给后台的值,`getTableData` 中使用)
|
||||||
|
param: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -81,8 +95,9 @@ const getTableData = () => {
|
|||||||
state.tableData.config.loading = false;
|
state.tableData.config.loading = false;
|
||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
// 搜索
|
// 搜索点击时表单回调
|
||||||
const onSearch = () => {
|
const onSearch = (data: EmptyObjectType) => {
|
||||||
|
state.tableData.param = Object.assign({}, state.tableData.param, { ...data });
|
||||||
tableRef.value.pageReset();
|
tableRef.value.pageReset();
|
||||||
};
|
};
|
||||||
// 删除当前项回调
|
// 删除当前项回调
|
||||||
@ -100,7 +115,6 @@ const onTablePageChange = (page: TableDemoPageType) => {
|
|||||||
const onSortHeader = (data: TableHeaderType[]) => {
|
const onSortHeader = (data: TableHeaderType[]) => {
|
||||||
state.tableData.header = data;
|
state.tableData.header = data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTableData();
|
getTableData();
|
||||||
|
|||||||
110
src/views/make/tableDemo/search.vue
Normal file
110
src/views/make/tableDemo/search.vue
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<template>
|
||||||
|
<div class="table-search-container" v-if="props.search.length > 0">
|
||||||
|
<el-form ref="tableSearchRef" :model="state.form" size="default" label-width="100px" class="table-form">
|
||||||
|
<el-row>
|
||||||
|
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20" v-for="(val, key) in search" :key="key" v-show="key === 0 || state.isToggle">
|
||||||
|
<template v-if="val.type !== ''">
|
||||||
|
<el-form-item
|
||||||
|
:label="val.label"
|
||||||
|
:prop="val.prop"
|
||||||
|
:rules="[{ required: val.required, message: `${val.label}不能为空`, trigger: val.type === 'input' ? 'blur' : 'change' }]"
|
||||||
|
>
|
||||||
|
<el-input v-model="state.form[val.prop]" :placeholder="val.placeholder" clearable v-if="val.type === 'input'" style="width: 100%" />
|
||||||
|
<el-date-picker
|
||||||
|
v-model="state.form[val.prop]"
|
||||||
|
type="date"
|
||||||
|
:placeholder="val.placeholder"
|
||||||
|
v-else-if="val.type === 'date'"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
<el-select v-model="state.form[val.prop]" :placeholder="val.placeholder" v-else-if="val.type === 'select'" style="width: 100%">
|
||||||
|
<el-option v-for="item in val.options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||||
|
<el-form-item class="table-form-btn" :label-width="search.length <= 1 ? '10px' : '100px'">
|
||||||
|
<template #label v-if="search.length > 1">
|
||||||
|
<div class="table-form-btn-toggle ml10" @click="state.isToggle = !state.isToggle">
|
||||||
|
<span>{{ state.isToggle ? '收筛选' : '展筛选' }}</span>
|
||||||
|
<SvgIcon :name="state.isToggle ? 'ele-ArrowUp' : 'ele-ArrowDown'" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<el-button size="default" type="primary" @click="onSearch(tableSearchRef)">查询 </el-button>
|
||||||
|
<el-button size="default" type="info" class="ml10" @click="onReset(tableSearchRef)"> 重置 </el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="makeTableDemoSearch">
|
||||||
|
import { reactive, ref, onMounted } from 'vue';
|
||||||
|
import type { FormInstance } from 'element-plus';
|
||||||
|
|
||||||
|
// 定义父组件传过来的值
|
||||||
|
const props = defineProps({
|
||||||
|
// 搜索表单
|
||||||
|
search: {
|
||||||
|
type: Array<TableSearchType>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['search']);
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
|
const tableSearchRef = ref<FormInstance>();
|
||||||
|
const state = reactive({
|
||||||
|
form: {},
|
||||||
|
isToggle: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
const onSearch = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate((valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
emit('search', state.form);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 重置
|
||||||
|
const onReset = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
emit('search', state.form);
|
||||||
|
};
|
||||||
|
// 初始化 form 字段,取自父组件 search.prop
|
||||||
|
const initFormField = () => {
|
||||||
|
if (props.search.length <= 0) return false;
|
||||||
|
props.search.forEach((v) => (state.form[v.prop] = ''));
|
||||||
|
};
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
initFormField();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.table-search-container {
|
||||||
|
display: flex;
|
||||||
|
.table-form {
|
||||||
|
flex: 1;
|
||||||
|
.table-form-btn-toggle {
|
||||||
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -15,8 +15,8 @@
|
|||||||
<span class="tree-custom-node">
|
<span class="tree-custom-node">
|
||||||
<span style="flex: 1">{{ node.label }}</span>
|
<span style="flex: 1">{{ node.label }}</span>
|
||||||
<span v-if="data.isShow" style="flex: 1; display: flex">
|
<span v-if="data.isShow" style="flex: 1; display: flex">
|
||||||
<span type="text" size="default" style="flex: 1">{{ data.label1 }}</span>
|
<span style="flex: 1">{{ data.label1 }}</span>
|
||||||
<span type="text" size="default" style="flex: 1">{{ data.label2 }}</span>
|
<span style="flex: 1">{{ data.label2 }}</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,143 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="system-add-dept-container">
|
|
||||||
<el-dialog title="新增部门" v-model="state.isShowDialog" width="769px">
|
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
|
||||||
<el-row :gutter="35">
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="上级部门">
|
|
||||||
<el-cascader
|
|
||||||
:options="state.deptData"
|
|
||||||
:props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }"
|
|
||||||
placeholder="请选择部门"
|
|
||||||
clearable
|
|
||||||
class="w100"
|
|
||||||
v-model="state.ruleForm.deptLevel"
|
|
||||||
>
|
|
||||||
<template #default="{ node, data }">
|
|
||||||
<span>{{ data.deptName }}</span>
|
|
||||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
|
||||||
</template>
|
|
||||||
</el-cascader>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="部门名称">
|
|
||||||
<el-input v-model="state.ruleForm.deptName" placeholder="请输入部门名称" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="负责人">
|
|
||||||
<el-input v-model="state.ruleForm.person" placeholder="请输入负责人" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="手机号">
|
|
||||||
<el-input v-model="state.ruleForm.phone" placeholder="请输入手机号" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="邮箱">
|
|
||||||
<el-input v-model="state.ruleForm.email" placeholder="请输入" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="排序">
|
|
||||||
<el-input-number v-model="state.ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="部门状态">
|
|
||||||
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="部门描述">
|
|
||||||
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入部门描述" maxlength="150"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="onSubmit" size="default">新 增</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="systemAddDept">
|
|
||||||
import { reactive, onMounted } from 'vue';
|
|
||||||
|
|
||||||
// 定义变量内容
|
|
||||||
const state = reactive({
|
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
|
||||||
deptLevel: [], // 上级部门
|
|
||||||
deptName: '', // 部门名称
|
|
||||||
person: '', // 负责人
|
|
||||||
phone: '', // 手机号
|
|
||||||
email: '', // 邮箱
|
|
||||||
sort: 0, // 排序
|
|
||||||
status: true, // 部门状态
|
|
||||||
describe: '', // 部门描述
|
|
||||||
},
|
|
||||||
deptData: [] as DeptTreeType[], // 部门数据
|
|
||||||
});
|
|
||||||
|
|
||||||
// 打开弹窗
|
|
||||||
const openDialog = () => {
|
|
||||||
state.isShowDialog = true;
|
|
||||||
};
|
|
||||||
// 关闭弹窗
|
|
||||||
const closeDialog = () => {
|
|
||||||
state.isShowDialog = false;
|
|
||||||
};
|
|
||||||
// 取消
|
|
||||||
const onCancel = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 新增
|
|
||||||
const onSubmit = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 初始化部门数据
|
|
||||||
const initTableData = () => {
|
|
||||||
state.deptData.push({
|
|
||||||
deptName: 'vueNextAdmin',
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
status: true,
|
|
||||||
sort: Math.random(),
|
|
||||||
describe: '顶级部门',
|
|
||||||
id: Math.random(),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
deptName: 'IT外包服务',
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
status: true,
|
|
||||||
sort: Math.random(),
|
|
||||||
describe: '总部',
|
|
||||||
id: Math.random(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deptName: '资本控股',
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
status: true,
|
|
||||||
sort: Math.random(),
|
|
||||||
describe: '分部',
|
|
||||||
id: Math.random(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {
|
|
||||||
initTableData();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 暴露变量
|
|
||||||
defineExpose({
|
|
||||||
openDialog,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="system-edit-dept-container">
|
<div class="system-dept-dialog-container">
|
||||||
<el-dialog title="修改部门" v-model="state.isShowDialog" width="769px">
|
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
<el-form ref="deptDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
||||||
<el-form-item label="上级部门">
|
<el-form-item label="上级部门">
|
||||||
@ -60,19 +60,22 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" size="default">修 改</el-button>
|
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemEditDept">
|
<script setup lang="ts" name="systemDeptDialog">
|
||||||
import { reactive, onMounted } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
|
const deptDialogFormRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
deptLevel: [] as string[], // 上级部门
|
deptLevel: [] as string[], // 上级部门
|
||||||
deptName: '', // 部门名称
|
deptName: '', // 部门名称
|
||||||
@ -84,31 +87,51 @@ const state = reactive({
|
|||||||
describe: '', // 部门描述
|
describe: '', // 部门描述
|
||||||
},
|
},
|
||||||
deptData: [] as DeptTreeType[], // 部门数据
|
deptData: [] as DeptTreeType[], // 部门数据
|
||||||
|
dialog: {
|
||||||
|
isShowDialog: false,
|
||||||
|
type: '',
|
||||||
|
title: '',
|
||||||
|
submitTxt: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (row: RowDeptType) => {
|
const openDialog = (type: string, row: RowDeptType) => {
|
||||||
row.deptLevel = ['vueNextAdmin'];
|
if (type === 'edit') {
|
||||||
row.person = 'lyt';
|
row.deptLevel = ['vueNextAdmin'];
|
||||||
row.phone = '12345678910';
|
row.person = 'lyt';
|
||||||
row.email = 'vueNextAdmin@123.com';
|
row.phone = '12345678910';
|
||||||
state.ruleForm = row;
|
row.email = 'vueNextAdmin@123.com';
|
||||||
state.isShowDialog = true;
|
state.ruleForm = row;
|
||||||
|
state.dialog.title = '修改部门';
|
||||||
|
state.dialog.submitTxt = '修 改';
|
||||||
|
} else {
|
||||||
|
state.dialog.title = '新增部门';
|
||||||
|
state.dialog.submitTxt = '新 增';
|
||||||
|
// 清空表单,此项需加表单验证才能使用
|
||||||
|
// nextTick(() => {
|
||||||
|
// deptDialogFormRef.value.resetFields();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
state.dialog.isShowDialog = true;
|
||||||
|
getMenuData();
|
||||||
};
|
};
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
state.isShowDialog = false;
|
state.dialog.isShowDialog = false;
|
||||||
};
|
};
|
||||||
// 取消
|
// 取消
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
// 新增
|
// 提交
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
emit('refresh');
|
||||||
|
// if (state.dialog.type === 'add') { }
|
||||||
};
|
};
|
||||||
// 初始化部门数据
|
// 初始化部门数据
|
||||||
const initTableData = () => {
|
const getMenuData = () => {
|
||||||
state.deptData.push({
|
state.deptData.push({
|
||||||
deptName: 'vueNextAdmin',
|
deptName: 'vueNextAdmin',
|
||||||
createTime: new Date().toLocaleString(),
|
createTime: new Date().toLocaleString(),
|
||||||
@ -136,10 +159,6 @@ const initTableData = () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {
|
|
||||||
initTableData();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@ -9,7 +9,7 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="default" type="success" class="ml10" @click="onOpenAddDept">
|
<el-button size="default" type="success" class="ml10" @click="onOpenAddDept('add')">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<ele-FolderAdd />
|
<ele-FolderAdd />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -18,6 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
:data="state.tableData.data"
|
:data="state.tableData.data"
|
||||||
|
v-loading="state.tableData.loading"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
default-expand-all
|
default-expand-all
|
||||||
@ -39,15 +40,14 @@
|
|||||||
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column label="操作" show-overflow-tooltip width="140">
|
<el-table-column label="操作" show-overflow-tooltip width="140">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" text type="primary" @click="onOpenAddDept">新增</el-button>
|
<el-button size="small" text type="primary" @click="onOpenAddDept('add')">新增</el-button>
|
||||||
<el-button size="small" text type="primary" @click="onOpenEditDept(scope.row)">修改</el-button>
|
<el-button size="small" text type="primary" @click="onOpenEditDept('edit', scope.row)">修改</el-button>
|
||||||
<el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
|
<el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
<AddDept ref="addDeptRef" />
|
<DeptDialog ref="deptDialogRef" @refresh="getTableData()" />
|
||||||
<EditDept ref="editDeptRef" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -56,12 +56,10 @@ import { defineAsyncComponent, ref, reactive, onMounted } from 'vue';
|
|||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const AddDept = defineAsyncComponent(() => import('/@/views/system/dept/component/addDept.vue'));
|
const DeptDialog = defineAsyncComponent(() => import('/@/views/system/dept/dialog.vue'));
|
||||||
const EditDept = defineAsyncComponent(() => import('/@/views/system/dept/component/editDept.vue'));
|
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const addDeptRef = ref();
|
const deptDialogRef = ref();
|
||||||
const editDeptRef = ref();
|
|
||||||
const state = reactive<SysDeptState>({
|
const state = reactive<SysDeptState>({
|
||||||
tableData: {
|
tableData: {
|
||||||
data: [],
|
data: [],
|
||||||
@ -75,7 +73,9 @@ const state = reactive<SysDeptState>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 初始化表格数据
|
// 初始化表格数据
|
||||||
const initTableData = () => {
|
const getTableData = () => {
|
||||||
|
state.tableData.loading = true;
|
||||||
|
state.tableData.data = [];
|
||||||
state.tableData.data.push({
|
state.tableData.data.push({
|
||||||
deptName: 'vueNextAdmin',
|
deptName: 'vueNextAdmin',
|
||||||
createTime: new Date().toLocaleString(),
|
createTime: new Date().toLocaleString(),
|
||||||
@ -103,14 +103,17 @@ const initTableData = () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
state.tableData.total = state.tableData.data.length;
|
state.tableData.total = state.tableData.data.length;
|
||||||
|
setTimeout(() => {
|
||||||
|
state.tableData.loading = false;
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
// 打开新增菜单弹窗
|
// 打开新增菜单弹窗
|
||||||
const onOpenAddDept = () => {
|
const onOpenAddDept = (type: string) => {
|
||||||
addDeptRef.value.openDialog();
|
deptDialogRef.value.openDialog(type);
|
||||||
};
|
};
|
||||||
// 打开编辑菜单弹窗
|
// 打开编辑菜单弹窗
|
||||||
const onOpenEditDept = (row: DeptTreeType) => {
|
const onOpenEditDept = (type: string, row: DeptTreeType) => {
|
||||||
editDeptRef.value.openDialog(row);
|
deptDialogRef.value.openDialog(type, row);
|
||||||
};
|
};
|
||||||
// 删除当前行
|
// 删除当前行
|
||||||
const onTabelRowDel = (row: DeptTreeType) => {
|
const onTabelRowDel = (row: DeptTreeType) => {
|
||||||
@ -120,12 +123,13 @@ const onTabelRowDel = (row: DeptTreeType) => {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
getTableData();
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initTableData();
|
getTableData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,114 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="system-add-dic-container">
|
|
||||||
<el-dialog title="新增字典" v-model="state.isShowDialog" width="769px">
|
|
||||||
<el-alert title="半成品,交互过于复杂,请自行扩展!" type="warning" :closable="false" class="mb20"> </el-alert>
|
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
|
||||||
<el-row :gutter="35">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="字典名称">
|
|
||||||
<el-input v-model="state.ruleForm.dicName" placeholder="请输入字典名称" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="字段名">
|
|
||||||
<el-input v-model="state.ruleForm.fieldName" placeholder="请输入字段名,拼接 ruleForm.list" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="字典状态">
|
|
||||||
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-row :gutter="35" v-for="(v, k) in state.ruleForm.list" :key="k">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item :prop="`list[${k}].label`">
|
|
||||||
<template #label>
|
|
||||||
<el-button type="primary" circle size="small" @click="onAddRow" v-if="k === 0">
|
|
||||||
<el-icon>
|
|
||||||
<ele-Plus />
|
|
||||||
</el-icon>
|
|
||||||
</el-button>
|
|
||||||
<el-button type="danger" circle size="small" @click="onDelRow(k)" v-else>
|
|
||||||
<el-icon>
|
|
||||||
<ele-Delete />
|
|
||||||
</el-icon>
|
|
||||||
</el-button>
|
|
||||||
<span class="ml10">字段</span>
|
|
||||||
</template>
|
|
||||||
<el-input v-model="v.label" style="width: 100%" placeholder="请输入字段名"> </el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="属性" :prop="`list[${k}].value`">
|
|
||||||
<el-input v-model="v.value" style="width: 100%" placeholder="请输入属性值"> </el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="字典描述">
|
|
||||||
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入字典描述" maxlength="150"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="onSubmit" size="default">新 增</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="systemAddDic">
|
|
||||||
import { reactive } from 'vue';
|
|
||||||
|
|
||||||
// 定义变量内容
|
|
||||||
const state = reactive({
|
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
|
||||||
dicName: '', // 字典名称
|
|
||||||
fieldName: '', // 字段名
|
|
||||||
status: true, // 字典状态
|
|
||||||
list: [] as ListType[], // 子集字段 + 属性值
|
|
||||||
describe: '', // 字典描述
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 打开弹窗
|
|
||||||
const openDialog = () => {
|
|
||||||
state.isShowDialog = true;
|
|
||||||
};
|
|
||||||
// 关闭弹窗
|
|
||||||
const closeDialog = () => {
|
|
||||||
state.isShowDialog = false;
|
|
||||||
};
|
|
||||||
// 取消
|
|
||||||
const onCancel = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 新增
|
|
||||||
const onSubmit = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 新增行
|
|
||||||
const onAddRow = () => {
|
|
||||||
state.ruleForm.list.push({
|
|
||||||
id: Math.random(),
|
|
||||||
label: '',
|
|
||||||
value: '',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 删除行
|
|
||||||
const onDelRow = (k: number) => {
|
|
||||||
state.ruleForm.list.splice(k, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 暴露变量
|
|
||||||
defineExpose({
|
|
||||||
openDialog,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="system-edit-dic-container">
|
<div class="system-dic-dialog-container">
|
||||||
<el-dialog title="修改字典" v-model="state.isShowDialog" width="769px">
|
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
|
||||||
<el-alert title="半成品,交互过于复杂,请自行扩展!" type="warning" :closable="false" class="mb20"> </el-alert>
|
<el-alert title="半成品,交互过于复杂,请自行扩展!" type="warning" :closable="false" class="mb20"> </el-alert>
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
<el-form ref="dicDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
<el-form-item label="字典名称">
|
<el-form-item label="字典名称">
|
||||||
@ -56,19 +56,22 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" size="default">修 改</el-button>
|
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemEditDic">
|
<script setup lang="ts" name="systemDicDialog">
|
||||||
import { reactive } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
|
const dicDialogFormRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
dicName: '', // 字典名称
|
dicName: '', // 字典名称
|
||||||
fieldName: '', // 字段名
|
fieldName: '', // 字段名
|
||||||
@ -76,37 +79,56 @@ const state = reactive({
|
|||||||
list: [] as ListType[], // 子集字段 + 属性值
|
list: [] as ListType[], // 子集字段 + 属性值
|
||||||
describe: '', // 字典描述
|
describe: '', // 字典描述
|
||||||
},
|
},
|
||||||
|
dialog: {
|
||||||
|
isShowDialog: false,
|
||||||
|
type: '',
|
||||||
|
title: '',
|
||||||
|
submitTxt: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (row: RowDicType) => {
|
const openDialog = (type: string, row: RowDicType) => {
|
||||||
if (row.fieldName === 'SYS_UERINFO') {
|
if (type === 'edit') {
|
||||||
row.list = [
|
if (row.fieldName === 'SYS_UERINFO') {
|
||||||
{ id: Math.random(), label: 'sex', value: '1' },
|
row.list = [
|
||||||
{ id: Math.random(), label: 'sex', value: '0' },
|
{ id: Math.random(), label: 'sex', value: '1' },
|
||||||
];
|
{ id: Math.random(), label: 'sex', value: '0' },
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
row.list = [
|
||||||
|
{ id: Math.random(), label: 'role', value: 'admin' },
|
||||||
|
{ id: Math.random(), label: 'role', value: 'common' },
|
||||||
|
{ id: Math.random(), label: 'roleName', value: '超级管理员' },
|
||||||
|
{ id: Math.random(), label: 'roleName', value: '普通用户' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
state.ruleForm = row;
|
||||||
|
state.dialog.title = '修改字典';
|
||||||
|
state.dialog.submitTxt = '修 改';
|
||||||
} else {
|
} else {
|
||||||
row.list = [
|
state.dialog.title = '新增字典';
|
||||||
{ id: Math.random(), label: 'role', value: 'admin' },
|
state.dialog.submitTxt = '新 增';
|
||||||
{ id: Math.random(), label: 'role', value: 'common' },
|
// 清空表单,此项需加表单验证才能使用
|
||||||
{ id: Math.random(), label: 'roleName', value: '超级管理员' },
|
// nextTick(() => {
|
||||||
{ id: Math.random(), label: 'roleName', value: '普通用户' },
|
// dicDialogFormRef.value.resetFields();
|
||||||
];
|
// });
|
||||||
}
|
}
|
||||||
state.ruleForm = row;
|
state.dialog.isShowDialog = true;
|
||||||
state.isShowDialog = true;
|
|
||||||
};
|
};
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
state.isShowDialog = false;
|
state.dialog.isShowDialog = false;
|
||||||
};
|
};
|
||||||
// 取消
|
// 取消
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
// 新增
|
// 提交
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
emit('refresh');
|
||||||
|
// if (state.dialog.type === 'add') { }
|
||||||
};
|
};
|
||||||
// 新增行
|
// 新增行
|
||||||
const onAddRow = () => {
|
const onAddRow = () => {
|
||||||
@ -9,14 +9,14 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="default" type="success" class="ml10" @click="onOpenAddDic">
|
<el-button size="default" type="success" class="ml10" @click="onOpenAddDic('add')">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<ele-FolderAdd />
|
<ele-FolderAdd />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
新增字典
|
新增字典
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="state.tableData.data" style="width: 100%">
|
<el-table :data="state.tableData.data" v-loading="state.tableData.loading" style="width: 100%">
|
||||||
<el-table-column type="index" label="序号" width="50" />
|
<el-table-column type="index" label="序号" width="50" />
|
||||||
<el-table-column prop="dicName" label="字典名称" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="dicName" label="字典名称" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column prop="fieldName" label="字段名" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="fieldName" label="字段名" show-overflow-tooltip></el-table-column>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column label="操作" width="100">
|
<el-table-column label="操作" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" text type="primary" @click="onOpenEditDic(scope.row)">修改</el-button>
|
<el-button size="small" text type="primary" @click="onOpenEditDic('edit', scope.row)">修改</el-button>
|
||||||
<el-button size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
<el-button size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -49,8 +49,7 @@
|
|||||||
>
|
>
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</el-card>
|
</el-card>
|
||||||
<AddDic ref="addDicRef" />
|
<DicDialog ref="dicDialogRef" @refresh="getTableData()" />
|
||||||
<EditDic ref="editDicRef" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -59,12 +58,10 @@ import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
|
|||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const AddDic = defineAsyncComponent(() => import('/@/views/system/dic/component/addDic.vue'));
|
const DicDialog = defineAsyncComponent(() => import('/@/views/system/dic/dialog.vue'));
|
||||||
const EditDic = defineAsyncComponent(() => import('/@/views/system/dic/component/editDic.vue'));
|
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const addDicRef = ref();
|
const dicDialogRef = ref();
|
||||||
const editDicRef = ref();
|
|
||||||
const state = reactive<SysDicState>({
|
const state = reactive<SysDicState>({
|
||||||
tableData: {
|
tableData: {
|
||||||
data: [],
|
data: [],
|
||||||
@ -78,7 +75,8 @@ const state = reactive<SysDicState>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 初始化表格数据
|
// 初始化表格数据
|
||||||
const initTableData = () => {
|
const getTableData = () => {
|
||||||
|
state.tableData.loading = true;
|
||||||
const data = [];
|
const data = [];
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
data.push({
|
data.push({
|
||||||
@ -92,14 +90,17 @@ const initTableData = () => {
|
|||||||
}
|
}
|
||||||
state.tableData.data = data;
|
state.tableData.data = data;
|
||||||
state.tableData.total = state.tableData.data.length;
|
state.tableData.total = state.tableData.data.length;
|
||||||
|
setTimeout(() => {
|
||||||
|
state.tableData.loading = false;
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
// 打开新增字典弹窗
|
// 打开新增字典弹窗
|
||||||
const onOpenAddDic = () => {
|
const onOpenAddDic = (type: string) => {
|
||||||
addDicRef.value.openDialog();
|
dicDialogRef.value.openDialog(type);
|
||||||
};
|
};
|
||||||
// 打开修改字典弹窗
|
// 打开修改字典弹窗
|
||||||
const onOpenEditDic = (row: RowDicType) => {
|
const onOpenEditDic = (type: string, row: RowDicType) => {
|
||||||
editDicRef.value.openDialog(row);
|
dicDialogRef.value.openDialog(type, row);
|
||||||
};
|
};
|
||||||
// 删除字典
|
// 删除字典
|
||||||
const onRowDel = (row: RowDicType) => {
|
const onRowDel = (row: RowDicType) => {
|
||||||
@ -109,6 +110,7 @@ const onRowDel = (row: RowDicType) => {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
getTableData();
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
@ -116,13 +118,15 @@ const onRowDel = (row: RowDicType) => {
|
|||||||
// 分页改变
|
// 分页改变
|
||||||
const onHandleSizeChange = (val: number) => {
|
const onHandleSizeChange = (val: number) => {
|
||||||
state.tableData.param.pageSize = val;
|
state.tableData.param.pageSize = val;
|
||||||
|
getTableData();
|
||||||
};
|
};
|
||||||
// 分页改变
|
// 分页改变
|
||||||
const onHandleCurrentChange = (val: number) => {
|
const onHandleCurrentChange = (val: number) => {
|
||||||
state.tableData.param.pageNum = val;
|
state.tableData.param.pageNum = val;
|
||||||
|
getTableData();
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initTableData();
|
getTableData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,237 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="system-edit-menu-container">
|
|
||||||
<el-dialog title="修改菜单" v-model="state.isShowDialog" width="769px">
|
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="80px">
|
|
||||||
<el-row :gutter="35">
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="上级菜单">
|
|
||||||
<el-cascader
|
|
||||||
:options="state.menuData"
|
|
||||||
:props="{ checkStrictly: true, value: 'path', label: 'title' }"
|
|
||||||
placeholder="请选择上级菜单"
|
|
||||||
clearable
|
|
||||||
class="w100"
|
|
||||||
v-model="state.ruleForm.menuSuperior"
|
|
||||||
>
|
|
||||||
<template #default="{ node, data }">
|
|
||||||
<span>{{ data.title }}</span>
|
|
||||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
|
||||||
</template>
|
|
||||||
</el-cascader>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="菜单类型">
|
|
||||||
<el-radio-group v-model="state.ruleForm.menuType">
|
|
||||||
<el-radio label="menu">菜单</el-radio>
|
|
||||||
<el-radio label="btn">按钮</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="菜单名称">
|
|
||||||
<el-input v-model="state.ruleForm.meta.title" placeholder="格式:message.router.xxx" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<template v-if="state.ruleForm.menuType === 'menu'">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="路由名称">
|
|
||||||
<el-input v-model="state.ruleForm.name" placeholder="路由中的 name 值" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="路由路径">
|
|
||||||
<el-input v-model="state.ruleForm.path" placeholder="路由中的 path 值" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="重定向">
|
|
||||||
<el-input v-model="state.ruleForm.redirect" placeholder="请输入路由重定向" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="菜单图标">
|
|
||||||
<IconSelector placeholder="请输入菜单图标" v-model="state.ruleForm.meta.icon" type="all" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="组件路径">
|
|
||||||
<el-input v-model="state.ruleForm.component" placeholder="组件路径" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="链接地址">
|
|
||||||
<el-input
|
|
||||||
v-model="state.ruleForm.meta.isLink"
|
|
||||||
placeholder="外链/内嵌时链接地址(http:xxx.com)"
|
|
||||||
clearable
|
|
||||||
:disabled="!state.ruleForm.isLink"
|
|
||||||
>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="权限标识">
|
|
||||||
<el-select v-model="state.ruleForm.meta.roles" multiple placeholder="取角色管理" clearable class="w100">
|
|
||||||
<el-option label="admin" value="admin"></el-option>
|
|
||||||
<el-option label="common" value="common"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</template>
|
|
||||||
<template v-if="state.ruleForm.menuType === 'btn'">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="权限标识">
|
|
||||||
<el-input v-model="state.ruleForm.btnPower" placeholder="请输入权限标识" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</template>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="菜单排序">
|
|
||||||
<el-input-number v-model="state.ruleForm.menuSort" controls-position="right" placeholder="请输入排序" class="w100" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<template v-if="state.ruleForm.menuType === 'menu'">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="是否隐藏">
|
|
||||||
<el-radio-group v-model="state.ruleForm.meta.isHide">
|
|
||||||
<el-radio :label="true">隐藏</el-radio>
|
|
||||||
<el-radio :label="false">不隐藏</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="页面缓存">
|
|
||||||
<el-radio-group v-model="state.ruleForm.meta.isKeepAlive">
|
|
||||||
<el-radio :label="true">缓存</el-radio>
|
|
||||||
<el-radio :label="false">不缓存</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="是否固定">
|
|
||||||
<el-radio-group v-model="state.ruleForm.meta.isAffix">
|
|
||||||
<el-radio :label="true">固定</el-radio>
|
|
||||||
<el-radio :label="false">不固定</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="是否外链">
|
|
||||||
<el-radio-group v-model="state.ruleForm.isLink" :disabled="state.ruleForm.meta.isIframe">
|
|
||||||
<el-radio :label="true">是</el-radio>
|
|
||||||
<el-radio :label="false">否</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="是否内嵌">
|
|
||||||
<el-radio-group v-model="state.ruleForm.meta.isIframe" @change="onSelectIframeChange">
|
|
||||||
<el-radio :label="true">是</el-radio>
|
|
||||||
<el-radio :label="false">否</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</template>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="onSubmit" size="default">修 改</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="systemEditMenu">
|
|
||||||
import { defineAsyncComponent, reactive, onMounted } from 'vue';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
|
||||||
import { i18n } from '/@/i18n/index';
|
|
||||||
// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
|
|
||||||
|
|
||||||
// 引入组件
|
|
||||||
const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
|
|
||||||
|
|
||||||
// 定义变量内容
|
|
||||||
const stores = useRoutesList();
|
|
||||||
const { routesList } = storeToRefs(stores);
|
|
||||||
const state = reactive({
|
|
||||||
isShowDialog: false,
|
|
||||||
// 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式
|
|
||||||
ruleForm: {
|
|
||||||
menuSuperior: [], // 上级菜单
|
|
||||||
menuType: 'menu', // 菜单类型
|
|
||||||
name: '', // 路由名称
|
|
||||||
component: '', // 组件路径
|
|
||||||
isLink: false, // 是否外链
|
|
||||||
menuSort: 0, // 菜单排序
|
|
||||||
path: '', // 路由路径
|
|
||||||
redirect: '', // 路由重定向,有子集 children 时
|
|
||||||
meta: {
|
|
||||||
title: '', // 菜单名称
|
|
||||||
icon: '', // 菜单图标
|
|
||||||
isHide: false, // 是否隐藏
|
|
||||||
isKeepAlive: true, // 是否缓存
|
|
||||||
isAffix: false, // 是否固定
|
|
||||||
isLink: '', // 外链/内嵌时链接地址(http:xxx.com),开启外链条件,`1、isLink: 链接地址不为空`
|
|
||||||
isIframe: false, // 是否内嵌,开启条件,`1、isIframe:true 2、isLink:链接地址不为空`
|
|
||||||
roles: '', // 权限标识,取角色管理
|
|
||||||
},
|
|
||||||
btnPower: '', // 菜单类型为按钮时,权限标识
|
|
||||||
},
|
|
||||||
menuData: [] as RouteItems, // 上级菜单数据
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取 pinia 中的路由
|
|
||||||
const getMenuData = (routes: RouteItems) => {
|
|
||||||
const arr: RouteItems = [];
|
|
||||||
routes.map((val: RouteItem) => {
|
|
||||||
val['title'] = i18n.global.t(val.meta?.title as string);
|
|
||||||
arr.push({ ...val });
|
|
||||||
if (val.children) getMenuData(val.children);
|
|
||||||
});
|
|
||||||
return arr;
|
|
||||||
};
|
|
||||||
// 打开弹窗
|
|
||||||
const openDialog = (row: any) => {
|
|
||||||
// 模拟数据,实际请走接口
|
|
||||||
row.menuType = 'menu';
|
|
||||||
row.menuSort = Math.random();
|
|
||||||
row.component = `${row.component} `
|
|
||||||
.match(/\'(.+)\'/g)
|
|
||||||
?.join('')
|
|
||||||
.replace(/\'/g, '');
|
|
||||||
state.ruleForm = row;
|
|
||||||
state.isShowDialog = true;
|
|
||||||
};
|
|
||||||
// 关闭弹窗
|
|
||||||
const closeDialog = () => {
|
|
||||||
state.isShowDialog = false;
|
|
||||||
};
|
|
||||||
// 是否内嵌下拉改变
|
|
||||||
const onSelectIframeChange = () => {
|
|
||||||
if (state.ruleForm.meta.isIframe) state.ruleForm.isLink = true;
|
|
||||||
else state.ruleForm.isLink = false;
|
|
||||||
};
|
|
||||||
// 取消
|
|
||||||
const onCancel = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 新增
|
|
||||||
const onSubmit = () => {
|
|
||||||
closeDialog(); // 关闭弹窗
|
|
||||||
// setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试
|
|
||||||
};
|
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {
|
|
||||||
state.menuData = getMenuData(routesList.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 暴露变量
|
|
||||||
defineExpose({
|
|
||||||
openDialog,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="system-add-menu-container">
|
<div class="system-menu-dialog-container">
|
||||||
<el-dialog title="新增菜单" v-model="state.isShowDialog" width="769px">
|
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="80px">
|
<el-form ref="menuDialogFormRef" :model="state.ruleForm" size="default" label-width="80px">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
||||||
<el-form-item label="上级菜单">
|
<el-form-item label="上级菜单">
|
||||||
@ -51,7 +51,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
<el-form-item label="菜单图标">
|
<el-form-item label="菜单图标">
|
||||||
<IconSelector placeholder="请输入菜单图标" v-model="state.ruleForm.meta.icon" type="all" />
|
<IconSelector placeholder="请输入菜单图标" v-model="state.ruleForm.meta.icon" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
@ -138,28 +138,31 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" size="default">新 增</el-button>
|
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemAddMenu">
|
<script setup lang="ts" name="systemMenuDialog">
|
||||||
import { defineAsyncComponent, reactive, onMounted } from 'vue';
|
import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
import { i18n } from '/@/i18n/index';
|
import { i18n } from '/@/i18n/index';
|
||||||
// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
|
// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
|
const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
|
const menuDialogFormRef = ref();
|
||||||
const stores = useRoutesList();
|
const stores = useRoutesList();
|
||||||
const { routesList } = storeToRefs(stores);
|
const { routesList } = storeToRefs(stores);
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowDialog: false,
|
|
||||||
// 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式
|
// 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
menuSuperior: [], // 上级菜单
|
menuSuperior: [], // 上级菜单
|
||||||
@ -183,6 +186,12 @@ const state = reactive({
|
|||||||
btnPower: '', // 菜单类型为按钮时,权限标识
|
btnPower: '', // 菜单类型为按钮时,权限标识
|
||||||
},
|
},
|
||||||
menuData: [] as RouteItems, // 上级菜单数据
|
menuData: [] as RouteItems, // 上级菜单数据
|
||||||
|
dialog: {
|
||||||
|
isShowDialog: false,
|
||||||
|
type: '',
|
||||||
|
title: '',
|
||||||
|
submitTxt: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取 pinia 中的路由
|
// 获取 pinia 中的路由
|
||||||
@ -196,12 +205,32 @@ const getMenuData = (routes: RouteItems) => {
|
|||||||
return arr;
|
return arr;
|
||||||
};
|
};
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = () => {
|
const openDialog = (type: string, row?: any) => {
|
||||||
state.isShowDialog = true;
|
if (type === 'edit') {
|
||||||
|
// 模拟数据,实际请走接口
|
||||||
|
row.menuType = 'menu';
|
||||||
|
row.menuSort = Math.random();
|
||||||
|
row.component = `${row.component} `
|
||||||
|
.match(/\'(.+)\'/g)
|
||||||
|
?.join('')
|
||||||
|
.replace(/\'/g, '');
|
||||||
|
state.ruleForm = row;
|
||||||
|
state.dialog.title = '修改菜单';
|
||||||
|
state.dialog.submitTxt = '修 改';
|
||||||
|
} else {
|
||||||
|
state.dialog.title = '新增菜单';
|
||||||
|
state.dialog.submitTxt = '新 增';
|
||||||
|
// 清空表单,此项需加表单验证才能使用
|
||||||
|
// nextTick(() => {
|
||||||
|
// menuDialogFormRef.value.resetFields();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
state.dialog.type = type;
|
||||||
|
state.dialog.isShowDialog = true;
|
||||||
};
|
};
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
state.isShowDialog = false;
|
state.dialog.isShowDialog = false;
|
||||||
};
|
};
|
||||||
// 是否内嵌下拉改变
|
// 是否内嵌下拉改变
|
||||||
const onSelectIframeChange = () => {
|
const onSelectIframeChange = () => {
|
||||||
@ -212,9 +241,11 @@ const onSelectIframeChange = () => {
|
|||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
// 新增
|
// 提交
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
closeDialog(); // 关闭弹窗
|
closeDialog(); // 关闭弹窗
|
||||||
|
emit('refresh');
|
||||||
|
// if (state.dialog.type === 'add') { }
|
||||||
// setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试
|
// setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
@ -16,7 +16,13 @@
|
|||||||
新增菜单
|
新增菜单
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="menuTableData" style="width: 100%" row-key="path" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
|
<el-table
|
||||||
|
:data="state.tableData.data"
|
||||||
|
v-loading="state.tableData.loading"
|
||||||
|
style="width: 100%"
|
||||||
|
row-key="path"
|
||||||
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
|
>
|
||||||
<el-table-column label="菜单名称" show-overflow-tooltip>
|
<el-table-column label="菜单名称" show-overflow-tooltip>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<SvgIcon :name="scope.row.meta.icon" />
|
<SvgIcon :name="scope.row.meta.icon" />
|
||||||
@ -46,46 +52,54 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" show-overflow-tooltip width="140">
|
<el-table-column label="操作" show-overflow-tooltip width="140">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" text type="primary" @click="onOpenAddMenu">新增</el-button>
|
<el-button size="small" text type="primary" @click="onOpenAddMenu('add')">新增</el-button>
|
||||||
<el-button size="small" text type="primary" @click="onOpenEditMenu(scope.row)">修改</el-button>
|
<el-button size="small" text type="primary" @click="onOpenEditMenu('edit', scope.row)">修改</el-button>
|
||||||
<el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
|
<el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
<AddMenu ref="addMenuRef" />
|
<MenuDialog ref="menuDialogRef" @refresh="getTableData()" />
|
||||||
<EditMenu ref="editMenuRef" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemMenu">
|
<script setup lang="ts" name="systemMenu">
|
||||||
import { defineAsyncComponent, ref, computed } from 'vue';
|
import { defineAsyncComponent, ref, onMounted, reactive } from 'vue';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
|
// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const AddMenu = defineAsyncComponent(() => import('/@/views/system/menu/component/addMenu.vue'));
|
const MenuDialog = defineAsyncComponent(() => import('/@/views/system/menu/dialog.vue'));
|
||||||
const EditMenu = defineAsyncComponent(() => import('/@/views/system/menu/component/editMenu.vue'));
|
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const stores = useRoutesList();
|
const stores = useRoutesList();
|
||||||
const { routesList } = storeToRefs(stores);
|
const { routesList } = storeToRefs(stores);
|
||||||
const addMenuRef = ref();
|
const menuDialogRef = ref();
|
||||||
const editMenuRef = ref();
|
const state = reactive({
|
||||||
|
tableData: {
|
||||||
// 获取 pinia 中的路由
|
data: [] as RouteRecordRaw[],
|
||||||
const menuTableData = computed(() => {
|
loading: true,
|
||||||
return routesList.value;
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 获取路由数据,真实请从接口获取
|
||||||
|
const getTableData = () => {
|
||||||
|
state.tableData.loading = true;
|
||||||
|
state.tableData.data = routesList.value;
|
||||||
|
setTimeout(() => {
|
||||||
|
state.tableData.loading = false;
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
// 打开新增菜单弹窗
|
// 打开新增菜单弹窗
|
||||||
const onOpenAddMenu = () => {
|
const onOpenAddMenu = (type: string) => {
|
||||||
addMenuRef.value.openDialog();
|
menuDialogRef.value.openDialog(type);
|
||||||
};
|
};
|
||||||
// 打开编辑菜单弹窗
|
// 打开编辑菜单弹窗
|
||||||
const onOpenEditMenu = (row: RouteRecordRaw) => {
|
const onOpenEditMenu = (type: string, row: RouteRecordRaw) => {
|
||||||
editMenuRef.value.openDialog(row);
|
menuDialogRef.value.openDialog(type, row);
|
||||||
};
|
};
|
||||||
// 删除当前行
|
// 删除当前行
|
||||||
const onTabelRowDel = (row: RouteRecordRaw) => {
|
const onTabelRowDel = (row: RouteRecordRaw) => {
|
||||||
@ -96,7 +110,13 @@ const onTabelRowDel = (row: RouteRecordRaw) => {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
|
getTableData();
|
||||||
|
//await setBackEndControlRefreshRoutes() // 刷新菜单,未进行后端接口测试
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
};
|
};
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
getTableData();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,221 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="system-edit-role-container">
|
|
||||||
<el-dialog title="修改角色" v-model="state.isShowDialog" width="769px">
|
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
|
||||||
<el-row :gutter="35">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="角色名称">
|
|
||||||
<el-input v-model="state.ruleForm.roleName" placeholder="请输入角色名称" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="角色标识">
|
|
||||||
<template #label>
|
|
||||||
<el-tooltip effect="dark" content="用于 `router/route.ts` meta.roles" placement="top-start">
|
|
||||||
<span>角色标识</span>
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
|
||||||
<el-input v-model="state.ruleForm.roleSign" placeholder="请输入角色标识" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="排序">
|
|
||||||
<el-input-number v-model="state.ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w100" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="角色状态">
|
|
||||||
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="角色描述">
|
|
||||||
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入角色描述" maxlength="150"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="菜单权限">
|
|
||||||
<el-tree
|
|
||||||
:data="state.menuData"
|
|
||||||
:props="state.menuProps"
|
|
||||||
:default-checked-keys="[112, 113]"
|
|
||||||
node-key="id"
|
|
||||||
show-checkbox
|
|
||||||
class="menu-data-tree"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="onSubmit" size="default">修 改</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="systemEditRole">
|
|
||||||
import { reactive } from 'vue';
|
|
||||||
|
|
||||||
// 定义变量内容
|
|
||||||
const state = reactive({
|
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
|
||||||
roleName: '', // 角色名称
|
|
||||||
roleSign: '', // 角色标识
|
|
||||||
sort: 0, // 排序
|
|
||||||
status: true, // 角色状态
|
|
||||||
describe: '', // 角色描述
|
|
||||||
},
|
|
||||||
menuData: [] as TreeType[],
|
|
||||||
menuProps: {
|
|
||||||
children: 'children',
|
|
||||||
label: 'label',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 打开弹窗
|
|
||||||
const openDialog = (row: RowRoleType) => {
|
|
||||||
state.ruleForm = row;
|
|
||||||
state.isShowDialog = true;
|
|
||||||
getMenuData();
|
|
||||||
};
|
|
||||||
// 关闭弹窗
|
|
||||||
const closeDialog = () => {
|
|
||||||
state.isShowDialog = false;
|
|
||||||
};
|
|
||||||
// 取消
|
|
||||||
const onCancel = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 新增
|
|
||||||
const onSubmit = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 获取菜单结构数据
|
|
||||||
const getMenuData = () => {
|
|
||||||
state.menuData = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
label: '系统管理',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
label: '菜单管理',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 111,
|
|
||||||
label: '菜单新增',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 112,
|
|
||||||
label: '菜单修改',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 113,
|
|
||||||
label: '菜单删除',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 114,
|
|
||||||
label: '菜单查询',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
label: '角色管理',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 121,
|
|
||||||
label: '角色新增',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 122,
|
|
||||||
label: '角色修改',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 123,
|
|
||||||
label: '角色删除',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 124,
|
|
||||||
label: '角色查询',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 13,
|
|
||||||
label: '用户管理',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 131,
|
|
||||||
label: '用户新增',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 132,
|
|
||||||
label: '用户修改',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 133,
|
|
||||||
label: '用户删除',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 134,
|
|
||||||
label: '用户查询',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
label: '权限管理',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 21,
|
|
||||||
label: '前端控制',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 211,
|
|
||||||
label: '页面权限',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 212,
|
|
||||||
label: '页面权限',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 22,
|
|
||||||
label: '后端控制',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 221,
|
|
||||||
label: '页面权限',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 暴露变量
|
|
||||||
defineExpose({
|
|
||||||
openDialog,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.system-edit-role-container {
|
|
||||||
.menu-data-tree {
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid var(--el-border-color);
|
|
||||||
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="system-add-role-container">
|
<div class="system-role-dialog-container">
|
||||||
<el-dialog title="新增角色" v-model="state.isShowDialog" width="769px">
|
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
<el-form ref="roleDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
<el-form-item label="角色名称">
|
<el-form-item label="角色名称">
|
||||||
@ -43,19 +43,22 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" size="default">新 增</el-button>
|
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemAddRole">
|
<script setup lang="ts" name="systemRoleDialog">
|
||||||
import { reactive } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
|
const roleDialogFormRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
roleName: '', // 角色名称
|
roleName: '', // 角色名称
|
||||||
roleSign: '', // 角色标识
|
roleSign: '', // 角色标识
|
||||||
@ -68,24 +71,44 @@ const state = reactive({
|
|||||||
children: 'children',
|
children: 'children',
|
||||||
label: 'label',
|
label: 'label',
|
||||||
},
|
},
|
||||||
|
dialog: {
|
||||||
|
isShowDialog: false,
|
||||||
|
type: '',
|
||||||
|
title: '',
|
||||||
|
submitTxt: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = () => {
|
const openDialog = (type: string, row: RowRoleType) => {
|
||||||
state.isShowDialog = true;
|
if (type === 'edit') {
|
||||||
|
state.ruleForm = row;
|
||||||
|
state.dialog.title = '修改角色';
|
||||||
|
state.dialog.submitTxt = '修 改';
|
||||||
|
} else {
|
||||||
|
state.dialog.title = '新增角色';
|
||||||
|
state.dialog.submitTxt = '新 增';
|
||||||
|
// 清空表单,此项需加表单验证才能使用
|
||||||
|
// nextTick(() => {
|
||||||
|
// roleDialogFormRef.value.resetFields();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
state.dialog.isShowDialog = true;
|
||||||
getMenuData();
|
getMenuData();
|
||||||
};
|
};
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
state.isShowDialog = false;
|
state.dialog.isShowDialog = false;
|
||||||
};
|
};
|
||||||
// 取消
|
// 取消
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
// 新增
|
// 提交
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
emit('refresh');
|
||||||
|
// if (state.dialog.type === 'add') { }
|
||||||
};
|
};
|
||||||
// 获取菜单结构数据
|
// 获取菜单结构数据
|
||||||
const getMenuData = () => {
|
const getMenuData = () => {
|
||||||
@ -202,7 +225,7 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.system-add-role-container {
|
.system-role-dialog-container {
|
||||||
.menu-data-tree {
|
.menu-data-tree {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid var(--el-border-color);
|
border: 1px solid var(--el-border-color);
|
||||||
@ -9,14 +9,14 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="default" type="success" class="ml10" @click="onOpenAddRole">
|
<el-button size="default" type="success" class="ml10" @click="onOpenAddRole('add')">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<ele-FolderAdd />
|
<ele-FolderAdd />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
新增角色
|
新增角色
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="state.tableData.data" style="width: 100%">
|
<el-table :data="state.tableData.data" v-loading="state.tableData.loading" style="width: 100%">
|
||||||
<el-table-column type="index" label="序号" width="60" />
|
<el-table-column type="index" label="序号" width="60" />
|
||||||
<el-table-column prop="roleName" label="角色名称" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="roleName" label="角色名称" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column prop="roleSign" label="角色标识" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="roleSign" label="角色标识" show-overflow-tooltip></el-table-column>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column label="操作" width="100">
|
<el-table-column label="操作" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onOpenEditRole(scope.row)"
|
<el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onOpenEditRole('edit', scope.row)"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
<el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
<el-button :disabled="scope.row.roleName === '超级管理员'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
||||||
@ -52,8 +52,7 @@
|
|||||||
>
|
>
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</div>
|
</div>
|
||||||
<AddRole ref="addRoleRef" />
|
<RoleDialog ref="roleDialogRef" @refresh="getTableData()" />
|
||||||
<EditRole ref="editRoleRef" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -62,12 +61,10 @@ import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
|
|||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const AddRole = defineAsyncComponent(() => import('/@/views/system/role/component/addRole.vue'));
|
const RoleDialog = defineAsyncComponent(() => import('/@/views/system/role/dialog.vue'));
|
||||||
const EditRole = defineAsyncComponent(() => import('/@/views/system/role/component/editRole.vue'));
|
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const addRoleRef = ref();
|
const roleDialogRef = ref();
|
||||||
const editRoleRef = ref();
|
|
||||||
const state = reactive<SysRoleState>({
|
const state = reactive<SysRoleState>({
|
||||||
tableData: {
|
tableData: {
|
||||||
data: [],
|
data: [],
|
||||||
@ -81,7 +78,8 @@ const state = reactive<SysRoleState>({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
// 初始化表格数据
|
// 初始化表格数据
|
||||||
const initTableData = () => {
|
const getTableData = () => {
|
||||||
|
state.tableData.loading = true;
|
||||||
const data = [];
|
const data = [];
|
||||||
for (let i = 0; i < 20; i++) {
|
for (let i = 0; i < 20; i++) {
|
||||||
data.push({
|
data.push({
|
||||||
@ -95,14 +93,17 @@ const initTableData = () => {
|
|||||||
}
|
}
|
||||||
state.tableData.data = data;
|
state.tableData.data = data;
|
||||||
state.tableData.total = state.tableData.data.length;
|
state.tableData.total = state.tableData.data.length;
|
||||||
|
setTimeout(() => {
|
||||||
|
state.tableData.loading = false;
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
// 打开新增角色弹窗
|
// 打开新增角色弹窗
|
||||||
const onOpenAddRole = () => {
|
const onOpenAddRole = (type: string) => {
|
||||||
addRoleRef.value.openDialog();
|
roleDialogRef.value.openDialog(type);
|
||||||
};
|
};
|
||||||
// 打开修改角色弹窗
|
// 打开修改角色弹窗
|
||||||
const onOpenEditRole = (row: Object) => {
|
const onOpenEditRole = (type: string, row: Object) => {
|
||||||
editRoleRef.value.openDialog(row);
|
roleDialogRef.value.openDialog(type, row);
|
||||||
};
|
};
|
||||||
// 删除角色
|
// 删除角色
|
||||||
const onRowDel = (row: RowRoleType) => {
|
const onRowDel = (row: RowRoleType) => {
|
||||||
@ -112,6 +113,7 @@ const onRowDel = (row: RowRoleType) => {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
getTableData();
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
@ -119,14 +121,16 @@ const onRowDel = (row: RowRoleType) => {
|
|||||||
// 分页改变
|
// 分页改变
|
||||||
const onHandleSizeChange = (val: number) => {
|
const onHandleSizeChange = (val: number) => {
|
||||||
state.tableData.param.pageSize = val;
|
state.tableData.param.pageSize = val;
|
||||||
|
getTableData();
|
||||||
};
|
};
|
||||||
// 分页改变
|
// 分页改变
|
||||||
const onHandleCurrentChange = (val: number) => {
|
const onHandleCurrentChange = (val: number) => {
|
||||||
state.tableData.param.pageNum = val;
|
state.tableData.param.pageNum = val;
|
||||||
|
getTableData();
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initTableData();
|
getTableData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,167 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="system-add-user-container">
|
|
||||||
<el-dialog title="新增用户" v-model="state.isShowDialog" width="769px">
|
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
|
||||||
<el-row :gutter="35">
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="账户名称">
|
|
||||||
<el-input v-model="state.ruleForm.userName" placeholder="请输入账户名称" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="用户昵称">
|
|
||||||
<el-input v-model="state.ruleForm.userNickname" placeholder="请输入用户昵称" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="关联角色">
|
|
||||||
<el-select v-model="state.ruleForm.roleSign" placeholder="请选择" clearable class="w100">
|
|
||||||
<el-option label="超级管理员" value="admin"></el-option>
|
|
||||||
<el-option label="普通用户" value="common"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="部门">
|
|
||||||
<el-cascader
|
|
||||||
:options="state.deptData"
|
|
||||||
:props="{ checkStrictly: true, value: 'deptName', label: 'deptName' }"
|
|
||||||
placeholder="请选择部门"
|
|
||||||
clearable
|
|
||||||
class="w100"
|
|
||||||
v-model="state.ruleForm.department"
|
|
||||||
>
|
|
||||||
<template #default="{ node, data }">
|
|
||||||
<span>{{ data.deptName }}</span>
|
|
||||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
|
||||||
</template>
|
|
||||||
</el-cascader>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="手机号">
|
|
||||||
<el-input v-model="state.ruleForm.phone" placeholder="请输入手机号" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="邮箱">
|
|
||||||
<el-input v-model="state.ruleForm.email" placeholder="请输入" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="性别">
|
|
||||||
<el-select v-model="state.ruleForm.sex" placeholder="请选择" clearable class="w100">
|
|
||||||
<el-option label="男" value="男"></el-option>
|
|
||||||
<el-option label="女" value="女"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="账户密码">
|
|
||||||
<el-input v-model="state.ruleForm.password" placeholder="请输入" type="password" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="账户过期">
|
|
||||||
<el-date-picker v-model="state.ruleForm.overdueTime" type="date" placeholder="请选择" class="w100"> </el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
|
||||||
<el-form-item label="用户状态">
|
|
||||||
<el-switch v-model="state.ruleForm.status" inline-prompt active-text="启" inactive-text="禁"></el-switch>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
|
||||||
<el-form-item label="用户描述">
|
|
||||||
<el-input v-model="state.ruleForm.describe" type="textarea" placeholder="请输入用户描述" maxlength="150"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="onSubmit" size="default">新 增</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="systemAddUser">
|
|
||||||
import { reactive, onMounted } from 'vue';
|
|
||||||
|
|
||||||
// 定义变量内容
|
|
||||||
const state = reactive({
|
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
|
||||||
userName: '', // 账户名称
|
|
||||||
userNickname: '', // 用户昵称
|
|
||||||
roleSign: '', // 关联角色
|
|
||||||
department: [], // 部门
|
|
||||||
phone: '', // 手机号
|
|
||||||
email: '', // 邮箱
|
|
||||||
sex: '', // 性别
|
|
||||||
password: '', // 账户密码
|
|
||||||
overdueTime: '', // 账户过期
|
|
||||||
status: true, // 用户状态
|
|
||||||
describe: '', // 用户描述
|
|
||||||
},
|
|
||||||
deptData: [] as DeptTreeType[], // 部门数据
|
|
||||||
});
|
|
||||||
|
|
||||||
// 打开弹窗
|
|
||||||
const openDialog = () => {
|
|
||||||
state.isShowDialog = true;
|
|
||||||
};
|
|
||||||
// 关闭弹窗
|
|
||||||
const closeDialog = () => {
|
|
||||||
state.isShowDialog = false;
|
|
||||||
};
|
|
||||||
// 取消
|
|
||||||
const onCancel = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 新增
|
|
||||||
const onSubmit = () => {
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
// 初始化部门数据
|
|
||||||
const initTableData = () => {
|
|
||||||
state.deptData.push({
|
|
||||||
deptName: 'vueNextAdmin',
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
status: true,
|
|
||||||
sort: Math.random(),
|
|
||||||
describe: '顶级部门',
|
|
||||||
id: Math.random(),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
deptName: 'IT外包服务',
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
status: true,
|
|
||||||
sort: Math.random(),
|
|
||||||
describe: '总部',
|
|
||||||
id: Math.random(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deptName: '资本控股',
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
status: true,
|
|
||||||
sort: Math.random(),
|
|
||||||
describe: '分部',
|
|
||||||
id: Math.random(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {
|
|
||||||
initTableData();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 暴露变量
|
|
||||||
defineExpose({
|
|
||||||
openDialog,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="system-edit-user-container">
|
<div class="system-user-dialog-container">
|
||||||
<el-dialog title="修改用户" v-model="state.isShowDialog" width="769px">
|
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
|
||||||
<el-form :model="state.ruleForm" size="default" label-width="90px">
|
<el-form ref="userDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
<el-form-item label="账户名称">
|
<el-form-item label="账户名称">
|
||||||
@ -81,19 +81,22 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" size="default">修 改</el-button>
|
<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemEditUser">
|
<script setup lang="ts" name="systemUserDialog">
|
||||||
import { reactive, onMounted } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
|
const userDialogFormRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowDialog: false,
|
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
userName: '', // 账户名称
|
userName: '', // 账户名称
|
||||||
userNickname: '', // 用户昵称
|
userNickname: '', // 用户昵称
|
||||||
@ -108,27 +111,47 @@ const state = reactive({
|
|||||||
describe: '', // 用户描述
|
describe: '', // 用户描述
|
||||||
},
|
},
|
||||||
deptData: [] as DeptTreeType[], // 部门数据
|
deptData: [] as DeptTreeType[], // 部门数据
|
||||||
|
dialog: {
|
||||||
|
isShowDialog: false,
|
||||||
|
type: '',
|
||||||
|
title: '',
|
||||||
|
submitTxt: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (row: RowUserType) => {
|
const openDialog = (type: string, row: RowUserType) => {
|
||||||
state.ruleForm = row;
|
if (type === 'edit') {
|
||||||
state.isShowDialog = true;
|
state.ruleForm = row;
|
||||||
|
state.dialog.title = '修改用户';
|
||||||
|
state.dialog.submitTxt = '修 改';
|
||||||
|
} else {
|
||||||
|
state.dialog.title = '新增用户';
|
||||||
|
state.dialog.submitTxt = '新 增';
|
||||||
|
// 清空表单,此项需加表单验证才能使用
|
||||||
|
// nextTick(() => {
|
||||||
|
// userDialogFormRef.value.resetFields();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
state.dialog.isShowDialog = true;
|
||||||
|
getMenuData();
|
||||||
};
|
};
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
state.isShowDialog = false;
|
state.dialog.isShowDialog = false;
|
||||||
};
|
};
|
||||||
// 取消
|
// 取消
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
// 新增
|
// 提交
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
emit('refresh');
|
||||||
|
// if (state.dialog.type === 'add') { }
|
||||||
};
|
};
|
||||||
// 初始化部门数据
|
// 初始化部门数据
|
||||||
const initTableData = () => {
|
const getMenuData = () => {
|
||||||
state.deptData.push({
|
state.deptData.push({
|
||||||
deptName: 'vueNextAdmin',
|
deptName: 'vueNextAdmin',
|
||||||
createTime: new Date().toLocaleString(),
|
createTime: new Date().toLocaleString(),
|
||||||
@ -156,10 +179,6 @@ const initTableData = () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {
|
|
||||||
initTableData();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@ -9,14 +9,14 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="default" type="success" class="ml10" @click="onOpenAddUser">
|
<el-button size="default" type="success" class="ml10" @click="onOpenAddUser('add')">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<ele-FolderAdd />
|
<ele-FolderAdd />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
新增用户
|
新增用户
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="state.tableData.data" style="width: 100%">
|
<el-table :data="state.tableData.data" v-loading="state.tableData.loading" style="width: 100%">
|
||||||
<el-table-column type="index" label="序号" width="60" />
|
<el-table-column type="index" label="序号" width="60" />
|
||||||
<el-table-column prop="userName" label="账户名称" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="userName" label="账户名称" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column prop="userNickname" label="用户昵称" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="userNickname" label="用户昵称" show-overflow-tooltip></el-table-column>
|
||||||
@ -34,7 +34,9 @@
|
|||||||
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column label="操作" width="100">
|
<el-table-column label="操作" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onOpenEditUser(scope.row)">修改</el-button>
|
<el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onOpenEditUser('edit', scope.row)"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
<el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
<el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -53,8 +55,7 @@
|
|||||||
>
|
>
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</el-card>
|
</el-card>
|
||||||
<AddUer ref="addUserRef" />
|
<UserDialog ref="userDialogRef" @refresh="getTableData()" />
|
||||||
<EditUser ref="editUserRef" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -63,12 +64,10 @@ import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
|
|||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const AddUer = defineAsyncComponent(() => import('/@/views/system/user/component/addUser.vue'));
|
const UserDialog = defineAsyncComponent(() => import('/@/views/system/user/dialog.vue'));
|
||||||
const EditUser = defineAsyncComponent(() => import('/@/views/system/user/component/editUser.vue'));
|
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const addUserRef = ref();
|
const userDialogRef = ref();
|
||||||
const editUserRef = ref();
|
|
||||||
const state = reactive<SysUserState>({
|
const state = reactive<SysUserState>({
|
||||||
tableData: {
|
tableData: {
|
||||||
data: [],
|
data: [],
|
||||||
@ -82,7 +81,8 @@ const state = reactive<SysUserState>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 初始化表格数据
|
// 初始化表格数据
|
||||||
const initTableData = () => {
|
const getTableData = () => {
|
||||||
|
state.tableData.loading = true;
|
||||||
const data = [];
|
const data = [];
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
data.push({
|
data.push({
|
||||||
@ -102,14 +102,17 @@ const initTableData = () => {
|
|||||||
}
|
}
|
||||||
state.tableData.data = data;
|
state.tableData.data = data;
|
||||||
state.tableData.total = state.tableData.data.length;
|
state.tableData.total = state.tableData.data.length;
|
||||||
|
setTimeout(() => {
|
||||||
|
state.tableData.loading = false;
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
// 打开新增用户弹窗
|
// 打开新增用户弹窗
|
||||||
const onOpenAddUser = () => {
|
const onOpenAddUser = (type: string) => {
|
||||||
addUserRef.value.openDialog();
|
userDialogRef.value.openDialog(type);
|
||||||
};
|
};
|
||||||
// 打开修改用户弹窗
|
// 打开修改用户弹窗
|
||||||
const onOpenEditUser = (row: RowUserType) => {
|
const onOpenEditUser = (type: string, row: RowUserType) => {
|
||||||
editUserRef.value.openDialog(row);
|
userDialogRef.value.openDialog(type, row);
|
||||||
};
|
};
|
||||||
// 删除用户
|
// 删除用户
|
||||||
const onRowDel = (row: RowUserType) => {
|
const onRowDel = (row: RowUserType) => {
|
||||||
@ -119,6 +122,7 @@ const onRowDel = (row: RowUserType) => {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
getTableData();
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
@ -126,14 +130,16 @@ const onRowDel = (row: RowUserType) => {
|
|||||||
// 分页改变
|
// 分页改变
|
||||||
const onHandleSizeChange = (val: number) => {
|
const onHandleSizeChange = (val: number) => {
|
||||||
state.tableData.param.pageSize = val;
|
state.tableData.param.pageSize = val;
|
||||||
|
getTableData();
|
||||||
};
|
};
|
||||||
// 分页改变
|
// 分页改变
|
||||||
const onHandleCurrentChange = (val: number) => {
|
const onHandleCurrentChange = (val: number) => {
|
||||||
state.tableData.param.pageNum = val;
|
state.tableData.param.pageNum = val;
|
||||||
|
getTableData();
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initTableData();
|
getTableData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -127,7 +127,7 @@
|
|||||||
<div class="big-data-down-center">
|
<div class="big-data-down-center">
|
||||||
<div class="big-data-down-center-one">
|
<div class="big-data-down-center-one">
|
||||||
<div class="big-data-down-center-one-content" ref="rightChartData5">
|
<div class="big-data-down-center-one-content" ref="rightChartData5">
|
||||||
<div ref="the3DEarth"></div>
|
<div id="3DEarth"></div>
|
||||||
<div :class="v.topLevelClass" v-for="(v, k) in state.earth3DBtnList" :key="k">
|
<div :class="v.topLevelClass" v-for="(v, k) in state.earth3DBtnList" :key="k">
|
||||||
<div class="circle" v-for="i in 4" :key="i"></div>
|
<div class="circle" v-for="i in 4" :key="i"></div>
|
||||||
<div class="text-box">
|
<div class="text-box">
|
||||||
@ -259,7 +259,6 @@ const state = reactive<Demo2State>({
|
|||||||
earth3DBtnList,
|
earth3DBtnList,
|
||||||
chartData4List,
|
chartData4List,
|
||||||
myCharts: [],
|
myCharts: [],
|
||||||
the3DEarth: null,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化时间
|
// 初始化时间
|
||||||
@ -690,7 +689,7 @@ const initRightChartData2 = () => {
|
|||||||
};
|
};
|
||||||
// 3DEarth 地图
|
// 3DEarth 地图
|
||||||
const init3DEarth = (globeRadius: any) => {
|
const init3DEarth = (globeRadius: any) => {
|
||||||
let el = state.the3DEarth!;
|
let el = <HTMLElement>document.getElementById('3DEarth');
|
||||||
el.style.height = `${rightChartData5.value.offsetHeight}px`;
|
el.style.height = `${rightChartData5.value.offsetHeight}px`;
|
||||||
const myChart = echarts.init(el);
|
const myChart = echarts.init(el);
|
||||||
const option = {
|
const option = {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { resolve } from 'path';
|
|||||||
import { defineConfig, loadEnv, ConfigEnv } from 'vite';
|
import { defineConfig, loadEnv, ConfigEnv } from 'vite';
|
||||||
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
|
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
|
||||||
|
|
||||||
const pathResolve = (dir: string): any => {
|
const pathResolve = (dir: string) => {
|
||||||
return resolve(__dirname, '.', dir);
|
return resolve(__dirname, '.', dir);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,7 +19,6 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
|
|||||||
root: process.cwd(),
|
root: process.cwd(),
|
||||||
resolve: { alias },
|
resolve: { alias },
|
||||||
base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH,
|
base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH,
|
||||||
hmr: true,
|
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
include: ['element-plus/lib/locale/lang/zh-cn', 'element-plus/lib/locale/lang/en', 'element-plus/lib/locale/lang/zh-tw'],
|
include: ['element-plus/lib/locale/lang/zh-cn', 'element-plus/lib/locale/lang/en', 'element-plus/lib/locale/lang/zh-tw'],
|
||||||
},
|
},
|
||||||
@ -27,6 +26,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
|
|||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: env.VITE_PORT as unknown as number,
|
port: env.VITE_PORT as unknown as number,
|
||||||
open: env.VITE_OPEN,
|
open: env.VITE_OPEN,
|
||||||
|
hmr: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/gitee': {
|
'/gitee': {
|
||||||
target: 'https://gitee.com',
|
target: 'https://gitee.com',
|
||||||
@ -38,7 +38,6 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
|
|||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
sourcemap: false,
|
|
||||||
chunkSizeWarningLimit: 1500,
|
chunkSizeWarningLimit: 1500,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
@ -58,6 +57,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
|
|||||||
__VUE_I18N_LEGACY_API__: JSON.stringify(false),
|
__VUE_I18N_LEGACY_API__: JSON.stringify(false),
|
||||||
__VUE_I18N_FULL_INSTALL__: JSON.stringify(false),
|
__VUE_I18N_FULL_INSTALL__: JSON.stringify(false),
|
||||||
__INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false),
|
__INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false),
|
||||||
|
__VERSION__: JSON.stringify(process.env.npm_package_version),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user