mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-12 17:22:26 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
905984367c | ||
|
|
d3f7fa0f9e | ||
|
|
9c512002d2 | ||
|
|
737f967aab | ||
|
|
1cdb02c9d7 | ||
|
|
bc8dd21405 | ||
|
|
2dba60405e | ||
|
|
eba3047be2 | ||
|
|
0979b5af5d | ||
|
|
ade138997d | ||
|
|
d388ae5656 | ||
|
|
8f05b20ffa | ||
|
|
d973b2a543 | ||
|
|
1d5113a663 | ||
|
|
f331d9c4c7 | ||
|
|
c647e19d06 | ||
|
|
5c5c52d9fa | ||
|
|
3e0b8efe7e | ||
|
|
450234e7ea |
63
CHANGELOG.md
63
CHANGELOG.md
@@ -1,4 +1,63 @@
|
|||||||
# 1.5.1 (2021-08-07)
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 1.5.5 (2021-08-14)
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 修复路由只存在一个子路由,图标不显示问题
|
||||||
|
- UI样式美化
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 支持 Vue 3.2.x
|
||||||
|
- 代码全部按 `script setup` 语法重写(完成80%)
|
||||||
|
- 新增 `回到顶部` 功能
|
||||||
|
- 新增 `拖拽` 示例页面
|
||||||
|
- 新增 `富文本` 组件
|
||||||
|
- 新增 `路由切换动画` 可在项目设置切换
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 1.5.4 (2021-08-10)
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- `暗色模式下多页签背景问题 ` 合并 [#23](https://github.com/jekip/naive-ui-admin/pull/23) 感谢 [@Dishone](https://github.com/Dishone)
|
||||||
|
- `表格设置列,重复添加action列样式错乱问题` 合并 [#24](https://github.com/jekip/naive-ui-admin/pull/24) 感谢 [@CasbaL](https://github.com/CasbaL)
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 新增 `路由支持(内联外部地址)`配置
|
||||||
|
- 新增 `顶部菜单` logo展示
|
||||||
|
-(破坏性更新)
|
||||||
|
- 优化 `动态路由配置` 取消`constantRouterComponents.ts`,中组件映射配置,更名为 `router-icons.ts`
|
||||||
|
- 优化 `admin_info接口结构`,roles 更名为:permissions,roles.roleName,更名为:label
|
||||||
|
- 优化 多级路由,当没有配置`redirect`时,默认为第一个子路由,配置则优先按配置
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
|
# 1.5.3 (2021-08-09)
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 修复顶部菜单,选中联动
|
||||||
|
- 修复混合菜单模式,切换其他模式菜单未重置
|
||||||
|
- 实例基础列表,和表格组件实例,开启横向滚动特性
|
||||||
|
- `naiveui` 升级成最新版
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- table组件,默认开启 `ellipsis` 特性
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1.5.2 (2021-08-06)
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 修复已知bug
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 新增 `混合菜单模式`
|
||||||
|
- 新增 `根路由`
|
||||||
|
- 新增 `关于` 根路由示例页面
|
||||||
|
- 文档同步更新,组件和示例
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1.5.1 (2021-08-05)
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
- 修复windows系统获取项目换行符问题
|
- 修复windows系统获取项目换行符问题
|
||||||
- 修复表格分页计算问题 [@Chika99](https://github.com/Chika99)
|
- 修复表格分页计算问题 [@Chika99](https://github.com/Chika99)
|
||||||
@@ -6,8 +65,6 @@
|
|||||||
- 依赖 dayjs 移除,用date-fns,和UI框架底层保持一致
|
- 依赖 dayjs 移除,用date-fns,和UI框架底层保持一致
|
||||||
- 修复已知bug
|
- 修复已知bug
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- ### ✨ Features
|
- ### ✨ Features
|
||||||
- 新增 `baseForm` 组件,和`基础`,`useForm`使用方式
|
- 新增 `baseForm` 组件,和`基础`,`useForm`使用方式
|
||||||
- 新增 `baseModal`,组件,和 `useForm`使用方式
|
- 新增 `baseModal`,组件,和 `useForm`使用方式
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
|
|
||||||
|
|
||||||
## 在线预览
|
## 在线预览
|
||||||
- [naive-ui-admin](https://jekip.github.io)
|
- [naive-ui-admin](https://naive-ui-admin.vercel.app)
|
||||||
|
|
||||||
账号:admin,密码:123456(随意)
|
账号:admin,密码:123456(随意)
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
[文档地址](https://jekip.github.io/docs/)
|
[文档地址](https://naive-ui-admin-docs.vercel.app)
|
||||||
|
|
||||||
## 准备
|
## 准备
|
||||||
|
|
||||||
@@ -117,3 +117,7 @@ yarn build
|
|||||||
|
|
||||||
- QQ 群 `328347666`
|
- QQ 群 `328347666`
|
||||||
|
|
||||||
|
## 赞助
|
||||||
|
#### 如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 🍹。
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: 'Layout',
|
component: 'LAYOUT',
|
||||||
redirect: '/dashboard/console',
|
redirect: '/dashboard/console',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'DashboardOutlined',
|
icon: 'DashboardOutlined',
|
||||||
@@ -14,7 +14,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: 'console',
|
path: 'console',
|
||||||
name: 'dashboard_console',
|
name: 'dashboard_console',
|
||||||
component: 'DashboardConsole',
|
component: '/dashboard/console/console',
|
||||||
meta: {
|
meta: {
|
||||||
title: '主控台',
|
title: '主控台',
|
||||||
},
|
},
|
||||||
@@ -22,7 +22,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: 'monitor',
|
path: 'monitor',
|
||||||
name: 'dashboard_monitor',
|
name: 'dashboard_monitor',
|
||||||
component: 'DashboardMonitor',
|
component: '/dashboard/monitor/monitor',
|
||||||
meta: {
|
meta: {
|
||||||
title: '监控页',
|
title: '监控页',
|
||||||
},
|
},
|
||||||
@@ -30,7 +30,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: 'workplace',
|
path: 'workplace',
|
||||||
name: 'dashboard_workplace',
|
name: 'dashboard_workplace',
|
||||||
component: 'DashboardWorkplace',
|
component: '/dashboard/workplace/workplace',
|
||||||
meta: {
|
meta: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
title: '工作台',
|
title: '工作台',
|
||||||
|
|||||||
@@ -13,25 +13,25 @@ const adminInfo = {
|
|||||||
desc: 'manager',
|
desc: 'manager',
|
||||||
password: Random.string('upper', 4, 16),
|
password: Random.string('upper', 4, 16),
|
||||||
token,
|
token,
|
||||||
roles: [
|
permissions: [
|
||||||
{
|
{
|
||||||
roleName: '主控台',
|
label: '主控台',
|
||||||
value: 'dashboard_console',
|
value: 'dashboard_console',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '监控页',
|
label: '监控页',
|
||||||
value: 'dashboard_monitor',
|
value: 'dashboard_monitor',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '工作台',
|
label: '工作台',
|
||||||
value: 'dashboard_workplace',
|
value: 'dashboard_workplace',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '基础列表',
|
label: '基础列表',
|
||||||
value: 'basic_list',
|
value: 'basic_list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '基础列表删除',
|
label: '基础列表删除',
|
||||||
value: 'basic_list_delete',
|
value: 'basic_list_delete',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
21
package.json
21
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "naive-ui-admin",
|
"name": "naive-ui-admin",
|
||||||
"version": "1.5.1",
|
"version": "1.5.5",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Ahjung",
|
"name": "Ahjung",
|
||||||
"email": "735878602@qq.com",
|
"email": "735878602@qq.com",
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vicons/antd": "^0.10.0",
|
"@vicons/antd": "^0.10.0",
|
||||||
"@vicons/ionicons5": "^0.10.0",
|
"@vicons/ionicons5": "^0.10.0",
|
||||||
|
"@vueup/vue-quill": "^1.0.0-beta.7",
|
||||||
"@vueuse/core": "^5.0.3",
|
"@vueuse/core": "^5.0.3",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"blueimp-md5": "^2.18.0",
|
"blueimp-md5": "^2.18.0",
|
||||||
@@ -38,12 +39,12 @@
|
|||||||
"makeit-captcha": "^1.2.5",
|
"makeit-captcha": "^1.2.5",
|
||||||
"mitt": "^2.1.0",
|
"mitt": "^2.1.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"naive-ui": "^2.16.0",
|
"naive-ui": "^2.16.2",
|
||||||
"pinia": "^2.0.0-beta.3",
|
"pinia": "^2.0.0-rc.4",
|
||||||
"qs": "^6.10.1",
|
"qs": "^6.10.1",
|
||||||
"vfonts": "^0.1.0",
|
"vfonts": "^0.1.0",
|
||||||
"vue": "^3.1.2",
|
"vue": "^3.2.2",
|
||||||
"vue-router": "^4.0.10",
|
"vue-router": "^4.0.11",
|
||||||
"vue-types": "^4.0.0",
|
"vue-types": "^4.0.0",
|
||||||
"vuedraggable": "^4.0.3",
|
"vuedraggable": "^4.0.3",
|
||||||
"vuex": "^4.0.2"
|
"vuex": "^4.0.2"
|
||||||
@@ -53,17 +54,17 @@
|
|||||||
"@commitlint/config-conventional": "^12.1.4",
|
"@commitlint/config-conventional": "^12.1.4",
|
||||||
"@types/lodash": "^4.14.170",
|
"@types/lodash": "^4.14.170",
|
||||||
"@types/node": "^15.12.2",
|
"@types/node": "^15.12.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.26.1",
|
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
||||||
"@typescript-eslint/parser": "^4.26.1",
|
"@typescript-eslint/parser": "^4.29.1",
|
||||||
"@vitejs/plugin-vue": "^1.2.3",
|
"@vitejs/plugin-vue": "^1.2.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^1.1.5",
|
"@vitejs/plugin-vue-jsx": "^1.1.5",
|
||||||
"@vue/compiler-sfc": "3.1.1",
|
"@vue/compiler-sfc": "^3.2.2",
|
||||||
"@vue/eslint-config-typescript": "^7.0.0",
|
"@vue/eslint-config-typescript": "^7.0.0",
|
||||||
"autoprefixer": "^10.3.1",
|
"autoprefixer": "^10.3.1",
|
||||||
"commitizen": "^4.2.4",
|
"commitizen": "^4.2.4",
|
||||||
"core-js": "^3.14.0",
|
"core-js": "^3.14.0",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"eslint": "^7.28.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-define-config": "^1.0.9",
|
"eslint-define-config": "^1.0.9",
|
||||||
"eslint-plugin-jest": "^24.4.0",
|
"eslint-plugin-jest": "^24.4.0",
|
||||||
@@ -87,7 +88,7 @@
|
|||||||
"stylelint-scss": "^3.19.0",
|
"stylelint-scss": "^3.19.0",
|
||||||
"tailwindcss": "^2.2.7",
|
"tailwindcss": "^2.2.7",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
"vite": "2.3.6",
|
"vite": "2.4.4",
|
||||||
"vite-plugin-compression": "^0.3.1",
|
"vite-plugin-compression": "^0.3.1",
|
||||||
"vite-plugin-html": "^2.0.7",
|
"vite-plugin-html": "^2.0.7",
|
||||||
"vite-plugin-mock": "^2.9.3",
|
"vite-plugin-mock": "^2.9.3",
|
||||||
|
|||||||
123
src/App.vue
123
src/App.vue
@@ -16,8 +16,8 @@
|
|||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, computed, onMounted, onUnmounted } from 'vue';
|
import { computed, onMounted, onUnmounted } from 'vue';
|
||||||
import { zhCN, dateZhCN, createTheme, inputDark, datePickerDark, darkTheme } from 'naive-ui';
|
import { zhCN, dateZhCN, createTheme, inputDark, datePickerDark, darkTheme } from 'naive-ui';
|
||||||
import { LockScreen } from '@/components/Lockscreen';
|
import { LockScreen } from '@/components/Lockscreen';
|
||||||
import { AppProvider } from '@/components/Application';
|
import { AppProvider } from '@/components/Application';
|
||||||
@@ -26,86 +26,61 @@
|
|||||||
import { useDesignSettingStore } from '@/store/modules/designSetting';
|
import { useDesignSettingStore } from '@/store/modules/designSetting';
|
||||||
import { lighten } from '@/utils/index';
|
import { lighten } from '@/utils/index';
|
||||||
|
|
||||||
export default defineComponent({
|
const route = useRoute();
|
||||||
name: 'App',
|
const useLockscreen = useLockscreenStore();
|
||||||
components: { LockScreen, AppProvider },
|
const designStore = useDesignSettingStore();
|
||||||
setup() {
|
const isLock = computed(() => useLockscreen.isLock);
|
||||||
const route = useRoute();
|
const lockTime = computed(() => useLockscreen.lockTime);
|
||||||
const useLockscreen = useLockscreenStore();
|
|
||||||
const designStore = useDesignSettingStore();
|
|
||||||
const isLock = computed(() => useLockscreen.isLock);
|
|
||||||
const lockTime = computed(() => useLockscreen.lockTime);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type import('naive-ui').GlobalThemeOverrides
|
* @type import('naive-ui').GlobalThemeOverrides
|
||||||
*/
|
*/
|
||||||
const getThemeOverrides = computed(() => {
|
const getThemeOverrides = computed(() => {
|
||||||
const appTheme = designStore.appTheme;
|
const appTheme = designStore.appTheme;
|
||||||
const lightenStr = lighten(designStore.appTheme, 6);
|
const lightenStr = lighten(designStore.appTheme, 6);
|
||||||
return {
|
return {
|
||||||
common: {
|
common: {
|
||||||
primaryColor: appTheme,
|
primaryColor: appTheme,
|
||||||
primaryColorHover: lightenStr,
|
primaryColorHover: lightenStr,
|
||||||
primaryColorPressed: lightenStr,
|
primaryColorPressed: lightenStr,
|
||||||
},
|
},
|
||||||
LoadingBar: {
|
LoadingBar: {
|
||||||
colorLoading: appTheme,
|
colorLoading: appTheme,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const getDarkTheme = computed(() => (designStore.darkTheme ? darkTheme : undefined));
|
const getDarkTheme = computed(() => (designStore.darkTheme ? darkTheme : undefined));
|
||||||
|
|
||||||
let timer;
|
let timer;
|
||||||
|
|
||||||
const timekeeping = () => {
|
const timekeeping = () => {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
if (route.name == 'login' || isLock.value) return;
|
if (route.name == 'login' || isLock.value) return;
|
||||||
// 设置不锁屏
|
// 设置不锁屏
|
||||||
useLockscreen.setLock(false);
|
useLockscreen.setLock(false);
|
||||||
// 重置锁屏时间
|
// 重置锁屏时间
|
||||||
useLockscreen.setLockTime();
|
useLockscreen.setLockTime();
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
// 锁屏倒计时递减
|
// 锁屏倒计时递减
|
||||||
useLockscreen.setLockTime(lockTime.value - 1);
|
useLockscreen.setLockTime(lockTime.value - 1);
|
||||||
if (lockTime.value <= 0) {
|
if (lockTime.value <= 0) {
|
||||||
// 设置锁屏
|
// 设置锁屏
|
||||||
useLockscreen.setLock(true);
|
useLockscreen.setLock(true);
|
||||||
return clearInterval(timer);
|
return clearInterval(timer);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('mousedown', timekeeping);
|
document.addEventListener('mousedown', timekeeping);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener('mousedown', timekeeping);
|
document.removeEventListener('mousedown', timekeeping);
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
darkTheme: createTheme([inputDark, datePickerDark]),
|
|
||||||
getDarkTheme,
|
|
||||||
zhCN,
|
|
||||||
dateZhCN,
|
|
||||||
isLock,
|
|
||||||
getThemeOverrides,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import 'styles/common.less';
|
@import 'styles/index.less';
|
||||||
|
|
||||||
.slide-up-enter-active,
|
|
||||||
.slide-up-leave-active {
|
|
||||||
transition: transform 0.35s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.slide-up-enter-form,
|
|
||||||
.slide-up-leave-to {
|
|
||||||
transform: translateY(-100%);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import http from '@/utils/http/axios';
|
|||||||
/**
|
/**
|
||||||
* @description: 角色列表
|
* @description: 角色列表
|
||||||
*/
|
*/
|
||||||
export function getRoleList() {
|
export function getRoleList(params) {
|
||||||
return http.request({
|
return http.request({
|
||||||
url: '/role/list',
|
url: '/role/list',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.3 KiB |
15
src/assets/images/nav-horizontal-mix.svg
Normal file
15
src/assets/images/nav-horizontal-mix.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="52px" height="45px" viewBox="0 0 52 45" enable-background="new 0 0 52 45" xml:space="preserve"> <image id="image0" width="52" height="45" x="0" y="0"
|
||||||
|
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAAtCAMAAADWf7iKAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
|
||||||
|
AAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAAdVBMVEX///8AAABkbnc9RVY7
|
||||||
|
QE9fY3GIiJZjbHk9QFOCi5QAAAA9QlZfZHMAAAA4QFEAAADt7/Lf5OTt7/KChoYAAADu8PTf3+Nw
|
||||||
|
c3MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyNUkyOEn////w8vWhURXFAAAAI3RS
|
||||||
|
TlMAAE/2/uZJUP45AvfkBP4F9LrwPwP0vUkOAREsNjk0JwYHCLrjEiIAAAABYktHRACIBR1IAAAA
|
||||||
|
CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5QgGAhE5kB5L+gAAAIZJREFUSMft1rsSgjAQhWEW
|
||||||
|
FTUYIopKlPui7/+IZqFhbMxmhm7//qvPiaKgAOIN+rbdJQCE9qO3cR2OhFTKMYgn5ZDmGcy0Q4aJ
|
||||||
|
0AhaoPdPnz8JEiRIkKCV0DkE5YQ0D12uBQ01B93uj9LSJdDPV1V71rRlMf0Iq7p+8Kw3aj4fAJYR
|
||||||
|
TCigL0lMJ5P4y7LRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIxLTA4LTA2VDAyOjE3OjU2KzAwOjAw
|
||||||
|
Kbo8/wAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMS0wOC0wNlQwMjoxNzo1NiswMDowMFjnhEMAAAAA
|
||||||
|
SUVORK5CYII=" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -102,11 +102,7 @@
|
|||||||
type="primary"
|
type="primary"
|
||||||
text
|
text
|
||||||
icon-placement="right"
|
icon-placement="right"
|
||||||
v-if="
|
v-if="isInline && getProps.showAdvancedButton"
|
||||||
isInline &&
|
|
||||||
getSchema.length > (getProps.gridProps?.cols || 0) &&
|
|
||||||
getProps.showAdvancedButton
|
|
||||||
"
|
|
||||||
@click="unfoldToggle"
|
@click="unfoldToggle"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@@ -212,6 +208,7 @@
|
|||||||
return {
|
return {
|
||||||
...gridProps,
|
...gridProps,
|
||||||
collapsed: isInline.value ? gridCollapsed.value : false,
|
collapsed: isInline.value ? gridCollapsed.value : false,
|
||||||
|
responsive: 'screen',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
type="password"
|
type="password"
|
||||||
autofocus
|
autofocus
|
||||||
v-model:value="loginParams.password"
|
v-model:value="loginParams.password"
|
||||||
|
@keyup.enter="onLogin"
|
||||||
placeholder="请输入登录密码"
|
placeholder="请输入登录密码"
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
|
|||||||
@@ -20,104 +20,88 @@
|
|||||||
</n-modal>
|
</n-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
ref,
|
ref,
|
||||||
nextTick,
|
nextTick,
|
||||||
unref,
|
unref,
|
||||||
toRefs,
|
|
||||||
reactive,
|
|
||||||
computed,
|
computed,
|
||||||
|
useAttrs,
|
||||||
|
defineEmits,
|
||||||
|
defineProps,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import startDrag from '@/utils/Drag';
|
import startDrag from '@/utils/Drag';
|
||||||
import { deepMerge } from '@/utils';
|
import { deepMerge } from '@/utils';
|
||||||
import { FormProps } from '@/components/Form';
|
import { FormProps } from '@/components/Form';
|
||||||
export default defineComponent({
|
import { ModalProps, ModalMethods } from './type';
|
||||||
name: 'BasicModal',
|
|
||||||
components: {},
|
|
||||||
props: {
|
|
||||||
...basicProps,
|
|
||||||
},
|
|
||||||
emits: ['on-close', 'on-ok', 'register'],
|
|
||||||
setup(props, { emit, attrs }) {
|
|
||||||
const propsRef = ref<Partial>({});
|
|
||||||
|
|
||||||
const state = reactive({
|
const attrs = useAttrs();
|
||||||
isModal: false,
|
const props = defineProps({ ...basicProps });
|
||||||
subLoading: false,
|
const emit = defineEmits(['on-close', 'on-ok', 'register']);
|
||||||
});
|
|
||||||
|
|
||||||
const getProps = computed((): FormProps => {
|
const propsRef = ref(<Partial<ModalProps> | null>null);
|
||||||
const modalProps = { ...props, ...unref(propsRef) };
|
|
||||||
return { ...modalProps };
|
|
||||||
});
|
|
||||||
|
|
||||||
async function setProps(modalProps: Partial): Promise<void> {
|
const isModal = ref(false);
|
||||||
propsRef.value = deepMerge(unref(propsRef) || {}, modalProps);
|
const subLoading = ref(false);
|
||||||
}
|
|
||||||
|
|
||||||
const getBindValue = computed(() => {
|
const getProps = computed((): FormProps => {
|
||||||
return {
|
return { ...props, ...(unref(propsRef) as any) };
|
||||||
...attrs,
|
|
||||||
...unref(getProps),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
function setSubLoading(status: boolean) {
|
|
||||||
state.subLoading = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openModal() {
|
|
||||||
state.isModal = true;
|
|
||||||
nextTick(() => {
|
|
||||||
const oBox = document.getElementById('basic-modal');
|
|
||||||
const oBar = document.getElementById('basic-modal-bar');
|
|
||||||
startDrag(oBar, oBox);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeModal() {
|
|
||||||
state.isModal = false;
|
|
||||||
state.subLoading = false;
|
|
||||||
emit('on-close');
|
|
||||||
}
|
|
||||||
|
|
||||||
function onCloseModal() {
|
|
||||||
state.isModal = false;
|
|
||||||
emit('on-close');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
state.subLoading = true;
|
|
||||||
emit('on-ok');
|
|
||||||
}
|
|
||||||
|
|
||||||
const modalMethods: ModalMethods = {
|
|
||||||
setProps,
|
|
||||||
openModal,
|
|
||||||
closeModal,
|
|
||||||
setSubLoading,
|
|
||||||
};
|
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
|
||||||
if (instance) {
|
|
||||||
emit('register', modalMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
getBindValue,
|
|
||||||
openModal,
|
|
||||||
closeModal,
|
|
||||||
onCloseModal,
|
|
||||||
handleSubmit,
|
|
||||||
setProps,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function setProps(modalProps: Partial<ModalProps>): Promise<void> {
|
||||||
|
propsRef.value = deepMerge(unref(propsRef) || ({} as any), modalProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBindValue = computed(() => {
|
||||||
|
return {
|
||||||
|
...attrs,
|
||||||
|
...unref(getProps),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function setSubLoading(status: boolean) {
|
||||||
|
subLoading.value = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openModal() {
|
||||||
|
isModal.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
const oBox = document.getElementById('basic-modal');
|
||||||
|
const oBar = document.getElementById('basic-modal-bar');
|
||||||
|
startDrag(oBar, oBox);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
isModal.value = false;
|
||||||
|
subLoading.value = false;
|
||||||
|
emit('on-close');
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCloseModal() {
|
||||||
|
isModal.value = false;
|
||||||
|
emit('on-close');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
subLoading.value = true;
|
||||||
|
emit('on-ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalMethods: ModalMethods = {
|
||||||
|
setProps,
|
||||||
|
openModal,
|
||||||
|
closeModal,
|
||||||
|
setSubLoading,
|
||||||
|
};
|
||||||
|
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
if (instance) {
|
||||||
|
emit('register', modalMethods);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|||||||
@@ -1,46 +1,43 @@
|
|||||||
import { ref, onUnmounted, unref, getCurrentInstance, watch } from 'vue';
|
import { ref, onUnmounted, unref, getCurrentInstance, watch, nextTick } from 'vue';
|
||||||
import { isProdMode } from '@/utils/env';
|
import { isProdMode } from '@/utils/env';
|
||||||
import { UseModalReturnType, ModalMethods } from './type';
|
import { ModalMethods, UseModalReturnType } from '../type';
|
||||||
import { getDynamicProps } from '@/utils';
|
import { getDynamicProps } from '@/utils';
|
||||||
export function useModal(props?: Props): UseModalReturnType {
|
import { tryOnUnmounted } from '@vueuse/core';
|
||||||
const modal = ref<Nullable<ModalMethods>>(null);
|
export function useModal(props): UseModalReturnType {
|
||||||
const loaded = ref<Nullable<boolean>>(false);
|
|
||||||
|
|
||||||
function register(modalMethod: ModalMethods) {
|
const modalRef = ref<Nullable<ModalMethods>>(null);
|
||||||
if (!getCurrentInstance()) {
|
const currentInstance = getCurrentInstance();
|
||||||
throw new Error('useModal() can only be used inside setup() or functional components!');
|
|
||||||
|
const getInstance = () => {
|
||||||
|
const instance = unref(modalRef.value);
|
||||||
|
if (!instance) {
|
||||||
|
console.error('useModal instance is undefined!');
|
||||||
}
|
}
|
||||||
|
return instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
const register = (modalInstance: ModalMethods) => {
|
||||||
isProdMode() &&
|
isProdMode() &&
|
||||||
onUnmounted(() => {
|
tryOnUnmounted(() => {
|
||||||
modal.value = null;
|
modalRef.value = null;
|
||||||
loaded.value = false;
|
|
||||||
});
|
});
|
||||||
if (unref(loaded) && isProdMode() && modalMethod === unref(modal)) return;
|
modalRef.value = modalInstance;
|
||||||
modal.value = modalMethod;
|
currentInstance?.emit('register', modalInstance);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props,
|
() => props,
|
||||||
() => {
|
() => {
|
||||||
const { setProps } = modal.value;
|
props && modalInstance.setProps(getDynamicProps(props));
|
||||||
props && setProps(getDynamicProps(props));
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true,
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
const getInstance = () => {
|
|
||||||
const instance = unref(modal);
|
|
||||||
if (!instance) {
|
|
||||||
error('useModal instance is undefined!');
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const methods: ReturnMethods = {
|
const methods: ModalMethods = {
|
||||||
setProps: (props: Partial<ModalProps>): void => {
|
setProps: (props): void => {
|
||||||
getInstance()?.setProps(props);
|
getInstance()?.setProps(props);
|
||||||
},
|
},
|
||||||
openModal: () => {
|
openModal: () => {
|
||||||
@@ -49,9 +46,10 @@ export function useModal(props?: Props): UseModalReturnType {
|
|||||||
closeModal: () => {
|
closeModal: () => {
|
||||||
getInstance()?.closeModal();
|
getInstance()?.closeModal();
|
||||||
},
|
},
|
||||||
setSubLoading: () => {
|
setSubLoading: (status) => {
|
||||||
getInstance()?.setSubLoading();
|
getInstance()?.setSubLoading(status);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return [register, methods];
|
return [register, methods];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
export interface ModalProps {
|
import type { DialogOptions } from 'naive-ui/lib/dialog';
|
||||||
subBtuText?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 弹窗对外暴露的方法
|
* @description: 弹窗对外暴露的方法
|
||||||
*/
|
*/
|
||||||
export interface ModalMethods {
|
export interface ModalMethods {
|
||||||
setProps: (props: Partial<ModalProps>) => void;
|
setProps: (props) => void;
|
||||||
openModal: () => void;
|
openModal: () => void;
|
||||||
closeModal: () => void;
|
closeModal: () => void;
|
||||||
|
setSubLoading: (status) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支持修改,DialogOptions 參數
|
||||||
|
*/
|
||||||
|
export interface ModalProps extends DialogOptions { }
|
||||||
|
|
||||||
|
export type RegisterFn = (ModalInstance: ModalMethods) => void;
|
||||||
|
|
||||||
|
export type UseModalReturnType = [RegisterFn, ModalMethods];
|
||||||
@@ -233,9 +233,6 @@
|
|||||||
getCacheColumns,
|
getCacheColumns,
|
||||||
setCacheColumnsField,
|
setCacheColumnsField,
|
||||||
emit,
|
emit,
|
||||||
getSize: () => {
|
|
||||||
return unref(getBindValues).size;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCanResize = computed(() => {
|
const getCanResize = computed(() => {
|
||||||
@@ -288,7 +285,6 @@
|
|||||||
densitySelect,
|
densitySelect,
|
||||||
updatePage,
|
updatePage,
|
||||||
updatePageSize,
|
updatePageSize,
|
||||||
updateCheckedRowKeys,
|
|
||||||
pagination,
|
pagination,
|
||||||
tableAction,
|
tableAction,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,23 +7,25 @@
|
|||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex editable-cell-content" v-show="isEdit" v-click-outside="onClickOutside">
|
<div class="flex editable-cell-content" v-show="isEdit" v-click-outside="onClickOutside">
|
||||||
<CellComponent
|
<div class="editable-cell-content-comp">
|
||||||
v-bind="getComponentProps"
|
<CellComponent
|
||||||
:component="getComponent"
|
v-bind="getComponentProps"
|
||||||
:style="getWrapperStyle"
|
:component="getComponent"
|
||||||
:popoverVisible="getRuleVisible"
|
:style="getWrapperStyle"
|
||||||
:ruleMessage="ruleMessage"
|
:popoverVisible="getRuleVisible"
|
||||||
:rule="getRule"
|
:ruleMessage="ruleMessage"
|
||||||
:class="getWrapperClass"
|
:rule="getRule"
|
||||||
ref="elRef"
|
:class="getWrapperClass"
|
||||||
@options-change="handleOptionsChange"
|
ref="elRef"
|
||||||
@pressEnter="handleEnter"
|
@options-change="handleOptionsChange"
|
||||||
/>
|
@pressEnter="handleEnter"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="editable-cell-action" v-if="!getRowEditable">
|
<div class="editable-cell-action" v-if="!getRowEditable">
|
||||||
<n-icon class="cursor-pointer mx-2">
|
<n-icon class="mx-2 cursor-pointer">
|
||||||
<CheckOutlined @click="handleSubmit" />
|
<CheckOutlined @click="handleSubmit" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
<n-icon class="cursor-pointer mx-2">
|
<n-icon class="mx-2 cursor-pointer">
|
||||||
<CloseOutlined @click="handleCancel" />
|
<CloseOutlined @click="handleCancel" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
import { set, omit } from 'lodash-es';
|
import { set, omit } from 'lodash-es';
|
||||||
import { EventEnum } from '@/components/Table/src/componentMap';
|
import { EventEnum } from '@/components/Table/src/componentMap';
|
||||||
|
|
||||||
import { milliseconds } from 'date-fns';
|
import { milliseconds, format } from 'date-fns';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'EditableCell',
|
name: 'EditableCell',
|
||||||
@@ -196,12 +198,9 @@
|
|||||||
currentValueRef.value = e;
|
currentValueRef.value = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO 这里组件参数格式,和dayjs格式不一致
|
//TODO 根据组件格式化值
|
||||||
// if (component === 'NDatePicker') {
|
// if (component === 'NDatePicker') {
|
||||||
// let format = (props.column.editComponentProps?.format)
|
// currentValueRef.value = format(currentValueRef.value,'yyyy-MM-dd HH:mm:ss');
|
||||||
// .replace(/yyyy/g, 'YYYY')
|
|
||||||
// .replace(/dd/g, 'DD');
|
|
||||||
// currentValueRef.value = dayjs(currentValueRef.value).format(format);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const onChange = props.column?.editComponentProps?.onChange;
|
const onChange = props.column?.editComponentProps?.onChange;
|
||||||
@@ -377,6 +376,10 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&-comp{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.edit-icon {
|
.edit-icon {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
//position: absolute;
|
//position: absolute;
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
|
|||||||
return hasPermission(column.auth) && isIfShow(column);
|
return hasPermission(column.auth) && isIfShow(column);
|
||||||
})
|
})
|
||||||
.map((column) => {
|
.map((column) => {
|
||||||
|
//默认 ellipsis 为true
|
||||||
|
column.ellipsis = typeof column.ellipsis === 'undefined' ? { tooltip: true } : false;
|
||||||
const { edit } = column;
|
const { edit } = column;
|
||||||
if (edit) {
|
if (edit) {
|
||||||
column.render = renderEditCell(column);
|
column.render = renderEditCell(column);
|
||||||
@@ -92,7 +94,7 @@ export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
|
|||||||
const { actionColumn } = unref(propsRef);
|
const { actionColumn } = unref(propsRef);
|
||||||
if (!actionColumn) return;
|
if (!actionColumn) return;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
columns.push({
|
!columns.find((col) => col.key === 'action') && columns.push({
|
||||||
...actionColumn,
|
...actionColumn,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,7 @@ export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//获取
|
//获取
|
||||||
function getColumns() {
|
function getColumns(): BasicColumn[] {
|
||||||
const columns = toRaw(unref(getColumnsRef));
|
const columns = toRaw(unref(getColumnsRef));
|
||||||
return columns.map((item) => {
|
return columns.map((item) => {
|
||||||
return { ...item, title: item.title, key: item.key, fixed: item.fixed || undefined };
|
return { ...item, title: item.title, key: item.key, fixed: item.fixed || undefined };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { NButton } from 'naive-ui';
|
import { NButton } from 'naive-ui';
|
||||||
import { RoleEnum } from '@/enums/roleEnum';
|
import { PermissionsEnum } from '@/enums/permissionsEnum';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export interface ActionItem extends NButton.props {
|
export interface ActionItem extends NButton.props {
|
||||||
onClick?: Fn;
|
onClick?: Fn;
|
||||||
@@ -11,7 +11,7 @@ export interface ActionItem extends NButton.props {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
divider?: boolean;
|
divider?: boolean;
|
||||||
// 权限编码控制是否显示
|
// 权限编码控制是否显示
|
||||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
auth?: PermissionsEnum | PermissionsEnum[] | string | string[];
|
||||||
// 业务控制是否显示
|
// 业务控制是否显示
|
||||||
ifShow?: boolean | ((action: ActionItem) => boolean);
|
ifShow?: boolean | ((action: ActionItem) => boolean);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,8 +101,8 @@
|
|||||||
const state = reactive({
|
const state = reactive({
|
||||||
showModal: false,
|
showModal: false,
|
||||||
previewUrl: '',
|
previewUrl: '',
|
||||||
originalImgList: [],
|
originalImgList: [] as string[],
|
||||||
imgList: [],
|
imgList: [] as string[],
|
||||||
});
|
});
|
||||||
|
|
||||||
//赋值默认图片显示
|
//赋值默认图片显示
|
||||||
@@ -176,7 +176,7 @@
|
|||||||
const result = res[infoField];
|
const result = res[infoField];
|
||||||
//成功
|
//成功
|
||||||
if (code === ResultEnum.SUCCESS) {
|
if (code === ResultEnum.SUCCESS) {
|
||||||
let imgUrl = getImgUrl(result.photo);
|
let imgUrl: string = getImgUrl(result.photo);
|
||||||
state.imgList.push(imgUrl);
|
state.imgList.push(imgUrl);
|
||||||
state.originalImgList.push(result.photo);
|
state.originalImgList.push(result.photo);
|
||||||
emit('uploadChange', state.originalImgList);
|
emit('uploadChange', state.originalImgList);
|
||||||
@@ -220,6 +220,7 @@
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: 0 0;
|
background: 0 0;
|
||||||
|
|
||||||
.upload-card-item-info::before {
|
.upload-card-item-info::before {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ export function useProjectSetting() {
|
|||||||
|
|
||||||
const getShowFooter = computed(() => projectStore.showFooter);
|
const getShowFooter = computed(() => projectStore.showFooter);
|
||||||
|
|
||||||
|
const getIsPageAnimate = computed(() => projectStore.isPageAnimate);
|
||||||
|
|
||||||
|
const getPageAnimateType = computed(() => projectStore.pageAnimateType);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getNavMode,
|
getNavMode,
|
||||||
getNavTheme,
|
getNavTheme,
|
||||||
@@ -29,5 +33,7 @@ export function useProjectSetting() {
|
|||||||
getCrumbsSetting,
|
getCrumbsSetting,
|
||||||
getPermissionMode,
|
getPermissionMode,
|
||||||
getShowFooter,
|
getShowFooter,
|
||||||
|
getIsPageAnimate,
|
||||||
|
getPageAnimateType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ export function usePermission() {
|
|||||||
* 检查权限
|
* 检查权限
|
||||||
* @param accesses
|
* @param accesses
|
||||||
*/
|
*/
|
||||||
function _someRoles(accesses: string[]) {
|
function _somePermissions(accesses: string[]) {
|
||||||
return userStore.getRoles.some((item) => {
|
return userStore.getPermissions.some((item) => {
|
||||||
const { value }: any = item;
|
const { value }: any = item;
|
||||||
return accesses.includes(value);
|
return accesses.includes(value);
|
||||||
});
|
});
|
||||||
@@ -20,7 +20,7 @@ export function usePermission() {
|
|||||||
* */
|
* */
|
||||||
function hasPermission(accesses: string[]): boolean {
|
function hasPermission(accesses: string[]): boolean {
|
||||||
if (!accesses || !accesses.length) return true;
|
if (!accesses || !accesses.length) return true;
|
||||||
return _someRoles(accesses);
|
return _somePermissions(accesses);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,9 +28,9 @@ export function usePermission() {
|
|||||||
* @param accesses
|
* @param accesses
|
||||||
*/
|
*/
|
||||||
function hasEveryPermission(accesses: string[]): boolean {
|
function hasEveryPermission(accesses: string[]): boolean {
|
||||||
const rolesList = userStore.getRoles;
|
const permissionsList = userStore.getPermissions;
|
||||||
if (Array.isArray(accesses)) {
|
if (Array.isArray(accesses)) {
|
||||||
return accesses.every((access) => !!rolesList[access]);
|
return accesses.every((access) => !!permissionsList[access]);
|
||||||
}
|
}
|
||||||
throw new Error(`[hasEveryPermission]: ${accesses} should be a array !`);
|
throw new Error(`[hasEveryPermission]: ${accesses} should be a array !`);
|
||||||
}
|
}
|
||||||
@@ -41,9 +41,9 @@ export function usePermission() {
|
|||||||
* @param accessMap
|
* @param accessMap
|
||||||
*/
|
*/
|
||||||
function hasSomePermission(accesses: string[]): boolean {
|
function hasSomePermission(accesses: string[]): boolean {
|
||||||
const rolesList = userStore.getRoles;
|
const permissionsList = userStore.getPermissions;
|
||||||
if (Array.isArray(accesses)) {
|
if (Array.isArray(accesses)) {
|
||||||
return accesses.some((access) => !!rolesList[access]);
|
return accesses.some((access) => !!permissionsList[access]);
|
||||||
}
|
}
|
||||||
throw new Error(`[hasSomePermission]: ${accesses} should be a array !`);
|
throw new Error(`[hasSomePermission]: ${accesses} should be a array !`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,11 @@
|
|||||||
<div class="drawer-setting-item-style align-items-top">
|
<div class="drawer-setting-item-style align-items-top">
|
||||||
<n-tooltip placement="top">
|
<n-tooltip placement="top">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<img src="~@/assets/images/nav-theme-dark.svg" @click="togNavMode('vertical')" />
|
<img
|
||||||
|
src="~@/assets/images/nav-theme-dark.svg"
|
||||||
|
@click="togNavMode('vertical')"
|
||||||
|
alt="左侧菜单模式"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<span>左侧菜单模式</span>
|
<span>左侧菜单模式</span>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
@@ -56,12 +60,30 @@
|
|||||||
<div class="drawer-setting-item-style">
|
<div class="drawer-setting-item-style">
|
||||||
<n-tooltip placement="top">
|
<n-tooltip placement="top">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<img src="~@/assets/images/nav-horizontal.svg" @click="togNavMode('horizontal')" />
|
<img
|
||||||
|
src="~@/assets/images/nav-horizontal.svg"
|
||||||
|
alt="顶部菜单模式"
|
||||||
|
@click="togNavMode('horizontal')"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<span>顶部菜单模式</span>
|
<span>顶部菜单模式</span>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
<n-badge dot color="#19be6b" v-show="settingStore.navMode === 'horizontal'" />
|
<n-badge dot color="#19be6b" v-show="settingStore.navMode === 'horizontal'" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-setting-item-style">
|
||||||
|
<n-tooltip placement="top">
|
||||||
|
<template #trigger>
|
||||||
|
<img
|
||||||
|
src="~@/assets/images/nav-horizontal-mix.svg"
|
||||||
|
@click="togNavMode('horizontal-mix')"
|
||||||
|
alt="顶部菜单混合模式"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<span>顶部菜单混合模式</span>
|
||||||
|
</n-tooltip>
|
||||||
|
<n-badge dot color="#19be6b" v-show="settingStore.navMode === 'horizontal-mix'" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<n-divider title-placement="center">导航栏风格</n-divider>
|
<n-divider title-placement="center">导航栏风格</n-divider>
|
||||||
@@ -70,7 +92,11 @@
|
|||||||
<div class="drawer-setting-item-style align-items-top">
|
<div class="drawer-setting-item-style align-items-top">
|
||||||
<n-tooltip placement="top">
|
<n-tooltip placement="top">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<img src="~@/assets/images/nav-theme-dark.svg" @click="togNavTheme('dark')" />
|
<img
|
||||||
|
src="~@/assets/images/nav-theme-dark.svg"
|
||||||
|
alt="暗色侧边栏"
|
||||||
|
@click="togNavTheme('dark')"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<span>暗色侧边栏</span>
|
<span>暗色侧边栏</span>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
@@ -80,7 +106,11 @@
|
|||||||
<div class="drawer-setting-item-style">
|
<div class="drawer-setting-item-style">
|
||||||
<n-tooltip placement="top">
|
<n-tooltip placement="top">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<img src="~@/assets/images/nav-theme-light.svg" @click="togNavTheme('light')" />
|
<img
|
||||||
|
src="~@/assets/images/nav-theme-light.svg"
|
||||||
|
alt="白色侧边栏"
|
||||||
|
@click="togNavTheme('light')"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<span>白色侧边栏</span>
|
<span>白色侧边栏</span>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
@@ -95,6 +125,7 @@
|
|||||||
<img
|
<img
|
||||||
src="~@/assets/images/header-theme-dark.svg"
|
src="~@/assets/images/header-theme-dark.svg"
|
||||||
@click="togNavTheme('header-dark')"
|
@click="togNavTheme('header-dark')"
|
||||||
|
alt="暗色顶栏"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<span>暗色顶栏</span>
|
<span>暗色顶栏</span>
|
||||||
@@ -105,6 +136,16 @@
|
|||||||
|
|
||||||
<n-divider title-placement="center">界面功能</n-divider>
|
<n-divider title-placement="center">界面功能</n-divider>
|
||||||
|
|
||||||
|
<div class="drawer-setting-item">
|
||||||
|
<div class="drawer-setting-item-title"> 分割菜单 </div>
|
||||||
|
<div class="drawer-setting-item-action">
|
||||||
|
<n-switch
|
||||||
|
:disabled="settingStore.navMode !== 'horizontal-mix'"
|
||||||
|
v-model:value="settingStore.menuSetting.mixMenu"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="drawer-setting-item">
|
<div class="drawer-setting-item">
|
||||||
<div class="drawer-setting-item-title"> 固定顶栏 </div>
|
<div class="drawer-setting-item-title"> 固定顶栏 </div>
|
||||||
<div class="drawer-setting-item-action">
|
<div class="drawer-setting-item-action">
|
||||||
@@ -165,6 +206,22 @@
|
|||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<n-divider title-placement="center">动画</n-divider>
|
||||||
|
|
||||||
|
<div class="drawer-setting-item">
|
||||||
|
<div class="drawer-setting-item-title"> 禁用动画 </div>
|
||||||
|
<div class="drawer-setting-item-action">
|
||||||
|
<n-switch v-model:value="settingStore.isPageAnimate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-setting-item">
|
||||||
|
<div class="drawer-setting-item-title"> 动画类型 </div>
|
||||||
|
<div class="drawer-setting-item-select">
|
||||||
|
<n-select v-model:value="settingStore.pageAnimateType" :options="animateOptions" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="drawer-setting-item">
|
<div class="drawer-setting-item">
|
||||||
<n-alert type="warning" :showIcon="false">
|
<n-alert type="warning" :showIcon="false">
|
||||||
<p>{{ alertText }}</p>
|
<p>{{ alertText }}</p>
|
||||||
@@ -176,12 +233,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, toRefs, watch } from 'vue';
|
import { defineComponent, reactive, toRefs, unref, watch, computed } from 'vue';
|
||||||
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||||
import { useDesignSettingStore } from '@/store/modules/designSetting';
|
import { useDesignSettingStore } from '@/store/modules/designSetting';
|
||||||
import { CheckOutlined } from '@vicons/antd';
|
import { CheckOutlined } from '@vicons/antd';
|
||||||
import { Moon, SunnySharp } from '@vicons/ionicons5';
|
import { Moon, SunnySharp } from '@vicons/ionicons5';
|
||||||
import { darkTheme } from 'naive-ui';
|
import { darkTheme } from 'naive-ui';
|
||||||
|
import { animates as animateOptions } from '@/settings/animateSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ProjectSetting',
|
name: 'ProjectSetting',
|
||||||
@@ -216,6 +274,10 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const directionsOptions = computed(() => {
|
||||||
|
return animateOptions.find((item) => item.value == unref(settingStore.pageAnimateType));
|
||||||
|
});
|
||||||
|
|
||||||
function openDrawer() {
|
function openDrawer() {
|
||||||
state.isDrawer = true;
|
state.isDrawer = true;
|
||||||
}
|
}
|
||||||
@@ -237,11 +299,7 @@
|
|||||||
|
|
||||||
function togNavMode(mode) {
|
function togNavMode(mode) {
|
||||||
settingStore.navMode = mode;
|
settingStore.navMode = mode;
|
||||||
// if (mode === 'header-dark') {
|
settingStore.menuSetting.mixMenu = false;
|
||||||
// settingStore.setNavTheme('dark');
|
|
||||||
// } else {
|
|
||||||
// settingStore.setNavTheme('light');
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -254,6 +312,8 @@
|
|||||||
darkTheme,
|
darkTheme,
|
||||||
openDrawer,
|
openDrawer,
|
||||||
closeDrawer,
|
closeDrawer,
|
||||||
|
animateOptions,
|
||||||
|
directionsOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -288,6 +348,10 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-select {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-item {
|
.theme-item {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
min-width: 20px;
|
min-width: 20px;
|
||||||
@@ -312,6 +376,7 @@
|
|||||||
.justify-center {
|
.justify-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark-switch .n-switch {
|
.dark-switch .n-switch {
|
||||||
::v-deep(.n-switch__rail) {
|
::v-deep(.n-switch__rail) {
|
||||||
background-color: #000e1c;
|
background-color: #000e1c;
|
||||||
|
|||||||
@@ -1,8 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-header">
|
<div class="layout-header">
|
||||||
<!--顶部菜单-->
|
<!--顶部菜单-->
|
||||||
<div class="layout-header-left" v-if="navMode === 'horizontal'">
|
<div
|
||||||
<AsideMenu v-model:collapsed="collapsed" :inverted="getInverted" mode="horizontal" />
|
class="layout-header-left"
|
||||||
|
v-if="navMode === 'horizontal' || (navMode === 'horizontal-mix' && mixMenu)"
|
||||||
|
>
|
||||||
|
<div class="logo">
|
||||||
|
<img src="~@/assets/images/logo.png" alt="" />
|
||||||
|
<h2 v-show="!collapsed" class="title">NaiveUiAdmin</h2>
|
||||||
|
</div>
|
||||||
|
<AsideMenu
|
||||||
|
v-model:collapsed="collapsed"
|
||||||
|
v-model:location="getMenuLocation"
|
||||||
|
:inverted="getInverted"
|
||||||
|
mode="horizontal"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!--左侧菜单-->
|
<!--左侧菜单-->
|
||||||
<div class="layout-header-left" v-else>
|
<div class="layout-header-left" v-else>
|
||||||
@@ -161,6 +173,10 @@
|
|||||||
return ['light', 'header-dark'].includes(navTheme) ? props.inverted : !props.inverted;
|
return ['light', 'header-dark'].includes(navTheme) ? props.inverted : !props.inverted;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mixMenu = computed(() => {
|
||||||
|
return unref(getMenuSetting).mixMenu;
|
||||||
|
});
|
||||||
|
|
||||||
const getChangeStyle = computed(() => {
|
const getChangeStyle = computed(() => {
|
||||||
const { collapsed } = props;
|
const { collapsed } = props;
|
||||||
const { minMenuWidth, menuWidth }: any = unref(getMenuSetting);
|
const { minMenuWidth, menuWidth }: any = unref(getMenuSetting);
|
||||||
@@ -170,6 +186,10 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getMenuLocation = computed(() => {
|
||||||
|
return 'header';
|
||||||
|
});
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
@@ -314,6 +334,8 @@
|
|||||||
drawerSetting,
|
drawerSetting,
|
||||||
openSetting,
|
openSetting,
|
||||||
getInverted,
|
getInverted,
|
||||||
|
getMenuLocation,
|
||||||
|
mixMenu,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -330,22 +352,34 @@
|
|||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
//color: #fff;
|
|
||||||
|
|
||||||
//.n-icon {
|
|
||||||
// color: #fff
|
|
||||||
//}
|
|
||||||
|
|
||||||
&-left {
|
&-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
::v-deep(.ant-breadcrumb span:last-child .link-text) {
|
.logo {
|
||||||
color: #515a6e;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 64px;
|
||||||
|
line-height: 64px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-left: 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: auto;
|
||||||
|
height: 32px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep(.n-breadcrumb .n-breadcrumb-item:last-child .n-breadcrumb-item__link) {
|
::v-deep(.ant-breadcrumb span:last-child .link-text) {
|
||||||
color: #fff;
|
color: #515a6e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.n-breadcrumb {
|
.n-breadcrumb {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<img src="~@/assets/images/logo.png" alt="" />
|
<img src="~@/assets/images/logo.png" alt="" :class="{ 'mr-2': !collapsed }" />
|
||||||
<h2 v-show="!collapsed" class="title"> NaiveUiAdmin</h2>
|
<h2 v-show="!collapsed" class="title">NaiveUiAdmin</h2>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -32,7 +32,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: white;
|
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<RouterView>
|
<RouterView>
|
||||||
<template #default="{ Component, route }">
|
<template #default="{ Component, route }">
|
||||||
<transition name="zoom-fade" mode="out-in" appear>
|
<transition :name="getTransitionName" mode="out-in" appear>
|
||||||
<keep-alive v-if="keepAliveComponents" :include="keepAliveComponents">
|
<keep-alive v-if="keepAliveComponents" :include="keepAliveComponents">
|
||||||
<component :is="Component" :key="route.fullPath" />
|
<component :is="Component" :key="route.fullPath" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
@@ -12,8 +12,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, computed } from 'vue';
|
import { defineComponent, computed, unref } from 'vue';
|
||||||
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
|
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
|
||||||
|
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'MainView',
|
name: 'MainView',
|
||||||
@@ -29,11 +30,18 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
const { getIsPageAnimate, getPageAnimateType } = useProjectSetting();
|
||||||
const asyncRouteStore = useAsyncRouteStore();
|
const asyncRouteStore = useAsyncRouteStore();
|
||||||
// 需要缓存的路由组件
|
// 需要缓存的路由组件
|
||||||
const keepAliveComponents = computed(() => asyncRouteStore.keepAliveComponents);
|
const keepAliveComponents = computed(() => asyncRouteStore.keepAliveComponents);
|
||||||
|
|
||||||
|
const getTransitionName = computed(() => {
|
||||||
|
return unref(getIsPageAnimate) ? unref(getPageAnimateType) : '';
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
keepAliveComponents,
|
keepAliveComponents,
|
||||||
|
getTransitionName,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,18 +8,19 @@
|
|||||||
:collapsed-icon-size="20"
|
:collapsed-icon-size="20"
|
||||||
:indent="24"
|
:indent="24"
|
||||||
:expanded-keys="openKeys"
|
:expanded-keys="openKeys"
|
||||||
v-model:value="selectedKeys"
|
:value="getSelectedKeys"
|
||||||
@update:value="clickMenuItem"
|
@update:value="clickMenuItem"
|
||||||
@update:expanded-keys="menuExpanded"
|
@update:expanded-keys="menuExpanded"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, computed, watch, toRefs, unref } from 'vue';
|
import { defineComponent, ref, onMounted, reactive, computed, watch, toRefs, unref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
|
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
|
||||||
import { generatorMenu } from '@/utils';
|
import { generatorMenu, generatorMenuMix } from '@/utils';
|
||||||
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||||
|
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Menu',
|
name: 'Menu',
|
||||||
@@ -34,13 +35,26 @@
|
|||||||
// 侧边栏菜单是否收起
|
// 侧边栏菜单是否收起
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
|
//位置
|
||||||
|
location: {
|
||||||
|
type: String,
|
||||||
|
default: 'left',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
emits: ['update:collapsed'],
|
||||||
|
setup(props, { emit }) {
|
||||||
// 当前路由
|
// 当前路由
|
||||||
const currentRoute = useRoute();
|
const currentRoute = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const asyncRouteStore = useAsyncRouteStore();
|
const asyncRouteStore = useAsyncRouteStore();
|
||||||
const settingStore = useProjectSettingStore();
|
const settingStore = useProjectSettingStore();
|
||||||
|
const menus = ref<any[]>([]);
|
||||||
|
const selectedKeys = ref<string>(currentRoute.name as string);
|
||||||
|
const headerMenuSelectKey = ref<string>('');
|
||||||
|
|
||||||
|
const { getNavMode } = useProjectSetting();
|
||||||
|
|
||||||
|
const navMode = getNavMode;
|
||||||
|
|
||||||
// 获取当前打开的子菜单
|
// 获取当前打开的子菜单
|
||||||
const matched = currentRoute.matched;
|
const matched = currentRoute.matched;
|
||||||
@@ -49,23 +63,36 @@
|
|||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
openKeys: getOpenKeys,
|
openKeys: getOpenKeys,
|
||||||
selectedKeys: currentRoute.name,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const inverted = computed(() => {
|
const inverted = computed(() => {
|
||||||
return ['dark', 'header-dark'].includes(settingStore.navTheme);
|
return ['dark', 'header-dark'].includes(settingStore.navTheme);
|
||||||
});
|
});
|
||||||
|
|
||||||
const menus = computed(() => {
|
const getSelectedKeys = computed(() => {
|
||||||
return generatorMenu(asyncRouteStore.getMenus);
|
let location = props.location;
|
||||||
|
return location === 'left' || (location === 'header' && unref(navMode) === 'horizontal')
|
||||||
|
? unref(selectedKeys)
|
||||||
|
: unref(headerMenuSelectKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听分割菜单
|
||||||
|
watch(
|
||||||
|
() => settingStore.menuSetting.mixMenu,
|
||||||
|
() => {
|
||||||
|
updateMenu();
|
||||||
|
if (props.collapsed) {
|
||||||
|
emit('update:collapsed', !props.collapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// 监听菜单收缩状态
|
// 监听菜单收缩状态
|
||||||
watch(
|
watch(
|
||||||
() => props.collapsed,
|
() => props.collapsed,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
state.openKeys = newVal ? [] : getOpenKeys;
|
state.openKeys = newVal ? [] : getOpenKeys;
|
||||||
state.selectedKeys = currentRoute.name;
|
selectedKeys.value = currentRoute.name as string;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -73,12 +100,26 @@
|
|||||||
watch(
|
watch(
|
||||||
() => currentRoute.fullPath,
|
() => currentRoute.fullPath,
|
||||||
() => {
|
() => {
|
||||||
|
updateMenu();
|
||||||
const matched = currentRoute.matched;
|
const matched = currentRoute.matched;
|
||||||
state.openKeys = matched.map((item) => item.name);
|
state.openKeys = matched.map((item) => item.name);
|
||||||
state.selectedKeys = currentRoute.name;
|
const activeMenu: string = (currentRoute.meta?.activeMenu as string) || '';
|
||||||
|
selectedKeys.value = activeMenu ? (activeMenu as string) : (currentRoute.name as string);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function updateMenu() {
|
||||||
|
if (!settingStore.menuSetting.mixMenu) {
|
||||||
|
menus.value = generatorMenu(asyncRouteStore.getMenus);
|
||||||
|
} else {
|
||||||
|
//混合菜单
|
||||||
|
const firstRouteName: string = (currentRoute.matched[0].name as string) || '';
|
||||||
|
menus.value = generatorMenuMix(asyncRouteStore.getMenus, firstRouteName, props.location);
|
||||||
|
const activeMenu: string = currentRoute?.matched[0].meta?.activeMenu as string;
|
||||||
|
headerMenuSelectKey.value = (activeMenu ? activeMenu : firstRouteName) || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 点击菜单
|
// 点击菜单
|
||||||
function clickMenuItem(key: string) {
|
function clickMenuItem(key: string) {
|
||||||
if (/http(s)?:/.test(key)) {
|
if (/http(s)?:/.test(key)) {
|
||||||
@@ -101,17 +142,24 @@
|
|||||||
if (!key) return false;
|
if (!key) return false;
|
||||||
const subRouteChildren: string[] = [];
|
const subRouteChildren: string[] = [];
|
||||||
for (const { children, key } of unref(menus)) {
|
for (const { children, key } of unref(menus)) {
|
||||||
if (children && children.length > 0) {
|
if (children && children.length) {
|
||||||
subRouteChildren.push(key as string);
|
subRouteChildren.push(key as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return subRouteChildren.includes(key);
|
return subRouteChildren.includes(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
updateMenu();
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
inverted,
|
inverted,
|
||||||
menus,
|
menus,
|
||||||
|
selectedKeys,
|
||||||
|
headerMenuSelectKey,
|
||||||
|
getSelectedKeys,
|
||||||
clickMenuItem,
|
clickMenuItem,
|
||||||
menuExpanded,
|
menuExpanded,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
'tabs-view-fix': multiTabsSetting.fixed,
|
'tabs-view-fix': multiTabsSetting.fixed,
|
||||||
'tabs-view-fixed-header': isMultiHeaderFixed,
|
'tabs-view-fixed-header': isMultiHeaderFixed,
|
||||||
'tabs-view-default-background': getDarkTheme === false,
|
'tabs-view-default-background': getDarkTheme === false,
|
||||||
|
'tabs-view-dark-background': getDarkTheme === true,
|
||||||
}"
|
}"
|
||||||
:style="getChangeStyle"
|
:style="getChangeStyle"
|
||||||
>
|
>
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
placement="bottom-end"
|
placement="bottom-end"
|
||||||
:options="TabsMenuOptions"
|
:options="TabsMenuOptions"
|
||||||
>
|
>
|
||||||
<div class="tabs-close-btn" @click.prevent>
|
<div class="tabs-close-btn">
|
||||||
<n-icon size="16" color="#515a6e">
|
<n-icon size="16" color="#515a6e">
|
||||||
<DownOutlined />
|
<DownOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
@@ -101,8 +102,7 @@
|
|||||||
import { RouteItem } from '@/store/modules/tabsView';
|
import { RouteItem } from '@/store/modules/tabsView';
|
||||||
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
// @ts-ignore
|
import Draggable from 'vuedraggable';
|
||||||
import Draggable from 'vuedraggable/src/vuedraggable';
|
|
||||||
import { PageEnum } from '@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
import {
|
import {
|
||||||
DownOutlined,
|
DownOutlined,
|
||||||
@@ -116,6 +116,7 @@
|
|||||||
import { renderIcon } from '@/utils/index';
|
import { renderIcon } from '@/utils/index';
|
||||||
import elementResizeDetectorMaker from 'element-resize-detector';
|
import elementResizeDetectorMaker from 'element-resize-detector';
|
||||||
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
||||||
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'TabsView',
|
name: 'TabsView',
|
||||||
@@ -135,6 +136,7 @@
|
|||||||
const { getDarkTheme } = useDesignSetting();
|
const { getDarkTheme } = useDesignSetting();
|
||||||
const { getNavMode, getHeaderSetting, getMenuSetting, getMultiTabsSetting } =
|
const { getNavMode, getHeaderSetting, getMenuSetting, getMultiTabsSetting } =
|
||||||
useProjectSetting();
|
useProjectSetting();
|
||||||
|
const settingStore = useProjectSettingStore();
|
||||||
|
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -165,6 +167,17 @@
|
|||||||
return { fullPath, hash, meta, name, params, path, query };
|
return { fullPath, hash, meta, name, params, path, query };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isMixMenuNoneSub = computed(() => {
|
||||||
|
const mixMenu = settingStore.menuSetting.mixMenu;
|
||||||
|
const currentRoute = useRoute();
|
||||||
|
const navMode = unref(getNavMode);
|
||||||
|
if (unref(navMode) != 'horizontal-mix') return true;
|
||||||
|
if (unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
//动态组装样式 菜单缩进
|
//动态组装样式 菜单缩进
|
||||||
const getChangeStyle = computed(() => {
|
const getChangeStyle = computed(() => {
|
||||||
const { collapsed } = props;
|
const { collapsed } = props;
|
||||||
@@ -172,7 +185,11 @@
|
|||||||
const { minMenuWidth, menuWidth }: any = unref(getMenuSetting);
|
const { minMenuWidth, menuWidth }: any = unref(getMenuSetting);
|
||||||
const { fixed }: any = unref(getMultiTabsSetting);
|
const { fixed }: any = unref(getMultiTabsSetting);
|
||||||
let lenNum =
|
let lenNum =
|
||||||
navMode === 'horizontal' ? '0px' : collapsed ? `${minMenuWidth}px` : `${menuWidth}px`;
|
navMode === 'horizontal' || !isMixMenuNoneSub.value
|
||||||
|
? '0px'
|
||||||
|
: collapsed
|
||||||
|
? `${minMenuWidth}px`
|
||||||
|
: `${menuWidth}px`;
|
||||||
return {
|
return {
|
||||||
left: lenNum,
|
left: lenNum,
|
||||||
width: `calc(100% - ${!fixed ? '0px' : lenNum})`,
|
width: `calc(100% - ${!fixed ? '0px' : lenNum})`,
|
||||||
@@ -354,6 +371,7 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
updateNavScroll();
|
updateNavScroll();
|
||||||
|
state.showDropdown = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getCurrentScrollOffset() {
|
function getCurrentScrollOffset() {
|
||||||
@@ -625,6 +643,10 @@
|
|||||||
background: #f5f7f9;
|
background: #f5f7f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabs-view-dark-background {
|
||||||
|
background: #101014;
|
||||||
|
}
|
||||||
|
|
||||||
.tabs-view-fix {
|
.tabs-view-fix {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<NLayout class="layout" :position="fixedMenu" has-sider>
|
<NLayout class="layout" :position="fixedMenu" has-sider>
|
||||||
<NLayoutSider
|
<NLayoutSider
|
||||||
v-if="navMode === 'vertical'"
|
v-if="isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')"
|
||||||
show-trigger
|
show-trigger
|
||||||
@collapse="collapsed = true"
|
@collapse="collapsed = true"
|
||||||
:position="fixedMenu"
|
:position="fixedMenu"
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
class="layout-sider"
|
class="layout-sider"
|
||||||
>
|
>
|
||||||
<Logo :collapsed="collapsed" />
|
<Logo :collapsed="collapsed" />
|
||||||
<AsideMenu v-model:collapsed="collapsed" />
|
<AsideMenu v-model:collapsed="collapsed" v-model:location="getMenuLocation" />
|
||||||
</NLayoutSider>
|
</NLayoutSider>
|
||||||
|
|
||||||
<NLayout :inverted="inverted">
|
<NLayout :inverted="inverted">
|
||||||
@@ -51,12 +51,13 @@
|
|||||||
<!-- <PageFooter />-->
|
<!-- <PageFooter />-->
|
||||||
<!-- </NLayoutFooter>-->
|
<!-- </NLayoutFooter>-->
|
||||||
</NLayoutContent>
|
</NLayoutContent>
|
||||||
|
<n-back-top :right="100" />
|
||||||
</NLayout>
|
</NLayout>
|
||||||
</NLayout>
|
</NLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref, unref, computed, onMounted } from 'vue';
|
import { ref, unref, computed, onMounted } from 'vue';
|
||||||
import { Logo } from './components/Logo';
|
import { Logo } from './components/Logo';
|
||||||
import { TabsView } from './components/TagsView';
|
import { TabsView } from './components/TagsView';
|
||||||
import { MainView } from './components/Main';
|
import { MainView } from './components/Main';
|
||||||
@@ -65,101 +66,92 @@
|
|||||||
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
||||||
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
||||||
import { useLoadingBar } from 'naive-ui';
|
import { useLoadingBar } from 'naive-ui';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
const { getDarkTheme } = useDesignSetting();
|
||||||
name: 'Layout',
|
const {
|
||||||
components: {
|
getShowFooter,
|
||||||
TabsView,
|
getNavMode,
|
||||||
MainView,
|
getNavTheme,
|
||||||
PageHeader,
|
getHeaderSetting,
|
||||||
AsideMenu,
|
getMenuSetting,
|
||||||
Logo,
|
getMultiTabsSetting,
|
||||||
},
|
} = useProjectSetting();
|
||||||
setup() {
|
|
||||||
const { getDarkTheme } = useDesignSetting();
|
|
||||||
|
|
||||||
const {
|
const settingStore = useProjectSettingStore();
|
||||||
getShowFooter,
|
|
||||||
getNavMode,
|
|
||||||
getNavTheme,
|
|
||||||
getHeaderSetting,
|
|
||||||
getMenuSetting,
|
|
||||||
getMultiTabsSetting,
|
|
||||||
} = useProjectSetting();
|
|
||||||
|
|
||||||
const navMode = getNavMode;
|
const navMode = getNavMode;
|
||||||
|
|
||||||
const collapsed = ref<boolean>(false);
|
const collapsed = ref<boolean>(false);
|
||||||
|
|
||||||
const fixedHeader = computed(() => {
|
const fixedHeader = computed(() => {
|
||||||
const { fixed } = unref(getHeaderSetting);
|
const { fixed } = unref(getHeaderSetting);
|
||||||
return fixed ? 'absolute' : 'static';
|
return fixed ? 'absolute' : 'static';
|
||||||
});
|
|
||||||
|
|
||||||
const fixedMenu = computed(() => {
|
|
||||||
const { fixed } = unref(getHeaderSetting);
|
|
||||||
return fixed ? 'absolute' : 'static';
|
|
||||||
});
|
|
||||||
|
|
||||||
const isMultiTabs = computed(() => {
|
|
||||||
return unref(getMultiTabsSetting).show;
|
|
||||||
});
|
|
||||||
|
|
||||||
const fixedMulti = computed(() => {
|
|
||||||
return unref(getMultiTabsSetting).fixed;
|
|
||||||
});
|
|
||||||
|
|
||||||
const inverted = computed(() => {
|
|
||||||
return ['dark', 'header-dark'].includes(unref(getNavTheme));
|
|
||||||
});
|
|
||||||
|
|
||||||
const getHeaderInverted = computed(() => {
|
|
||||||
const navTheme = unref(getNavTheme);
|
|
||||||
return ['light', 'header-dark'].includes(navTheme) ? unref(inverted) : !unref(inverted);
|
|
||||||
});
|
|
||||||
|
|
||||||
const leftMenuWidth = computed(() => {
|
|
||||||
const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
|
||||||
return collapsed.value ? minMenuWidth : menuWidth;
|
|
||||||
});
|
|
||||||
|
|
||||||
const getChangeStyle = computed(() => {
|
|
||||||
const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
|
||||||
return {
|
|
||||||
'padding-left': collapsed.value ? `${minMenuWidth}px` : `${menuWidth}px`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
function watchWidth() {
|
|
||||||
const Width = document.body.clientWidth;
|
|
||||||
if (Width <= 950) {
|
|
||||||
collapsed.value = true;
|
|
||||||
} else collapsed.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
window.addEventListener('resize', watchWidth);
|
|
||||||
//挂载在 window 方便与在js中使用
|
|
||||||
window['$loading'] = useLoadingBar();
|
|
||||||
window['$loading'].finish();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
fixedMenu,
|
|
||||||
fixedMulti,
|
|
||||||
fixedHeader,
|
|
||||||
collapsed,
|
|
||||||
inverted,
|
|
||||||
isMultiTabs,
|
|
||||||
leftMenuWidth,
|
|
||||||
getChangeStyle,
|
|
||||||
navMode,
|
|
||||||
getShowFooter,
|
|
||||||
getDarkTheme,
|
|
||||||
getHeaderInverted,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isMixMenuNoneSub = computed(() => {
|
||||||
|
const mixMenu = settingStore.menuSetting.mixMenu;
|
||||||
|
const currentRoute = useRoute();
|
||||||
|
if (unref(navMode) != 'horizontal-mix') return true;
|
||||||
|
if (unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixedMenu = computed(() => {
|
||||||
|
const { fixed } = unref(getHeaderSetting);
|
||||||
|
return fixed ? 'absolute' : 'static';
|
||||||
|
});
|
||||||
|
|
||||||
|
const isMultiTabs = computed(() => {
|
||||||
|
return unref(getMultiTabsSetting).show;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixedMulti = computed(() => {
|
||||||
|
return unref(getMultiTabsSetting).fixed;
|
||||||
|
});
|
||||||
|
|
||||||
|
const inverted = computed(() => {
|
||||||
|
return ['dark', 'header-dark'].includes(unref(getNavTheme));
|
||||||
|
});
|
||||||
|
|
||||||
|
const getHeaderInverted = computed(() => {
|
||||||
|
const navTheme = unref(getNavTheme);
|
||||||
|
return ['light', 'header-dark'].includes(navTheme) ? unref(inverted) : !unref(inverted);
|
||||||
|
});
|
||||||
|
|
||||||
|
const leftMenuWidth = computed(() => {
|
||||||
|
const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
||||||
|
return collapsed.value ? minMenuWidth : menuWidth;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getChangeStyle = computed(() => {
|
||||||
|
const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
||||||
|
return {
|
||||||
|
'padding-left': collapsed.value ? `${minMenuWidth}px` : `${menuWidth}px`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMenuLocation = computed(() => {
|
||||||
|
return 'left';
|
||||||
|
});
|
||||||
|
|
||||||
|
const watchWidth = () => {
|
||||||
|
const Width = document.body.clientWidth;
|
||||||
|
if (Width <= 950) {
|
||||||
|
collapsed.value = true;
|
||||||
|
} else collapsed.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', watchWidth);
|
||||||
|
//挂载在 window 方便与在js中使用
|
||||||
|
window['$loading'] = useLoadingBar();
|
||||||
|
window['$loading'].finish();
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import {
|
|||||||
NSpin,
|
NSpin,
|
||||||
NTimePicker,
|
NTimePicker,
|
||||||
NBackTop,
|
NBackTop,
|
||||||
|
NSkeleton,
|
||||||
} from 'naive-ui';
|
} from 'naive-ui';
|
||||||
|
|
||||||
const naive = create({
|
const naive = create({
|
||||||
@@ -133,6 +134,7 @@ const naive = create({
|
|||||||
NSpin,
|
NSpin,
|
||||||
NTimePicker,
|
NTimePicker,
|
||||||
NBackTop,
|
NBackTop,
|
||||||
|
NSkeleton,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const ErrorPageRoute: AppRouteRecordRaw = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/:path(.*)*',
|
path: '/:path(.*)*',
|
||||||
name: 'ErrorPage',
|
name: 'ErrorPageSon',
|
||||||
component: ErrorPage,
|
component: ErrorPage,
|
||||||
meta: {
|
meta: {
|
||||||
title: 'ErrorPage',
|
title: 'ErrorPage',
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { renderIcon } from '@/utils/index';
|
|
||||||
import { DashboardOutlined } from '@vicons/antd';
|
|
||||||
// import { RouterTransition } from '@/components/transition'
|
|
||||||
|
|
||||||
//前端路由映射表
|
|
||||||
export const constantRouterComponents = {
|
|
||||||
Layout: () => import('@/layout/index.vue'), //布局
|
|
||||||
DashboardConsole: () => import('@/views/dashboard/console/console.vue'), // 主控台
|
|
||||||
DashboardMonitor: () => import('@/views/dashboard/monitor/monitor.vue'), // 监控页
|
|
||||||
DashboardWorkplace: () => import('@/views/dashboard/workplace/workplace.vue'), // 工作台
|
|
||||||
};
|
|
||||||
|
|
||||||
//前端路由图标映射表
|
|
||||||
export const constantRouterIcon = {
|
|
||||||
DashboardOutlined: renderIcon(DashboardOutlined),
|
|
||||||
};
|
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
import { adminMenus } from '@/api/system/menu';
|
import { adminMenus } from '@/api/system/menu';
|
||||||
import { constantRouterComponents, constantRouterIcon } from './constantRouterComponents';
|
import { constantRouterIcon } from './router-icons';
|
||||||
import router from '@/router/index';
|
import router from '@/router/index';
|
||||||
import { constantRouter } from '@/router/index';
|
import { constantRouter } from '@/router/index';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
import { Layout, ParentLayout } from '@/router/constant';
|
||||||
|
import type { AppRouteRecordRaw } from '@/router/types';
|
||||||
|
|
||||||
|
const Iframe = () => import('@/views/iframe/index.vue');
|
||||||
|
const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>();
|
||||||
|
|
||||||
|
LayoutMap.set('LAYOUT', Layout);
|
||||||
|
LayoutMap.set('IFRAME', Iframe);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化 后端 结构信息并递归生成层级路由表
|
* 格式化 后端 结构信息并递归生成层级路由表
|
||||||
*
|
|
||||||
* @param routerMap
|
* @param routerMap
|
||||||
* @param parent
|
* @param parent
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
@@ -19,21 +26,24 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
|||||||
// 路由名称,建议唯一
|
// 路由名称,建议唯一
|
||||||
name: item.name || '',
|
name: item.name || '',
|
||||||
// 该路由对应页面的 组件
|
// 该路由对应页面的 组件
|
||||||
component: constantRouterComponents[item.component],
|
component: item.component,
|
||||||
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
||||||
meta: {
|
meta: {
|
||||||
...item.meta,
|
...item.meta,
|
||||||
label: item.meta.title,
|
label: item.meta.title,
|
||||||
icon: constantRouterIcon[item.meta.icon] || null,
|
icon: constantRouterIcon[item.meta.icon] || null,
|
||||||
permission: item.meta.permission || null,
|
permissions: item.meta.permissions || null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
|
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
|
||||||
currentRouter.path = currentRouter.path.replace('//', '/');
|
currentRouter.path = currentRouter.path.replace('//', '/');
|
||||||
// 重定向
|
// 重定向
|
||||||
item.redirect && (currentRouter.redirect = item.redirect);
|
item.redirect && (currentRouter.redirect = item.redirect);
|
||||||
// 是否有子菜单,并递归处理
|
// 是否有子菜单,并递归处理
|
||||||
if (item.children && item.children.length > 0) {
|
if (item.children && item.children.length > 0) {
|
||||||
|
//如果未定义 redirect 默认第一个子路由为 redirect
|
||||||
|
!item.redirect && (currentRouter.redirect = `${item.path}/${item.children[0].path}`);
|
||||||
// Recursion
|
// Recursion
|
||||||
currentRouter.children = routerGenerator(item.children, currentRouter);
|
currentRouter.children = routerGenerator(item.children, currentRouter);
|
||||||
}
|
}
|
||||||
@@ -43,7 +53,6 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 动态生成菜单
|
* 动态生成菜单
|
||||||
* @param token
|
|
||||||
* @returns {Promise<Router>}
|
* @returns {Promise<Router>}
|
||||||
*/
|
*/
|
||||||
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
||||||
@@ -51,7 +60,8 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
|||||||
adminMenus()
|
adminMenus()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
const routeList = routerGenerator(result);
|
const routeList = routerGenerator(result);
|
||||||
const asyncRoutesList = [...constantRouter, ...routeList];
|
asyncImportRoute(routeList);
|
||||||
|
const asyncRoutesList = [...routeList, ...constantRouter];
|
||||||
asyncRoutesList.forEach((item) => {
|
asyncRoutesList.forEach((item) => {
|
||||||
router.addRoute(item);
|
router.addRoute(item);
|
||||||
});
|
});
|
||||||
@@ -62,3 +72,56 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找views中对应的组件文件
|
||||||
|
* */
|
||||||
|
let viewsModules: Record<string, () => Promise<Recordable>>;
|
||||||
|
export const asyncImportRoute = (routes: AppRouteRecordRaw[] | undefined): void => {
|
||||||
|
viewsModules = viewsModules || import.meta.glob('../views/**/*.{vue,tsx}');
|
||||||
|
if (!routes) return;
|
||||||
|
routes.forEach((item) => {
|
||||||
|
if (!item.component && item.meta?.frameSrc) {
|
||||||
|
item.component = 'IFRAME';
|
||||||
|
}
|
||||||
|
const { component, name } = item;
|
||||||
|
const { children } = item;
|
||||||
|
if (component) {
|
||||||
|
const layoutFound = LayoutMap.get(component as string);
|
||||||
|
if (layoutFound) {
|
||||||
|
item.component = layoutFound;
|
||||||
|
} else {
|
||||||
|
item.component = dynamicImport(viewsModules, component as string);
|
||||||
|
}
|
||||||
|
} else if (name) {
|
||||||
|
item.component = ParentLayout;
|
||||||
|
}
|
||||||
|
children && asyncImportRoute(children);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态导入
|
||||||
|
* */
|
||||||
|
export const dynamicImport = (
|
||||||
|
viewsModules: Record<string, () => Promise<Recordable>>,
|
||||||
|
component: string
|
||||||
|
) => {
|
||||||
|
const keys = Object.keys(viewsModules);
|
||||||
|
const matchKeys = keys.filter((key) => {
|
||||||
|
let k = key.replace('../views', '');
|
||||||
|
const lastIndex = k.lastIndexOf('.');
|
||||||
|
k = k.substring(0, lastIndex);
|
||||||
|
return k === component;
|
||||||
|
});
|
||||||
|
if (matchKeys?.length === 1) {
|
||||||
|
const matchKey = matchKeys[0];
|
||||||
|
return viewsModules[matchKey];
|
||||||
|
}
|
||||||
|
if (matchKeys?.length > 1) {
|
||||||
|
console.warn(
|
||||||
|
'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { App } from 'vue';
|
import { App } from 'vue';
|
||||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||||
import { ErrorPageRoute, RedirectRoute } from '@/router/base';
|
import { RedirectRoute } from '@/router/base';
|
||||||
import { PageEnum } from '@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
import { createRouterGuards } from './router-guards';
|
import { createRouterGuards } from './router-guards';
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export const LoginRoute: RouteRecordRaw = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//需要验证权限
|
//需要验证权限
|
||||||
export const asyncRoutes = [ErrorPageRoute, ...routeModuleList];
|
export const asyncRoutes = [...routeModuleList];
|
||||||
|
|
||||||
//普通路由 无需验证权限
|
//普通路由 无需验证权限
|
||||||
export const constantRouter: any[] = [LoginRoute, RootRoute, RedirectRoute];
|
export const constantRouter: any[] = [LoginRoute, RootRoute, RedirectRoute];
|
||||||
|
|||||||
32
src/router/modules/about.ts
Normal file
32
src/router/modules/about.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
import { Layout } from '@/router/constant';
|
||||||
|
import { ProjectOutlined } from '@vicons/antd';
|
||||||
|
import { renderIcon, renderNew } from '@/utils/index';
|
||||||
|
|
||||||
|
const routes: Array<RouteRecordRaw> = [
|
||||||
|
{
|
||||||
|
path: '/about',
|
||||||
|
name: 'about',
|
||||||
|
component: Layout,
|
||||||
|
meta: {
|
||||||
|
sort: 10,
|
||||||
|
isRoot: true,
|
||||||
|
activeMenu: 'about_index',
|
||||||
|
icon: renderIcon(ProjectOutlined),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
name: `about_index`,
|
||||||
|
meta: {
|
||||||
|
title: '关于',
|
||||||
|
extra: renderNew(),
|
||||||
|
activeMenu: 'about_index',
|
||||||
|
},
|
||||||
|
component: () => import('@/views/about/index.vue'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default routes;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import { Layout, ParentLayout } from '@/router/constant';
|
import { Layout, ParentLayout } from '@/router/constant';
|
||||||
import { WalletOutlined } from '@vicons/antd';
|
import { WalletOutlined } from '@vicons/antd';
|
||||||
import { renderIcon } from '@/utils/index';
|
import { renderIcon, renderNew } from '@/utils';
|
||||||
|
|
||||||
const routeName = 'comp';
|
const routeName = 'comp';
|
||||||
|
|
||||||
@@ -106,6 +106,24 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
component: () => import('@/views/comp/modal/index.vue'),
|
component: () => import('@/views/comp/modal/index.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'richtext',
|
||||||
|
name: `richtext`,
|
||||||
|
meta: {
|
||||||
|
title: '富文本',
|
||||||
|
extra: renderNew(),
|
||||||
|
},
|
||||||
|
component: () => import('@/views/comp/richtext/vue-quill.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'drag',
|
||||||
|
name: `Drag`,
|
||||||
|
meta: {
|
||||||
|
title: '拖拽',
|
||||||
|
extra: renderNew(),
|
||||||
|
},
|
||||||
|
component: () => import('@/views/comp/drag/index.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: 'Dashboard',
|
title: 'Dashboard',
|
||||||
icon: renderIcon(DashboardOutlined),
|
icon: renderIcon(DashboardOutlined),
|
||||||
permission: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
|
permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
|
||||||
sort: 0,
|
sort: 0,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
@@ -33,7 +33,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: `${routeName}_console`,
|
name: `${routeName}_console`,
|
||||||
meta: {
|
meta: {
|
||||||
title: '主控台',
|
title: '主控台',
|
||||||
permission: ['dashboard_console'],
|
permissions: ['dashboard_console'],
|
||||||
},
|
},
|
||||||
component: () => import('@/views/dashboard/console/console.vue'),
|
component: () => import('@/views/dashboard/console/console.vue'),
|
||||||
},
|
},
|
||||||
@@ -42,7 +42,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
// name: `${ routeName }_monitor`,
|
// name: `${ routeName }_monitor`,
|
||||||
// meta: {
|
// meta: {
|
||||||
// title: '监控页',
|
// title: '监控页',
|
||||||
// permission: ['dashboard_monitor']
|
// permissions: ['dashboard_monitor']
|
||||||
// },
|
// },
|
||||||
// component: () => import('@/views/dashboard/monitor/monitor.vue')
|
// component: () => import('@/views/dashboard/monitor/monitor.vue')
|
||||||
// },
|
// },
|
||||||
@@ -52,7 +52,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: '工作台',
|
title: '工作台',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
permission: ['dashboard_workplace'],
|
permissions: ['dashboard_workplace'],
|
||||||
},
|
},
|
||||||
component: () => import('@/views/dashboard/workplace/workplace.vue'),
|
component: () => import('@/views/dashboard/workplace/workplace.vue'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import { Layout } from '@/router/constant';
|
import { Layout } from '@/router/constant';
|
||||||
import { DocumentTextOutline } from '@vicons/ionicons5';
|
import { DocumentTextOutline } from '@vicons/ionicons5';
|
||||||
import { renderIcon, renderNew } from '@/utils/index';
|
import { renderIcon } from '@/utils/index';
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
{
|
{
|
||||||
path: '/external',
|
path: '/external',
|
||||||
name: 'https://jekip.github.io/docs/',
|
name: 'https://naive-ui-admin-docs.vercel.app',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
meta: {
|
meta: {
|
||||||
title: '项目文档',
|
title: '项目文档',
|
||||||
icon: renderIcon(DocumentTextOutline),
|
icon: renderIcon(DocumentTextOutline),
|
||||||
sort: 8,
|
sort: 9,
|
||||||
extra: renderNew(),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
42
src/router/modules/frame.ts
Normal file
42
src/router/modules/frame.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
import { Layout } from '@/router/constant';
|
||||||
|
import { DesktopOutline } from '@vicons/ionicons5';
|
||||||
|
import { renderIcon } from '@/utils/index';
|
||||||
|
|
||||||
|
const IFrame = () => import('@/views/iframe/index.vue');
|
||||||
|
|
||||||
|
const routes: Array<RouteRecordRaw> = [
|
||||||
|
{
|
||||||
|
path: '/frame',
|
||||||
|
name: 'Frame',
|
||||||
|
redirect: '/frame/docs',
|
||||||
|
component: Layout,
|
||||||
|
meta: {
|
||||||
|
title: '外部页面',
|
||||||
|
sort: 8,
|
||||||
|
icon: renderIcon(DesktopOutline),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'docs',
|
||||||
|
name: 'frame-docs',
|
||||||
|
meta: {
|
||||||
|
title: '项目文档(内嵌)',
|
||||||
|
frameSrc: 'https://naive-ui-admin-docs.vercel.app',
|
||||||
|
},
|
||||||
|
component: IFrame,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'naive',
|
||||||
|
name: 'frame-naive',
|
||||||
|
meta: {
|
||||||
|
title: 'NaiveUi(内嵌)',
|
||||||
|
frameSrc: 'https://www.naiveui.com',
|
||||||
|
},
|
||||||
|
component: IFrame,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default routes;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import { Layout } from '@/router/constant';
|
import { Layout } from '@/router/constant';
|
||||||
import { TableOutlined } from '@vicons/antd';
|
import { TableOutlined } from '@vicons/antd';
|
||||||
import { renderIcon, renderNew } from '@/utils/index';
|
import { renderIcon } from '@/utils/index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name 路由名称, 必须设置,且不能重名
|
* @param name 路由名称, 必须设置,且不能重名
|
||||||
@@ -31,7 +31,6 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: 'basic-list',
|
name: 'basic-list',
|
||||||
meta: {
|
meta: {
|
||||||
title: '基础列表',
|
title: '基础列表',
|
||||||
extra: renderNew(),
|
|
||||||
},
|
},
|
||||||
component: () => import('@/views/list/basicList/index.vue'),
|
component: () => import('@/views/list/basicList/index.vue'),
|
||||||
},
|
},
|
||||||
@@ -41,6 +40,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: '基础详情',
|
title: '基础详情',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
|
activeMenu: 'basic-list',
|
||||||
},
|
},
|
||||||
component: () => import('@/views/list/basicList/info.vue'),
|
component: () => import('@/views/list/basicList/info.vue'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
import { isNavigationFailure, Router } from 'vue-router';
|
import { isNavigationFailure, Router } from 'vue-router';
|
||||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||||
import { useAsyncRouteStoreWidthOut } from '@/store/modules/asyncRoute';
|
import { useAsyncRouteStoreWidthOut } from '@/store/modules/asyncRoute';
|
||||||
import { ACCESS_TOKEN } from '@/store/mutation-types';
|
import { ACCESS_TOKEN } from '@/store/mutation-types';
|
||||||
import { storage } from '@/utils/Storage';
|
import { storage } from '@/utils/Storage';
|
||||||
import { PageEnum } from '@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
import { ErrorPageRoute } from '@/router/base';
|
||||||
|
|
||||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ export function createRouterGuards(router: Router) {
|
|||||||
const token = storage.get(ACCESS_TOKEN);
|
const token = storage.get(ACCESS_TOKEN);
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// You can access without permission. You need to set the routing meta.ignoreAuth to true
|
// You can access without permissions. You need to set the routing meta.ignoreAuth to true
|
||||||
if (to.meta.ignoreAuth) {
|
if (to.meta.ignoreAuth) {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
@@ -60,9 +62,15 @@ export function createRouterGuards(router: Router) {
|
|||||||
|
|
||||||
// 动态添加可访问路由表
|
// 动态添加可访问路由表
|
||||||
routes.forEach((item) => {
|
routes.forEach((item) => {
|
||||||
router.addRoute(item);
|
router.addRoute(item as unknown as RouteRecordRaw);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//添加404
|
||||||
|
const isErrorPage = router.getRoutes().findIndex((item) => item.name === ErrorPageRoute.name);
|
||||||
|
if (isErrorPage === -1) {
|
||||||
|
router.addRoute(ErrorPageRoute as unknown as RouteRecordRaw);
|
||||||
|
}
|
||||||
|
|
||||||
const redirectPath = (from.query.redirect || to.path) as string;
|
const redirectPath = (from.query.redirect || to.path) as string;
|
||||||
const redirect = decodeURIComponent(redirectPath);
|
const redirect = decodeURIComponent(redirectPath);
|
||||||
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
||||||
|
|||||||
7
src/router/router-icons.ts
Normal file
7
src/router/router-icons.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { renderIcon } from '@/utils/index';
|
||||||
|
import { DashboardOutlined } from '@vicons/antd';
|
||||||
|
|
||||||
|
//前端路由图标映射表
|
||||||
|
export const constantRouterIcon = {
|
||||||
|
DashboardOutlined: renderIcon(DashboardOutlined),
|
||||||
|
};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { RouteRecordRaw, RouteMeta } from 'vue-router';
|
import type { RouteRecordRaw, RouteMeta } from 'vue-router';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { RoleEnum } from '@/enums/roleEnum';
|
|
||||||
|
|
||||||
export type Component<T extends any = any> =
|
export type Component<T extends any = any> =
|
||||||
| ReturnType<typeof defineComponent>
|
| ReturnType<typeof defineComponent>
|
||||||
@@ -23,7 +22,7 @@ export interface Meta {
|
|||||||
title: string;
|
title: string;
|
||||||
// 是否忽略权限
|
// 是否忽略权限
|
||||||
ignoreAuth?: boolean;
|
ignoreAuth?: boolean;
|
||||||
roles?: RoleEnum[];
|
permissions?: string[];
|
||||||
// 是否不缓存
|
// 是否不缓存
|
||||||
noKeepAlive?: boolean;
|
noKeepAlive?: boolean;
|
||||||
// 是否固定在tab上
|
// 是否固定在tab上
|
||||||
|
|||||||
8
src/settings/animateSetting.ts
Normal file
8
src/settings/animateSetting.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const animates = [
|
||||||
|
{ value: 'zoom-fade', label: '渐变' },
|
||||||
|
{ value: 'zoom-out', label: '闪现' },
|
||||||
|
{ value: 'fade-slide', label: '滑动' },
|
||||||
|
{ value: 'fade', label: '消退' },
|
||||||
|
{ value: 'fade-bottom', label: '底部消退' },
|
||||||
|
{ value: 'fade-scale', label: '缩放消退' },
|
||||||
|
];
|
||||||
@@ -31,6 +31,8 @@ const setting = {
|
|||||||
menuWidth: 200,
|
menuWidth: 200,
|
||||||
//固定菜单
|
//固定菜单
|
||||||
fixed: true,
|
fixed: true,
|
||||||
|
//分割菜单
|
||||||
|
mixMenu: false,
|
||||||
},
|
},
|
||||||
//面包屑
|
//面包屑
|
||||||
crumbsSetting: {
|
crumbsSetting: {
|
||||||
@@ -39,7 +41,11 @@ const setting = {
|
|||||||
//显示图标
|
//显示图标
|
||||||
showIcon: false,
|
showIcon: false,
|
||||||
},
|
},
|
||||||
//菜单权限模式 ROLE 前端固定角色 BACK 动态获取
|
//菜单权限模式 FIXED 前端固定路由 BACK 动态获取
|
||||||
permissionMode: 'ROLE',
|
permissionMode: 'FIXED',
|
||||||
|
//是否开启路由动画
|
||||||
|
isPageAnimate: true,
|
||||||
|
//路由动画类型
|
||||||
|
pageAnimateType: 'zoom-fade',
|
||||||
};
|
};
|
||||||
export default setting;
|
export default setting;
|
||||||
|
|||||||
@@ -88,12 +88,12 @@ export const useAsyncRouteStore = defineStore({
|
|||||||
},
|
},
|
||||||
async generateRoutes(data) {
|
async generateRoutes(data) {
|
||||||
let accessedRouters;
|
let accessedRouters;
|
||||||
const roleList = data.roles || [];
|
const permissionsList = data.permissions || [];
|
||||||
const routeFilter = (route) => {
|
const routeFilter = (route) => {
|
||||||
const { meta } = route;
|
const { meta } = route;
|
||||||
const { permission } = meta || {};
|
const { permissions } = meta || {};
|
||||||
if (!permission) return true;
|
if (!permissions) return true;
|
||||||
return roleList.some((role) => permission.includes(role.value));
|
return permissionsList.some((item) => permissions.includes(item.value));
|
||||||
};
|
};
|
||||||
const { getPermissionMode } = useProjectSetting();
|
const { getPermissionMode } = useProjectSetting();
|
||||||
const permissionMode = unref(getPermissionMode);
|
const permissionMode = unref(getPermissionMode);
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const {
|
|||||||
multiTabsSetting,
|
multiTabsSetting,
|
||||||
crumbsSetting,
|
crumbsSetting,
|
||||||
permissionMode,
|
permissionMode,
|
||||||
|
isPageAnimate,
|
||||||
|
pageAnimateType,
|
||||||
} = projectSetting;
|
} = projectSetting;
|
||||||
|
|
||||||
interface ProjectSettingState {
|
interface ProjectSettingState {
|
||||||
@@ -23,6 +25,8 @@ interface ProjectSettingState {
|
|||||||
multiTabsSetting: ImultiTabsSetting; //多标签
|
multiTabsSetting: ImultiTabsSetting; //多标签
|
||||||
crumbsSetting: IcrumbsSetting; //面包屑
|
crumbsSetting: IcrumbsSetting; //面包屑
|
||||||
permissionMode: string; //权限模式
|
permissionMode: string; //权限模式
|
||||||
|
isPageAnimate: boolean; //是否开启路由动画
|
||||||
|
pageAnimateType: string; //路由动画类型
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useProjectSettingStore = defineStore({
|
export const useProjectSettingStore = defineStore({
|
||||||
@@ -36,6 +40,8 @@ export const useProjectSettingStore = defineStore({
|
|||||||
multiTabsSetting,
|
multiTabsSetting,
|
||||||
crumbsSetting,
|
crumbsSetting,
|
||||||
permissionMode,
|
permissionMode,
|
||||||
|
isPageAnimate,
|
||||||
|
pageAnimateType,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getNavMode(): string {
|
getNavMode(): string {
|
||||||
@@ -62,6 +68,12 @@ export const useProjectSettingStore = defineStore({
|
|||||||
getPermissionMode(): string {
|
getPermissionMode(): string {
|
||||||
return this.permissionMode;
|
return this.permissionMode;
|
||||||
},
|
},
|
||||||
|
getIsPageAnimate(): boolean {
|
||||||
|
return this.isPageAnimate;
|
||||||
|
},
|
||||||
|
getPageAnimateType(): string {
|
||||||
|
return this.pageAnimateType;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setNavTheme(value: string): void {
|
setNavTheme(value: string): void {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export interface IUserState {
|
|||||||
username: string;
|
username: string;
|
||||||
welcome: string;
|
welcome: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
roles: any[];
|
permissions: any[];
|
||||||
info: any;
|
info: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export const useUserStore = defineStore({
|
|||||||
username: '',
|
username: '',
|
||||||
welcome: '',
|
welcome: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
roles: [],
|
permissions: [],
|
||||||
info: Storage.get(CURRENT_USER, {}),
|
info: Storage.get(CURRENT_USER, {}),
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
@@ -37,8 +37,8 @@ export const useUserStore = defineStore({
|
|||||||
getNickname(): string {
|
getNickname(): string {
|
||||||
return this.username;
|
return this.username;
|
||||||
},
|
},
|
||||||
getRoles(): [any][] {
|
getPermissions(): [any][] {
|
||||||
return this.roles;
|
return this.permissions;
|
||||||
},
|
},
|
||||||
getUserInfo(): object {
|
getUserInfo(): object {
|
||||||
return this.info;
|
return this.info;
|
||||||
@@ -51,8 +51,8 @@ export const useUserStore = defineStore({
|
|||||||
setAvatar(avatar: string) {
|
setAvatar(avatar: string) {
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
},
|
},
|
||||||
setRoles(roles) {
|
setPermissions(permissions) {
|
||||||
this.roles = roles;
|
this.permissions = permissions;
|
||||||
},
|
},
|
||||||
setUserInfo(info) {
|
setUserInfo(info) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
@@ -83,12 +83,12 @@ export const useUserStore = defineStore({
|
|||||||
getUserInfo()
|
getUserInfo()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const result = res;
|
const result = res;
|
||||||
if (result.roles && result.roles.length) {
|
if (result.permissions && result.permissions.length) {
|
||||||
const roles = result.roles;
|
const permissionsList = result.permissions;
|
||||||
that.setRoles(roles);
|
that.setPermissions(permissionsList);
|
||||||
that.setUserInfo(result);
|
that.setUserInfo(result);
|
||||||
} else {
|
} else {
|
||||||
reject(new Error('getInfo: roles must be a non-null array !'));
|
reject(new Error('getInfo: permissionsList must be a non-null array !'));
|
||||||
}
|
}
|
||||||
that.setAvatar(result.avatar);
|
that.setAvatar(result.avatar);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
@@ -101,7 +101,7 @@ export const useUserStore = defineStore({
|
|||||||
|
|
||||||
// 登出
|
// 登出
|
||||||
async logout() {
|
async logout() {
|
||||||
this.setRoles([]);
|
this.setPermissions([]);
|
||||||
this.setUserInfo('');
|
this.setUserInfo('');
|
||||||
storage.remove(ACCESS_TOKEN);
|
storage.remove(ACCESS_TOKEN);
|
||||||
storage.remove(CURRENT_USER);
|
storage.remove(CURRENT_USER);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ a:active, a:hover {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*滚动条凹槽的颜色,还可以设置边框属性 */
|
/* 滚动条凹槽的颜色,还可以设置边框属性 */
|
||||||
*::-webkit-scrollbar-track-piece {
|
*::-webkit-scrollbar-track-piece {
|
||||||
background-color: #f8f8f8;
|
background-color: #f8f8f8;
|
||||||
-webkit-border-radius: 2em;
|
-webkit-border-radius: 2em;
|
||||||
@@ -53,22 +53,22 @@ a:active, a:hover {
|
|||||||
border-radius: 2em;
|
border-radius: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*滚动条的宽度*/
|
/* 滚动条的宽度 */
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
width: 9px;
|
width: 9px;
|
||||||
height: 9px;
|
height: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*滚动条的设置*/
|
/* 滚动条的设置 */
|
||||||
*::-webkit-scrollbar-thumb {
|
*::-webkit-scrollbar-thumb {
|
||||||
background-color: #dddddd;
|
background-color: #ddd;
|
||||||
background-clip: padding-box;
|
background-clip: padding-box;
|
||||||
-webkit-border-radius: 2em;
|
-webkit-border-radius: 2em;
|
||||||
-moz-border-radius: 2em;
|
-moz-border-radius: 2em;
|
||||||
border-radius: 2em;
|
border-radius: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*滚动条鼠标移上去*/
|
/* 滚动条鼠标移上去 */
|
||||||
*::-webkit-scrollbar-thumb:hover {
|
*::-webkit-scrollbar-thumb:hover {
|
||||||
background-color: #bbb;
|
background-color: #bbb;
|
||||||
}
|
}
|
||||||
|
|||||||
3
src/styles/index.less
Normal file
3
src/styles/index.less
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@import 'transition/index.less';
|
||||||
|
@import './var.less';
|
||||||
|
@import './common.less';
|
||||||
18
src/styles/transition/base.less
Normal file
18
src/styles/transition/base.less
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.transition-default() {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-move {
|
||||||
|
transition: transform 0.4s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-transition {
|
||||||
|
.transition-default();
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-x-transition {
|
||||||
|
.transition-default();
|
||||||
|
}
|
||||||
81
src/styles/transition/fade.less
Normal file
81
src/styles/transition/fade.less
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fade-slide */
|
||||||
|
.fade-slide-leave-active,
|
||||||
|
.fade-slide-enter-active {
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-slide-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-slide-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ///////////////////////////////////////////////
|
||||||
|
// Fade Bottom
|
||||||
|
// ///////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Speed: 1x
|
||||||
|
.fade-bottom-enter-active,
|
||||||
|
.fade-bottom-leave-active {
|
||||||
|
transition: opacity 0.25s, transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-bottom-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-bottom-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fade-scale
|
||||||
|
.fade-scale-leave-active,
|
||||||
|
.fade-scale-enter-active {
|
||||||
|
transition: all 0.28s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-scale-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-scale-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ///////////////////////////////////////////////
|
||||||
|
// Fade Top
|
||||||
|
// ///////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Speed: 1x
|
||||||
|
.fade-top-enter-active,
|
||||||
|
.fade-top-leave-active {
|
||||||
|
transition: opacity 0.2s, transform 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-top-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(8%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-top-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-8%);
|
||||||
|
}
|
||||||
10
src/styles/transition/index.less
Normal file
10
src/styles/transition/index.less
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@import './base.less';
|
||||||
|
@import './fade.less';
|
||||||
|
@import './scale.less';
|
||||||
|
@import './slide.less';
|
||||||
|
@import './scroll.less';
|
||||||
|
@import './zoom.less';
|
||||||
|
|
||||||
|
.collapse-transition {
|
||||||
|
transition: 0.2s height ease-in-out, 0.2s padding-top ease-in-out, 0.2s padding-bottom ease-in-out;
|
||||||
|
}
|
||||||
21
src/styles/transition/scale.less
Normal file
21
src/styles/transition/scale.less
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.scale-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scale-rotate-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/styles/transition/scroll.less
Normal file
67
src/styles/transition/scroll.less
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
.scroll-y-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from {
|
||||||
|
transform: translateY(-15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-to {
|
||||||
|
transform: translateY(15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-y-reverse-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from {
|
||||||
|
transform: translateY(15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-to {
|
||||||
|
transform: translateY(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-x-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from {
|
||||||
|
transform: translateX(-15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-to {
|
||||||
|
transform: translateX(15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-x-reverse-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from {
|
||||||
|
transform: translateX(15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-to {
|
||||||
|
transform: translateX(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/styles/transition/slide.less
Normal file
39
src/styles/transition/slide.less
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
.slide-y-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-y-reverse-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-x-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-x-reverse-transition {
|
||||||
|
.transition-default();
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/styles/transition/zoom.less
Normal file
27
src/styles/transition/zoom.less
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// zoom-out
|
||||||
|
.zoom-out-enter-active,
|
||||||
|
.zoom-out-leave-active {
|
||||||
|
transition: opacity 0.1 ease-in-out, transform 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-out-enter-from,
|
||||||
|
.zoom-out-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoom-fade
|
||||||
|
.zoom-fade-enter-active,
|
||||||
|
.zoom-fade-leave-active {
|
||||||
|
transition: transform 0.2s, opacity 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-fade-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.06);
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
//获取相关CSS属性
|
//获取相关CSS属性
|
||||||
const getCss = function (o, key) {
|
const getCss = function (o, key) {
|
||||||
|
// @ts-ignore
|
||||||
return o.currentStyle
|
return o.currentStyle
|
||||||
? o.currentStyle[key]
|
? o.currentStyle[key]
|
||||||
: document.defaultView.getComputedStyle(o, false)[key];
|
: document.defaultView?.getComputedStyle(o, null)[key];
|
||||||
};
|
};
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
@@ -13,7 +14,7 @@ const params = {
|
|||||||
flag: false,
|
flag: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const startDrag = function (bar, target, callback) {
|
const startDrag = function (bar, target, callback?) {
|
||||||
const screenWidth = document.body.clientWidth; // body当前宽度
|
const screenWidth = document.body.clientWidth; // body当前宽度
|
||||||
const screenHeight = document.documentElement.clientHeight; // 可见区域高度
|
const screenHeight = document.documentElement.clientHeight; // 可见区域高度
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ const startDrag = function (bar, target, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.onmousemove = function (event) {
|
document.onmousemove = function (event) {
|
||||||
const e = event ? event : window.event;
|
const e: any = event ? event : window.event;
|
||||||
if (params.flag) {
|
if (params.flag) {
|
||||||
const nowX = e.clientX,
|
const nowX = e.clientX,
|
||||||
nowY = e.clientY;
|
nowY = e.clientY;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const transform: AxiosTransform = {
|
|||||||
* @description: 处理请求数据
|
* @description: 处理请求数据
|
||||||
*/
|
*/
|
||||||
transformRequestData: (res: AxiosResponse<Result>, options: RequestOptions) => {
|
transformRequestData: (res: AxiosResponse<Result>, options: RequestOptions) => {
|
||||||
|
// @ts-ignore
|
||||||
const { $message: Message, $dialog: Modal } = window;
|
const { $message: Message, $dialog: Modal } = window;
|
||||||
const {
|
const {
|
||||||
isShowMessage = true,
|
isShowMessage = true,
|
||||||
@@ -186,6 +187,7 @@ const transform: AxiosTransform = {
|
|||||||
* @description: 响应错误处理
|
* @description: 响应错误处理
|
||||||
*/
|
*/
|
||||||
responseInterceptorsCatch: (error: any) => {
|
responseInterceptorsCatch: (error: any) => {
|
||||||
|
// @ts-ignore
|
||||||
const { $message: Message, $dialog: Modal } = window;
|
const { $message: Message, $dialog: Modal } = window;
|
||||||
const { response, code, message } = error || {};
|
const { response, code, message } = error || {};
|
||||||
// TODO 此处要根据后端接口返回格式修改
|
// TODO 此处要根据后端接口返回格式修改
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ export interface RequestOptions {
|
|||||||
joinParamsToUrl?: boolean;
|
joinParamsToUrl?: boolean;
|
||||||
// 格式化请求参数时间
|
// 格式化请求参数时间
|
||||||
formatDate?: boolean;
|
formatDate?: boolean;
|
||||||
// 是否处理请求结果
|
|
||||||
isTransformResponse?: boolean;
|
|
||||||
// 是否显示提示信息
|
// 是否显示提示信息
|
||||||
isShowMessage?: boolean;
|
isShowMessage?: boolean;
|
||||||
// 是否解析成JSON
|
// 是否解析成JSON
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { App, Plugin } from 'vue';
|
|||||||
import { NIcon, NTag } from 'naive-ui';
|
import { NIcon, NTag } from 'naive-ui';
|
||||||
import { PageEnum } from '@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
import { isObject } from './is/index';
|
import { isObject } from './is/index';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
/**
|
/**
|
||||||
* render 图标
|
* render 图标
|
||||||
* */
|
* */
|
||||||
@@ -33,29 +33,90 @@ export function renderNew(type = 'warning', text = 'New', color: object = newTag
|
|||||||
* 递归组装菜单格式
|
* 递归组装菜单格式
|
||||||
*/
|
*/
|
||||||
export function generatorMenu(routerMap: Array<any>) {
|
export function generatorMenu(routerMap: Array<any>) {
|
||||||
return routerMap
|
return filterRouter(routerMap).map((item) => {
|
||||||
.filter((item) => {
|
const isRoot = isRootRouter(item);
|
||||||
return (
|
const info = isRoot ? item.children[0] : item;
|
||||||
(item.meta?.hidden || false) != true &&
|
const currentMenu = {
|
||||||
!['/:path(.*)*', '/', PageEnum.REDIRECT, PageEnum.BASE_LOGIN].includes(item.path)
|
...info,
|
||||||
);
|
...info.meta,
|
||||||
})
|
label: info.meta?.title,
|
||||||
.map((item) => {
|
key: info.name,
|
||||||
const info =
|
icon: isRoot ? item.meta?.icon : info.meta?.icon,
|
||||||
item.meta?.alwaysShow != true && item.children?.length === 1 ? item.children[0] : item;
|
};
|
||||||
|
// 是否有子菜单,并递归处理
|
||||||
|
if (info.children && info.children.length > 0) {
|
||||||
|
// Recursion
|
||||||
|
currentMenu.children = generatorMenu(info.children);
|
||||||
|
}
|
||||||
|
return currentMenu;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混合菜单
|
||||||
|
* */
|
||||||
|
export function generatorMenuMix(routerMap: Array<any>, routerName: string, location: string) {
|
||||||
|
const cloneRouterMap = cloneDeep(routerMap);
|
||||||
|
const newRouter = filterRouter(cloneRouterMap);
|
||||||
|
if (location === 'header') {
|
||||||
|
const firstRouter: any[] = [];
|
||||||
|
newRouter.forEach((item) => {
|
||||||
|
const isRoot = isRootRouter(item);
|
||||||
|
const info = isRoot ? item.children[0] : item;
|
||||||
|
info.children = undefined;
|
||||||
const currentMenu = {
|
const currentMenu = {
|
||||||
...info,
|
...info,
|
||||||
...info.meta,
|
...info.meta,
|
||||||
label: info.meta?.title,
|
label: info.meta?.title,
|
||||||
key: info.name,
|
key: info.name,
|
||||||
};
|
};
|
||||||
// 是否有子菜单,并递归处理
|
firstRouter.push(currentMenu);
|
||||||
if (info.children && info.children.length > 0) {
|
|
||||||
// Recursion
|
|
||||||
currentMenu.children = generatorMenu(info.children);
|
|
||||||
}
|
|
||||||
return currentMenu;
|
|
||||||
});
|
});
|
||||||
|
return firstRouter;
|
||||||
|
} else {
|
||||||
|
return getChildrenRouter(newRouter.filter((item) => item.name === routerName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归组装子菜单
|
||||||
|
* */
|
||||||
|
export function getChildrenRouter(routerMap: Array<any>) {
|
||||||
|
return filterRouter(routerMap).map((item) => {
|
||||||
|
const isRoot = isRootRouter(item);
|
||||||
|
const info = isRoot ? item.children[0] : item;
|
||||||
|
const currentMenu = {
|
||||||
|
...info,
|
||||||
|
...info.meta,
|
||||||
|
label: info.meta?.title,
|
||||||
|
key: info.name,
|
||||||
|
};
|
||||||
|
// 是否有子菜单,并递归处理
|
||||||
|
if (info.children && info.children.length > 0) {
|
||||||
|
// Recursion
|
||||||
|
currentMenu.children = getChildrenRouter(info.children);
|
||||||
|
}
|
||||||
|
return currentMenu;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断根路由 Router
|
||||||
|
* */
|
||||||
|
export function isRootRouter(item) {
|
||||||
|
return item.meta?.alwaysShow != true && item.children?.length === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排除Router
|
||||||
|
* */
|
||||||
|
export function filterRouter(routerMap: Array<any>) {
|
||||||
|
return routerMap.filter((item) => {
|
||||||
|
return (
|
||||||
|
(item.meta?.hidden || false) != true &&
|
||||||
|
!['/:path(.*)*', '/', PageEnum.REDIRECT, PageEnum.BASE_LOGIN].includes(item.path)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const withInstall = <T>(component: T, alias?: string) => {
|
export const withInstall = <T>(component: T, alias?: string) => {
|
||||||
|
|||||||
105
src/views/about/index.vue
Normal file
105
src/views/about/index.vue
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="n-layout-page-header">
|
||||||
|
<n-card :bordered="false" title="关于">
|
||||||
|
{{ name }} 是一个基于 vue3,vite2,TypeScript
|
||||||
|
的中后台解决方案,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你,持续更新中。
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
<n-card
|
||||||
|
:bordered="false"
|
||||||
|
title="项目信息"
|
||||||
|
class="mt-4 proCard"
|
||||||
|
size="small"
|
||||||
|
:segmented="{ content: 'hard' }"
|
||||||
|
>
|
||||||
|
<n-descriptions bordered label-placement="left" class="py-2">
|
||||||
|
<n-descriptions-item label="版本">
|
||||||
|
<n-tag type="info"> {{ version }} </n-tag>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="最后编译时间">
|
||||||
|
<n-tag type="info"> {{ lastBuildTime }} </n-tag>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="文档地址">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<a href="https://naive-ui-admin-docs.vercel.app" class="py-2" target="_blank"
|
||||||
|
>查看文档地址</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="预览地址">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<a href="https://naive-ui-admin.vercel.app" class="py-2" target="_blank"
|
||||||
|
>查看预览地址</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="Github">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<a href="https://github.com/jekip/naive-ui-admin" class="py-2" target="_blank"
|
||||||
|
>查看Github地址</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="QQ交流群">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<a href="https://jq.qq.com/?_wv=1027&k=xib9dU4C" class="py-2" target="_blank"
|
||||||
|
>点击链接加入群聊【Naive Admin】</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</n-card>
|
||||||
|
|
||||||
|
<n-card
|
||||||
|
:bordered="false"
|
||||||
|
title="开发环境依赖"
|
||||||
|
class="mt-4 proCard"
|
||||||
|
size="small"
|
||||||
|
:segmented="{ content: 'hard' }"
|
||||||
|
>
|
||||||
|
<n-descriptions bordered label-placement="left" class="py-2">
|
||||||
|
<n-descriptions-item v-for="item in devSchema" :key="item.field" :label="item.field">
|
||||||
|
{{ item.label }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</n-card>
|
||||||
|
|
||||||
|
<n-card
|
||||||
|
:bordered="false"
|
||||||
|
title="生产环境依赖"
|
||||||
|
class="mt-4 proCard"
|
||||||
|
size="small"
|
||||||
|
:segmented="{ content: 'hard' }"
|
||||||
|
>
|
||||||
|
<n-descriptions bordered label-placement="left" class="py-2">
|
||||||
|
<n-descriptions-item v-for="item in schema" :key="item.field" :label="item.field">
|
||||||
|
{{ item.label }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
export interface schemaItem {
|
||||||
|
field: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { pkg, lastBuildTime } = __APP_INFO__;
|
||||||
|
const { dependencies, devDependencies, name, version } = pkg;
|
||||||
|
|
||||||
|
const schema: schemaItem[] = [];
|
||||||
|
const devSchema: schemaItem[] = [];
|
||||||
|
|
||||||
|
Object.keys(dependencies).forEach((key) => {
|
||||||
|
schema.push({ field: key, label: dependencies[key] });
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(devDependencies).forEach((key) => {
|
||||||
|
devSchema.push({ field: key, label: devDependencies[key] });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
162
src/views/comp/drag/index.vue
Normal file
162
src/views/comp/drag/index.vue
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="n-layout-page-header">
|
||||||
|
<n-card :bordered="false" title="拖拽"> 常用于卡片,事项,预约,流程,计划等, </n-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<n-alert title="花式拖拽演示" type="info" class="mt-4">
|
||||||
|
每个卡片,都可以上下拖拽顺序,另外不同卡片,也可以拖拽过去,拖拽过来,都不在话下呢,快试试O(∩_∩)O哈哈~
|
||||||
|
</n-alert>
|
||||||
|
|
||||||
|
<n-grid
|
||||||
|
cols="1 s:2 m:3 l:4 xl:4 2xl:4"
|
||||||
|
class="mt-4 proCard"
|
||||||
|
responsive="screen"
|
||||||
|
:x-gap="12"
|
||||||
|
:y-gap="8"
|
||||||
|
>
|
||||||
|
<n-grid-item>
|
||||||
|
<NCard
|
||||||
|
title="需求池"
|
||||||
|
:segmented="{ content: 'hard', footer: 'hard' }"
|
||||||
|
size="small"
|
||||||
|
:bordered="false"
|
||||||
|
>
|
||||||
|
<template #header-extra>
|
||||||
|
<n-tag type="info">月</n-tag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<Draggable
|
||||||
|
class="draggable-ul"
|
||||||
|
animation="300"
|
||||||
|
:list="demandList"
|
||||||
|
group="people"
|
||||||
|
itemKey="name"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<div class="cursor-move draggable-li">
|
||||||
|
<n-tag type="info">需求</n-tag><span class="ml-2">{{ element.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Draggable>
|
||||||
|
</NCard>
|
||||||
|
</n-grid-item>
|
||||||
|
|
||||||
|
<n-grid-item>
|
||||||
|
<NCard
|
||||||
|
title="开发中"
|
||||||
|
:segmented="{ content: 'hard', footer: 'hard' }"
|
||||||
|
size="small"
|
||||||
|
:bordered="false"
|
||||||
|
>
|
||||||
|
<template #header-extra>
|
||||||
|
<n-tag type="info">月</n-tag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<Draggable
|
||||||
|
class="draggable-ul"
|
||||||
|
animation="300"
|
||||||
|
:list="exploitList"
|
||||||
|
group="people"
|
||||||
|
itemKey="name"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<div class="cursor-move draggable-li">
|
||||||
|
<n-tag type="warning">开发中</n-tag><span class="ml-2">{{ element.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Draggable>
|
||||||
|
</NCard>
|
||||||
|
</n-grid-item>
|
||||||
|
|
||||||
|
<n-grid-item>
|
||||||
|
<NCard
|
||||||
|
title="已完成"
|
||||||
|
:segmented="{ content: 'hard', footer: 'hard' }"
|
||||||
|
size="small"
|
||||||
|
:bordered="false"
|
||||||
|
>
|
||||||
|
<template #header-extra>
|
||||||
|
<n-tag type="info">月</n-tag>
|
||||||
|
</template>
|
||||||
|
<Draggable
|
||||||
|
class="draggable-ul"
|
||||||
|
animation="300"
|
||||||
|
:list="completeList"
|
||||||
|
group="people"
|
||||||
|
itemKey="name"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<div class="cursor-move draggable-li">
|
||||||
|
<n-tag type="error">已完成</n-tag><span class="ml-2">{{ element.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Draggable>
|
||||||
|
</NCard>
|
||||||
|
</n-grid-item>
|
||||||
|
|
||||||
|
<n-grid-item>
|
||||||
|
<NCard
|
||||||
|
title="已验收"
|
||||||
|
:segmented="{ content: 'hard', footer: 'hard' }"
|
||||||
|
size="small"
|
||||||
|
:bordered="false"
|
||||||
|
>
|
||||||
|
<template #header-extra>
|
||||||
|
<n-tag type="info">月</n-tag>
|
||||||
|
</template>
|
||||||
|
<Draggable
|
||||||
|
class="draggable-ul"
|
||||||
|
animation="300"
|
||||||
|
:list="approvedList"
|
||||||
|
group="people"
|
||||||
|
itemKey="name"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<div class="cursor-move draggable-li">
|
||||||
|
<n-tag type="success">已验收</n-tag><span class="ml-2">{{ element.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Draggable>
|
||||||
|
</NCard>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import Draggable from 'vuedraggable';
|
||||||
|
|
||||||
|
const demandList = reactive([
|
||||||
|
{ name: '预约表单页面,能填写预约相关信息', id: 1 },
|
||||||
|
{ name: '促销活动页面,包含促销广告展示', id: 2 },
|
||||||
|
{ name: '商品列表,需要一个到货提醒功能', id: 3 },
|
||||||
|
{ name: '商品需要一个评价功能', id: 4 },
|
||||||
|
{ name: '商品图片需要提供放大镜', id: 5 },
|
||||||
|
{ name: '订单需要提供删除到回收站', id: 6 },
|
||||||
|
{ name: '用户头像上传,需要支持裁剪', id: 7 },
|
||||||
|
{ name: '据说Vue3.2发布了,setup啥时候支持?', id: 8 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const exploitList = reactive([{ name: '商品图片需要提供放大镜', id: 5 }]);
|
||||||
|
|
||||||
|
const completeList = reactive([{ name: '商品图片需要提供放大镜', id: 5 }]);
|
||||||
|
|
||||||
|
const approvedList = reactive([{ name: '商品图片需要提供放大镜', id: 5 }]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.draggable-ul {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: -16px;
|
||||||
|
|
||||||
|
.draggable-li {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 10px;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 1px solid #efeff5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
172
src/views/comp/form/basic.vue
Normal file
172
src/views/comp/form/basic.vue
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="n-layout-page-header">
|
||||||
|
<n-card :bordered="false" title="基础表单"> 基础表单,用于向用户收集表单信息 </n-card>
|
||||||
|
</div>
|
||||||
|
<n-card :bordered="false" class="mt-4 proCard">
|
||||||
|
<div class="BasicForm">
|
||||||
|
<BasicForm
|
||||||
|
submitButtonText="提交预约"
|
||||||
|
layout="horizontal"
|
||||||
|
:gridProps="{ cols: 1 }"
|
||||||
|
:schemas="schemas"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
@reset="handleReset"
|
||||||
|
>
|
||||||
|
<template #statusSlot="{ model, field }">
|
||||||
|
<n-input v-model:value="model[field]" />
|
||||||
|
</template>
|
||||||
|
</BasicForm>
|
||||||
|
</div>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { BasicForm } from '@/components/Form/index';
|
||||||
|
import { useMessage } from 'naive-ui';
|
||||||
|
|
||||||
|
const schemas = [
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
component: 'NInput',
|
||||||
|
label: '姓名',
|
||||||
|
labelMessage: '这是一个提示',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入姓名',
|
||||||
|
onInput: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: [{ required: true, message: '请输入姓名', trigger: ['blur'] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'mobile',
|
||||||
|
component: 'NInputNumber',
|
||||||
|
label: '手机',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入手机号码',
|
||||||
|
showButton: false,
|
||||||
|
onInput: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'type',
|
||||||
|
component: 'NSelect',
|
||||||
|
label: '类型',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择类型',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '舒适性',
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '经济性',
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onUpdateValue: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'makeDate',
|
||||||
|
component: 'NDatePicker',
|
||||||
|
label: '预约时间',
|
||||||
|
componentProps: {
|
||||||
|
type: 'date',
|
||||||
|
clearable: true,
|
||||||
|
defaultValue: 1183135260000,
|
||||||
|
onUpdateValue: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'makeTime',
|
||||||
|
component: 'NTimePicker',
|
||||||
|
label: '停留时间',
|
||||||
|
componentProps: {
|
||||||
|
clearable: true,
|
||||||
|
onUpdateValue: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'makeProject',
|
||||||
|
component: 'NCheckbox',
|
||||||
|
label: '预约项目',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择预约项目',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '种牙',
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '补牙',
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '根管',
|
||||||
|
value: 3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onUpdateChecked: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'makeSource',
|
||||||
|
component: 'NRadioGroup',
|
||||||
|
label: '来源',
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '网上',
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '门店',
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onUpdateChecked: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
label: '状态',
|
||||||
|
//插槽
|
||||||
|
slot: 'statusSlot',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const message = useMessage();
|
||||||
|
|
||||||
|
function handleSubmit(values: Recordable) {
|
||||||
|
console.log(values);
|
||||||
|
message.success(JSON.stringify(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset(values: Recordable) {
|
||||||
|
console.log(values);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.BasicForm {
|
||||||
|
width: 550px;
|
||||||
|
margin: 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="n-layout-page-header">
|
<div class="n-layout-page-header">
|
||||||
<n-card :bordered="false" title="基础表单"> useForm 表单,用于向用户收集表单信息 </n-card>
|
<n-card :bordered="false" title="基础表单"> useForm 表单,用于向用户收集表单信息 </n-card>
|
||||||
</div>
|
</div>
|
||||||
<n-card :bordered="false" class="proCard mt-4">
|
<n-card :bordered="false" class="mt-4 proCard">
|
||||||
<div class="BasicForm">
|
<div class="BasicForm">
|
||||||
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset">
|
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset">
|
||||||
<template #statusSlot="{ model, field }">
|
<template #statusSlot="{ model, field }">
|
||||||
@@ -15,12 +15,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref } from 'vue';
|
import { BasicForm, useForm } from '@/components/Form/index';
|
||||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
|
|
||||||
const schemas: FormSchema[] = [
|
const schemas = [
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
component: 'NInput',
|
component: 'NInput',
|
||||||
@@ -165,43 +164,25 @@
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default defineComponent({
|
const message = useMessage();
|
||||||
components: { BasicForm },
|
|
||||||
setup() {
|
|
||||||
const formRef: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
|
|
||||||
const [register, { setFieldsValue }] = useForm({
|
const [register, {}] = useForm({
|
||||||
gridProps: { cols: 1 },
|
gridProps: { cols: 1 },
|
||||||
collapsedRows: 3,
|
collapsedRows: 3,
|
||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
layout: 'horizontal',
|
layout: 'horizontal',
|
||||||
submitButtonText: '提交预约',
|
submitButtonText: '提交预约',
|
||||||
schemas,
|
schemas,
|
||||||
});
|
|
||||||
|
|
||||||
function setName() {
|
|
||||||
setFieldsValue({ name: '小马哥' });
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit(values: Recordable) {
|
|
||||||
console.log(values);
|
|
||||||
message.success(JSON.stringify(values));
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleReset(values: Recordable) {
|
|
||||||
console.log(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
register,
|
|
||||||
formRef,
|
|
||||||
handleSubmit,
|
|
||||||
handleReset,
|
|
||||||
setName,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleSubmit(values: Recordable) {
|
||||||
|
console.log(values);
|
||||||
|
message.success(JSON.stringify(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset(values: Recordable) {
|
||||||
|
console.log(values);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
114
src/views/comp/richtext/vue-quill.vue
Normal file
114
src/views/comp/richtext/vue-quill.vue
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="n-layout-page-header">
|
||||||
|
<n-card :bordered="false" title="富文本">
|
||||||
|
富文本,用于展示图文信息,比如商品详情,文章详情等...
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
<n-card :bordered="false" class="mt-4 proCard">
|
||||||
|
<QuillEditor
|
||||||
|
ref="quillEditor"
|
||||||
|
:options="options"
|
||||||
|
v-model:content="myContent"
|
||||||
|
style="height: 350px"
|
||||||
|
@ready="readyQuill"
|
||||||
|
class="quillEditor"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
<n-space>
|
||||||
|
<n-button @click="addText">增加文本</n-button>
|
||||||
|
<n-button @click="addImg">增加图片</n-button>
|
||||||
|
<n-button @click="getHtml">获取HTML</n-button>
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
</n-card>
|
||||||
|
<n-card :bordered="false" class="mt-4 proCard" title="HTML 内容">
|
||||||
|
<n-input
|
||||||
|
v-model:value="myContentHtml"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="html"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 3,
|
||||||
|
maxRows: 6,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
|
import { QuillEditor } from '@vueup/vue-quill';
|
||||||
|
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||||
|
const quillEditor = ref();
|
||||||
|
const myContent = ref(
|
||||||
|
'<h4>Naive Ui Admin 是一个基于 vue3,vite2,TypeScript 的中后台解决方案</h4>'
|
||||||
|
);
|
||||||
|
const myContentHtml = ref(
|
||||||
|
'<h4>Naive Ui Admin 是一个基于 vue3,vite2,TypeScript 的中后台解决方案</h4>'
|
||||||
|
);
|
||||||
|
|
||||||
|
const options = reactive({
|
||||||
|
modules: {
|
||||||
|
toolbar: [
|
||||||
|
['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
||||||
|
['blockquote', 'code-block'],
|
||||||
|
|
||||||
|
[{ header: 1 }, { header: 2 }], // custom button values
|
||||||
|
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||||
|
[{ script: 'sub' }, { script: 'super' }], // superscript/subscript
|
||||||
|
[{ indent: '-1' }, { indent: '+1' }], // outdent/indent
|
||||||
|
[{ direction: 'rtl' }], // text direction
|
||||||
|
|
||||||
|
[{ size: ['small', false, 'large', 'huge'] }], // custom dropdown
|
||||||
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
|
||||||
|
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
|
||||||
|
[{ font: [] }],
|
||||||
|
[{ align: [] }],
|
||||||
|
['clean'],
|
||||||
|
['image'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
theme: 'snow',
|
||||||
|
placeholder: '输入您喜欢的内容吧!',
|
||||||
|
});
|
||||||
|
|
||||||
|
function readyQuill() {
|
||||||
|
console.log('Quill准备好了');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHtml() {
|
||||||
|
myContentHtml.value = getHtmlVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addText() {
|
||||||
|
const html = getHtmlVal() + '新增加的内容';
|
||||||
|
quillEditor.value.setHTML(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addImg() {
|
||||||
|
const html =
|
||||||
|
getHtmlVal() +
|
||||||
|
'<img style="width:100px" src="https://www.baidu.com/img/flexible/logo/pc/result.png"/>';
|
||||||
|
quillEditor.value.setHTML(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHtmlVal() {
|
||||||
|
return quillEditor.value.getHTML();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.ql-toolbar.ql-snow {
|
||||||
|
border-top: none;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-container.ql-snow {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,10 +5,12 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: 'id',
|
title: 'id',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '编码',
|
title: '编码',
|
||||||
key: 'no',
|
key: 'no',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
@@ -22,6 +24,7 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: '头像',
|
title: '头像',
|
||||||
key: 'avatar',
|
key: 'avatar',
|
||||||
|
width: 100,
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NAvatar, {
|
return h(NAvatar, {
|
||||||
size: 48,
|
size: 48,
|
||||||
@@ -47,29 +50,33 @@ export const columns = [
|
|||||||
},
|
},
|
||||||
edit: true,
|
edit: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
|
ellipsis: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '开始日期',
|
title: '开始日期',
|
||||||
key: 'beginTime',
|
key: 'beginTime',
|
||||||
edit: true,
|
edit: true,
|
||||||
width: 250,
|
width: 160,
|
||||||
editComponent: 'NDatePicker',
|
editComponent: 'NDatePicker',
|
||||||
editComponentProps: {
|
editComponentProps: {
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
format: 'yyyy-MM-dd HH:mm:ss',
|
format: 'yyyy-MM-dd HH:mm:ss',
|
||||||
},
|
},
|
||||||
|
ellipsis: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '结束日期',
|
title: '结束日期',
|
||||||
key: 'endTime',
|
key: 'endTime',
|
||||||
width: 200,
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'date',
|
key: 'date',
|
||||||
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '停留时间',
|
title: '停留时间',
|
||||||
key: 'time',
|
key: 'time',
|
||||||
|
width: 80,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
:row-key="(row) => row.id"
|
:row-key="(row) => row.id"
|
||||||
ref="actionRef"
|
ref="actionRef"
|
||||||
:actionColumn="actionColumn"
|
:actionColumn="actionColumn"
|
||||||
|
:scroll-x="1360"
|
||||||
@update:checked-row-keys="onCheckedRow"
|
@update:checked-row-keys="onCheckedRow"
|
||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
@@ -17,105 +18,90 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, ref, h } from 'vue';
|
import { reactive, ref, h } from 'vue';
|
||||||
import { BasicTable, TableAction } from '@/components/Table';
|
import { BasicTable, TableAction } from '@/components/Table';
|
||||||
import { getTableList } from '@/api/table/list';
|
import { getTableList } from '@/api/table/list';
|
||||||
import { columns } from './basicColumns';
|
import { columns } from './basicColumns';
|
||||||
import { useDialog, useMessage } from 'naive-ui';
|
import { useDialog, useMessage } from 'naive-ui';
|
||||||
|
|
||||||
export default defineComponent({
|
const message = useMessage();
|
||||||
components: { BasicTable },
|
const dialog = useDialog();
|
||||||
setup() {
|
const actionRef = ref();
|
||||||
const message = useMessage();
|
|
||||||
const dialog = useDialog();
|
const params = reactive({
|
||||||
const actionRef = ref();
|
pageSize: 5,
|
||||||
const state = reactive({
|
name: 'xiaoMa',
|
||||||
params: {
|
});
|
||||||
pageSize: 5,
|
|
||||||
name: 'xiaoMa',
|
const actionColumn = reactive({
|
||||||
},
|
width: 150,
|
||||||
actionColumn: {
|
title: '操作',
|
||||||
width: 150,
|
key: 'action',
|
||||||
title: '操作',
|
fixed: 'right',
|
||||||
key: 'action',
|
align: 'center',
|
||||||
fixed: 'right',
|
render(record) {
|
||||||
align: 'center',
|
return h(TableAction, {
|
||||||
render(record) {
|
style: 'button',
|
||||||
return h(TableAction, {
|
actions: createActions(record),
|
||||||
style: 'button',
|
|
||||||
actions: createActions(record),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function createActions(record) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
icon: 'ic:outline-delete-outline',
|
|
||||||
onClick: handleDelete.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
|
||||||
auth: ['basic_list'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '编辑',
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
auth: ['basic_list'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async (params) => {
|
|
||||||
const data = await getTableList(params);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
|
||||||
console.log(rowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
actionRef.value.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(record) {
|
|
||||||
console.log(record);
|
|
||||||
dialog.info({
|
|
||||||
title: '提示',
|
|
||||||
content: `您想删除${record.name}`,
|
|
||||||
positiveText: '确定',
|
|
||||||
negativeText: '取消',
|
|
||||||
onPositiveClick: () => {
|
|
||||||
message.success('删除成功');
|
|
||||||
},
|
|
||||||
onNegativeClick: () => {},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEdit(record) {
|
|
||||||
console.log(record);
|
|
||||||
message.success('您点击了编辑按钮');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
columns,
|
|
||||||
actionRef,
|
|
||||||
loadDataTable,
|
|
||||||
onCheckedRow,
|
|
||||||
reloadTable,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function createActions(record) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
icon: 'ic:outline-delete-outline',
|
||||||
|
onClick: handleDelete.bind(null, record),
|
||||||
|
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
||||||
|
auth: ['basic_list'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
onClick: handleEdit.bind(null, record),
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
auth: ['basic_list'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadDataTable = async (res) => {
|
||||||
|
return await getTableList({...res,...params});
|
||||||
|
};
|
||||||
|
|
||||||
|
function onCheckedRow(rowKeys) {
|
||||||
|
console.log(rowKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
actionRef.value.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDelete(record) {
|
||||||
|
console.log(record);
|
||||||
|
dialog.info({
|
||||||
|
title: '提示',
|
||||||
|
content: `您想删除${record.name}`,
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: () => {
|
||||||
|
message.success('删除成功');
|
||||||
|
},
|
||||||
|
onNegativeClick: () => {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEdit(record) {
|
||||||
|
console.log(record);
|
||||||
|
message.success('您点击了编辑按钮');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
@@ -5,19 +5,22 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: 'id',
|
title: 'id',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '编码',
|
title: '编码',
|
||||||
key: 'no',
|
key: 'no',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
width: 200,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '头像',
|
title: '头像',
|
||||||
key: 'avatar',
|
key: 'avatar',
|
||||||
|
width: 100,
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NAvatar, {
|
return h(NAvatar, {
|
||||||
size: 48,
|
size: 48,
|
||||||
@@ -28,21 +31,22 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: '地址',
|
title: '地址',
|
||||||
key: 'address',
|
key: 'address',
|
||||||
width: 200,
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '开始日期',
|
title: '开始日期',
|
||||||
key: 'beginTime',
|
key: 'beginTime',
|
||||||
width: 200,
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '结束日期',
|
title: '结束日期',
|
||||||
key: 'endTime',
|
key: 'endTime',
|
||||||
width: 200,
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'status',
|
key: 'status',
|
||||||
|
width: 100,
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(
|
return h(
|
||||||
NTag,
|
NTag,
|
||||||
@@ -58,9 +62,11 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'date',
|
key: 'date',
|
||||||
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '停留时间',
|
title: '停留时间',
|
||||||
key: 'time',
|
key: 'time',
|
||||||
|
width: 80,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
:request="loadDataTable"
|
:request="loadDataTable"
|
||||||
:row-key="(row) => row.id"
|
:row-key="(row) => row.id"
|
||||||
ref="actionRef"
|
ref="actionRef"
|
||||||
:actionColumn="actionColumn"
|
|
||||||
@edit-end="editEnd"
|
@edit-end="editEnd"
|
||||||
@edit-change="onEditChange"
|
@edit-change="onEditChange"
|
||||||
@update:checked-row-keys="onCheckedRow"
|
@update:checked-row-keys="onCheckedRow"
|
||||||
|
:scroll-x="1360"
|
||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<n-button type="primary" @click="reloadTable">刷新数据</n-button>
|
<n-button type="primary" @click="reloadTable">刷新数据</n-button>
|
||||||
@@ -19,113 +19,41 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, ref, h } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { BasicTable, TableAction } from '@/components/Table';
|
import { BasicTable } from '@/components/Table';
|
||||||
import { getTableList } from '@/api/table/list';
|
import { getTableList } from '@/api/table/list';
|
||||||
import { columns } from './CellColumns';
|
import { columns } from './CellColumns';
|
||||||
|
|
||||||
export default defineComponent({
|
const actionRef = ref();
|
||||||
components: { BasicTable },
|
const params = reactive({
|
||||||
setup() {
|
pageSize: 5,
|
||||||
const actionRef = ref();
|
name: 'xiaoMa',
|
||||||
const currentEditKeyRef = ref('');
|
|
||||||
const state = reactive({
|
|
||||||
params: {
|
|
||||||
pageSize: 5,
|
|
||||||
name: 'xiaoMa',
|
|
||||||
},
|
|
||||||
actionColumn: {
|
|
||||||
width: 150,
|
|
||||||
title: '操作',
|
|
||||||
key: 'action',
|
|
||||||
fixed: 'right',
|
|
||||||
align: 'center',
|
|
||||||
render(record) {
|
|
||||||
return h(TableAction, {
|
|
||||||
style: 'button',
|
|
||||||
actions: createActions(record),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleEdit(record) {
|
|
||||||
currentEditKeyRef.value = record.key;
|
|
||||||
record.onEdit?.(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCancel(record: EditRecordRow) {
|
|
||||||
currentEditKeyRef.value = '';
|
|
||||||
record.onEdit?.(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onEditChange({ column, value, record }) {
|
|
||||||
if (column.key === 'id') {
|
|
||||||
record.editValueRefs.name4.value = `${value}`;
|
|
||||||
}
|
|
||||||
console.log(column, value, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSave(record: EditRecordRow) {
|
|
||||||
const pass = await record.onEdit?.(false, true);
|
|
||||||
if (pass) {
|
|
||||||
currentEditKeyRef.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createActions(record) {
|
|
||||||
if (!record.editable) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: '编辑',
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: '保存',
|
|
||||||
onClick: handleSave.bind(null, record),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '取消',
|
|
||||||
onClick: handleCancel.bind(null, record),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async (params) => {
|
|
||||||
const data = await getTableList(params);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
|
||||||
console.log(rowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
console.log(actionRef.value);
|
|
||||||
actionRef.value.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
function editEnd({ record, index, key, value }) {
|
|
||||||
console.log(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
columns,
|
|
||||||
actionRef,
|
|
||||||
loadDataTable,
|
|
||||||
onCheckedRow,
|
|
||||||
reloadTable,
|
|
||||||
editEnd,
|
|
||||||
onEditChange,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onEditChange({ column, value, record }) {
|
||||||
|
if (column.key === 'id') {
|
||||||
|
record.editValueRefs.name4.value = `${value}`;
|
||||||
|
}
|
||||||
|
console.log(column, value, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadDataTable = async (res) => {
|
||||||
|
return await getTableList({ ...res, ...params });
|
||||||
|
};
|
||||||
|
|
||||||
|
function onCheckedRow(rowKeys) {
|
||||||
|
console.log(rowKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
console.log(actionRef.value);
|
||||||
|
actionRef.value.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function editEnd({ record, index, key, value }) {
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
@edit-end="editEnd"
|
@edit-end="editEnd"
|
||||||
@edit-change="onEditChange"
|
@edit-change="onEditChange"
|
||||||
@update:checked-row-keys="onCheckedRow"
|
@update:checked-row-keys="onCheckedRow"
|
||||||
|
:scroll-x="1590"
|
||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<n-button type="primary" @click="reloadTable">刷新数据</n-button>
|
<n-button type="primary" @click="reloadTable">刷新数据</n-button>
|
||||||
@@ -19,113 +20,95 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, ref, h } from 'vue';
|
import { reactive, ref, h } from 'vue';
|
||||||
import { BasicTable, TableAction } from '@/components/Table';
|
import { BasicTable, TableAction } from '@/components/Table';
|
||||||
import { getTableList } from '@/api/table/list';
|
import { getTableList } from '@/api/table/list';
|
||||||
import { columns } from './rowColumns';
|
import { columns } from './rowColumns';
|
||||||
|
|
||||||
export default defineComponent({
|
const actionRef = ref();
|
||||||
components: { BasicTable },
|
const currentEditKeyRef = ref('');
|
||||||
setup() {
|
const params = reactive({
|
||||||
const actionRef = ref();
|
pageSize: 5,
|
||||||
const currentEditKeyRef = ref('');
|
name: 'xiaoMa',
|
||||||
const state = reactive({
|
});
|
||||||
params: {
|
|
||||||
pageSize: 5,
|
const actionColumn = reactive({
|
||||||
name: 'xiaoMa',
|
width: 150,
|
||||||
},
|
title: '操作',
|
||||||
actionColumn: {
|
key: 'action',
|
||||||
width: 150,
|
fixed: 'right',
|
||||||
title: '操作',
|
align: 'center',
|
||||||
key: 'action',
|
render(record) {
|
||||||
fixed: 'right',
|
return h(TableAction, {
|
||||||
align: 'center',
|
style: 'button',
|
||||||
render(record) {
|
actions: createActions(record),
|
||||||
return h(TableAction, {
|
|
||||||
style: 'button',
|
|
||||||
actions: createActions(record),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleEdit(record) {
|
|
||||||
currentEditKeyRef.value = record.key;
|
|
||||||
record.onEdit?.(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCancel(record: EditRecordRow) {
|
|
||||||
currentEditKeyRef.value = '';
|
|
||||||
record.onEdit?.(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onEditChange({ column, value, record }) {
|
|
||||||
if (column.key === 'id') {
|
|
||||||
record.editValueRefs.name4.value = `${value}`;
|
|
||||||
}
|
|
||||||
console.log(column, value, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSave(record: EditRecordRow) {
|
|
||||||
const pass = await record.onEdit?.(false, true);
|
|
||||||
if (pass) {
|
|
||||||
currentEditKeyRef.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createActions(record) {
|
|
||||||
if (!record.editable) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: '编辑',
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: '保存',
|
|
||||||
onClick: handleSave.bind(null, record),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '取消',
|
|
||||||
onClick: handleCancel.bind(null, record),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async (params) => {
|
|
||||||
const data = await getTableList(params);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
|
||||||
console.log(rowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
console.log(actionRef.value);
|
|
||||||
actionRef.value.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
function editEnd({ record, index, key, value }) {
|
|
||||||
console.log(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
columns,
|
|
||||||
actionRef,
|
|
||||||
loadDataTable,
|
|
||||||
onCheckedRow,
|
|
||||||
reloadTable,
|
|
||||||
editEnd,
|
|
||||||
onEditChange,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleEdit(record) {
|
||||||
|
currentEditKeyRef.value = record.key;
|
||||||
|
record.onEdit?.(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel(record) {
|
||||||
|
currentEditKeyRef.value = '';
|
||||||
|
record.onEdit?.(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEditChange({ column, value, record }) {
|
||||||
|
if (column.key === 'id') {
|
||||||
|
record.editValueRefs.name4.value = `${value}`;
|
||||||
|
}
|
||||||
|
console.log(column, value, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSave(record) {
|
||||||
|
const pass = await record.onEdit?.(false, true);
|
||||||
|
if (pass) {
|
||||||
|
currentEditKeyRef.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createActions(record) {
|
||||||
|
if (!record.editable) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
onClick: handleEdit.bind(null, record),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '保存',
|
||||||
|
onClick: handleSave.bind(null, record),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '取消',
|
||||||
|
onClick: handleCancel.bind(null, record),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadDataTable = async (res) => {
|
||||||
|
return await getTableList({ ...res, ...params });
|
||||||
|
};
|
||||||
|
|
||||||
|
function onCheckedRow(rowKeys) {
|
||||||
|
console.log(rowKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
console.log(actionRef.value);
|
||||||
|
actionRef.value.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function editEnd({ record, index, key, value }) {
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: 'id',
|
title: 'id',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '编码',
|
title: '编码',
|
||||||
key: 'no',
|
key: 'no',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
@@ -23,6 +25,7 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: '头像',
|
title: '头像',
|
||||||
key: 'avatar',
|
key: 'avatar',
|
||||||
|
width: 100,
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NAvatar, {
|
return h(NAvatar, {
|
||||||
size: 48,
|
size: 48,
|
||||||
@@ -49,23 +52,25 @@ export const columns = [
|
|||||||
},
|
},
|
||||||
edit: true,
|
edit: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
|
ellipsis: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '开始日期',
|
title: '开始日期',
|
||||||
key: 'beginTime',
|
key: 'beginTime',
|
||||||
editRow: true,
|
editRow: true,
|
||||||
edit: true,
|
edit: true,
|
||||||
width: 250,
|
width: 240,
|
||||||
editComponent: 'NDatePicker',
|
editComponent: 'NDatePicker',
|
||||||
editComponentProps: {
|
editComponentProps: {
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
format: 'yyyy-MM-dd HH:mm:ss',
|
format: 'yyyy-MM-dd HH:mm:ss',
|
||||||
},
|
},
|
||||||
|
ellipsis: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '结束日期',
|
title: '结束日期',
|
||||||
key: 'endTime',
|
key: 'endTime',
|
||||||
width: 200,
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
@@ -81,9 +86,11 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'date',
|
key: 'date',
|
||||||
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '停留时间',
|
title: '停留时间',
|
||||||
key: 'time',
|
key: 'time',
|
||||||
|
width: 80,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="n-layout-page-header">
|
<div class="n-layout-page-header">
|
||||||
<n-card :bordered="false" title="上传图片"> 上传图片,用于向用户收集图片信息 </n-card>
|
<n-card :bordered="false" title="上传图片"> 上传图片,用于向用户收集图片信息 </n-card>
|
||||||
</div>
|
</div>
|
||||||
<n-card :bordered="false" class="proCard mt-4">
|
<n-card :bordered="false" class="mt-4 proCard">
|
||||||
<n-grid cols="2 s:1 m:3 l:3 xl:3 2xl:3" responsive="screen">
|
<n-grid cols="2 s:1 m:3 l:3 xl:3 2xl:3" responsive="screen">
|
||||||
<n-grid-item offset="0 s:0 m:1 l:1 xl:1 2xl:1">
|
<n-grid-item offset="0 s:0 m:1 l:1 xl:1 2xl:1">
|
||||||
<n-form
|
<n-form
|
||||||
@@ -47,8 +47,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref, unref, reactive, toRefs } from 'vue';
|
import { ref, unref, reactive } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { BasicUpload } from '@/components/Upload';
|
import { BasicUpload } from '@/components/Upload';
|
||||||
import { useGlobSetting } from '@/hooks/setting';
|
import { useGlobSetting } from '@/hooks/setting';
|
||||||
@@ -74,54 +74,38 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
const formRef: any = ref(null);
|
||||||
components: { BasicUpload },
|
const message = useMessage();
|
||||||
setup() {
|
const { uploadUrl } = globSetting;
|
||||||
const formRef: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
const { uploadUrl } = globSetting;
|
|
||||||
|
|
||||||
const state = reactive({
|
const formValue = reactive({
|
||||||
formValue: {
|
name: '',
|
||||||
name: '',
|
mobile: '',
|
||||||
mobile: '',
|
//图片列表 通常查看和编辑使用 绝对路径 | 相对路径都可以
|
||||||
//图片列表 通常查看和编辑使用 绝对路径 | 相对路径都可以
|
images: ['https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'],
|
||||||
images: ['https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'],
|
|
||||||
},
|
|
||||||
uploadHeaders: {
|
|
||||||
platform: 'miniPrograms',
|
|
||||||
timestamp: new Date().getTime(),
|
|
||||||
token: 'Q6fFCuhc1vkKn5JNFWaCLf6gRAc5n0LQHd08dSnG4qo=',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function formSubmit() {
|
|
||||||
formRef.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.success('验证成功');
|
|
||||||
} else {
|
|
||||||
message.error('验证失败,请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetForm() {
|
|
||||||
formRef.value.restoreValidation();
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploadChange(list: string[]) {
|
|
||||||
state.formValue.images = unref(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
formRef,
|
|
||||||
uploadUrl,
|
|
||||||
rules,
|
|
||||||
formSubmit,
|
|
||||||
resetForm,
|
|
||||||
uploadChange,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const uploadHeaders = reactive({
|
||||||
|
platform: 'miniPrograms',
|
||||||
|
timestamp: new Date().getTime(),
|
||||||
|
token: 'Q6fFCuhc1vkKn5JNFWaCLf6gRAc5n0LQHd08dSnG4qo=',
|
||||||
|
});
|
||||||
|
|
||||||
|
function formSubmit() {
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
message.success('验证成功');
|
||||||
|
} else {
|
||||||
|
message.error('验证失败,请填写完整信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
formRef.value.restoreValidation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadChange(list: string[]) {
|
||||||
|
formValue.images = unref(list);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="console">
|
<div class="console">
|
||||||
<!--数据卡片-->
|
<!--数据卡片-->
|
||||||
<n-grid cols="1 s:2 m:3 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12" :y-gap="8" :cols="4">
|
<n-grid cols="1 s:2 m:3 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12" :y-gap="8">
|
||||||
<n-grid-item>
|
<n-grid-item>
|
||||||
<NCard
|
<NCard
|
||||||
title="访问量"
|
title="访问量"
|
||||||
@@ -13,30 +13,40 @@
|
|||||||
<n-tag type="success">日</n-tag>
|
<n-tag type="success">日</n-tag>
|
||||||
</template>
|
</template>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<CountTo :startVal="1" :endVal="visits.dayVisits" class="text-3xl" />
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
|
<CountTo v-else :startVal="1" :endVal="visits.dayVisits" class="text-3xl" />
|
||||||
</div>
|
</div>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
日同比
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="visits.rise" />
|
<template v-else>
|
||||||
<n-icon size="12" style="color: #00ff6f">
|
日同比
|
||||||
<component is="CaretUpOutlined" />
|
<CountTo :startVal="1" suffix="%" :endVal="visits.rise" />
|
||||||
</n-icon>
|
<n-icon size="12" color="#00ff6f">
|
||||||
|
<component is="CaretUpOutlined" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
周同比
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="visits.decline" />
|
<template v-else>
|
||||||
<n-icon size="12" style="color: #ffde66">
|
周同比
|
||||||
<component is="CaretDownOutlined" />
|
<CountTo :startVal="1" suffix="%" :endVal="visits.decline" />
|
||||||
</n-icon>
|
<n-icon size="12" color="#ffde66">
|
||||||
|
<component is="CaretDownOutlined" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="text-sn"> 总访问量: </div>
|
<n-skeleton v-if="loading" text :repeat="2" />
|
||||||
<div class="text-sn">
|
<template v-else>
|
||||||
<CountTo :startVal="1" :endVal="visits.amount" />
|
<div class="text-sn"> 总访问量: </div>
|
||||||
</div>
|
<div class="text-sn">
|
||||||
|
<CountTo :startVal="1" :endVal="visits.amount" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
@@ -52,7 +62,14 @@
|
|||||||
<n-tag type="info">周</n-tag>
|
<n-tag type="info">周</n-tag>
|
||||||
</template>
|
</template>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<CountTo prefix="¥" :startVal="1" :endVal="saleroom.weekSaleroom" class="text-3xl" />
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
|
<CountTo
|
||||||
|
v-else
|
||||||
|
prefix="¥"
|
||||||
|
:startVal="1"
|
||||||
|
:endVal="saleroom.weekSaleroom"
|
||||||
|
class="text-3xl"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="py-2 px-2 flex justify-between">
|
<div class="py-2 px-2 flex justify-between">
|
||||||
<div class="text-sn flex-1">
|
<div class="text-sn flex-1">
|
||||||
@@ -66,10 +83,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="text-sn"> 总销售额: </div>
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<div class="text-sn">
|
<template v-else>
|
||||||
<CountTo prefix="¥" :startVal="1" :endVal="saleroom.amount" />
|
<div class="text-sn"> 总销售额: </div>
|
||||||
</div>
|
<div class="text-sn">
|
||||||
|
<CountTo prefix="¥" :startVal="1" :endVal="saleroom.amount" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
@@ -85,30 +105,40 @@
|
|||||||
<n-tag type="warning">周</n-tag>
|
<n-tag type="warning">周</n-tag>
|
||||||
</template>
|
</template>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<CountTo :startVal="1" :endVal="orderLarge.weekLarge" class="text-3xl" />
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
|
<CountTo v-else :startVal="1" :endVal="orderLarge.weekLarge" class="text-3xl" />
|
||||||
</div>
|
</div>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
日同比
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
<template v-else>
|
||||||
<n-icon size="12" style="color: #00ff6f">
|
日同比
|
||||||
<component is="CaretUpOutlined" />
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
||||||
</n-icon>
|
<n-icon size="12" color="#00ff6f">
|
||||||
|
<component is="CaretUpOutlined" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
周同比
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
<template v-else>
|
||||||
<n-icon size="12" style="color: #ffde66">
|
周同比
|
||||||
<component is="CaretDownOutlined" />
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
||||||
</n-icon>
|
<n-icon size="12" color="#ffde66">
|
||||||
|
<component is="CaretDownOutlined" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="text-sn"> 转化率: </div>
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<div class="text-sn">
|
<template v-else>
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.amount" />
|
<div class="text-sn"> 转化率: </div>
|
||||||
</div>
|
<div class="text-sn">
|
||||||
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.amount" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
@@ -124,30 +154,40 @@
|
|||||||
<n-tag type="error">月</n-tag>
|
<n-tag type="error">月</n-tag>
|
||||||
</template>
|
</template>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<CountTo prefix="¥" :startVal="1" :endVal="volume.weekLarge" class="text-3xl" />
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
|
<CountTo v-else prefix="¥" :startVal="1" :endVal="volume.weekLarge" class="text-3xl" />
|
||||||
</div>
|
</div>
|
||||||
<div class="py-1 px-1 flex justify-between">
|
<div class="py-1 px-1 flex justify-between">
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
月同比
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="volume.rise" />
|
<template v-else>
|
||||||
<n-icon size="12" style="color: #00ff6f">
|
月同比
|
||||||
<component is="CaretUpOutlined" />
|
<CountTo :startVal="1" suffix="%" :endVal="volume.rise" />
|
||||||
</n-icon>
|
<n-icon size="12" color="#00ff6f">
|
||||||
|
<component is="CaretUpOutlined" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
月同比
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="volume.decline" />
|
<template v-else>
|
||||||
<n-icon size="12" style="color: #ffde66">
|
月同比
|
||||||
<component is="CaretDownOutlined" />
|
<CountTo :startVal="1" suffix="%" :endVal="volume.decline" />
|
||||||
</n-icon>
|
<n-icon size="12" color="#ffde66">
|
||||||
|
<component is="CaretDownOutlined" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="text-sn"> 总成交额: </div>
|
<n-skeleton v-if="loading" :width="100" size="medium" />
|
||||||
<div class="text-sn">
|
<template v-else>
|
||||||
<CountTo prefix="¥" :startVal="1" :endVal="volume.amount" />
|
<div class="text-sn"> 总成交额: </div>
|
||||||
</div>
|
<div class="text-sn">
|
||||||
|
<CountTo prefix="¥" :startVal="1" :endVal="volume.amount" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
@@ -156,14 +196,15 @@
|
|||||||
|
|
||||||
<!--导航卡片-->
|
<!--导航卡片-->
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<n-grid cols="1 s:2 m:3 l:8 xl:8 2xl:8" responsive="screen" :x-gap="16" :y-gap="8" :cols="8">
|
<n-grid cols="1 s:2 m:3 l:8 xl:8 2xl:8" responsive="screen" :x-gap="16" :y-gap="8">
|
||||||
<n-grid-item v-for="(item, index) in iconList" :key="index">
|
<n-grid-item v-for="(item, index) in iconList" :key="index">
|
||||||
<NCard content-style="padding-top: 0;" size="small" :bordered="false">
|
<NCard content-style="padding-top: 0;" size="small" :bordered="false">
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="cursor-pointer">
|
<n-skeleton v-if="loading" size="medium" />
|
||||||
|
<div class="cursor-pointer" v-else>
|
||||||
<p class="flex justify-center">
|
<p class="flex justify-center">
|
||||||
<span>
|
<span>
|
||||||
<n-icon :size="item.size" class="flex-1" :style="{ color: `${item.color}` }">
|
<n-icon :size="item.size" class="flex-1" :color="item.color">
|
||||||
<component :is="item.icon" v-on="item.eventObject || {}" />
|
<component :is="item.icon" v-on="item.eventObject || {}" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -182,113 +223,115 @@
|
|||||||
<VisiTab />
|
<VisiTab />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, onMounted, reactive, toRefs } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import Icons from './components/Icons';
|
import { getConsoleInfo } from '@/api/dashboard/console';
|
||||||
import VisiTab from './components/VisiTab.vue';
|
import VisiTab from './components/VisiTab.vue';
|
||||||
import { CountTo } from '@/components/CountTo/index';
|
import { CountTo } from '@/components/CountTo/index';
|
||||||
import { getConsoleInfo } from '@/api/dashboard/console';
|
import {
|
||||||
|
CaretUpOutlined,
|
||||||
|
CaretDownOutlined,
|
||||||
|
UsergroupAddOutlined,
|
||||||
|
BarChartOutlined,
|
||||||
|
ShoppingCartOutlined,
|
||||||
|
AccountBookOutlined,
|
||||||
|
CreditCardOutlined,
|
||||||
|
MailOutlined,
|
||||||
|
TagsOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
} from '@vicons/antd';
|
||||||
|
|
||||||
export default defineComponent({
|
const cardHeaderStyle = ref({ 'border-bottom': '1px solid #eee', 'font-size': '16px' });
|
||||||
components: { ...Icons, VisiTab, CountTo },
|
|
||||||
setup() {
|
const loading = ref(true);
|
||||||
const state = reactive({
|
const visits = ref({});
|
||||||
cardHeaderStyle: {
|
const saleroom = ref({});
|
||||||
'border-bottom': '1px solid #eee',
|
const orderLarge = ref({});
|
||||||
'font-size': '16px',
|
const volume = ref({});
|
||||||
},
|
|
||||||
visits: {},
|
// 图标列表
|
||||||
saleroom: {},
|
const iconList = [
|
||||||
orderLarge: {},
|
{
|
||||||
volume: {},
|
icon: UsergroupAddOutlined,
|
||||||
});
|
size: '32',
|
||||||
// 图标列表
|
title: '用户',
|
||||||
const iconList = [
|
color: '#69c0ff',
|
||||||
{
|
eventObject: {
|
||||||
icon: 'UsergroupAddOutlined',
|
click: () => {},
|
||||||
size: '32',
|
},
|
||||||
title: '用户',
|
|
||||||
color: '#69c0ff',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'BarChartOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '分析',
|
|
||||||
color: '#69c0ff',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ShoppingCartOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '商品',
|
|
||||||
color: '#ff9c6e',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'AccountBookOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '订单',
|
|
||||||
color: '#b37feb',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'CreditCardOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '票据',
|
|
||||||
color: '#ffd666',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'MailOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '消息',
|
|
||||||
color: '#5cdbd3',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'TagsOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '标签',
|
|
||||||
color: '#ff85c0',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'SettingOutlined',
|
|
||||||
size: '32',
|
|
||||||
title: '配置',
|
|
||||||
color: '#ffc069',
|
|
||||||
eventObject: {
|
|
||||||
click: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
onMounted(async () => {
|
|
||||||
const { visits, saleroom, orderLarge, volume } = await getConsoleInfo();
|
|
||||||
state.visits = visits;
|
|
||||||
state.saleroom = saleroom;
|
|
||||||
state.orderLarge = orderLarge;
|
|
||||||
state.volume = volume;
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
iconList,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: BarChartOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '分析',
|
||||||
|
color: '#69c0ff',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: ShoppingCartOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '商品',
|
||||||
|
color: '#ff9c6e',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: AccountBookOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '订单',
|
||||||
|
color: '#b37feb',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: CreditCardOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '票据',
|
||||||
|
color: '#ffd666',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: MailOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '消息',
|
||||||
|
color: '#5cdbd3',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: TagsOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '标签',
|
||||||
|
color: '#ff85c0',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: SettingOutlined,
|
||||||
|
size: '32',
|
||||||
|
title: '配置',
|
||||||
|
color: '#ffc069',
|
||||||
|
eventObject: {
|
||||||
|
click: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const { visits, saleroom, orderLarge, volume } = await getConsoleInfo();
|
||||||
|
visits.value = visits;
|
||||||
|
saleroom.value = saleroom;
|
||||||
|
orderLarge.value = orderLarge;
|
||||||
|
volume.value = volume;
|
||||||
|
loading.value = false;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,6 @@
|
|||||||
<div>监控台</div>
|
<div>监控台</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup></script>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {},
|
|
||||||
setup() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
@@ -33,14 +33,7 @@
|
|||||||
</n-grid>
|
</n-grid>
|
||||||
</n-card>
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
<n-grid
|
<n-grid class="mt-4" cols="2 s:1 m:1 l:2 xl:2 2xl:2" responsive="screen" :x-gap="12" :y-gap="9">
|
||||||
class="mt-4"
|
|
||||||
cols="2 s:1 m:1 l:2 xl:2 2xl:2"
|
|
||||||
responsive="screen"
|
|
||||||
:x-gap="12"
|
|
||||||
:y-gap="9"
|
|
||||||
:cols="2"
|
|
||||||
>
|
|
||||||
<n-gi>
|
<n-gi>
|
||||||
<n-card
|
<n-card
|
||||||
:segmented="{ content: 'hard' }"
|
:segmented="{ content: 'hard' }"
|
||||||
@@ -75,7 +68,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span>
|
<span>
|
||||||
<n-icon size="30" style="color: #42b983">
|
<n-icon size="30" color="#42b983">
|
||||||
<LogoVue />
|
<LogoVue />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -91,7 +84,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span>
|
<span>
|
||||||
<n-icon size="30" style="color: #e44c27">
|
<n-icon size="30" color="#e44c27">
|
||||||
<Html5Outlined />
|
<Html5Outlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -107,7 +100,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span>
|
<span>
|
||||||
<n-icon size="30" style="color: #dd0031">
|
<n-icon size="30" color="#dd0031">
|
||||||
<LogoAngular />
|
<LogoAngular />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -123,7 +116,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span>
|
<span>
|
||||||
<n-icon size="30" style="color: #61dafb">
|
<n-icon size="30" color="#61dafb">
|
||||||
<LogoReact />
|
<LogoReact />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -238,7 +231,7 @@
|
|||||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
||||||
<div class="flex flex-col justify-center text-gray-500">
|
<div class="flex flex-col justify-center text-gray-500">
|
||||||
<span class="text-center">
|
<span class="text-center">
|
||||||
<n-icon size="30" style="color: #68c755">
|
<n-icon size="30" color="#68c755">
|
||||||
<DashboardOutlined />
|
<DashboardOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -248,7 +241,7 @@
|
|||||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
||||||
<div class="flex flex-col justify-center text-gray-500">
|
<div class="flex flex-col justify-center text-gray-500">
|
||||||
<span class="text-center">
|
<span class="text-center">
|
||||||
<n-icon size="30" style="color: #fab251">
|
<n-icon size="30" color="#fab251">
|
||||||
<ProfileOutlined />
|
<ProfileOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -258,7 +251,7 @@
|
|||||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
||||||
<div class="flex flex-col justify-center text-gray-500">
|
<div class="flex flex-col justify-center text-gray-500">
|
||||||
<span class="text-center">
|
<span class="text-center">
|
||||||
<n-icon size="30" style="color: #1890ff">
|
<n-icon size="30" color="#1890ff">
|
||||||
<FileProtectOutlined />
|
<FileProtectOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -268,7 +261,7 @@
|
|||||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
||||||
<div class="flex flex-col justify-center text-gray-500">
|
<div class="flex flex-col justify-center text-gray-500">
|
||||||
<span class="text-center">
|
<span class="text-center">
|
||||||
<n-icon size="30" style="color: #f06b96">
|
<n-icon size="30" color="#f06b96">
|
||||||
<ApartmentOutlined />
|
<ApartmentOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -278,7 +271,7 @@
|
|||||||
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
<n-card size="small" class="cursor-pointer project-card-item" hoverable>
|
||||||
<div class="flex flex-col justify-center text-gray-500">
|
<div class="flex flex-col justify-center text-gray-500">
|
||||||
<span class="text-center">
|
<span class="text-center">
|
||||||
<n-icon size="30" style="color: #7238d1">
|
<n-icon size="30" color="#7238d1">
|
||||||
<SettingOutlined />
|
<SettingOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -305,7 +298,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import schoolboy from '@/assets/images/schoolboy.png';
|
import schoolboy from '@/assets/images/schoolboy.png';
|
||||||
import {
|
import {
|
||||||
GithubOutlined,
|
GithubOutlined,
|
||||||
@@ -317,30 +310,6 @@
|
|||||||
Html5Outlined,
|
Html5Outlined,
|
||||||
} from '@vicons/antd';
|
} from '@vicons/antd';
|
||||||
import { LogoVue, LogoAngular, LogoReact, LogoJavascript } from '@vicons/ionicons5';
|
import { LogoVue, LogoAngular, LogoReact, LogoJavascript } from '@vicons/ionicons5';
|
||||||
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'DashboardWorkplace',
|
|
||||||
components: {
|
|
||||||
GithubOutlined,
|
|
||||||
LogoVue,
|
|
||||||
DashboardOutlined,
|
|
||||||
ProfileOutlined,
|
|
||||||
FileProtectOutlined,
|
|
||||||
SettingOutlined,
|
|
||||||
ApartmentOutlined,
|
|
||||||
Html5Outlined,
|
|
||||||
LogoAngular,
|
|
||||||
LogoReact,
|
|
||||||
LogoJavascript,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
schoolboy,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -10,28 +10,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
const router = useRouter();
|
||||||
export default defineComponent({
|
function goHome() {
|
||||||
setup() {
|
router.push('/');
|
||||||
const router = useRouter();
|
}
|
||||||
return {
|
|
||||||
goHome() {
|
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
h1 {
|
h1 {
|
||||||
|
|||||||
@@ -10,28 +10,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
const router = useRouter();
|
||||||
export default defineComponent({
|
function goHome() {
|
||||||
setup() {
|
router.push('/');
|
||||||
const router = useRouter();
|
}
|
||||||
return {
|
|
||||||
goHome() {
|
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
h1 {
|
h1 {
|
||||||
|
|||||||
@@ -10,28 +10,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
const router = useRouter();
|
||||||
export default defineComponent({
|
function goHome() {
|
||||||
setup() {
|
router.push('/');
|
||||||
const router = useRouter();
|
}
|
||||||
return {
|
|
||||||
goHome() {
|
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
h1 {
|
h1 {
|
||||||
|
|||||||
@@ -81,8 +81,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref, reactive, toRefs } from 'vue';
|
import { ref, unref, reactive } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { BasicUpload } from '@/components/Upload';
|
import { BasicUpload } from '@/components/Upload';
|
||||||
import { useGlobSetting } from '@/hooks/setting';
|
import { useGlobSetting } from '@/hooks/setting';
|
||||||
@@ -149,66 +149,46 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
const formRef: any = ref(null);
|
||||||
components: { BasicUpload },
|
const message = useMessage();
|
||||||
setup() {
|
const { uploadUrl } = globSetting;
|
||||||
const formRef: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
const { uploadUrl } = globSetting;
|
|
||||||
|
|
||||||
const defaultValueRef = () => ({
|
const defaultValueRef = () => ({
|
||||||
name: '',
|
name: '',
|
||||||
mobile: '',
|
mobile: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
matter: null,
|
matter: null,
|
||||||
doctor: null,
|
doctor: null,
|
||||||
datetime: [],
|
datetime: [],
|
||||||
});
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
formValue: defaultValueRef(),
|
|
||||||
//图片列表 通常查看和编辑使用 绝对路径 | 相对路径都可以
|
|
||||||
uploadList: [
|
|
||||||
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
|
||||||
],
|
|
||||||
uploadHeaders: {
|
|
||||||
platform: 'miniPrograms',
|
|
||||||
timestamp: new Date().getTime(),
|
|
||||||
token: 'Q6fFCuhc1vkKn5JNFWaCLf6gRAc5n0LQHd08dSnG4qo=',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function formSubmit() {
|
|
||||||
formRef.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.success('验证成功');
|
|
||||||
} else {
|
|
||||||
message.error('验证失败,请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetForm() {
|
|
||||||
formRef.value.restoreValidation();
|
|
||||||
state.formValue = Object.assign(state.formValue, defaultValueRef());
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploadChange(list: string[]) {
|
|
||||||
console.log(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
formRef,
|
|
||||||
uploadUrl,
|
|
||||||
rules,
|
|
||||||
doctorList,
|
|
||||||
matterList,
|
|
||||||
formSubmit,
|
|
||||||
resetForm,
|
|
||||||
uploadChange,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let formValue = reactive(defaultValueRef());
|
||||||
|
const uploadList = ref([
|
||||||
|
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
|
]);
|
||||||
|
const uploadHeaders = reactive({
|
||||||
|
platform: 'miniPrograms',
|
||||||
|
timestamp: new Date().getTime(),
|
||||||
|
token: 'Q6fFCuhc1vkKn5JNFWaCLf6gRAc5n0LQHd08dSnG4qo=',
|
||||||
|
});
|
||||||
|
|
||||||
|
function formSubmit() {
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
message.success('验证成功');
|
||||||
|
} else {
|
||||||
|
message.error('验证失败,请填写完整信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
formRef.value.restoreValidation();
|
||||||
|
formValue = Object.assign(unref(formValue), defaultValueRef());
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadChange(list: string[]) {
|
||||||
|
console.log(list);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<n-card
|
<n-card
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
title="基本信息"
|
title="基本信息"
|
||||||
class="proCard mt-4"
|
class="mt-4 proCard"
|
||||||
size="small"
|
size="small"
|
||||||
:segmented="{ content: 'hard' }"
|
:segmented="{ content: 'hard' }"
|
||||||
>
|
>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<n-card
|
<n-card
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
title="其它信息"
|
title="其它信息"
|
||||||
class="proCard mt-4"
|
class="mt-4 proCard"
|
||||||
size="small"
|
size="small"
|
||||||
:segmented="{ content: 'hard' }"
|
:segmented="{ content: 'hard' }"
|
||||||
>
|
>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
<n-card
|
<n-card
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
title="表格信息"
|
title="表格信息"
|
||||||
class="proCard mt-4"
|
class="mt-4 proCard"
|
||||||
size="small"
|
size="small"
|
||||||
:segmented="{ content: 'hard' }"
|
:segmented="{ content: 'hard' }"
|
||||||
>
|
>
|
||||||
@@ -119,14 +119,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup></script>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
@@ -47,8 +47,8 @@
|
|||||||
</n-form>
|
</n-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref } from 'vue';
|
import { ref, defineEmits } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
|
|
||||||
const myAccountList = [
|
const myAccountList = [
|
||||||
@@ -73,61 +73,50 @@
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default defineComponent({
|
const emit = defineEmits(['nextStep']);
|
||||||
emits: ['nextStep'],
|
|
||||||
setup(_, { emit }) {
|
|
||||||
const form1Ref: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
const current = ref(1);
|
|
||||||
|
|
||||||
return {
|
const form1Ref: any = ref(null);
|
||||||
form1Ref,
|
const message = useMessage();
|
||||||
current,
|
|
||||||
formValue: ref({
|
const formValue = ref({
|
||||||
accountType: 1,
|
accountType: 1,
|
||||||
myAccount: null,
|
myAccount: null,
|
||||||
account: 'xioama@qq.com',
|
account: 'xioama@qq.com',
|
||||||
money: '1980',
|
money: '1980',
|
||||||
name: 'Ah jung',
|
name: 'Ah jung',
|
||||||
}),
|
|
||||||
rules: {
|
|
||||||
name: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入收款人姓名',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
account: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入收款账户',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
money: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入转账金额',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
myAccount: {
|
|
||||||
required: true,
|
|
||||||
type: 'number',
|
|
||||||
message: '请选择付款账户',
|
|
||||||
trigger: 'change',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
myAccountList,
|
|
||||||
accountTypeList,
|
|
||||||
formSubmit() {
|
|
||||||
form1Ref.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
emit('nextStep');
|
|
||||||
} else {
|
|
||||||
message.error('验证失败,请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
resetForm() {
|
|
||||||
form1Ref.value.restoreValidation();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
name: {
|
||||||
|
required: true,
|
||||||
|
message: '请输入收款人姓名',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
account: {
|
||||||
|
required: true,
|
||||||
|
message: '请输入收款账户',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
money: {
|
||||||
|
required: true,
|
||||||
|
message: '请输入转账金额',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
myAccount: {
|
||||||
|
required: true,
|
||||||
|
type: 'number',
|
||||||
|
message: '请选择付款账户',
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function formSubmit() {
|
||||||
|
form1Ref.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
emit('nextStep');
|
||||||
|
} else {
|
||||||
|
message.error('验证失败,请填写完整信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -32,50 +32,41 @@
|
|||||||
</n-form>
|
</n-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref } from 'vue';
|
import { ref, defineEmits } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
|
const form2Ref: any = ref(null);
|
||||||
|
const message = useMessage();
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
export default defineComponent({
|
const formValue = ref({
|
||||||
emits: ['prevStep', 'nextStep'],
|
password: '086611',
|
||||||
setup(_, { emit }) {
|
|
||||||
const form2Ref: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
const loading = ref(false);
|
|
||||||
|
|
||||||
function prevStep() {
|
|
||||||
emit('prevStep');
|
|
||||||
}
|
|
||||||
|
|
||||||
function formSubmit() {
|
|
||||||
loading.value = true;
|
|
||||||
form2Ref.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
setTimeout(() => {
|
|
||||||
emit('nextStep');
|
|
||||||
}, 1500);
|
|
||||||
} else {
|
|
||||||
message.error('验证失败,请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
form2Ref,
|
|
||||||
loading,
|
|
||||||
formValue: ref({
|
|
||||||
password: '086611',
|
|
||||||
}),
|
|
||||||
rules: {
|
|
||||||
password: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入支付密码',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
prevStep,
|
|
||||||
formSubmit,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
password: {
|
||||||
|
required: true,
|
||||||
|
message: '请输入支付密码',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const emit = defineEmits(['prevStep', 'nextStep']);
|
||||||
|
|
||||||
|
function prevStep() {
|
||||||
|
emit('prevStep');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formSubmit() {
|
||||||
|
loading.value = true;
|
||||||
|
form2Ref.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('nextStep');
|
||||||
|
}, 1500);
|
||||||
|
} else {
|
||||||
|
message.error('验证失败,请填写完整信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,34 +31,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { defineEmits } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
|
|
||||||
export default defineComponent({
|
const emit = defineEmits(['finish', 'prevStep']);
|
||||||
emits: ['finish', 'prevStep'],
|
function prevStep() {
|
||||||
setup(_, { emit }) {
|
emit('prevStep');
|
||||||
const router = useRouter();
|
}
|
||||||
|
|
||||||
function prevStep() {
|
function finish() {
|
||||||
emit('prevStep');
|
emit('finish');
|
||||||
}
|
}
|
||||||
|
|
||||||
function finish() {
|
|
||||||
emit('finish');
|
|
||||||
}
|
|
||||||
|
|
||||||
function toOrderList() {
|
|
||||||
router.push('/form/step-form');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
prevStep,
|
|
||||||
finish,
|
|
||||||
toOrderList,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。
|
将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。
|
||||||
</n-card>
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
<n-card :bordered="false" class="proCard mt-4">
|
<n-card :bordered="false" class="mt-4 proCard">
|
||||||
<n-space vertical class="steps" justify="center">
|
<n-space vertical class="steps" justify="center">
|
||||||
<n-steps :current="currentTab" :status="currentStatus">
|
<n-steps :current="currentTab" :status="currentStatus">
|
||||||
<n-step title="填写转账信息" description="确保填写正确" />
|
<n-step title="填写转账信息" description="确保填写正确" />
|
||||||
@@ -20,43 +20,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { defineComponent, ref } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import step1 from './Step1.vue';
|
import step1 from './Step1.vue';
|
||||||
import step2 from './Step2.vue';
|
import step2 from './Step2.vue';
|
||||||
import step3 from './Step3.vue';
|
import step3 from './Step3.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
const currentTab = ref(1);
|
||||||
components: { step1, step2, step3 },
|
const currentStatus = ref('process');
|
||||||
setup() {
|
|
||||||
const currentTab = ref(1);
|
|
||||||
const currentStatus = ref('process');
|
|
||||||
|
|
||||||
function nextStep() {
|
function nextStep() {
|
||||||
if (currentTab.value < 3) {
|
if (currentTab.value < 3) {
|
||||||
currentTab.value += 1;
|
currentTab.value += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prevStep() {
|
function prevStep() {
|
||||||
if (currentTab.value > 1) {
|
if (currentTab.value > 1) {
|
||||||
currentTab.value -= 1;
|
currentTab.value -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function finish() {
|
function finish() {
|
||||||
currentTab.value = 1;
|
currentTab.value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
currentTab,
|
|
||||||
currentStatus,
|
|
||||||
nextStep,
|
|
||||||
prevStep,
|
|
||||||
finish,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
1
src/views/frame/docs.vue
Normal file
1
src/views/frame/docs.vue
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<template> 项目文档 </template>
|
||||||
62
src/views/iframe/index.vue
Normal file
62
src/views/iframe/index.vue
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<n-spin :show="loading">
|
||||||
|
<div class="frame">
|
||||||
|
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef"></iframe>
|
||||||
|
</div>
|
||||||
|
</n-spin>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, unref, onMounted, nextTick } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
const currentRoute = useRoute();
|
||||||
|
const loading = ref(false);
|
||||||
|
const frameRef = ref<HTMLFrameElement | null>(null);
|
||||||
|
const frameSrc = ref<string>('');
|
||||||
|
|
||||||
|
if (unref(currentRoute.meta)?.frameSrc) {
|
||||||
|
frameSrc.value = unref(currentRoute.meta)?.frameSrc as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideLoading() {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
nextTick(() => {
|
||||||
|
const iframe = unref(frameRef);
|
||||||
|
if (!iframe) return;
|
||||||
|
const _frame = iframe as any;
|
||||||
|
if (_frame.attachEvent) {
|
||||||
|
_frame.attachEvent('onload', () => {
|
||||||
|
hideLoading();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
iframe.onload = () => {
|
||||||
|
hideLoading();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loading.value = true;
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.frame {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
&-iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,14 +5,17 @@ export const columns = [
|
|||||||
{
|
{
|
||||||
title: 'id',
|
title: 'id',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '头像',
|
title: '头像',
|
||||||
key: 'avatar',
|
key: 'avatar',
|
||||||
|
width: 100,
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NAvatar, {
|
return h(NAvatar, {
|
||||||
size: 48,
|
size: 48,
|
||||||
@@ -27,48 +30,21 @@ export const columns = [
|
|||||||
ifShow: (_column) => {
|
ifShow: (_column) => {
|
||||||
return true; // 根据业务控制是否显示
|
return true; // 根据业务控制是否显示
|
||||||
},
|
},
|
||||||
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '开始日期',
|
title: '开始日期',
|
||||||
key: 'beginTime',
|
key: 'beginTime',
|
||||||
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '结束日期',
|
title: '结束日期',
|
||||||
key: 'endTime',
|
key: 'endTime',
|
||||||
|
width: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'date',
|
key: 'date',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// title: '操作',
|
|
||||||
// key: 'actions',
|
|
||||||
// width: 150,
|
|
||||||
// //简单写一下例子,不建议这么写,过段时间,这里封二次封装
|
|
||||||
// render() {
|
|
||||||
// return [
|
|
||||||
// h(
|
|
||||||
// NButton,
|
|
||||||
// {
|
|
||||||
// size: 'small',
|
|
||||||
// type: 'error',
|
|
||||||
// style: 'margin-right:10px',
|
|
||||||
// onClick: () => {
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// { default: () => '删除' }
|
|
||||||
// ),
|
|
||||||
// h(
|
|
||||||
// NButton,
|
|
||||||
// {
|
|
||||||
// size: 'small',
|
|
||||||
// onClick: () => {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// { default: () => '编辑' }
|
|
||||||
// )
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
ref="actionRef"
|
ref="actionRef"
|
||||||
:actionColumn="actionColumn"
|
:actionColumn="actionColumn"
|
||||||
@update:checked-row-keys="onCheckedRow"
|
@update:checked-row-keys="onCheckedRow"
|
||||||
|
:scroll-x="1090"
|
||||||
>
|
>
|
||||||
<template #tableTitle>
|
<template #tableTitle>
|
||||||
<n-button type="primary" @click="addTable">
|
<n-button type="primary" @click="addTable">
|
||||||
@@ -60,11 +61,11 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, h, reactive, ref, toRefs } from 'vue';
|
import { h, reactive, ref } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { BasicTable, TableAction } from '@/components/Table';
|
import { BasicTable, TableAction } from '@/components/Table';
|
||||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
import { BasicForm, useForm } from '@/components/Form/index';
|
||||||
import { getTableList } from '@/api/table/list';
|
import { getTableList } from '@/api/table/list';
|
||||||
import { columns } from './columns';
|
import { columns } from './columns';
|
||||||
import { PlusOutlined } from '@vicons/antd';
|
import { PlusOutlined } from '@vicons/antd';
|
||||||
@@ -89,7 +90,7 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemas: FormSchema[] = [
|
const schemas = [
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
labelMessage: '这是一个提示',
|
labelMessage: '这是一个提示',
|
||||||
@@ -213,164 +214,134 @@
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default defineComponent({
|
const router = useRouter();
|
||||||
// eslint-disable-next-line vue/no-unused-components
|
const formRef: any = ref(null);
|
||||||
components: { BasicTable, PlusOutlined, TableAction, BasicForm },
|
const message = useMessage();
|
||||||
setup() {
|
const actionRef = ref();
|
||||||
const router = useRouter();
|
|
||||||
const formRef: any = ref(null);
|
const showModal = ref(false);
|
||||||
const message = useMessage();
|
const formBtnLoading = ref(false);
|
||||||
const actionRef = ref();
|
const formParams = reactive({
|
||||||
const state = reactive({
|
name: '',
|
||||||
showModal: false,
|
address: '',
|
||||||
formBtnLoading: false,
|
date: null,
|
||||||
formParams: {},
|
});
|
||||||
params: {
|
|
||||||
pageSize: 5,
|
const params = ref({
|
||||||
name: 'xiaoMa',
|
pageSize: 5,
|
||||||
},
|
name: 'xiaoMa',
|
||||||
actionColumn: {
|
});
|
||||||
width: 250,
|
|
||||||
title: '操作',
|
const actionColumn = reactive({
|
||||||
key: 'action',
|
width: 220,
|
||||||
fixed: 'right',
|
title: '操作',
|
||||||
render(record) {
|
key: 'action',
|
||||||
return h(TableAction as any, {
|
fixed: 'right',
|
||||||
style: 'button',
|
render(record) {
|
||||||
actions: [
|
return h(TableAction as any, {
|
||||||
{
|
style: 'button',
|
||||||
label: '删除',
|
actions: [
|
||||||
icon: 'ic:outline-delete-outline',
|
{
|
||||||
onClick: handleDelete.bind(null, record),
|
label: '删除',
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
icon: 'ic:outline-delete-outline',
|
||||||
ifShow: () => {
|
onClick: handleDelete.bind(null, record),
|
||||||
return true;
|
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
||||||
},
|
ifShow: () => {
|
||||||
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
return true;
|
||||||
auth: ['basic_list'],
|
},
|
||||||
},
|
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
||||||
{
|
auth: ['basic_list'],
|
||||||
label: '编辑',
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
auth: ['basic_list'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
dropDownActions: [
|
|
||||||
{
|
|
||||||
label: '启用',
|
|
||||||
key: 'enabled',
|
|
||||||
// 根据业务控制是否显示: 非enable状态的不显示启用按钮
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '禁用',
|
|
||||||
key: 'disabled',
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
select: (key) => {
|
|
||||||
message.info(`您点击了,${key} 按钮`);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
onClick: handleEdit.bind(null, record),
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
auth: ['basic_list'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dropDownActions: [
|
||||||
|
{
|
||||||
|
label: '启用',
|
||||||
|
key: 'enabled',
|
||||||
|
// 根据业务控制是否显示: 非enable状态的不显示启用按钮
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '禁用',
|
||||||
|
key: 'disabled',
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
select: (key) => {
|
||||||
|
message.info(`您点击了,${key} 按钮`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [register, {}] = useForm({
|
|
||||||
gridProps: { cols: 5 },
|
|
||||||
labelWidth: 80,
|
|
||||||
schemas,
|
|
||||||
});
|
|
||||||
|
|
||||||
function addTable() {
|
|
||||||
state.showModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadDataTable = async (res) => {
|
|
||||||
let params = {
|
|
||||||
...res,
|
|
||||||
...state.formParams,
|
|
||||||
};
|
|
||||||
return await getTableList(params);
|
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
|
||||||
console.log(rowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
actionRef.value.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmForm(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
state.formBtnLoading = true;
|
|
||||||
formRef.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.success('新建成功');
|
|
||||||
setTimeout(() => {
|
|
||||||
state.showModal = false;
|
|
||||||
reloadTable();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.error('请填写完整信息');
|
|
||||||
}
|
|
||||||
state.formBtnLoading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEdit(record: Recordable) {
|
|
||||||
console.log('点击了编辑', record);
|
|
||||||
router.push({ name: 'basic-info', params: { id: record.id } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(record: Recordable) {
|
|
||||||
console.log('点击了删除', record);
|
|
||||||
message.info('点击了删除');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleOpen(record: Recordable) {
|
|
||||||
console.log('点击了启用', record);
|
|
||||||
message.info('点击了删除');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit(values: Recordable) {
|
|
||||||
console.log(values);
|
|
||||||
state.formParams = values;
|
|
||||||
reloadTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleReset(values: Recordable) {
|
|
||||||
console.log(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
formRef,
|
|
||||||
columns,
|
|
||||||
rules,
|
|
||||||
actionRef,
|
|
||||||
register,
|
|
||||||
confirmForm,
|
|
||||||
loadDataTable,
|
|
||||||
onCheckedRow,
|
|
||||||
reloadTable,
|
|
||||||
addTable,
|
|
||||||
handleEdit,
|
|
||||||
handleDelete,
|
|
||||||
handleOpen,
|
|
||||||
handleSubmit,
|
|
||||||
handleReset,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [register, {}] = useForm({
|
||||||
|
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||||
|
labelWidth: 80,
|
||||||
|
schemas,
|
||||||
|
});
|
||||||
|
|
||||||
|
function addTable() {
|
||||||
|
showModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadDataTable = async (res) => {
|
||||||
|
return await getTableList({...res, ...formParams, ...params.value});
|
||||||
|
};
|
||||||
|
|
||||||
|
function onCheckedRow(rowKeys) {
|
||||||
|
console.log(rowKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
actionRef.value.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmForm(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
formBtnLoading.value = true;
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
message.success('新建成功');
|
||||||
|
setTimeout(() => {
|
||||||
|
showModal.value = false;
|
||||||
|
reloadTable();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error('请填写完整信息');
|
||||||
|
}
|
||||||
|
formBtnLoading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEdit(record: Recordable) {
|
||||||
|
console.log('点击了编辑', record);
|
||||||
|
router.push({ name: 'basic-info', params: { id: record.id } });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDelete(record: Recordable) {
|
||||||
|
console.log('点击了删除', record);
|
||||||
|
message.info('点击了删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit(values: Recordable) {
|
||||||
|
console.log(values);
|
||||||
|
reloadTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset(values: Recordable) {
|
||||||
|
console.log(values);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<n-checkbox v-model:checked="autoLogin">自动登录</n-checkbox>
|
<n-checkbox v-model:checked="autoLogin">自动登录</n-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-initial order-last">
|
<div class="flex-initial order-last">
|
||||||
<a href="javascript:;">忘记密码</a>
|
<a href="javascript:">忘记密码</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
@@ -65,21 +65,21 @@
|
|||||||
<span>其它登录方式</span>
|
<span>其它登录方式</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-initial mx-2">
|
<div class="flex-initial mx-2">
|
||||||
<a href="javascript:;">
|
<a href="javascript:">
|
||||||
<n-icon size="24" color="#2d8cf0">
|
<n-icon size="24" color="#2d8cf0">
|
||||||
<LogoGithub />
|
<LogoGithub />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-initial mx-2">
|
<div class="flex-initial mx-2">
|
||||||
<a href="javascript:;">
|
<a href="javascript:">
|
||||||
<n-icon size="24" color="#2d8cf0">
|
<n-icon size="24" color="#2d8cf0">
|
||||||
<LogoFacebook />
|
<LogoFacebook />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-initial" style="margin-left: auto">
|
<div class="flex-initial" style="margin-left: auto">
|
||||||
<a href="javascript:;">注册账号</a>
|
<a href="javascript:">注册账号</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
@@ -89,95 +89,83 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook } from '@vicons/ionicons5';
|
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { ResultEnum } from '@/enums/httpEnum';
|
import { ResultEnum } from '@/enums/httpEnum';
|
||||||
import logo from '@/assets/images/logo.png';
|
import logo from '@/assets/images/logo.png';
|
||||||
|
import { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook } from '@vicons/ionicons5';
|
||||||
|
|
||||||
interface FormState {
|
interface FormState {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
const formRef = ref();
|
||||||
components: { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook },
|
const message = useMessage();
|
||||||
setup() {
|
const loading = ref(false);
|
||||||
const formRef = ref();
|
const autoLogin = ref(true);
|
||||||
const message = useMessage();
|
|
||||||
const state = reactive({
|
|
||||||
loading: false,
|
|
||||||
autoLogin: true,
|
|
||||||
formInline: {
|
|
||||||
username: 'admin',
|
|
||||||
password: '123456',
|
|
||||||
isCaptcha: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const rules = {
|
|
||||||
username: { required: true, message: '请输入用户名', trigger: 'blur' },
|
|
||||||
password: { required: true, message: '请输入密码', trigger: 'blur' },
|
|
||||||
isCaptcha: {
|
|
||||||
required: true,
|
|
||||||
type: 'boolean',
|
|
||||||
trigger: 'change',
|
|
||||||
message: '请点击按钮进行验证码校验',
|
|
||||||
validator: (_, value) => value === true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const userStore = useUserStore();
|
|
||||||
|
|
||||||
const router = useRouter();
|
const formInline = reactive({
|
||||||
const route = useRoute();
|
username: 'admin',
|
||||||
const handleSubmit = (e) => {
|
password: '123456',
|
||||||
e.preventDefault();
|
isCaptcha: false,
|
||||||
formRef.value.validate(async (errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
const { username, password } = state.formInline;
|
|
||||||
message.loading('登录中...');
|
|
||||||
state.loading = true;
|
|
||||||
|
|
||||||
const params: FormState = {
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { code, message: msg } = await userStore.login(params);
|
|
||||||
|
|
||||||
if (code == ResultEnum.SUCCESS) {
|
|
||||||
const toPath = decodeURIComponent((route.query?.redirect || '/') as string);
|
|
||||||
message.success('登录成功!');
|
|
||||||
router.replace(toPath).then((_) => {
|
|
||||||
if (route.name == 'login') {
|
|
||||||
router.replace('/');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.info(msg || '登录失败');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.error('请填写完整信息,并且进行验证码校验');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function onAuthCode() {
|
|
||||||
state.formInline.isCaptcha = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
formRef,
|
|
||||||
rules,
|
|
||||||
logo,
|
|
||||||
handleSubmit,
|
|
||||||
onAuthCode,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
username: { required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
|
password: { required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
|
isCaptcha: {
|
||||||
|
required: true,
|
||||||
|
type: 'boolean',
|
||||||
|
trigger: 'change',
|
||||||
|
message: '请点击按钮进行验证码校验',
|
||||||
|
validator: (_, value) => value === true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
formRef.value.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
const { username, password } = formInline;
|
||||||
|
message.loading('登录中...');
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
const params: FormState = {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { code, message: msg } = await userStore.login(params);
|
||||||
|
|
||||||
|
if (code == ResultEnum.SUCCESS) {
|
||||||
|
const toPath = decodeURIComponent((route.query?.redirect || '/') as string);
|
||||||
|
message.success('登录成功!');
|
||||||
|
router.replace(toPath).then((_) => {
|
||||||
|
if (route.name == 'login') {
|
||||||
|
router.replace('/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.info(msg || '登录失败');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error('请填写完整信息,并且进行验证码校验');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAuthCode = () => {
|
||||||
|
formInline.isCaptcha = true;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -36,22 +36,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { InfoCircleOutlined } from '@vicons/antd';
|
import { InfoCircleOutlined } from '@vicons/antd';
|
||||||
|
|
||||||
export default defineComponent({
|
const router = useRouter();
|
||||||
components: { InfoCircleOutlined },
|
|
||||||
setup() {
|
function goHome() {
|
||||||
const router = useRouter();
|
router.push('/');
|
||||||
return {
|
}
|
||||||
goHome() {
|
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.result-box {
|
.result-box {
|
||||||
|
|||||||
@@ -40,22 +40,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { CheckCircleOutlined } from '@vicons/antd';
|
import { CheckCircleOutlined } from '@vicons/antd';
|
||||||
|
|
||||||
export default defineComponent({
|
const router = useRouter();
|
||||||
components: { CheckCircleOutlined },
|
|
||||||
setup() {
|
function goHome() {
|
||||||
const router = useRouter();
|
router.push('/');
|
||||||
return {
|
}
|
||||||
goHome() {
|
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.result-box {
|
.result-box {
|
||||||
|
|||||||
@@ -22,20 +22,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
export default defineComponent({
|
const router = useRouter();
|
||||||
setup() {
|
|
||||||
const router = useRouter();
|
function goHome() {
|
||||||
return {
|
router.push('/');
|
||||||
goHome() {
|
}
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.result-box {
|
.result-box {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
</n-grid>
|
</n-grid>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, ref, toRefs } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
@@ -49,37 +49,23 @@
|
|||||||
trigger: 'input',
|
trigger: 'input',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const formRef: any = ref(null);
|
||||||
|
const message = useMessage();
|
||||||
|
|
||||||
export default defineComponent({
|
const formValue = reactive({
|
||||||
setup() {
|
name: '',
|
||||||
const formRef: any = ref(null);
|
mobile: '',
|
||||||
const message = useMessage();
|
email: '',
|
||||||
|
address: '',
|
||||||
const state = reactive({
|
|
||||||
formValue: {
|
|
||||||
name: '',
|
|
||||||
mobile: '',
|
|
||||||
email: '',
|
|
||||||
address: '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function formSubmit() {
|
|
||||||
formRef.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.success('验证成功');
|
|
||||||
} else {
|
|
||||||
message.error('验证失败,请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
formRef,
|
|
||||||
...toRefs(state),
|
|
||||||
rules,
|
|
||||||
formSubmit,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function formSubmit() {
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
message.success('验证成功');
|
||||||
|
} else {
|
||||||
|
message.error('验证失败,请填写完整信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -49,58 +49,4 @@
|
|||||||
</n-grid>
|
</n-grid>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup></script>
|
||||||
import { defineComponent, reactive, ref, toRefs } from 'vue';
|
|
||||||
import { useMessage } from 'naive-ui';
|
|
||||||
|
|
||||||
const rules = {
|
|
||||||
name: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入昵称',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入邮箱',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
mobile: {
|
|
||||||
required: true,
|
|
||||||
message: '请输入联系电话',
|
|
||||||
trigger: 'input',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
const formRef: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
formValue: {
|
|
||||||
name: '',
|
|
||||||
mobile: '',
|
|
||||||
email: '',
|
|
||||||
address: '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function formSubmit() {
|
|
||||||
formRef.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.success('验证成功');
|
|
||||||
} else {
|
|
||||||
message.error('验证失败,请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
formRef,
|
|
||||||
...toRefs(state),
|
|
||||||
rules,
|
|
||||||
formSubmit,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
</n-grid>
|
</n-grid>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs } from 'vue';
|
import { ref } from 'vue';
|
||||||
import BasicSetting from './BasicSetting.vue';
|
import BasicSetting from './BasicSetting.vue';
|
||||||
import SafetySetting from './SafetySetting.vue';
|
import SafetySetting from './SafetySetting.vue';
|
||||||
|
|
||||||
@@ -41,26 +41,14 @@
|
|||||||
key: 2,
|
key: 2,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
export default defineComponent({
|
|
||||||
components: { BasicSetting, SafetySetting },
|
|
||||||
setup() {
|
|
||||||
const state = reactive({
|
|
||||||
type: 1,
|
|
||||||
typeTitle: '基本设置',
|
|
||||||
});
|
|
||||||
|
|
||||||
function switchType(e) {
|
const type = ref(1);
|
||||||
state.type = e.key;
|
const typeTitle = ref('基本设置');
|
||||||
state.typeTitle = e.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
function switchType(e) {
|
||||||
...toRefs(state),
|
type.value = e.key;
|
||||||
switchType,
|
typeTitle.value = e.name;
|
||||||
typeTabList,
|
}
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.thing-cell {
|
.thing-cell {
|
||||||
|
|||||||
@@ -124,8 +124,8 @@
|
|||||||
<CreateDrawer ref="createDrawerRef" :title="drawerTitle" />
|
<CreateDrawer ref="createDrawerRef" :title="drawerTitle" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref, unref, reactive, toRefs, onMounted, computed } from 'vue';
|
import { ref, unref, reactive, onMounted, computed } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { DownOutlined, AlignLeftOutlined, SearchOutlined, FormOutlined } from '@vicons/antd';
|
import { DownOutlined, AlignLeftOutlined, SearchOutlined, FormOutlined } from '@vicons/antd';
|
||||||
import { getMenuList } from '@/api/system/menu';
|
import { getMenuList } from '@/api/system/menu';
|
||||||
@@ -145,127 +145,104 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
const formRef: any = ref(null);
|
||||||
components: { DownOutlined, AlignLeftOutlined, SearchOutlined, FormOutlined, CreateDrawer },
|
const createDrawerRef = ref();
|
||||||
setup() {
|
const message = useMessage();
|
||||||
const formRef: any = ref(null);
|
|
||||||
const createDrawerRef = ref();
|
|
||||||
const message = useMessage();
|
|
||||||
|
|
||||||
const isAddSon = computed(() => {
|
let treeItemKey = ref([]);
|
||||||
return !state.treeItemKey.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
const addMenuOptions = ref([
|
let expandedKeys = ref([]);
|
||||||
{
|
|
||||||
label: '添加顶级菜单',
|
|
||||||
key: 'home',
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '添加子菜单',
|
|
||||||
key: 'son',
|
|
||||||
disabled: isAddSon,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const treeItemKey: string[] = reactive([]);
|
const treeData = ref([]);
|
||||||
|
|
||||||
const expandedKeys: string[] = reactive([]);
|
const loading = ref(true);
|
||||||
|
const subLoading = ref(false);
|
||||||
|
const isEditMenu = ref(false);
|
||||||
|
const treeItemTitle = ref('');
|
||||||
|
const pattern = ref('');
|
||||||
|
const drawerTitle = ref('');
|
||||||
|
|
||||||
const treeData: string[] = reactive([]);
|
const isAddSon = computed(() => {
|
||||||
|
return !treeItemKey.value.length;
|
||||||
const state = reactive({
|
|
||||||
loading: true,
|
|
||||||
subLoading: false,
|
|
||||||
isEditMenu: false,
|
|
||||||
treeItemTitle: '',
|
|
||||||
formParams: {
|
|
||||||
type: 1,
|
|
||||||
label: '',
|
|
||||||
subtitle: '',
|
|
||||||
path: '',
|
|
||||||
auth: '',
|
|
||||||
openType: 1,
|
|
||||||
},
|
|
||||||
pattern: '',
|
|
||||||
drawerTitle: '',
|
|
||||||
treeItemKey,
|
|
||||||
expandedKeys,
|
|
||||||
treeData,
|
|
||||||
});
|
|
||||||
|
|
||||||
function selectAddMenu(key: string) {
|
|
||||||
state.drawerTitle = key === 'home' ? '添加顶栏菜单' : `添加子菜单:${state.treeItemTitle}`;
|
|
||||||
openCreateDrawer();
|
|
||||||
}
|
|
||||||
|
|
||||||
function openCreateDrawer() {
|
|
||||||
const { openDrawer } = createDrawerRef.value;
|
|
||||||
openDrawer();
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectedTree(keys: string[]) {
|
|
||||||
if (keys.length) {
|
|
||||||
const treeItem = getTreeItem(unref(state.treeData), keys[0]);
|
|
||||||
state.treeItemKey = keys;
|
|
||||||
state.treeItemTitle = treeItem.label;
|
|
||||||
state.formParams = Object.assign(state.formParams, treeItem);
|
|
||||||
state.isEditMenu = true;
|
|
||||||
} else {
|
|
||||||
state.isEditMenu = false;
|
|
||||||
state.treeItemKey = [];
|
|
||||||
state.treeItemTitle = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleReset() {
|
|
||||||
const treeItem = getTreeItem(unref(state.treeData), state.treeItemKey[0]);
|
|
||||||
state.formParams = Object.assign(state.formParams, treeItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formSubmit() {
|
|
||||||
formRef.value.validate((errors: boolean) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.error('抱歉,您没有该权限');
|
|
||||||
} else {
|
|
||||||
message.error('请填写完整信息');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function packHandle() {
|
|
||||||
if (state.expandedKeys.length) {
|
|
||||||
state.expandedKeys = [];
|
|
||||||
} else {
|
|
||||||
state.expandedKeys = state.treeData.map((item: any) => item.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const treeMenuList = await getMenuList();
|
|
||||||
state.expandedKeys = treeMenuList.list.map((item) => item.key);
|
|
||||||
state.treeData = treeMenuList.list;
|
|
||||||
state.loading = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
function onExpandedKeys(keys: string[]) {
|
|
||||||
state.expandedKeys = keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
addMenuOptions,
|
|
||||||
createDrawerRef,
|
|
||||||
formRef,
|
|
||||||
rules,
|
|
||||||
selectedTree,
|
|
||||||
handleReset,
|
|
||||||
formSubmit,
|
|
||||||
packHandle,
|
|
||||||
onExpandedKeys,
|
|
||||||
selectAddMenu,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const addMenuOptions = ref([
|
||||||
|
{
|
||||||
|
label: '添加顶级菜单',
|
||||||
|
key: 'home',
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '添加子菜单',
|
||||||
|
key: 'son',
|
||||||
|
disabled: isAddSon,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let formParams = reactive({
|
||||||
|
type: 1,
|
||||||
|
label: '',
|
||||||
|
subtitle: '',
|
||||||
|
path: '',
|
||||||
|
auth: '',
|
||||||
|
openType: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
function selectAddMenu(key: string) {
|
||||||
|
drawerTitle.value = key === 'home' ? '添加顶栏菜单' : `添加子菜单:${treeItemTitle.value}`;
|
||||||
|
openCreateDrawer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openCreateDrawer() {
|
||||||
|
const { openDrawer } = createDrawerRef.value;
|
||||||
|
openDrawer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedTree(keys) {
|
||||||
|
if (keys.length) {
|
||||||
|
const treeItem = getTreeItem(unref(treeData), keys[0]);
|
||||||
|
treeItemKey.value = keys;
|
||||||
|
treeItemTitle.value = treeItem.label;
|
||||||
|
formParams = Object.assign(formParams, treeItem);
|
||||||
|
isEditMenu.value = true;
|
||||||
|
} else {
|
||||||
|
isEditMenu.value = false;
|
||||||
|
treeItemKey.value = [];
|
||||||
|
treeItemTitle.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset() {
|
||||||
|
const treeItem = getTreeItem(unref(treeData), treeItemKey[0]);
|
||||||
|
formParams = Object.assign(formParams, treeItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formSubmit() {
|
||||||
|
formRef.value.validate((errors: boolean) => {
|
||||||
|
if (!errors) {
|
||||||
|
message.error('抱歉,您没有该权限');
|
||||||
|
} else {
|
||||||
|
message.error('请填写完整信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function packHandle() {
|
||||||
|
if (expandedKeys.value.length) {
|
||||||
|
expandedKeys.value = [];
|
||||||
|
} else {
|
||||||
|
expandedKeys.value = unref(treeData).map((item: any) => item.key as string) as [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const treeMenuList = await getMenuList();
|
||||||
|
formParams = treeMenuList.list.map((item) => item.key);
|
||||||
|
treeData.value = treeMenuList.list;
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function onExpandedKeys(keys) {
|
||||||
|
expandedKeys.value = keys;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -61,8 +61,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, ref, h, onMounted } from 'vue';
|
import { reactive, ref, unref, h, onMounted } from 'vue';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { BasicTable, TableAction } from '@/components/Table';
|
import { BasicTable, TableAction } from '@/components/Table';
|
||||||
import { getRoleList } from '@/api/system/role';
|
import { getRoleList } from '@/api/system/role';
|
||||||
@@ -70,191 +70,144 @@
|
|||||||
import { columns } from './columns';
|
import { columns } from './columns';
|
||||||
import { PlusOutlined } from '@vicons/antd';
|
import { PlusOutlined } from '@vicons/antd';
|
||||||
import { getTreeAll } from '@/utils';
|
import { getTreeAll } from '@/utils';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
const rules = {
|
const router = useRouter();
|
||||||
name: {
|
const formRef: any = ref(null);
|
||||||
required: true,
|
const message = useMessage();
|
||||||
trigger: ['blur', 'input'],
|
const actionRef = ref();
|
||||||
message: '请输入名称',
|
|
||||||
},
|
const showModal = ref(false);
|
||||||
address: {
|
const formBtnLoading = ref(false);
|
||||||
required: true,
|
const checkedAll = ref(false);
|
||||||
trigger: ['blur', 'input'],
|
const editRoleTitle = ref('');
|
||||||
message: '请输入地址',
|
const treeData = ref([]);
|
||||||
},
|
const expandedKeys = ref([]);
|
||||||
date: {
|
const checkedKeys = ref(['console', 'step-form']);
|
||||||
type: 'number',
|
|
||||||
required: true,
|
const params = reactive({
|
||||||
trigger: ['blur', 'change'],
|
pageSize: 5,
|
||||||
message: '请选择日期',
|
name: 'xiaoMa',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actionColumn = reactive({
|
||||||
|
width: 250,
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
render(record) {
|
||||||
|
return h(TableAction, {
|
||||||
|
style: 'button',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '菜单权限',
|
||||||
|
onClick: handleMenuAuth.bind(null, record),
|
||||||
|
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
||||||
|
auth: ['basic_list'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
onClick: handleEdit.bind(null, record),
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
auth: ['basic_list'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
icon: 'ic:outline-delete-outline',
|
||||||
|
onClick: handleDelete.bind(null, record),
|
||||||
|
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
||||||
|
ifShow: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
||||||
|
auth: ['basic_list'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadDataTable = async (res: any) => {
|
||||||
|
let _params = {
|
||||||
|
...res,
|
||||||
|
...unref(params),
|
||||||
|
};
|
||||||
|
return await getRoleList(_params);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
function onCheckedRow(rowKeys: any[]) {
|
||||||
components: { BasicTable, TableAction, PlusOutlined },
|
console.log(rowKeys);
|
||||||
setup() {
|
}
|
||||||
const formRef: any = ref(null);
|
|
||||||
const message = useMessage();
|
|
||||||
const actionRef = ref();
|
|
||||||
const state = reactive({
|
|
||||||
showModal: false,
|
|
||||||
formBtnLoading: false,
|
|
||||||
checkedAll: false,
|
|
||||||
editRoleTitle: '',
|
|
||||||
treeData: [],
|
|
||||||
expandedKeys: [],
|
|
||||||
checkedKeys: ['console', 'step-form'],
|
|
||||||
formParams: {
|
|
||||||
name: '',
|
|
||||||
address: '',
|
|
||||||
date: [],
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
pageSize: 5,
|
|
||||||
name: 'xiaoMa',
|
|
||||||
},
|
|
||||||
actionColumn: {
|
|
||||||
width: 250,
|
|
||||||
title: '操作',
|
|
||||||
key: 'action',
|
|
||||||
fixed: 'right',
|
|
||||||
render(record) {
|
|
||||||
return h(TableAction, {
|
|
||||||
style: 'button',
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: '菜单权限',
|
|
||||||
onClick: handleMenuAuth.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
|
||||||
auth: ['basic_list'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '编辑',
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
auth: ['basic_list'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
icon: 'ic:outline-delete-outline',
|
|
||||||
onClick: handleDelete.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
|
||||||
auth: ['basic_list'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadDataTable = async (params) => {
|
function reloadTable() {
|
||||||
const data = await getRoleList(params);
|
actionRef.value.reload();
|
||||||
return data;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
function confirmForm(e: any) {
|
||||||
console.log(rowKeys);
|
e.preventDefault();
|
||||||
}
|
formBtnLoading.value = true;
|
||||||
|
formRef.value.validate((errors) => {
|
||||||
function reloadTable() {
|
if (!errors) {
|
||||||
actionRef.value.reload();
|
message.success('新建成功');
|
||||||
}
|
setTimeout(() => {
|
||||||
|
showModal.value = false;
|
||||||
function confirmForm(e) {
|
reloadTable();
|
||||||
e.preventDefault();
|
|
||||||
state.formBtnLoading = true;
|
|
||||||
formRef.value.validate((errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
message.success('新建成功');
|
|
||||||
setTimeout(() => {
|
|
||||||
state.showModal = false;
|
|
||||||
reloadTable();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.error('请填写完整信息');
|
|
||||||
}
|
|
||||||
state.formBtnLoading = false;
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
message.error('请填写完整信息');
|
||||||
}
|
}
|
||||||
|
formBtnLoading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function handleEdit(record: Recordable) {
|
function handleEdit(record: Recordable) {
|
||||||
console.log('点击了编辑', record);
|
console.log('点击了编辑', record);
|
||||||
router.push({ name: 'basic-info', params: { id: record.id } });
|
router.push({ name: 'basic-info', params: { id: record.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDelete(record: Recordable) {
|
function handleDelete(record: Recordable) {
|
||||||
console.log('点击了删除', record);
|
console.log('点击了删除', record);
|
||||||
message.info('点击了删除');
|
message.info('点击了删除');
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOpen(record: Recordable) {
|
function handleMenuAuth(record: Recordable) {
|
||||||
console.log('点击了启用', record);
|
editRoleTitle.value = `分配 ${record.name} 的菜单权限`;
|
||||||
message.info('点击了删除');
|
checkedKeys.value = record.menu_keys;
|
||||||
}
|
showModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
function handleMenuAuth(record: Recordable) {
|
function checkedTree(keys) {
|
||||||
state.editRoleTitle = `分配 ${record.name} 的菜单权限`;
|
checkedKeys.value = [checkedKeys.value, ...keys];
|
||||||
state.checkedKeys = record.menu_keys;
|
}
|
||||||
state.showModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkedTree(keys) {
|
function packHandle() {
|
||||||
state.checkedKeys = [state.checkedKeys, ...keys];
|
if (expandedKeys.value.length) {
|
||||||
}
|
expandedKeys.value = [];
|
||||||
|
} else {
|
||||||
|
expandedKeys.value = treeData.value.map((item: any) => item.key) as [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function packHandle() {
|
function checkedAllHandle() {
|
||||||
if (state.expandedKeys.length) {
|
if (!checkedAll.value) {
|
||||||
state.expandedKeys = [];
|
checkedKeys.value = getTreeAll(treeData.value);
|
||||||
} else {
|
checkedAll.value = true;
|
||||||
state.expandedKeys = state.treeData.map((item) => item.key);
|
} else {
|
||||||
}
|
checkedKeys.value = [];
|
||||||
}
|
checkedAll.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkedAllHandle() {
|
onMounted(async () => {
|
||||||
if (!state.checkedAll) {
|
const treeMenuList = await getMenuList();
|
||||||
state.checkedKeys = getTreeAll(state.treeData);
|
expandedKeys.value = treeMenuList.list.map((item) => item.key);
|
||||||
state.checkedAll = true;
|
treeData.value = treeMenuList.list;
|
||||||
} else {
|
|
||||||
state.checkedKeys = [];
|
|
||||||
state.checkedAll = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const treeMenuList = await getMenuList();
|
|
||||||
state.expandedKeys = treeMenuList.list.map((item) => item.key);
|
|
||||||
state.treeData = treeMenuList.list;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
formRef,
|
|
||||||
columns,
|
|
||||||
rules,
|
|
||||||
actionRef,
|
|
||||||
confirmForm,
|
|
||||||
loadDataTable,
|
|
||||||
onCheckedRow,
|
|
||||||
reloadTable,
|
|
||||||
handleEdit,
|
|
||||||
handleDelete,
|
|
||||||
handleOpen,
|
|
||||||
handleMenuAuth,
|
|
||||||
checkedTree,
|
|
||||||
packHandle,
|
|
||||||
checkedAllHandle,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -14,20 +14,11 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": false,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [
|
"lib": ["dom", "esnext"],
|
||||||
"dom",
|
"types": ["vite/client", "jest"],
|
||||||
"esnext"
|
"typeRoots": ["./node_modules/@types/", "./types"],
|
||||||
],
|
|
||||||
"types": [
|
|
||||||
"vite/client",
|
|
||||||
"jest"
|
|
||||||
],
|
|
||||||
"typeRoots": [
|
|
||||||
"./node_modules/@types/",
|
|
||||||
"./types"
|
|
||||||
],
|
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
@@ -40,7 +31,6 @@
|
|||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"src/**/*.tsx",
|
"src/**/*.tsx",
|
||||||
"src/**/*.vue",
|
"src/**/*.vue",
|
||||||
"types/*.ts",
|
|
||||||
"types/**/*.d.ts",
|
"types/**/*.d.ts",
|
||||||
"types/**/*.ts",
|
"types/**/*.ts",
|
||||||
"build/**/*.ts",
|
"build/**/*.ts",
|
||||||
@@ -48,9 +38,5 @@
|
|||||||
"mock/**/*.ts",
|
"mock/**/*.ts",
|
||||||
"vite.config.ts"
|
"vite.config.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": ["node_modules", "dist", "**/*.js"]
|
||||||
"node_modules",
|
|
||||||
"dist",
|
|
||||||
"**/*.js"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
1
types/config.d.ts
vendored
1
types/config.d.ts
vendored
@@ -27,6 +27,7 @@ export interface ImenuSetting {
|
|||||||
minMenuWidth: number;
|
minMenuWidth: number;
|
||||||
menuWidth: number;
|
menuWidth: number;
|
||||||
fixed: boolean;
|
fixed: boolean;
|
||||||
|
mixMenu: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IcrumbsSetting {
|
export interface IcrumbsSetting {
|
||||||
|
|||||||
@@ -5,6 +5,14 @@ import { wrapperEnv } from './build/utils';
|
|||||||
import { createVitePlugins } from './build/vite/plugin';
|
import { createVitePlugins } from './build/vite/plugin';
|
||||||
import { OUTPUT_DIR } from './build/constant';
|
import { OUTPUT_DIR } from './build/constant';
|
||||||
import { createProxy } from './build/vite/proxy';
|
import { createProxy } from './build/vite/proxy';
|
||||||
|
import pkg from './package.json';
|
||||||
|
import { format } from 'date-fns';
|
||||||
|
const { dependencies, devDependencies, name, version } = pkg;
|
||||||
|
|
||||||
|
const __APP_INFO__ = {
|
||||||
|
pkg: { dependencies, devDependencies, name, version },
|
||||||
|
lastBuildTime: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
|
||||||
|
};
|
||||||
|
|
||||||
function pathResolve(dir: string) {
|
function pathResolve(dir: string) {
|
||||||
return resolve(process.cwd(), '.', dir);
|
return resolve(process.cwd(), '.', dir);
|
||||||
@@ -35,6 +43,9 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||||||
dedupe: ['vue'],
|
dedupe: ['vue'],
|
||||||
},
|
},
|
||||||
plugins: createVitePlugins(viteEnv, isBuild, prodMock),
|
plugins: createVitePlugins(viteEnv, isBuild, prodMock),
|
||||||
|
define: {
|
||||||
|
__APP_INFO__: JSON.stringify(__APP_INFO__),
|
||||||
|
},
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
less: {
|
less: {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user