mirror of
https://github.com/zclzone/vue-naive-admin.git
synced 2026-01-22 23:50:22 +08:00
Compare commits
32 Commits
0a93419eb5
...
2.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22693b02ee | ||
|
|
cba38db3c9 | ||
|
|
2e03a4b1a6 | ||
|
|
a5a20a30c9 | ||
|
|
9a7170f10c | ||
|
|
fb4d18cc0a | ||
|
|
d078bba63e | ||
|
|
5663f58b6e | ||
|
|
32700aee17 | ||
|
|
e593ba3ca5 | ||
|
|
d9de814074 | ||
|
|
5457c4e70b | ||
|
|
6757e47fb1 | ||
|
|
3fbcfdf0e1 | ||
|
|
d6764158f3 | ||
|
|
4785842629 | ||
|
|
5b4b0bd9ad | ||
|
|
3c04bbce8e | ||
|
|
0b69d55765 | ||
|
|
91739a0cd5 | ||
|
|
c925ca3e00 | ||
|
|
11b0f45381 | ||
|
|
0fe0b9d41b | ||
|
|
7243f4f38e | ||
|
|
5178b70aca | ||
|
|
1934776063 | ||
|
|
c675a4d420 | ||
|
|
e29343586f | ||
|
|
6fea2a1b69 | ||
|
|
2513e475be | ||
|
|
dde25dd7ab | ||
|
|
1eb59b7cad |
@@ -6,7 +6,7 @@ VITE_PUBLIC_PATH = '/'
|
|||||||
|
|
||||||
# Axios 基础路径
|
# Axios 基础路径
|
||||||
# VITE_AXIOS_BASE_URL = '/api' # 用于代理
|
# VITE_AXIOS_BASE_URL = '/api' # 用于代理
|
||||||
VITE_AXIOS_BASE_URL = 'https://mock.apipark.cn/m1/3776410-0-default' # apifox云端mock
|
VITE_AXIOS_BASE_URL = 'https://m1.apifoxmock.com/m1/3776410-3408296-default' # apifox云端mock
|
||||||
|
|
||||||
# 代理配置-target
|
# 代理配置-target
|
||||||
VITE_PROXY_TARGET = 'http://localhost:8085'
|
VITE_PROXY_TARGET = 'http://localhost:8085'
|
||||||
|
|||||||
@@ -4,7 +4,5 @@ VITE_USE_HASH = 'false'
|
|||||||
# 资源公共路径,需要以 /开头和结尾
|
# 资源公共路径,需要以 /开头和结尾
|
||||||
VITE_PUBLIC_PATH = '/'
|
VITE_PUBLIC_PATH = '/'
|
||||||
|
|
||||||
VITE_AXIOS_BASE_URL = '/api' # 用于代理
|
# VITE_AXIOS_BASE_URL = '/api' # 用于代理
|
||||||
|
VITE_AXIOS_BASE_URL = 'https://m1.apifoxmock.com/m1/3776410-3408296-default' # apifox云端mock
|
||||||
# 代理配置-target
|
|
||||||
VITE_PROXY_TARGET = 'http://localhost:8085'
|
|
||||||
|
|||||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -7,6 +7,6 @@
|
|||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"sdras.vue-vscode-snippets",
|
"sdras.vue-vscode-snippets",
|
||||||
"mikestead.dotenv",
|
"mikestead.dotenv",
|
||||||
"simonhe.common-intellisense"
|
"tu6ge.naive-ui-intelligence"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -5,8 +5,17 @@
|
|||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="./LICENSE"><img alt="MIT License" src="https://badgen.net/github/license/zclzone/vue-naive-admin"/></a>
|
<a href="./LICENSE"><img alt="MIT License" src="https://badgen.net/github/license/zclzone/vue-naive-admin"/></a>
|
||||||
|
<a href="https://gitcode.com/zclzone/vue-naive-admin"><img alt="GitCode" src="https://gitcode.com/zclzone/vue-naive-admin/star/badge.svg
|
||||||
|
"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href="https://hellogithub.com/repository/54f19ba1f9ae4238b3cbd111f3c428b0" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=54f19ba1f9ae4238b3cbd111f3c428b0&claim_uid=jXGayRdJZScqMNr" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||||
|
|
||||||
|
> [!Tip]
|
||||||
|
> 我们提供Web(PC+H5+小程序)的技术支持服务及定制开发,不限前后端,详细需求可联系作者,微信: isme-admin,邮箱: zclzone@outlook.com
|
||||||
|
|
||||||
## 简介
|
## 简介
|
||||||
|
|
||||||
Vue Naive Admin 是一款极简风格的后台管理模板,包含前后端解决方案,前端使用 Vite + Vue3 + Pinia + Unocss,后端使用 Nestjs + TypeOrm + MySql,简单易用,赏心悦目,历经十几次重构和细节打磨,诚意满满!!
|
Vue Naive Admin 是一款极简风格的后台管理模板,包含前后端解决方案,前端使用 Vite + Vue3 + Pinia + Unocss,后端使用 Nestjs + TypeOrm + MySql,简单易用,赏心悦目,历经十几次重构和细节打磨,诚意满满!!
|
||||||
@@ -51,6 +60,7 @@ Vue Naive Admin 提供一套后端代码,技术栈使用 Nestjs + TypeOrm + My
|
|||||||
|
|
||||||
- 源码-github: [isme-nest-serve | github](https://github.com/zclzone/isme-nest-serve)
|
- 源码-github: [isme-nest-serve | github](https://github.com/zclzone/isme-nest-serve)
|
||||||
- 源码-gitee: [isme-nest-serve | gitee](https://gitee.com/isme-admin/isme-nest-serve)
|
- 源码-gitee: [isme-nest-serve | gitee](https://gitee.com/isme-admin/isme-nest-serve)
|
||||||
|
- 源码-gitcode: [isme-nest-serve | gitcode](https://gitcode.com/zclzone/isme-nest-serve)
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
|
"jsx": "preserve",
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"],
|
"@/*": ["src/*"],
|
||||||
"~/*": ["./*"]
|
"~/*": ["./*"]
|
||||||
},
|
},
|
||||||
"jsx": "preserve",
|
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
|
|||||||
66
package.json
66
package.json
@@ -13,46 +13,46 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@arco-design/color": "^0.4.0",
|
"@arco-design/color": "^0.4.0",
|
||||||
"@vueuse/core": "^12.7.0",
|
"@vueuse/core": "^14.1.0",
|
||||||
"axios": "^1.8.1",
|
"axios": "^1.13.2",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.19",
|
||||||
"echarts": "^5.6.0",
|
"echarts": "^6.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.22",
|
||||||
"naive-ui": "^2.41.0",
|
"naive-ui": "^2.43.2",
|
||||||
"pinia": "^3.0.1",
|
"pinia": "^3.0.4",
|
||||||
"pinia-plugin-persistedstate": "^4.2.0",
|
"pinia-plugin-persistedstate": "^4.7.1",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.27",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^8.0.1",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.6.4",
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^4.3.0",
|
"@antfu/eslint-config": "^7.0.1",
|
||||||
"@iconify/json": "^2.2.311",
|
"@iconify/json": "^2.2.430",
|
||||||
"@unocss/eslint-config": "^66.0.0",
|
"@unocss/eslint-config": "^66.6.0",
|
||||||
"@unocss/eslint-plugin": "^66.0.0",
|
"@unocss/eslint-plugin": "^66.6.0",
|
||||||
"@unocss/preset-rem-to-px": "^66.0.0",
|
"@unocss/preset-rem-to-px": "^66.6.0",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^6.0.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
"@vitejs/plugin-vue-jsx": "^5.1.3",
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.39.2",
|
||||||
"eslint-plugin-format": "^1.0.1",
|
"eslint-plugin-format": "^1.3.1",
|
||||||
"esno": "^4.8.0",
|
"esno": "^4.8.0",
|
||||||
"fs-extra": "^11.3.0",
|
"fs-extra": "^11.3.3",
|
||||||
"glob": "^11.0.1",
|
"glob": "^13.0.0",
|
||||||
"lint-staged": "^15.4.3",
|
"lint-staged": "^16.2.7",
|
||||||
"rollup-plugin-visualizer": "^5.14.0",
|
"rollup-plugin-visualizer": "^6.0.5",
|
||||||
"simple-git-hooks": "^2.11.1",
|
"simple-git-hooks": "^2.13.1",
|
||||||
"taze": "^18.6.0",
|
"taze": "^19.9.2",
|
||||||
"unocss": "^66.0.0",
|
"unocss": "^66.6.0",
|
||||||
"unplugin-auto-import": "^19.1.1",
|
"unplugin-auto-import": "^21.0.0",
|
||||||
"unplugin-vue-components": "^28.4.1",
|
"unplugin-vue-components": "^31.0.0",
|
||||||
"vite": "^6.2.0",
|
"vite": "^7.3.1",
|
||||||
"vite-plugin-router-warn": "^1.0.0",
|
"vite-plugin-router-warn": "^2.0.0",
|
||||||
"vite-plugin-vue-devtools": "^7.7.2",
|
"vite-plugin-vue-devtools": "^8.0.5",
|
||||||
"vue3-intro-step": "^1.0.5"
|
"vue3-intro-step": "^1.0.5"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
"simple-git-hooks": {
|
||||||
"pre-commit": "pnpm lint-staged"
|
"pre-commit": "npx lint-staged"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*": "eslint --fix"
|
"*": "eslint --fix"
|
||||||
|
|||||||
5639
pnpm-lock.yaml
generated
5639
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -29,9 +29,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { darkTheme, dateZhCN, zhCN } from 'naive-ui'
|
||||||
import { LayoutSetting } from '@/components'
|
import { LayoutSetting } from '@/components'
|
||||||
import { useAppStore, useTabStore } from '@/store'
|
import { useAppStore, useTabStore } from '@/store'
|
||||||
import { darkTheme, dateZhCN, zhCN } from 'naive-ui'
|
|
||||||
import { layoutSettingVisible } from './settings'
|
import { layoutSettingVisible } from './settings'
|
||||||
|
|
||||||
const layouts = new Map()
|
const layouts = new Map()
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-tooltip trigger="hover">
|
<div class="f-c-c">
|
||||||
<template #trigger>
|
<n-tooltip trigger="hover" placement="bottom">
|
||||||
<n-color-picker
|
<template #trigger>
|
||||||
id="theme-setting"
|
<n-color-picker
|
||||||
class="mr-16 h-32 w-32"
|
id="theme-setting"
|
||||||
:value="appStore.primaryColor"
|
class="h-32 w-32"
|
||||||
:swatches="primaryColors"
|
:value="appStore.primaryColor"
|
||||||
:on-update:value="(v) => appStore.setPrimaryColor(v)"
|
:swatches="primaryColors"
|
||||||
:render-label="() => ''"
|
:on-update:value="(v) => appStore.setPrimaryColor(v)"
|
||||||
/>
|
:render-label="() => ''"
|
||||||
</template>
|
/>
|
||||||
设置主题色
|
</template>
|
||||||
</n-tooltip>
|
设置主题色
|
||||||
|
</n-tooltip>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useAppStore } from '@/store'
|
|
||||||
import { getPresetColors } from '@arco-design/color'
|
import { getPresetColors } from '@arco-design/color'
|
||||||
|
import { useAppStore } from '@/store'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useAppStore } from '@/store'
|
|
||||||
import { useDark, useToggle } from '@vueuse/core'
|
import { useDark, useToggle } from '@vueuse/core'
|
||||||
|
import { useAppStore } from '@/store'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const isDark = useDark()
|
const isDark = useDark()
|
||||||
@@ -39,6 +39,7 @@ async function toggleDark({ clientX, clientY }) {
|
|||||||
duration: 500,
|
duration: 500,
|
||||||
easing: 'ease-in',
|
easing: 'ease-in',
|
||||||
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`,
|
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`,
|
||||||
|
fill: 'both',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,48 +7,52 @@
|
|||||||
--------------------------------->
|
--------------------------------->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AppCard v-if="$slots.default" bordered bg="#fafafc dark:black" class="mb-30 min-h-60 rounded-4">
|
<div class="h-full flex flex-col overflow-hidden">
|
||||||
<form class="flex justify-between p-16" @submit.prevent="handleSearch()">
|
<AppCard v-if="$slots.default" bordered bg="#fafafc dark:black" class="mb-30 min-h-60 rounded-4">
|
||||||
<n-scrollbar x-scrollable>
|
<form class="flex justify-between p-16" @submit.prevent="handleSearch()">
|
||||||
<n-space :wrap="!expand || isExpanded" :size="[32, 16]" class="p-10">
|
<n-scrollbar x-scrollable>
|
||||||
<slot />
|
<n-space :wrap="!expand || isExpanded" :size="[32, 16]" class="p-10">
|
||||||
</n-space>
|
<slot />
|
||||||
</n-scrollbar>
|
</n-space>
|
||||||
<div class="flex-shrink-0 p-10">
|
</n-scrollbar>
|
||||||
<n-button ghost type="primary" @click="handleReset">
|
<div class="flex-shrink-0 p-10">
|
||||||
<i class="i-fe:rotate-ccw mr-4" />
|
<n-button ghost type="primary" @click="handleReset">
|
||||||
重置
|
<i class="i-fe:rotate-ccw mr-4" />
|
||||||
</n-button>
|
重置
|
||||||
<n-button attr-type="submit" class="ml-20" type="primary">
|
|
||||||
<i class="i-fe:search mr-4" />
|
|
||||||
搜索
|
|
||||||
</n-button>
|
|
||||||
|
|
||||||
<template v-if="expand">
|
|
||||||
<n-button v-if="!isExpanded" type="primary" text @click="toggleExpand">
|
|
||||||
<i class="i-fe:chevrons-down ml-4" />
|
|
||||||
展开
|
|
||||||
</n-button>
|
</n-button>
|
||||||
<n-button v-else text type="primary" @click="toggleExpand">
|
<n-button attr-type="submit" class="ml-20" type="primary">
|
||||||
<i class="i-fe:chevrons-up ml-4" />
|
<i class="i-fe:search mr-4" />
|
||||||
收起
|
搜索
|
||||||
</n-button>
|
</n-button>
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</AppCard>
|
|
||||||
|
|
||||||
<NDataTable
|
<template v-if="expand">
|
||||||
:remote="remote"
|
<n-button v-if="!isExpanded" type="primary" text @click="toggleExpand">
|
||||||
:loading="loading"
|
<i class="i-fe:chevrons-down ml-4" />
|
||||||
:scroll-x="scrollX"
|
展开
|
||||||
:columns="columns"
|
</n-button>
|
||||||
:data="tableData"
|
<n-button v-else text type="primary" @click="toggleExpand">
|
||||||
:row-key="(row) => row[rowKey]"
|
<i class="i-fe:chevrons-up ml-4" />
|
||||||
:pagination="isPagination ? pagination : false"
|
收起
|
||||||
@update:checked-row-keys="onChecked"
|
</n-button>
|
||||||
@update:page="onPageChange"
|
</template>
|
||||||
/>
|
</div>
|
||||||
|
</form>
|
||||||
|
</AppCard>
|
||||||
|
|
||||||
|
<NDataTable
|
||||||
|
:remote="remote"
|
||||||
|
:loading="loading"
|
||||||
|
:scroll-x="scrollX"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:row-key="(row) => row[rowKey]"
|
||||||
|
:pagination="isPagination ? pagination : false"
|
||||||
|
flex-height
|
||||||
|
class="flex-1"
|
||||||
|
@update:checked-row-keys="onChecked"
|
||||||
|
@update:page="onPageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
import { router } from '@/router'
|
|
||||||
import { withDirectives } from 'vue'
|
import { withDirectives } from 'vue'
|
||||||
|
import { router } from '@/router'
|
||||||
|
|
||||||
const permission = {
|
const permission = {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
id="menu-collapse"
|
id="menu-collapse"
|
||||||
class="f-c-c cursor-pointer rounded-4 p-6 text-22 transition-all-300 auto-bg-hover"
|
class="f-c-c cursor-pointer rounded-4 auto-bg-hover p-6 text-22 transition-all-300"
|
||||||
@click="appStore.switchCollapsed"
|
@click="appStore.switchCollapsed"
|
||||||
>
|
>
|
||||||
<i :class="appStore.collapsed ? 'i-line-md-menu-unfold-left' : 'i-line-md-menu-fold-left'" />
|
<i :class="appStore.collapsed ? 'i-line-md-menu-unfold-left' : 'i-line-md-menu-fold-left'" />
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ function handleMenuSelect(key, item) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (!item.path)
|
||||||
|
return
|
||||||
router.push(item.path)
|
router.push(item.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { basePermissions } from '@/settings'
|
import { basePermissions } from '@/settings'
|
||||||
|
|
||||||
@@ -26,5 +27,5 @@ export async function getPermissions() {
|
|||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
return basePermissions.concat(asyncPermissions)
|
return cloneDeep(basePermissions).concat(asyncPermissions)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
import { defaultLayout, defaultPrimaryColor, naiveThemeOverrides } from '@/settings'
|
|
||||||
import { generate, getRgbStr } from '@arco-design/color'
|
import { generate, getRgbStr } from '@arco-design/color'
|
||||||
import { useDark } from '@vueuse/core'
|
import { useDark } from '@vueuse/core'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { defaultLayout, defaultPrimaryColor, naiveThemeOverrides } from '@/settings'
|
||||||
|
|
||||||
export const useAppStore = defineStore('app', {
|
export const useAppStore = defineStore('app', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
import { usePermissionStore, useRouterStore, useTabStore, useUserStore } from '@/store'
|
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { usePermissionStore, useRouterStore, useTabStore, useUserStore } from '@/store'
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', {
|
export const useAuthStore = defineStore('auth', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
import { isExternal } from '@/utils'
|
|
||||||
import { hyphenate } from '@vueuse/core'
|
import { hyphenate } from '@vueuse/core'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { isExternal } from '@/utils'
|
||||||
|
|
||||||
export const usePermissionStore = defineStore('permission', {
|
export const usePermissionStore = defineStore('permission', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -29,8 +29,6 @@ export const usePermissionStore = defineStore('permission', {
|
|||||||
const route = this.generateRoute(item, item.show ? null : parent?.key)
|
const route = this.generateRoute(item, item.show ? null : parent?.key)
|
||||||
if (item.enable && route.path && !route.path.startsWith('http'))
|
if (item.enable && route.path && !route.path.startsWith('http'))
|
||||||
this.accessRoutes.push(route)
|
this.accessRoutes.push(route)
|
||||||
if (!item.show)
|
|
||||||
return null
|
|
||||||
const menuItem = {
|
const menuItem = {
|
||||||
label: route.meta.title,
|
label: route.meta.title,
|
||||||
key: route.name,
|
key: route.name,
|
||||||
@@ -48,6 +46,8 @@ export const usePermissionStore = defineStore('permission', {
|
|||||||
if (!menuItem.children.length)
|
if (!menuItem.children.length)
|
||||||
delete menuItem.children
|
delete menuItem.children
|
||||||
}
|
}
|
||||||
|
if (!item.show)
|
||||||
|
return null
|
||||||
return menuItem
|
return menuItem
|
||||||
},
|
},
|
||||||
generateRoute(item, parentKey) {
|
generateRoute(item, parentKey) {
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ html,
|
|||||||
-webkit-text-size-adjust: 100%; /* 2 */
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
-moz-tab-size: 4; /* 3 */
|
-moz-tab-size: 4; /* 3 */
|
||||||
tab-size: 4; /* 3 */
|
tab-size: 4; /* 3 */
|
||||||
font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
font-family:
|
||||||
'Noto Color Emoji'; /* 4 */
|
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; /* 4 */
|
||||||
font-feature-settings: normal; /* 5 */
|
font-feature-settings: normal; /* 5 */
|
||||||
font-variation-settings: normal; /* 6 */
|
font-variation-settings: normal; /* 6 */
|
||||||
-webkit-tap-highlight-color: transparent; /* 7 */
|
-webkit-tap-highlight-color: transparent; /* 7 */
|
||||||
@@ -114,7 +114,8 @@ code,
|
|||||||
kbd,
|
kbd,
|
||||||
samp,
|
samp,
|
||||||
pre {
|
pre {
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; /* 1 */
|
font-family:
|
||||||
|
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; /* 1 */
|
||||||
font-feature-settings: normal; /* 2 */
|
font-feature-settings: normal; /* 2 */
|
||||||
font-variation-settings: normal; /* 3 */
|
font-variation-settings: normal; /* 3 */
|
||||||
font-size: 1em; /* 4 */
|
font-size: 1em; /* 4 */
|
||||||
|
|||||||
@@ -10,45 +10,34 @@
|
|||||||
import { useAuthStore } from '@/store'
|
import { useAuthStore } from '@/store'
|
||||||
|
|
||||||
let isConfirming = false
|
let isConfirming = false
|
||||||
|
|
||||||
|
function handleAuthExpired(content, needTip) {
|
||||||
|
if (isConfirming || !needTip)
|
||||||
|
return
|
||||||
|
isConfirming = true
|
||||||
|
$dialog.confirm({
|
||||||
|
title: '提示',
|
||||||
|
type: 'info',
|
||||||
|
content,
|
||||||
|
confirm() {
|
||||||
|
useAuthStore().logout()
|
||||||
|
window.$message?.success('已退出登录')
|
||||||
|
isConfirming = false
|
||||||
|
},
|
||||||
|
cancel() {
|
||||||
|
isConfirming = false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveResError(code, message, needTip = true) {
|
export function resolveResError(code, message, needTip = true) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 401:
|
case 401:
|
||||||
if (isConfirming || !needTip)
|
return handleAuthExpired('登录已过期,是否重新登录?', needTip)
|
||||||
return
|
|
||||||
isConfirming = true
|
|
||||||
$dialog.confirm({
|
|
||||||
title: '提示',
|
|
||||||
type: 'info',
|
|
||||||
content: '登录已过期,是否重新登录?',
|
|
||||||
confirm() {
|
|
||||||
useAuthStore().logout()
|
|
||||||
window.$message?.success('已退出登录')
|
|
||||||
isConfirming = false
|
|
||||||
},
|
|
||||||
cancel() {
|
|
||||||
isConfirming = false
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
case 11007:
|
case 11007:
|
||||||
case 11008:
|
case 11008:
|
||||||
if (isConfirming || !needTip)
|
return handleAuthExpired(`${message},是否重新登录?`, needTip)
|
||||||
return
|
|
||||||
isConfirming = true
|
|
||||||
$dialog.confirm({
|
|
||||||
title: '提示',
|
|
||||||
type: 'info',
|
|
||||||
content: `${message},是否重新登录?`,
|
|
||||||
confirm() {
|
|
||||||
useAuthStore().logout()
|
|
||||||
window.$message?.success('已退出登录')
|
|
||||||
isConfirming = false
|
|
||||||
},
|
|
||||||
cancel() {
|
|
||||||
isConfirming = false
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
case 403:
|
case 403:
|
||||||
message = '请求被拒绝'
|
message = '请求被拒绝'
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
|
import * as NaiveUI from 'naive-ui'
|
||||||
import { useAppStore } from '@/store'
|
import { useAppStore } from '@/store'
|
||||||
import { isNullOrUndef } from '@/utils'
|
import { isNullOrUndef } from '@/utils'
|
||||||
import * as NaiveUI from 'naive-ui'
|
|
||||||
|
|
||||||
export function setupMessage(NMessage) {
|
export function setupMessage(NMessage) {
|
||||||
class Message {
|
class Message {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<li
|
<li
|
||||||
v-for="item in icons"
|
v-for="item in icons"
|
||||||
:key="item"
|
:key="item"
|
||||||
class="w-160 f-c-c flex-col cursor-pointer rounded-12 px-12 py-24 card-border auto-bg"
|
class="w-160 f-c-c flex-col cursor-pointer card-border rounded-12 auto-bg px-12 py-24"
|
||||||
@click="copy(`<i class="${item}" />`)"
|
@click="copy(`<i class="${item}" />`)"
|
||||||
>
|
>
|
||||||
<i :class="`${item}?mask`" class="text-28 text-gray-600 hover:bg-primary" />
|
<i :class="`${item}?mask`" class="text-28 text-gray-600 hover:bg-primary" />
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div mt-20 w-350 f-c-c flex-col>
|
<div mt-20 w-350 f-c-c flex-col>
|
||||||
<div flex flex-wrap justify-around rounded-10 p-10 card-border>
|
<div flex flex-wrap justify-around card-border rounded-10 p-10>
|
||||||
<div m-20 h-50 w-50 f-c-c rounded-5 p-10 border="1 solid">
|
<div m-20 h-50 w-50 f-c-c rounded-5 p-10 border="1 solid">
|
||||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,11 +62,7 @@ defineOptions({ name: 'ImgUpload' })
|
|||||||
|
|
||||||
const { copy, copied } = useClipboard()
|
const { copy, copied } = useClipboard()
|
||||||
|
|
||||||
const imgList = reactive([
|
const imgList = reactive([])
|
||||||
{ url: 'https://img.isme.top/isme/67208863145ef.jpg' },
|
|
||||||
{ url: 'https://img.isme.top/isme/67208ab2a9de0.jpg' },
|
|
||||||
{ url: 'https://img.isme.top/isme/67208ab4c6596.jpg' },
|
|
||||||
])
|
|
||||||
|
|
||||||
watch(copied, (val) => {
|
watch(copied, (val) => {
|
||||||
if (val)
|
if (val)
|
||||||
|
|||||||
@@ -30,10 +30,9 @@
|
|||||||
<n-card class="ml-12 w-70%" title="✨ 欢迎使用 Vue Naive Admin 2.0">
|
<n-card class="ml-12 w-70%" title="✨ 欢迎使用 Vue Naive Admin 2.0">
|
||||||
<template #header-extra>
|
<template #header-extra>
|
||||||
<a
|
<a
|
||||||
class="text-14 text-primary text-highlight hover:underline hover:opacity-80"
|
class="text-highlight text-14 text-primary hover:underline hover:opacity-80"
|
||||||
href="https://isme.top"
|
href="https://isme.top"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@click.prevent="message?.info('官网正在火速开发中...')"
|
|
||||||
>
|
>
|
||||||
isme.top
|
isme.top
|
||||||
</a>
|
</a>
|
||||||
@@ -69,7 +68,7 @@
|
|||||||
<div class="mt-12 flex">
|
<div class="mt-12 flex">
|
||||||
<n-card class="w-50%" title="💯 特性" segmented>
|
<n-card class="w-50%" title="💯 特性" segmented>
|
||||||
<template #header-extra>
|
<template #header-extra>
|
||||||
<span class="opacity-90 text-highlight">👏 历经十几次重构和细节打磨</span>
|
<span class="text-highlight opacity-90">👏 历经十几次重构和细节打磨</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<ul class="opacity-90">
|
<ul class="opacity-90">
|
||||||
@@ -160,13 +159,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useUserStore } from '@/store'
|
|
||||||
import { BarChart, LineChart, PieChart } from 'echarts/charts'
|
import { BarChart, LineChart, PieChart } from 'echarts/charts'
|
||||||
import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||||
import * as echarts from 'echarts/core'
|
import * as echarts from 'echarts/core'
|
||||||
import { UniversalTransition } from 'echarts/features'
|
import { UniversalTransition } from 'echarts/features'
|
||||||
import { CanvasRenderer } from 'echarts/renderers'
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
import VChart from 'vue-echarts'
|
import VChart from 'vue-echarts'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
@@ -251,7 +250,7 @@ const skillOption = {
|
|||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
top: '12%',
|
bottom: '12%',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['35%', '90%'],
|
radius: ['35%', '90%'],
|
||||||
avoidLabelOverlap: true,
|
avoidLabelOverlap: true,
|
||||||
@@ -284,6 +283,4 @@ const skillOption = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = $message
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wh-full flex-col bg-[url(@/assets/images/login_bg.webp)] bg-cover">
|
<div class="wh-full flex-col bg-[url(@/assets/images/login_bg.webp)] bg-cover">
|
||||||
<div
|
<div
|
||||||
class="m-auto max-w-700 min-w-345 f-c-c rounded-8 bg-opacity-20 bg-cover p-12 card-shadow auto-bg"
|
class="m-auto max-w-700 min-w-345 f-c-c rounded-8 auto-bg bg-opacity-20 bg-cover p-12 card-shadow"
|
||||||
>
|
>
|
||||||
<div class="hidden w-380 px-20 py-35 md:block">
|
<div class="hidden w-380 px-20 py-35 md:block">
|
||||||
<img src="@/assets/images/login_banner.webp" class="w-full" alt="login_banner">
|
<img src="@/assets/images/login_banner.webp" class="w-full" alt="login_banner">
|
||||||
@@ -101,9 +101,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { useStorage } from '@vueuse/core'
|
||||||
import { useAuthStore } from '@/store'
|
import { useAuthStore } from '@/store'
|
||||||
import { lStorage, throttle } from '@/utils'
|
import { lStorage, throttle } from '@/utils'
|
||||||
import { useStorage } from '@vueuse/core'
|
|
||||||
import api from './api'
|
import api from './api'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
import { request } from '@/utils'
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { request } from '@/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getMenuTree: () => request.get('/permission/menu/tree'),
|
getMenuTree: () => request.get('/permission/menu/tree'),
|
||||||
|
|||||||
@@ -159,10 +159,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { MeModal } from '@/components'
|
|
||||||
import { useForm, useModal } from '@/composables'
|
|
||||||
import icons from 'isme:icons'
|
import icons from 'isme:icons'
|
||||||
import pagePathes from 'isme:page-pathes'
|
import pagePathes from 'isme:page-pathes'
|
||||||
|
import { MeModal } from '@/components'
|
||||||
|
import { useForm, useModal } from '@/composables'
|
||||||
import api from '../api'
|
import api from '../api'
|
||||||
import QuestionLabel from './QuestionLabel.vue'
|
import QuestionLabel from './QuestionLabel.vue'
|
||||||
|
|
||||||
|
|||||||
@@ -92,8 +92,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { MeCrud } from '@/components'
|
|
||||||
import { NButton, NSwitch } from 'naive-ui'
|
import { NButton, NSwitch } from 'naive-ui'
|
||||||
|
import { MeCrud } from '@/components'
|
||||||
import api from './api'
|
import api from './api'
|
||||||
import MenuTree from './components/MenuTree.vue'
|
import MenuTree from './components/MenuTree.vue'
|
||||||
import ResAddOrEdit from './components/ResAddOrEdit.vue'
|
import ResAddOrEdit from './components/ResAddOrEdit.vue'
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
:checked-keys="modalForm.permissionIds"
|
:checked-keys="modalForm.permissionIds"
|
||||||
:on-update:checked-keys="(keys) => (modalForm.permissionIds = keys)"
|
:on-update:checked-keys="(keys) => (modalForm.permissionIds = keys)"
|
||||||
|
|
||||||
default-expand-all checkable check-on-click
|
checkable check-on-click default-expand-all
|
||||||
class="cus-scroll max-h-200 w-full"
|
class="cus-scroll max-h-200 w-full"
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
@@ -95,9 +95,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { NButton, NSwitch } from 'naive-ui'
|
||||||
import { MeCrud, MeModal, MeQueryItem } from '@/components'
|
import { MeCrud, MeModal, MeQueryItem } from '@/components'
|
||||||
import { useCrud } from '@/composables'
|
import { useCrud } from '@/composables'
|
||||||
import { NButton, NSwitch } from 'naive-ui'
|
|
||||||
import api from './api'
|
import api from './api'
|
||||||
|
|
||||||
defineOptions({ name: 'RoleMgt' })
|
defineOptions({ name: 'RoleMgt' })
|
||||||
|
|||||||
@@ -67,10 +67,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { MeCrud, MeQueryItem } from '@/components'
|
|
||||||
import { formatDateTime } from '@/utils'
|
|
||||||
import { NAvatar, NButton, NSwitch, NTag } from 'naive-ui'
|
import { NAvatar, NButton, NSwitch, NTag } from 'naive-ui'
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
|
import { MeCrud, MeQueryItem } from '@/components'
|
||||||
|
import { formatDateTime } from '@/utils'
|
||||||
import api from './api'
|
import api from './api'
|
||||||
|
|
||||||
defineOptions({ name: 'RoleUser' })
|
defineOptions({ name: 'RoleUser' })
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
trigger: ['input', 'blur'],
|
trigger: ['input', 'blur'],
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<n-input v-model:value="modalForm.password" />
|
<n-input v-model:value="modalForm.password" type="password" show-password-on="mousedown" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
|
|
||||||
<n-form-item v-if="['add', 'setRole'].includes(modalAction)" label="角色" path="roleIds">
|
<n-form-item v-if="['add', 'setRole'].includes(modalAction)" label="角色" path="roleIds">
|
||||||
@@ -110,11 +110,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { NAvatar, NButton, NSwitch, NTag } from 'naive-ui'
|
||||||
import { MeCrud, MeModal, MeQueryItem } from '@/components'
|
import { MeCrud, MeModal, MeQueryItem } from '@/components'
|
||||||
import { useCrud } from '@/composables'
|
import { useCrud } from '@/composables'
|
||||||
import { withPermission } from '@/directives'
|
import { withPermission } from '@/directives'
|
||||||
import { formatDateTime } from '@/utils'
|
import { formatDateTime } from '@/utils'
|
||||||
import { NAvatar, NButton, NSwitch, NTag } from 'naive-ui'
|
|
||||||
import api from './api'
|
import api from './api'
|
||||||
|
|
||||||
defineOptions({ name: 'UserMgt' })
|
defineOptions({ name: 'UserMgt' })
|
||||||
@@ -220,7 +220,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
width: 320,
|
width: 420,
|
||||||
align: 'right',
|
align: 'right',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
hideInExcel: true,
|
hideInExcel: true,
|
||||||
|
|||||||
@@ -73,10 +73,10 @@
|
|||||||
require-mark-placement="left"
|
require-mark-placement="left"
|
||||||
>
|
>
|
||||||
<n-form-item label="原密码" path="oldPassword" :rule="required">
|
<n-form-item label="原密码" path="oldPassword" :rule="required">
|
||||||
<n-input v-model:value="pwdForm.oldPassword" type="password" placeholder="请输入原密码" />
|
<n-input v-model:value="pwdForm.oldPassword" type="password" placeholder="请输入原密码" show-password-on="mousedown" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="新密码" path="newPassword" :rule="required">
|
<n-form-item label="新密码" path="newPassword" :rule="required">
|
||||||
<n-input v-model:value="pwdForm.newPassword" type="password" placeholder="请输入新密码" />
|
<n-input v-model:value="pwdForm.newPassword" type="password" placeholder="请输入新密码" show-password-on="mousedown" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-form>
|
</n-form>
|
||||||
</MeModal>
|
</MeModal>
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ export default defineConfig(({ mode }) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['vue3-intro-step'],
|
||||||
|
},
|
||||||
build: {
|
build: {
|
||||||
chunkSizeWarningLimit: 1024, // chunk 大小警告的限制(单位kb)
|
chunkSizeWarningLimit: 1024, // chunk 大小警告的限制(单位kb)
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user