mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-11 16:52:28 +08:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ab8b5b221 | ||
|
|
fc5e138ed8 | ||
|
|
b9b2c6a07e | ||
|
|
3503569dfe | ||
|
|
125b7f44e3 | ||
|
|
3307b927a4 | ||
|
|
97de86eacb | ||
|
|
cb92f6e87b | ||
|
|
4f81743f90 | ||
|
|
7837c87392 | ||
|
|
17a5d08d94 | ||
|
|
19e5e5fc4a | ||
|
|
822e69deec | ||
|
|
3bf1e941d4 | ||
|
|
ef4912636e | ||
|
|
7929a74d20 | ||
|
|
45862d4f9d | ||
|
|
8e6471060c | ||
|
|
30c0cd5c95 | ||
|
|
259e73c056 | ||
|
|
8eaa889399 | ||
|
|
d1635add5f | ||
|
|
531a31ee5d | ||
|
|
3b64fc1563 | ||
|
|
229fc72cda | ||
|
|
900954d757 | ||
|
|
fca4dddaf6 | ||
|
|
4add3c3eaa | ||
|
|
21e80f8041 | ||
|
|
a63c34dbb5 | ||
|
|
e02e96d4e0 | ||
|
|
70c2b75f17 | ||
|
|
b186e045bc | ||
|
|
742749a838 | ||
|
|
82dc7d2589 | ||
|
|
f11af4fc76 | ||
|
|
85f1dbd5e9 | ||
|
|
ae001fc7bd | ||
|
|
be770016bf | ||
|
|
1bf722bed0 | ||
|
|
8c7dd14004 | ||
|
|
a0490e3b97 |
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
*.sh
|
*.sh
|
||||||
node_modules
|
node_modules
|
||||||
*.md
|
*.md
|
||||||
@@ -13,3 +12,5 @@ dist
|
|||||||
.local
|
.local
|
||||||
/bin
|
/bin
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
components.d.ts
|
||||||
|
components.d.ts
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ module.exports = defineConfig({
|
|||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'prettier',
|
'prettier',
|
||||||
'plugin:prettier/recommended',
|
'plugin:prettier/recommended',
|
||||||
'plugin:jest/recommended',
|
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
|
'vue/script-setup-uses-vars': 'error',
|
||||||
'@typescript-eslint/ban-ts-ignore': 'off',
|
'@typescript-eslint/ban-ts-ignore': 'off',
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
@@ -61,7 +61,6 @@ module.exports = defineConfig({
|
|||||||
'vue/singleline-html-element-content-newline': 'off',
|
'vue/singleline-html-element-content-newline': 'off',
|
||||||
'vue/attribute-hyphenation': 'off',
|
'vue/attribute-hyphenation': 'off',
|
||||||
'vue/require-default-prop': 'off',
|
'vue/require-default-prop': 'off',
|
||||||
'vue/script-setup-uses-vars': 'off',
|
|
||||||
'vue/html-self-closing': [
|
'vue/html-self-closing': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -23,3 +23,5 @@ pnpm-debug.log*
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
/components.d.ts
|
||||||
|
/components.d.ts
|
||||||
|
|||||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,5 +1,18 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 1.6.0 (2021-12-24)
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 修复 `低版本浏览器` 报 globalThis 未定义
|
||||||
|
- 修复 `Axios` api地址拼接异常
|
||||||
|
- 修复 `createStorage存在prefixKey` 会出bug
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 破坏 `Axios` 取消默认导出 `http` 可支持多个请求导出
|
||||||
|
- 搜索 `import http from '@/utils/http/axios'` 替换为 `import { http } from '@/utils/http/axios`
|
||||||
|
- 新增 `Axios` 多项配置 `urlPrefix`,`joinTime`,`ignoreCancelToken`,`withToken`,`uploadFile方法`
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
## 1.5.5 (2021-08-14)
|
## 1.5.5 (2021-08-14)
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|||||||
52
README.md
52
README.md
@@ -1,24 +1,51 @@
|
|||||||
|
## 留步
|
||||||
|
少侠留步,早知如此绊人心,何如当初莫相识,右上角免费的 `Star` 点一点,帮我们突破一下 `1.5k`,谢谢!O(∩_∩)O
|
||||||
|
|
||||||
## 简介
|
## 简介
|
||||||
|
|
||||||
[Naive Ui Admin](https://github.com/jekip/naive-ui-admin) 是一个基于 [Vue3.0](https://github.com/vuejs/vue-next)、[Vite](https://github.com/vitejs/vite)、 [Naive UI](https://www.naiveui.com/)、[TypeScript](https://www.typescriptlang.org/) 的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你。
|
[Naive Ui Admin](https://github.com/jekip/naive-ui-admin) 完全免费,且可商用,基于 [Vue3.0](https://github.com/vuejs/vue-next)、[Vite](https://github.com/vitejs/vite)、 [Naive UI](https://www.naiveui.com/)、[TypeScript](https://www.typescriptlang.org/) 的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目, 相信不管是从新技术使用还是其他方面,都能帮助到你。
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
- **最新技术栈**:使用 Vue3/vite2 等前端前沿技术开发
|
- 二次封装实用高扩展性组件
|
||||||
- **TypeScript**: 应用程序级 JavaScript 的语言
|
- 响应式、多主题,多配置,快速集成,开箱即用
|
||||||
- **主题**:可配置的主题
|
- 最新技术栈,使用 `Vue3`、`Typescript`、`Pinia`、`Vite` 等前端前沿技术
|
||||||
- **Mock 数据** 内置 Mock 数据方案
|
- 强大的鉴权系统,对路由、菜单、功能点等支持`三种鉴权模式`,满足不同的业务鉴权需求
|
||||||
- **权限** 内置完善的动态路由权限生成方案
|
- 持续更新,实用性页面模板功能和交互,随意搭配组合,让构建页面变得简单化
|
||||||
- **组件** 二次封装了多个常用的组件
|
|
||||||
|
|
||||||
|
|
||||||
## 在线预览
|
## 预览
|
||||||
- [naive-ui-admin](https://naive-ui-admin.vercel.app)
|
- [naive-ui-admin](https://naive-ui-admin.vercel.app)
|
||||||
|
|
||||||
账号:admin,密码:123456(随意)
|
账号:admin,密码:123456(随意)
|
||||||
|
|
||||||
|
## 提示
|
||||||
|
|
||||||
|
如果这个版本的功能和组件,并不能满足您的需求,不妨看看,我们全新 `NaiveAdmin v2` 他或许能让您眼前一亮O(∩_∩)O哈哈~
|
||||||
|
|
||||||
|
[NaiveAdmin 官网](https://www.naiveadmin.com)
|
||||||
|
|
||||||
|
[NaiveAdmin v2 预览](https://pro.naiveadmin.com)
|
||||||
|
|
||||||
|
[NaiveAdmin v2 变更日志](https://www.naiveadmin.com/guide/changelog)
|
||||||
|
|
||||||
|
## 新品
|
||||||
|
|
||||||
|
### Antd vue
|
||||||
|
|
||||||
|
千呼万唤 `Naive Admin Antd` 也迎来了第一个版本,同时具备 `Naive Ui Admin` 优点,如果您选的技术栈是 `Antd` 的话,不妨看看。
|
||||||
|
|
||||||
|
[NaiveAdmin Antd 预览](https://antd.naiveadmin.com)
|
||||||
|
|
||||||
|
### Arco vue
|
||||||
|
|
||||||
|
新产品,新生态,智能设计体系,连接轻盈体验,一如既往、开箱即用,欢迎前往查看。
|
||||||
|
|
||||||
|
[NaiveAdmin Arco 预览](https://arco.naiveadmin.com)
|
||||||
|
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
[文档地址](https://naive-ui-admin-docs.vercel.app)
|
[v1文档地址](https://naive-ui-admin-docs.vercel.app)
|
||||||
|
|
||||||
## 准备
|
## 准备
|
||||||
|
|
||||||
@@ -31,7 +58,7 @@
|
|||||||
- [Naive-ui-admin](https://www.naiveui.com/) - ui 基本使用
|
- [Naive-ui-admin](https://www.naiveui.com/) - ui 基本使用
|
||||||
- [Mock.js](https://github.com/nuysoft/Mock) - mockjs 基本语法
|
- [Mock.js](https://github.com/nuysoft/Mock) - mockjs 基本语法
|
||||||
|
|
||||||
## 安装使用
|
## 使用
|
||||||
|
|
||||||
- 获取项目代码
|
- 获取项目代码
|
||||||
|
|
||||||
@@ -64,9 +91,6 @@ yarn build
|
|||||||
|
|
||||||
[CHANGELOG](./CHANGELOG.md)
|
[CHANGELOG](./CHANGELOG.md)
|
||||||
|
|
||||||
## 感谢
|
|
||||||
[@Vben](https://github.com/anncwb/vue-vben-admin) 借鉴 vue-vben-admin 实现的骨架,同时也使用作者开发的 vite 插件,再次感谢作者。
|
|
||||||
|
|
||||||
|
|
||||||
## 如何贡献
|
## 如何贡献
|
||||||
|
|
||||||
@@ -113,7 +137,7 @@ yarn build
|
|||||||
|
|
||||||
## 交流
|
## 交流
|
||||||
|
|
||||||
`Naive Ui Admin` 是完全开源免费的项目,在帮助开发者更方便地进行中大型管理系统开发,同时也提供 QQ 交流群使用问题欢迎在群内提问。
|
`Naive Ui Admin` 在帮助开发者更方便地进行中大型管理系统开发,同时也提供 QQ 交流群使用问题欢迎在群内提问。
|
||||||
|
|
||||||
- QQ 群 `328347666`
|
- QQ 群 `328347666`
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
|
import Components from 'unplugin-vue-components/vite';
|
||||||
|
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
|
||||||
|
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||||
@@ -15,6 +17,12 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, prodMock)
|
|||||||
vue(),
|
vue(),
|
||||||
// have to
|
// have to
|
||||||
vueJsx(),
|
vueJsx(),
|
||||||
|
|
||||||
|
// 按需引入NaiveUi且自动创建组件声明
|
||||||
|
Components({
|
||||||
|
dts: true,
|
||||||
|
resolvers: [NaiveUiResolver()],
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
// vite-plugin-html
|
// vite-plugin-html
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module.exports = {
|
|||||||
'fixed',
|
'fixed',
|
||||||
'resolve',
|
'resolve',
|
||||||
'resolves',
|
'resolves',
|
||||||
'resolved'
|
'resolved',
|
||||||
],
|
],
|
||||||
issuePrefixes: ['#'],
|
issuePrefixes: ['#'],
|
||||||
noteKeywords: ['BREAKING CHANGE'],
|
noteKeywords: ['BREAKING CHANGE'],
|
||||||
@@ -23,8 +23,8 @@ module.exports = {
|
|||||||
revertCorrespondence: ['header', 'hash'],
|
revertCorrespondence: ['header', 'hash'],
|
||||||
warn() {},
|
warn() {},
|
||||||
mergePattern: null,
|
mergePattern: null,
|
||||||
mergeCorrespondence: null
|
mergeCorrespondence: null,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
'body-leading-blank': [2, 'always'],
|
'body-leading-blank': [2, 'always'],
|
||||||
@@ -50,8 +50,8 @@ module.exports = {
|
|||||||
'wip',
|
'wip',
|
||||||
'workflow',
|
'workflow',
|
||||||
'types',
|
'types',
|
||||||
'release'
|
'release',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
116
index.html
116
index.html
@@ -1,26 +1,122 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-cmn-Hans">
|
<html lang="zh-cmn-Hans" id="htmlRoot" data-theme="light">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/>
|
||||||
<meta name="renderer" content="webkit"/>
|
<meta content="webkit" name="renderer"/>
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
|
||||||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
|
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
|
||||||
|
name="viewport"
|
||||||
/>
|
/>
|
||||||
<link rel="icon" href="/favicon.ico"/>
|
<link href="/favicon.ico" rel="icon"/>
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="appProvider" style="display: none"></div>
|
<div id="appProvider" style="display: none"></div>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div class="first-loading-wrp">
|
<style>
|
||||||
<div class="loading-wrp">
|
.first-loading-wrap {
|
||||||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-loading-wrap > h1 {
|
||||||
|
font-size: 128px
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-loading-wrap .loading-wrap {
|
||||||
|
padding: 98px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
animation: antRotate 1.2s infinite linear;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 32px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
box-sizing: border-box
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
background-color: #1890ff;
|
||||||
|
border-radius: 100%;
|
||||||
|
transform: scale(.75);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
opacity: .3;
|
||||||
|
animation: antSpinMove 1s infinite linear alternate
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(1) {
|
||||||
|
top: 0;
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(2) {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
-webkit-animation-delay: .4s;
|
||||||
|
animation-delay: .4s
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(3) {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
-webkit-animation-delay: .8s;
|
||||||
|
animation-delay: .8s
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(4) {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antRotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antRotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antSpinMove {
|
||||||
|
to {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antSpinMove {
|
||||||
|
to {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}</style>
|
||||||
|
<div class="first-loading-wrap">
|
||||||
|
<div class="loading-wrap">
|
||||||
|
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script>var globalThis = window;</script>
|
||||||
|
<script src="/src/main.ts" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
30
package.json
30
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "naive-ui-admin",
|
"name": "naive-ui-admin",
|
||||||
"version": "1.5.5",
|
"version": "1.6.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Ahjung",
|
"name": "Ahjung",
|
||||||
"email": "735878602@qq.com",
|
"email": "735878602@qq.com",
|
||||||
@@ -39,26 +39,25 @@
|
|||||||
"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.2",
|
"naive-ui": "^2.23.1",
|
||||||
"pinia": "^2.0.0-rc.4",
|
"pinia": "^2.0.0-rc.4",
|
||||||
"qs": "^6.10.1",
|
"qs": "^6.10.1",
|
||||||
"vfonts": "^0.1.0",
|
"vfonts": "^0.1.0",
|
||||||
"vue": "^3.2.2",
|
"vue": "^3.2.16",
|
||||||
"vue-router": "^4.0.11",
|
"vue-router": "^4.0.11",
|
||||||
"vue-types": "^4.0.0",
|
"vue-types": "^4.1.0",
|
||||||
"vuedraggable": "^4.0.3",
|
"vuedraggable": "^4.0.3"
|
||||||
"vuex": "^4.0.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^12.1.4",
|
"@commitlint/cli": "^12.1.4",
|
||||||
"@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.29.1",
|
"@typescript-eslint/eslint-plugin": "^4.31.2",
|
||||||
"@typescript-eslint/parser": "^4.29.1",
|
"@typescript-eslint/parser": "^4.31.2",
|
||||||
"@vitejs/plugin-vue": "^1.2.3",
|
"@vitejs/plugin-vue": "^1.9.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^1.1.5",
|
"@vitejs/plugin-vue-jsx": "^1.1.8",
|
||||||
"@vue/compiler-sfc": "^3.2.2",
|
"@vue/compiler-sfc": "^3.2.16",
|
||||||
"@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",
|
||||||
@@ -69,7 +68,7 @@
|
|||||||
"eslint-define-config": "^1.0.9",
|
"eslint-define-config": "^1.0.9",
|
||||||
"eslint-plugin-jest": "^24.4.0",
|
"eslint-plugin-jest": "^24.4.0",
|
||||||
"eslint-plugin-prettier": "^3.4.0",
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
"eslint-plugin-vue": "^7.11.1",
|
"eslint-plugin-vue": "^7.18.0",
|
||||||
"esno": "^0.7.3",
|
"esno": "^0.7.3",
|
||||||
"gh-pages": "^3.2.0",
|
"gh-pages": "^3.2.0",
|
||||||
"husky": "^6.0.0",
|
"husky": "^6.0.0",
|
||||||
@@ -87,13 +86,14 @@
|
|||||||
"stylelint-order": "^4.1.0",
|
"stylelint-order": "^4.1.0",
|
||||||
"stylelint-scss": "^3.19.0",
|
"stylelint-scss": "^3.19.0",
|
||||||
"tailwindcss": "^2.2.7",
|
"tailwindcss": "^2.2.7",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.4.3",
|
||||||
"vite": "2.4.4",
|
"unplugin-vue-components": "^0.17.2",
|
||||||
|
"vite": "^2.5.10",
|
||||||
"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",
|
||||||
"vite-plugin-style-import": "^1.0.1",
|
"vite-plugin-style-import": "^1.0.1",
|
||||||
"vue-eslint-parser": "^7.8.0"
|
"vue-eslint-parser": "^7.11.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{vue,js,ts,tsx}": "eslint --fix"
|
"*.{vue,js,ts,tsx}": "eslint --fix"
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ module.exports = {
|
|||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import http from '@/utils/http/axios';
|
import { http } from '@/utils/http/axios';
|
||||||
|
|
||||||
//获取主控台信息
|
//获取主控台信息
|
||||||
export function getConsoleInfo() {
|
export function getConsoleInfo() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import http from '@/utils/http/axios';
|
import { http } from '@/utils/http/axios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 根据用户id获取用户菜单
|
* @description: 根据用户id获取用户菜单
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import http from '@/utils/http/axios';
|
import { http } from '@/utils/http/axios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 角色列表
|
* @description: 角色列表
|
||||||
*/
|
*/
|
||||||
export function getRoleList(params) {
|
export function getRoleList() {
|
||||||
return http.request({
|
return http.request({
|
||||||
url: '/role/list',
|
url: '/role/list',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import http from '@/utils/http/axios';
|
import { http } from '@/utils/http/axios';
|
||||||
|
|
||||||
export interface BasicResponseModel<T = any> {
|
export interface BasicResponseModel<T = any> {
|
||||||
code: number;
|
code: number;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import http from '@/utils/http/axios';
|
import { http } from '@/utils/http/axios';
|
||||||
|
|
||||||
//获取table
|
//获取table
|
||||||
export function getTableList(params) {
|
export function getTableList(params) {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { FormProps, FormActionType, UseFormReturnType } from '../types/form';
|
import type { FormProps, FormActionType, UseFormReturnType } from '../types/form';
|
||||||
// @ts-ignore
|
|
||||||
import type { DynamicProps } from '/#/utils';
|
import type { DynamicProps } from '/#/utils';
|
||||||
|
|
||||||
import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
|
import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
|
||||||
|
|||||||
@@ -50,6 +50,11 @@
|
|||||||
return { ...props, ...(unref(propsRef) as any) };
|
return { ...props, ...(unref(propsRef) as any) };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const subBtuText = computed(() => {
|
||||||
|
const { subBtuText } = propsRef.value as any;
|
||||||
|
return subBtuText || props.subBtuText;
|
||||||
|
});
|
||||||
|
|
||||||
async function setProps(modalProps: Partial<ModalProps>): Promise<void> {
|
async function setProps(modalProps: Partial<ModalProps>): Promise<void> {
|
||||||
propsRef.value = deepMerge(unref(propsRef) || ({} as any), modalProps);
|
propsRef.value = deepMerge(unref(propsRef) || ({} as any), modalProps);
|
||||||
}
|
}
|
||||||
@@ -58,6 +63,7 @@
|
|||||||
return {
|
return {
|
||||||
...attrs,
|
...attrs,
|
||||||
...unref(getProps),
|
...unref(getProps),
|
||||||
|
...unref(propsRef),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -87,6 +93,7 @@
|
|||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
subLoading.value = true;
|
subLoading.value = true;
|
||||||
|
console.log(subLoading.value)
|
||||||
emit('on-ok');
|
emit('on-ok');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +108,6 @@
|
|||||||
if (instance) {
|
if (instance) {
|
||||||
emit('register', modalMethods);
|
emit('register', modalMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
{{ title }}
|
{{ title }}
|
||||||
<n-tooltip trigger="hover" v-if="titleTooltip">
|
<n-tooltip trigger="hover" v-if="titleTooltip">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<n-icon size="18" class="ml-1 cursor-pointer text-gray-400">
|
<n-icon size="18" class="ml-1 text-gray-400 cursor-pointer">
|
||||||
<QuestionCircleOutlined />
|
<QuestionCircleOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
|
|
||||||
const { getPaginationInfo, setPagination } = usePagination(getProps);
|
const { getPaginationInfo, setPagination } = usePagination(getProps);
|
||||||
|
|
||||||
const { getDataSourceRef, getRowKey, reload } = useDataSource(
|
const { getDataSourceRef, getDataSource, getRowKey, reload } = useDataSource(
|
||||||
getProps,
|
getProps,
|
||||||
{
|
{
|
||||||
getPaginationInfo,
|
getPaginationInfo,
|
||||||
@@ -171,7 +171,7 @@
|
|||||||
useColumns(getProps);
|
useColumns(getProps);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tableSize: 'medium',
|
tableSize: unref(getProps as any).size || 'medium',
|
||||||
isColumnSetting: false,
|
isColumnSetting: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -280,6 +280,7 @@
|
|||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
tableElRef,
|
tableElRef,
|
||||||
getBindValues,
|
getBindValues,
|
||||||
|
getDataSource,
|
||||||
densityOptions,
|
densityOptions,
|
||||||
reload,
|
reload,
|
||||||
densitySelect,
|
densitySelect,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
|
|
||||||
const getIsCheckComp = computed(() => {
|
const getIsCheckComp = computed(() => {
|
||||||
const component = unref(getComponent);
|
const component = unref(getComponent);
|
||||||
return ['NCheckbox', 'NSwitch'].includes(component);
|
return ['NCheckbox', 'NRadio'].includes(component);
|
||||||
});
|
});
|
||||||
|
|
||||||
const getComponentProps = computed(() => {
|
const getComponentProps = computed(() => {
|
||||||
|
|||||||
@@ -88,7 +88,6 @@
|
|||||||
VerticalRightOutlined,
|
VerticalRightOutlined,
|
||||||
VerticalLeftOutlined,
|
VerticalLeftOutlined,
|
||||||
} from '@vicons/antd';
|
} from '@vicons/antd';
|
||||||
// @ts-ignore
|
|
||||||
import Draggable from 'vuedraggable/src/vuedraggable';
|
import Draggable from 'vuedraggable/src/vuedraggable';
|
||||||
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
|
|||||||
const columns = cloneDeep(pageColumns);
|
const columns = cloneDeep(pageColumns);
|
||||||
return columns
|
return columns
|
||||||
.filter((column) => {
|
.filter((column) => {
|
||||||
// @ts-ignore
|
return hasPermission(column.auth as string[]) && isIfShow(column);
|
||||||
return hasPermission(column.auth) && isIfShow(column);
|
|
||||||
})
|
})
|
||||||
.map((column) => {
|
.map((column) => {
|
||||||
//默认 ellipsis 为true
|
//默认 ellipsis 为true
|
||||||
@@ -93,10 +92,10 @@ export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
|
|||||||
function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
|
function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
|
||||||
const { actionColumn } = unref(propsRef);
|
const { actionColumn } = unref(propsRef);
|
||||||
if (!actionColumn) return;
|
if (!actionColumn) return;
|
||||||
// @ts-ignore
|
!columns.find((col) => col.key === 'action') &&
|
||||||
!columns.find((col) => col.key === 'action') && columns.push({
|
columns.push({
|
||||||
...actionColumn,
|
...(actionColumn as any),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置
|
//设置
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function useDataSource(
|
|||||||
{ getPaginationInfo, setPagination, setLoading, tableData },
|
{ getPaginationInfo, setPagination, setLoading, tableData },
|
||||||
emit
|
emit
|
||||||
) {
|
) {
|
||||||
const dataSourceRef = ref([]);
|
const dataSourceRef = ref<Recordable[]>([]);
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
tableData.value = unref(dataSourceRef);
|
tableData.value = unref(dataSourceRef);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { BasicTableProps } from '../types/table';
|
|||||||
import { computed, unref, ref, ComputedRef } from 'vue';
|
import { computed, unref, ref, ComputedRef } from 'vue';
|
||||||
|
|
||||||
import { isBoolean } from '@/utils/is';
|
import { isBoolean } from '@/utils/is';
|
||||||
import { DEFAULTPAGESIZE, PAGESIZES } from '../const';
|
import { APISETTING, DEFAULTPAGESIZE, PAGESIZES } from '../const';
|
||||||
|
|
||||||
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||||
const configRef = ref<PaginationProps>({});
|
const configRef = ref<PaginationProps>({});
|
||||||
@@ -14,6 +14,7 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
|||||||
if (!unref(show) || (isBoolean(pagination) && !pagination)) {
|
if (!unref(show) || (isBoolean(pagination) && !pagination)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const { totalField } = APISETTING;
|
||||||
return {
|
return {
|
||||||
pageSize: DEFAULTPAGESIZE,
|
pageSize: DEFAULTPAGESIZE,
|
||||||
pageSizes: PAGESIZES,
|
pageSizes: PAGESIZES,
|
||||||
@@ -21,6 +22,7 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
|||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
...(isBoolean(pagination) ? {} : pagination),
|
...(isBoolean(pagination) ? {} : pagination),
|
||||||
...unref(configRef),
|
...unref(configRef),
|
||||||
|
pageCount: unref(configRef)[totalField],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// @ts-ignore
|
|
||||||
import { NButton } from 'naive-ui';
|
import { NButton } from 'naive-ui';
|
||||||
import { PermissionsEnum } from '@/enums/permissionsEnum';
|
import { PermissionsEnum } from '@/enums/permissionsEnum';
|
||||||
// @ts-ignore
|
|
||||||
export interface ActionItem extends NButton.props {
|
export interface ActionItem extends NButton.props {
|
||||||
onClick?: Fn;
|
onClick?: Fn;
|
||||||
label?: string;
|
label?: string;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function usePermission() {
|
|||||||
function hasEveryPermission(accesses: string[]): boolean {
|
function hasEveryPermission(accesses: string[]): boolean {
|
||||||
const permissionsList = userStore.getPermissions;
|
const permissionsList = userStore.getPermissions;
|
||||||
if (Array.isArray(accesses)) {
|
if (Array.isArray(accesses)) {
|
||||||
return accesses.every((access) => !!permissionsList[access]);
|
return permissionsList.every((access: any) => accesses.includes(access.value));
|
||||||
}
|
}
|
||||||
throw new Error(`[hasEveryPermission]: ${accesses} should be a array !`);
|
throw new Error(`[hasEveryPermission]: ${accesses} should be a array !`);
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ export function usePermission() {
|
|||||||
function hasSomePermission(accesses: string[]): boolean {
|
function hasSomePermission(accesses: string[]): boolean {
|
||||||
const permissionsList = userStore.getPermissions;
|
const permissionsList = userStore.getPermissions;
|
||||||
if (Array.isArray(accesses)) {
|
if (Array.isArray(accesses)) {
|
||||||
return accesses.some((access) => !!permissionsList[access]);
|
return permissionsList.some((access: any) => accesses.includes(access.value));
|
||||||
}
|
}
|
||||||
throw new Error(`[hasSomePermission]: ${accesses} should be a array !`);
|
throw new Error(`[hasSomePermission]: ${accesses} should be a array !`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</n-switch>
|
</n-switch>
|
||||||
</template>
|
</template>
|
||||||
<span>深色主题</span>
|
<span>{{ designStore.darkTheme ? '深' : '浅' }}色主题</span>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
class="layout-header-left"
|
class="layout-header-left"
|
||||||
v-if="navMode === 'horizontal' || (navMode === 'horizontal-mix' && mixMenu)"
|
v-if="navMode === 'horizontal' || (navMode === 'horizontal-mix' && mixMenu)"
|
||||||
>
|
>
|
||||||
<div class="logo">
|
<div class="logo" v-if="navMode === 'horizontal'">
|
||||||
<img src="~@/assets/images/logo.png" alt="" />
|
<img src="~@/assets/images/logo.png" alt="" />
|
||||||
<h2 v-show="!collapsed" class="title">NaiveUiAdmin</h2>
|
<h2 v-show="!collapsed" class="title">NaiveUiAdmin</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -88,13 +88,11 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 监听菜单收缩状态
|
// 监听菜单收缩状态
|
||||||
watch(
|
// watch(
|
||||||
() => props.collapsed,
|
// () => props.collapsed,
|
||||||
(newVal) => {
|
// (newVal) => {
|
||||||
state.openKeys = newVal ? [] : getOpenKeys;
|
// }
|
||||||
selectedKeys.value = currentRoute.name as string;
|
// );
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 跟随页面路由变化,切换菜单选中状态
|
// 跟随页面路由变化,切换菜单选中状态
|
||||||
watch(
|
watch(
|
||||||
|
|||||||
@@ -30,27 +30,26 @@
|
|||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
<div ref="navScroll" class="tabs-card-scroll">
|
<div ref="navScroll" class="tabs-card-scroll">
|
||||||
<div ref="navRef" class="tabs-card-nav" :style="getNavStyle">
|
<Draggable :list="tabsList" animation="300" item-key="fullPath" class="flex">
|
||||||
<Draggable :list="tabsList" animation="300" item-key="fullPath" class="flex">
|
<template #item="{ element }">
|
||||||
<template #item="{ element }">
|
<div
|
||||||
<div
|
:id="`tag${element.fullPath.split('/').join('\/')}`"
|
||||||
class="tabs-card-scroll-item"
|
class="tabs-card-scroll-item"
|
||||||
:class="{ 'active-item': activeKey === element.path }"
|
:class="{ 'active-item': activeKey === element.path }"
|
||||||
@click.stop="goPage(element)"
|
@click.stop="goPage(element)"
|
||||||
@contextmenu="handleContextMenu($event, element)"
|
@contextmenu="handleContextMenu($event, element)"
|
||||||
|
>
|
||||||
|
<span>{{ element.meta.title }}</span>
|
||||||
|
<n-icon
|
||||||
|
size="14"
|
||||||
|
@click.stop="closeTabItem(element)"
|
||||||
|
v-if="element.path !== baseHome"
|
||||||
>
|
>
|
||||||
<span>{{ element.meta.title }}</span>
|
<CloseOutlined />
|
||||||
<n-icon
|
</n-icon>
|
||||||
size="14"
|
</div>
|
||||||
@click.stop="closeTabItem(element)"
|
</template>
|
||||||
v-if="element.path != baseHome"
|
</Draggable>
|
||||||
>
|
|
||||||
<CloseOutlined />
|
|
||||||
</n-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Draggable>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs-close">
|
<div class="tabs-close">
|
||||||
@@ -87,7 +86,6 @@
|
|||||||
computed,
|
computed,
|
||||||
ref,
|
ref,
|
||||||
toRefs,
|
toRefs,
|
||||||
toRaw,
|
|
||||||
unref,
|
unref,
|
||||||
provide,
|
provide,
|
||||||
watch,
|
watch,
|
||||||
@@ -113,7 +111,7 @@
|
|||||||
LeftOutlined,
|
LeftOutlined,
|
||||||
RightOutlined,
|
RightOutlined,
|
||||||
} from '@vicons/antd';
|
} from '@vicons/antd';
|
||||||
import { renderIcon } from '@/utils/index';
|
import { renderIcon } from '@/utils';
|
||||||
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';
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||||
@@ -133,7 +131,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { getDarkTheme } = useDesignSetting();
|
const { getDarkTheme, getAppTheme } = useDesignSetting();
|
||||||
const { getNavMode, getHeaderSetting, getMenuSetting, getMultiTabsSetting } =
|
const { getNavMode, getHeaderSetting, getMenuSetting, getMultiTabsSetting } =
|
||||||
useProjectSetting();
|
useProjectSetting();
|
||||||
const settingStore = useProjectSettingStore();
|
const settingStore = useProjectSettingStore();
|
||||||
@@ -143,7 +141,6 @@
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const tabsViewStore = useTabsViewStore();
|
const tabsViewStore = useTabsViewStore();
|
||||||
const asyncRouteStore = useAsyncRouteStore();
|
const asyncRouteStore = useAsyncRouteStore();
|
||||||
const navRef: any = ref(null);
|
|
||||||
const navScroll: any = ref(null);
|
const navScroll: any = ref(null);
|
||||||
const navWrap: any = ref(null);
|
const navWrap: any = ref(null);
|
||||||
const isCurrent = ref(false);
|
const isCurrent = ref(false);
|
||||||
@@ -151,9 +148,6 @@
|
|||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeKey: route.fullPath,
|
activeKey: route.fullPath,
|
||||||
scrollable: false,
|
scrollable: false,
|
||||||
navStyle: {
|
|
||||||
transform: '',
|
|
||||||
},
|
|
||||||
dropdownX: 0,
|
dropdownX: 0,
|
||||||
dropdownY: 0,
|
dropdownY: 0,
|
||||||
showDropdown: false,
|
showDropdown: false,
|
||||||
@@ -172,10 +166,7 @@
|
|||||||
const currentRoute = useRoute();
|
const currentRoute = useRoute();
|
||||||
const navMode = unref(getNavMode);
|
const navMode = unref(getNavMode);
|
||||||
if (unref(navMode) != 'horizontal-mix') return true;
|
if (unref(navMode) != 'horizontal-mix') return true;
|
||||||
if (unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot) {
|
return !(unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//动态组装样式 菜单缩进
|
//动态组装样式 菜单缩进
|
||||||
@@ -198,7 +189,7 @@
|
|||||||
|
|
||||||
//tags 右侧下拉菜单
|
//tags 右侧下拉菜单
|
||||||
const TabsMenuOptions = computed(() => {
|
const TabsMenuOptions = computed(() => {
|
||||||
const isDisabled = unref(tabsList).length <= 1 ? true : false;
|
const isDisabled = unref(tabsList).length <= 1;
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: '刷新当前',
|
label: '刷新当前',
|
||||||
@@ -226,17 +217,27 @@
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
let routes: RouteItem[] = [];
|
let cacheRoutes: RouteItem[] = [];
|
||||||
|
const simpleRoute = getSimpleRoute(route);
|
||||||
try {
|
try {
|
||||||
const routesStr = storage.get(TABS_ROUTES) as string | null | undefined;
|
const routesStr = storage.get(TABS_ROUTES) as string | null | undefined;
|
||||||
routes = routesStr ? JSON.parse(routesStr) : [getSimpleRoute(route)];
|
cacheRoutes = routesStr ? JSON.parse(routesStr) : [simpleRoute];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
routes = [getSimpleRoute(route)];
|
cacheRoutes = [simpleRoute];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将最新的路由信息同步到 localStorage 中
|
||||||
|
const routes = router.getRoutes();
|
||||||
|
cacheRoutes.forEach((cacheRoute) => {
|
||||||
|
const route = routes.find((route) => route.path === cacheRoute.path);
|
||||||
|
if (route) {
|
||||||
|
cacheRoute.meta = route.meta || cacheRoute.meta;
|
||||||
|
cacheRoute.name = (route.name || cacheRoute.name) as string;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化标签页
|
// 初始化标签页
|
||||||
tabsViewStore.initTabs(routes);
|
tabsViewStore.initTabs(cacheRoutes);
|
||||||
|
|
||||||
//监听滚动条
|
//监听滚动条
|
||||||
function onScroll(e) {
|
function onScroll(e) {
|
||||||
@@ -245,11 +246,11 @@
|
|||||||
document.documentElement.scrollTop ||
|
document.documentElement.scrollTop ||
|
||||||
window.pageYOffset ||
|
window.pageYOffset ||
|
||||||
document.body.scrollTop; // 滚动条偏移量
|
document.body.scrollTop; // 滚动条偏移量
|
||||||
if (!getHeaderSetting.fixed && getMultiTabsSetting.fixed && scrollTop >= 64) {
|
state.isMultiHeaderFixed = !!(
|
||||||
state.isMultiHeaderFixed = true;
|
!getHeaderSetting.fixed &&
|
||||||
} else {
|
getMultiTabsSetting.fixed &&
|
||||||
state.isMultiHeaderFixed = false;
|
scrollTop >= 64
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('scroll', onScroll, true);
|
window.addEventListener('scroll', onScroll, true);
|
||||||
@@ -281,7 +282,7 @@
|
|||||||
if (whiteList.includes(route.name as string)) return;
|
if (whiteList.includes(route.name as string)) return;
|
||||||
state.activeKey = to;
|
state.activeKey = to;
|
||||||
tabsViewStore.addTabs(getSimpleRoute(route));
|
tabsViewStore.addTabs(getSimpleRoute(route));
|
||||||
updateNavScroll();
|
updateNavScroll(true);
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
@@ -374,64 +375,73 @@
|
|||||||
state.showDropdown = false;
|
state.showDropdown = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getCurrentScrollOffset() {
|
/**
|
||||||
const { navStyle } = state;
|
* @param value 要滚动到的位置
|
||||||
const transform: any = toRaw(navStyle.transform);
|
* @param amplitude 每次滚动的长度
|
||||||
return transform ? Number(transform.match(/translateX\(-(\d+(\.\d+)*)px\)/)[1]) : 0;
|
*/
|
||||||
}
|
function scrollTo(value: number, amplitude: number) {
|
||||||
|
const currentScroll = navScroll.value.scrollLeft;
|
||||||
function setOffset(value) {
|
const scrollWidth =
|
||||||
state.navStyle.transform = `translateX(-${value}px)`;
|
(amplitude > 0 && currentScroll + amplitude >= value) ||
|
||||||
|
(amplitude < 0 && currentScroll + amplitude <= value)
|
||||||
|
? value
|
||||||
|
: currentScroll + amplitude;
|
||||||
|
navScroll.value && navScroll.value.scrollTo(scrollWidth, 0);
|
||||||
|
if (scrollWidth === value) return;
|
||||||
|
return window.requestAnimationFrame(() => scrollTo(value, amplitude));
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollPrev() {
|
function scrollPrev() {
|
||||||
const containerWidth = navScroll.value.offsetWidth;
|
const containerWidth = navScroll.value.offsetWidth;
|
||||||
const currentOffset = getCurrentScrollOffset();
|
const currentScroll = navScroll.value.scrollLeft;
|
||||||
if (!currentOffset) return;
|
|
||||||
let newOffset = currentOffset > containerWidth ? currentOffset - containerWidth : 0;
|
if (!currentScroll) return;
|
||||||
setOffset(newOffset);
|
const scrollLeft = currentScroll > containerWidth ? currentScroll - containerWidth : 0;
|
||||||
|
scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollNext() {
|
function scrollNext() {
|
||||||
const navWidth = navRef.value.scrollWidth;
|
|
||||||
const containerWidth = navScroll.value.offsetWidth;
|
const containerWidth = navScroll.value.offsetWidth;
|
||||||
const currentOffset = getCurrentScrollOffset();
|
const navWidth = navScroll.value.scrollWidth;
|
||||||
if (navWidth - currentOffset <= containerWidth) return;
|
const currentScroll = navScroll.value.scrollLeft;
|
||||||
|
|
||||||
let newOffset =
|
if (navWidth - currentScroll <= containerWidth) return;
|
||||||
navWidth - currentOffset > containerWidth * 2
|
const scrollLeft =
|
||||||
? currentOffset + containerWidth
|
navWidth - currentScroll > containerWidth * 2
|
||||||
|
? currentScroll + containerWidth
|
||||||
: navWidth - containerWidth;
|
: navWidth - containerWidth;
|
||||||
|
scrollTo(scrollLeft, (scrollLeft - currentScroll) / 20);
|
||||||
setOffset(newOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNavScroll() {
|
/**
|
||||||
if (!navRef.value) return;
|
* @param autoScroll 是否开启自动滚动功能
|
||||||
let navWidth = navRef.value.scrollWidth;
|
*/
|
||||||
let containerWidth = navScroll.value.offsetWidth;
|
async function updateNavScroll(autoScroll?: boolean) {
|
||||||
const currentOffset = getCurrentScrollOffset();
|
await nextTick();
|
||||||
|
if (!navScroll.value) return;
|
||||||
|
const containerWidth = navScroll.value.offsetWidth;
|
||||||
|
const navWidth = navScroll.value.scrollWidth;
|
||||||
|
|
||||||
if (containerWidth < navWidth) {
|
if (containerWidth < navWidth) {
|
||||||
state.scrollable = true;
|
state.scrollable = true;
|
||||||
if (navWidth - currentOffset < containerWidth) {
|
if (autoScroll) {
|
||||||
setOffset(navWidth - containerWidth);
|
let tagList = navScroll.value.querySelectorAll('.tabs-card-scroll-item') || [];
|
||||||
|
[...tagList].forEach((tag: HTMLElement) => {
|
||||||
|
// fix SyntaxError
|
||||||
|
if (tag.id === `tag${state.activeKey.split('/').join('\/')}`) {
|
||||||
|
tag.scrollIntoView && tag.scrollIntoView();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.scrollable = false;
|
state.scrollable = false;
|
||||||
if (currentOffset > 0) {
|
|
||||||
setOffset(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleResize() {
|
function handleResize() {
|
||||||
updateNavScroll();
|
updateNavScroll(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getNavStyle = computed(() => {
|
|
||||||
return state.navStyle;
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleContextMenu(e, item) {
|
function handleContextMenu(e, item) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
isCurrent.value = PageEnum.BASE_HOME_REDIRECT === item.path;
|
isCurrent.value = PageEnum.BASE_HOME_REDIRECT === item.path;
|
||||||
@@ -475,7 +485,6 @@
|
|||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
navWrap,
|
navWrap,
|
||||||
navRef,
|
|
||||||
navScroll,
|
navScroll,
|
||||||
route,
|
route,
|
||||||
tabsList,
|
tabsList,
|
||||||
@@ -492,10 +501,10 @@
|
|||||||
closeHandleSelect,
|
closeHandleSelect,
|
||||||
scrollNext,
|
scrollNext,
|
||||||
scrollPrev,
|
scrollPrev,
|
||||||
getNavStyle,
|
|
||||||
handleContextMenu,
|
handleContextMenu,
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
getDarkTheme,
|
getDarkTheme,
|
||||||
|
getAppTheme,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -552,18 +561,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-scroll {
|
&-scroll {
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
.tabs-card-nav {
|
|
||||||
padding-left: 0;
|
|
||||||
margin: 0;
|
|
||||||
float: left;
|
|
||||||
list-style: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
transition: transform 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
background: var(--color);
|
background: var(--color);
|
||||||
@@ -607,7 +606,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.active-item {
|
.active-item {
|
||||||
color: #2d8cf0;
|
color: v-bind(getAppTheme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<NLayout class="layout" :position="fixedMenu" has-sider>
|
<n-layout class="layout" :position="fixedMenu" has-sider>
|
||||||
<NLayoutSider
|
<n-layout-sider
|
||||||
v-if="isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')"
|
v-if="isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')"
|
||||||
show-trigger
|
show-trigger="bar"
|
||||||
@collapse="collapsed = true"
|
@collapse="collapsed = true"
|
||||||
:position="fixedMenu"
|
:position="fixedMenu"
|
||||||
@expand="collapsed = false"
|
@expand="collapsed = false"
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
>
|
>
|
||||||
<Logo :collapsed="collapsed" />
|
<Logo :collapsed="collapsed" />
|
||||||
<AsideMenu v-model:collapsed="collapsed" v-model:location="getMenuLocation" />
|
<AsideMenu v-model:collapsed="collapsed" v-model:location="getMenuLocation" />
|
||||||
</NLayoutSider>
|
</n-layout-sider>
|
||||||
|
|
||||||
<NLayout :inverted="inverted">
|
<n-layout :inverted="inverted">
|
||||||
<NLayoutHeader :inverted="getHeaderInverted" :position="fixedHeader">
|
<n-layout-header :inverted="getHeaderInverted" :position="fixedHeader">
|
||||||
<PageHeader v-model:collapsed="collapsed" :inverted="inverted" />
|
<PageHeader v-model:collapsed="collapsed" :inverted="inverted" />
|
||||||
</NLayoutHeader>
|
</n-layout-header>
|
||||||
|
|
||||||
<NLayoutContent
|
<n-layout-content
|
||||||
class="layout-content"
|
class="layout-content"
|
||||||
:class="{ 'layout-default-background': getDarkTheme === false }"
|
:class="{ 'layout-default-background': getDarkTheme === false }"
|
||||||
>
|
>
|
||||||
@@ -50,10 +50,10 @@
|
|||||||
<!-- <NLayoutFooter v-if="getShowFooter">-->
|
<!-- <NLayoutFooter v-if="getShowFooter">-->
|
||||||
<!-- <PageFooter />-->
|
<!-- <PageFooter />-->
|
||||||
<!-- </NLayoutFooter>-->
|
<!-- </NLayoutFooter>-->
|
||||||
</NLayoutContent>
|
</n-layout-content>
|
||||||
<n-back-top :right="100" />
|
<n-back-top :right="100" />
|
||||||
</NLayout>
|
</n-layout>
|
||||||
</NLayout>
|
</n-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
if (Width <= 950) {
|
if (Width <= 950) {
|
||||||
collapsed.value = true;
|
collapsed.value = true;
|
||||||
} else collapsed.value = false;
|
} else collapsed.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('resize', watchWidth);
|
window.addEventListener('resize', watchWidth);
|
||||||
@@ -151,7 +151,6 @@
|
|||||||
window['$loading'] = useLoadingBar();
|
window['$loading'] = useLoadingBar();
|
||||||
window['$loading'].finish();
|
window['$loading'].finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { adminMenus } from '@/api/system/menu';
|
import { adminMenus } from '@/api/system/menu';
|
||||||
import { constantRouterIcon } from './router-icons';
|
import { constantRouterIcon } from './router-icons';
|
||||||
import router 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 { Layout, ParentLayout } from '@/router/constant';
|
||||||
import type { AppRouteRecordRaw } from '@/router/types';
|
import type { AppRouteRecordRaw } from '@/router/types';
|
||||||
@@ -61,11 +59,8 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
|||||||
.then((result) => {
|
.then((result) => {
|
||||||
const routeList = routerGenerator(result);
|
const routeList = routerGenerator(result);
|
||||||
asyncImportRoute(routeList);
|
asyncImportRoute(routeList);
|
||||||
const asyncRoutesList = [...routeList, ...constantRouter];
|
|
||||||
asyncRoutesList.forEach((item) => {
|
resolve(routeList);
|
||||||
router.addRoute(item);
|
|
||||||
});
|
|
||||||
resolve(asyncRoutesList);
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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';
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const modules = import.meta.globEager('./modules/**/*.ts');
|
const modules = import.meta.globEager('./modules/**/*.ts');
|
||||||
|
|
||||||
const routeModuleList: RouteRecordRaw[] = [];
|
const routeModuleList: RouteRecordRaw[] = [];
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export type Component<T extends any = any> =
|
|||||||
| (() => Promise<typeof import('*.vue')>)
|
| (() => Promise<typeof import('*.vue')>)
|
||||||
| (() => Promise<T>);
|
| (() => Promise<T>);
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
||||||
name: string;
|
name: string;
|
||||||
meta: RouteMeta;
|
meta: RouteMeta;
|
||||||
@@ -33,4 +32,24 @@ export interface Meta {
|
|||||||
frameSrc?: string;
|
frameSrc?: string;
|
||||||
// 外链跳转地址
|
// 外链跳转地址
|
||||||
externalLink?: string;
|
externalLink?: string;
|
||||||
|
//隐藏
|
||||||
|
hidden?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Menu {
|
||||||
|
title: string;
|
||||||
|
label: string;
|
||||||
|
key: string;
|
||||||
|
meta: RouteMeta;
|
||||||
|
name: string;
|
||||||
|
component?: Component | string;
|
||||||
|
components?: Component;
|
||||||
|
children?: AppRouteRecordRaw[];
|
||||||
|
props?: Recordable;
|
||||||
|
fullPath?: string;
|
||||||
|
icon?: any;
|
||||||
|
path: string;
|
||||||
|
permissions?: string[];
|
||||||
|
redirect?: string;
|
||||||
|
sort?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export const useAsyncRouteStore = defineStore({
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
//过滤账户是否拥有某一个权限,并将菜单从加载列表移除
|
//过滤账户是否拥有某一个权限,并将菜单从加载列表移除
|
||||||
accessedRouters = filter([...asyncRoutes, ...constantRouter], routeFilter);
|
accessedRouters = filter(asyncRoutes, routeFilter);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export const ACCESS_TOKEN = 'Access-Token'; // 用户token
|
export const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用户token
|
||||||
export const CURRENT_USER = 'Current-User'; // 当前用户信息
|
export const CURRENT_USER = 'CURRENT-USER'; // 当前用户信息
|
||||||
export const IS_LOCKSCREEN = 'Is-Lockscreen'; // 是否锁屏
|
export const IS_LOCKSCREEN = 'IS-LOCKSCREEN'; // 是否锁屏
|
||||||
export const TABS_ROUTES = 'Tabs-Routes'; // 标签页
|
export const TABS_ROUTES = 'TABS-ROUTES'; // 标签页
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//获取相关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, null)[key];
|
: document.defaultView?.getComputedStyle(o, null)[key];
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const createStorage = ({ prefixKey = '', storage = localStorage } = {}) =
|
|||||||
if (expire === null || expire >= Date.now()) {
|
if (expire === null || expire >= Date.now()) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
this.remove(this.getKey(key));
|
this.remove(key);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { AxiosCanceler } from './axiosCancel';
|
|||||||
import { isFunction } from '@/utils/is';
|
import { isFunction } from '@/utils/is';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import type { RequestOptions, CreateAxiosOptions, Result } from './types';
|
import type { RequestOptions, CreateAxiosOptions, Result, UploadFileParams } from './types';
|
||||||
// import { ContentTypeEnum } from '/@/enums/httpEnum';
|
import { ContentTypeEnum } from '@/enums/httpEnum';
|
||||||
|
|
||||||
export * from './axiosTransform';
|
export * from './axiosTransform';
|
||||||
|
|
||||||
@@ -23,18 +23,6 @@ export class VAxios {
|
|||||||
this.setupInterceptors();
|
this.setupInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 创建axios实例
|
|
||||||
*/
|
|
||||||
private createAxios(config: CreateAxiosOptions): void {
|
|
||||||
this.axiosInstance = axios.create(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTransform() {
|
|
||||||
const { transform } = this.options;
|
|
||||||
return transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAxios(): AxiosInstance {
|
getAxios(): AxiosInstance {
|
||||||
return this.axiosInstance;
|
return this.axiosInstance;
|
||||||
}
|
}
|
||||||
@@ -59,6 +47,103 @@ export class VAxios {
|
|||||||
Object.assign(this.axiosInstance.defaults.headers, headers);
|
Object.assign(this.axiosInstance.defaults.headers, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 请求方法
|
||||||
|
*/
|
||||||
|
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||||
|
let conf: AxiosRequestConfig = cloneDeep(config);
|
||||||
|
const transform = this.getTransform();
|
||||||
|
|
||||||
|
const { requestOptions } = this.options;
|
||||||
|
|
||||||
|
const opt: RequestOptions = Object.assign({}, requestOptions, options);
|
||||||
|
|
||||||
|
const { beforeRequestHook, requestCatch, transformRequestData } = transform || {};
|
||||||
|
if (beforeRequestHook && isFunction(beforeRequestHook)) {
|
||||||
|
conf = beforeRequestHook(conf, opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//这里重新 赋值成最新的配置
|
||||||
|
// @ts-ignore
|
||||||
|
conf.requestOptions = opt;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.axiosInstance
|
||||||
|
.request<any, AxiosResponse<Result>>(conf)
|
||||||
|
.then((res: AxiosResponse<Result>) => {
|
||||||
|
// 请求是否被取消
|
||||||
|
const isCancel = axios.isCancel(res);
|
||||||
|
if (transformRequestData && isFunction(transformRequestData) && !isCancel) {
|
||||||
|
try {
|
||||||
|
const ret = transformRequestData(res, opt);
|
||||||
|
resolve(ret);
|
||||||
|
} catch (err) {
|
||||||
|
reject(err || new Error('request error!'));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(res as unknown as Promise<T>);
|
||||||
|
})
|
||||||
|
.catch((e: Error) => {
|
||||||
|
if (requestCatch && isFunction(requestCatch)) {
|
||||||
|
reject(requestCatch(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 创建axios实例
|
||||||
|
*/
|
||||||
|
private createAxios(config: CreateAxiosOptions): void {
|
||||||
|
this.axiosInstance = axios.create(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTransform() {
|
||||||
|
const { transform } = this.options;
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 文件上传
|
||||||
|
*/
|
||||||
|
uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
|
||||||
|
const formData = new window.FormData();
|
||||||
|
const customFilename = params.name || 'file';
|
||||||
|
|
||||||
|
if (params.filename) {
|
||||||
|
formData.append(customFilename, params.file, params.filename);
|
||||||
|
} else {
|
||||||
|
formData.append(customFilename, params.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.data) {
|
||||||
|
Object.keys(params.data).forEach((key) => {
|
||||||
|
const value = params.data![key];
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach((item) => {
|
||||||
|
formData.append(`${key}[]`, item);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.append(key, params.data![key]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.axiosInstance.request<T>({
|
||||||
|
method: 'POST',
|
||||||
|
data: formData,
|
||||||
|
headers: {
|
||||||
|
'Content-type': ContentTypeEnum.FORM_DATA,
|
||||||
|
ignoreCancelToken: true,
|
||||||
|
},
|
||||||
|
...config,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 拦截器配置
|
* @description: 拦截器配置
|
||||||
*/
|
*/
|
||||||
@@ -78,10 +163,17 @@ export class VAxios {
|
|||||||
|
|
||||||
// 请求拦截器配置处理
|
// 请求拦截器配置处理
|
||||||
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
|
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
|
||||||
const { headers: { ignoreCancelToken } = { ignoreCancelToken: false } } = config;
|
const {
|
||||||
!ignoreCancelToken && axiosCanceler.addPending(config);
|
headers: { ignoreCancelToken },
|
||||||
|
} = config;
|
||||||
|
const ignoreCancel =
|
||||||
|
ignoreCancelToken !== undefined
|
||||||
|
? ignoreCancelToken
|
||||||
|
: this.options.requestOptions?.ignoreCancelToken;
|
||||||
|
|
||||||
|
!ignoreCancel && axiosCanceler.addPending(config);
|
||||||
if (requestInterceptors && isFunction(requestInterceptors)) {
|
if (requestInterceptors && isFunction(requestInterceptors)) {
|
||||||
config = requestInterceptors(config);
|
config = requestInterceptors(config, this.options);
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
}, undefined);
|
}, undefined);
|
||||||
@@ -105,62 +197,4 @@ export class VAxios {
|
|||||||
isFunction(responseInterceptorsCatch) &&
|
isFunction(responseInterceptorsCatch) &&
|
||||||
this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
|
this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @description: 文件上传
|
|
||||||
// */
|
|
||||||
// uploadFiles(config: AxiosRequestConfig, params: File[]) {
|
|
||||||
// const formData = new FormData();
|
|
||||||
|
|
||||||
// Object.keys(params).forEach((key) => {
|
|
||||||
// formData.append(key, params[key as any]);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return this.request({
|
|
||||||
// ...config,
|
|
||||||
// method: 'POST',
|
|
||||||
// data: formData,
|
|
||||||
// headers: {
|
|
||||||
// 'Content-type': ContentTypeEnum.FORM_DATA,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 请求方法
|
|
||||||
*/
|
|
||||||
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
||||||
let conf: AxiosRequestConfig = cloneDeep(config);
|
|
||||||
const transform = this.getTransform();
|
|
||||||
|
|
||||||
const { requestOptions } = this.options;
|
|
||||||
|
|
||||||
const opt: RequestOptions = Object.assign({}, requestOptions, options);
|
|
||||||
|
|
||||||
const { beforeRequestHook, requestCatch, transformRequestData } = transform || {};
|
|
||||||
if (beforeRequestHook && isFunction(beforeRequestHook)) {
|
|
||||||
conf = beforeRequestHook(conf, opt);
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.axiosInstance
|
|
||||||
.request<any, AxiosResponse<Result>>(conf)
|
|
||||||
.then((res: AxiosResponse<Result>) => {
|
|
||||||
// 请求是否被取消
|
|
||||||
const isCancel = axios.isCancel(res);
|
|
||||||
if (transformRequestData && isFunction(transformRequestData) && !isCancel) {
|
|
||||||
const ret = transformRequestData(res, opt);
|
|
||||||
// ret !== undefined ? resolve(ret) : reject(new Error('request error!'));
|
|
||||||
return resolve(ret);
|
|
||||||
}
|
|
||||||
reject(res as unknown as Promise<T>);
|
|
||||||
})
|
|
||||||
.catch((e: Error) => {
|
|
||||||
if (requestCatch && isFunction(requestCatch)) {
|
|
||||||
reject(requestCatch(e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
|
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import type { RequestOptions, Result } from './types';
|
import type { RequestOptions, Result } from './types';
|
||||||
|
|
||||||
|
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
||||||
|
authenticationScheme?: string;
|
||||||
|
transform?: AxiosTransform;
|
||||||
|
requestOptions?: RequestOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class AxiosTransform {
|
export abstract class AxiosTransform {
|
||||||
/**
|
/**
|
||||||
* @description: 请求之前处理配置
|
* @description: 请求之前处理配置
|
||||||
@@ -24,7 +30,10 @@ export abstract class AxiosTransform {
|
|||||||
/**
|
/**
|
||||||
* @description: 请求之前的拦截器
|
* @description: 请求之前的拦截器
|
||||||
*/
|
*/
|
||||||
requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig;
|
requestInterceptors?: (
|
||||||
|
config: AxiosRequestConfig,
|
||||||
|
options: CreateAxiosOptions
|
||||||
|
) => AxiosRequestConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 请求之后的拦截器
|
* @description: 请求之后的拦截器
|
||||||
|
|||||||
@@ -1,46 +1,47 @@
|
|||||||
export function checkStatus(status: number, msg: string, message: any): void {
|
export function checkStatus(status: number, msg: string): void {
|
||||||
|
const $message = window['$message'];
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 400:
|
case 400:
|
||||||
message.error(`${msg}`);
|
$message.error(msg);
|
||||||
break;
|
break;
|
||||||
// 401: 未登录
|
// 401: 未登录
|
||||||
// 未登录则跳转登录页面,并携带当前页面的路径
|
// 未登录则跳转登录页面,并携带当前页面的路径
|
||||||
// 在登录成功后返回当前页面,这一步需要在登录页操作。
|
// 在登录成功后返回当前页面,这一步需要在登录页操作。
|
||||||
case 401:
|
case 401:
|
||||||
message.error('用户没有权限(令牌、用户名、密码错误)!');
|
$message.error('用户没有权限(令牌、用户名、密码错误)!');
|
||||||
break;
|
break;
|
||||||
case 403:
|
case 403:
|
||||||
message.error('用户得到授权,但是访问是被禁止的。!');
|
$message.error('用户得到授权,但是访问是被禁止的。!');
|
||||||
break;
|
break;
|
||||||
// 404请求不存在
|
// 404请求不存在
|
||||||
case 404:
|
case 404:
|
||||||
message.error('网络请求错误,未找到该资源!');
|
$message.error('网络请求错误,未找到该资源!');
|
||||||
break;
|
break;
|
||||||
case 405:
|
case 405:
|
||||||
message.error('网络请求错误,请求方法未允许!');
|
$message.error('网络请求错误,请求方法未允许!');
|
||||||
break;
|
break;
|
||||||
case 408:
|
case 408:
|
||||||
message.error('网络请求超时!');
|
$message.error('网络请求超时');
|
||||||
break;
|
break;
|
||||||
case 500:
|
case 500:
|
||||||
message.error('服务器错误,请联系管理员!');
|
$message.error('服务器错误,请联系管理员!');
|
||||||
break;
|
break;
|
||||||
case 501:
|
case 501:
|
||||||
message.error('网络未实现!');
|
$message.error('网络未实现');
|
||||||
break;
|
break;
|
||||||
case 502:
|
case 502:
|
||||||
message.error('网络错误!');
|
$message.error('网络错误');
|
||||||
break;
|
break;
|
||||||
case 503:
|
case 503:
|
||||||
message.error('服务不可用,服务器暂时过载或维护!');
|
$message.error('服务不可用,服务器暂时过载或维护!');
|
||||||
break;
|
break;
|
||||||
case 504:
|
case 504:
|
||||||
message.error('网络超时!');
|
$message.error('网络超时');
|
||||||
break;
|
break;
|
||||||
case 505:
|
case 505:
|
||||||
message.error('http版本不支持该请求!');
|
$message.error('http版本不支持该请求!');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
message.error(msg);
|
$message.error(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function formatRequestDate(params: Recordable) {
|
|||||||
try {
|
try {
|
||||||
params[key] = isString(value) ? value.trim() : value;
|
params[key] = isString(value) ? value.trim() : value;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error);
|
throw new Error(error as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ import axios, { AxiosResponse } from 'axios';
|
|||||||
import { checkStatus } from './checkStatus';
|
import { checkStatus } from './checkStatus';
|
||||||
import { joinTimestamp, formatRequestDate } from './helper';
|
import { joinTimestamp, formatRequestDate } from './helper';
|
||||||
import { RequestEnum, ResultEnum, ContentTypeEnum } from '@/enums/httpEnum';
|
import { RequestEnum, ResultEnum, ContentTypeEnum } from '@/enums/httpEnum';
|
||||||
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
|
||||||
import { useGlobSetting } from '@/hooks/setting';
|
import { useGlobSetting } from '@/hooks/setting';
|
||||||
|
|
||||||
import { isString } from '@/utils/is/';
|
import { isString } from '@/utils/is/';
|
||||||
|
import { deepMerge, isUrl } from '@/utils';
|
||||||
import { setObjToUrlParams } from '@/utils/urlUtils';
|
import { setObjToUrlParams } from '@/utils/urlUtils';
|
||||||
|
|
||||||
import { RequestOptions, Result } from './types';
|
import { RequestOptions, Result, CreateAxiosOptions } from './types';
|
||||||
|
|
||||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||||
|
|
||||||
@@ -29,8 +31,6 @@ 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 {
|
const {
|
||||||
isShowMessage = true,
|
isShowMessage = true,
|
||||||
isShowErrorMessage,
|
isShowErrorMessage,
|
||||||
@@ -51,15 +51,16 @@ const transform: AxiosTransform = {
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reject = Promise.reject;
|
|
||||||
|
|
||||||
const { data } = res;
|
const { data } = res;
|
||||||
|
|
||||||
|
const $dialog = window['$dialog'];
|
||||||
|
const $message = window['$message'];
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
// return '[HTTP] Request has no return value';
|
// return '[HTTP] Request has no return value';
|
||||||
return reject(data);
|
throw new Error('请求出错,请稍候重试');
|
||||||
}
|
}
|
||||||
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
|
// 这里 code,result,message为 后台统一的字段,需要修改为项目自己的接口返回格式
|
||||||
const { code, result, message } = data;
|
const { code, result, message } = data;
|
||||||
// 请求成功
|
// 请求成功
|
||||||
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
|
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
|
||||||
@@ -67,13 +68,16 @@ const transform: AxiosTransform = {
|
|||||||
if (isShowMessage) {
|
if (isShowMessage) {
|
||||||
if (hasSuccess && (successMessageText || isShowSuccessMessage)) {
|
if (hasSuccess && (successMessageText || isShowSuccessMessage)) {
|
||||||
// 是否显示自定义信息提示
|
// 是否显示自定义信息提示
|
||||||
Message.success(successMessageText || message || '操作成功!');
|
$dialog.success({
|
||||||
|
type: 'success',
|
||||||
|
content: successMessageText || message || '操作成功!',
|
||||||
|
});
|
||||||
} else if (!hasSuccess && (errorMessageText || isShowErrorMessage)) {
|
} else if (!hasSuccess && (errorMessageText || isShowErrorMessage)) {
|
||||||
// 是否显示自定义信息提示
|
// 是否显示自定义信息提示
|
||||||
Message.error(message || errorMessageText || '操作失败!');
|
$message.error(message || errorMessageText || '操作失败!');
|
||||||
} else if (!hasSuccess && options.errorMessageMode === 'modal') {
|
} else if (!hasSuccess && options.errorMessageMode === 'modal') {
|
||||||
// errorMessageMode=‘custom-modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
|
// errorMessageMode=‘custom-modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
|
||||||
Modal.info({
|
$dialog.info({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: message,
|
content: message,
|
||||||
positiveText: '确定',
|
positiveText: '确定',
|
||||||
@@ -86,63 +90,53 @@ const transform: AxiosTransform = {
|
|||||||
if (code === ResultEnum.SUCCESS) {
|
if (code === ResultEnum.SUCCESS) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// 接口请求错误,统一提示错误信息
|
// 接口请求错误,统一提示错误信息 这里逻辑可以根据项目进行修改
|
||||||
if (code === ResultEnum.ERROR) {
|
let errorMsg = message;
|
||||||
if (message) {
|
switch (code) {
|
||||||
Message.error(data.message);
|
// 请求失败
|
||||||
Promise.reject(new Error(message));
|
case ResultEnum.ERROR:
|
||||||
} else {
|
$message.error(errorMsg);
|
||||||
const msg = '操作失败,系统异常!';
|
break;
|
||||||
Message.error(msg);
|
// 登录超时
|
||||||
Promise.reject(new Error(msg));
|
case ResultEnum.TIMEOUT:
|
||||||
}
|
const LoginName = PageEnum.BASE_LOGIN_NAME;
|
||||||
return reject();
|
const LoginPath = PageEnum.BASE_LOGIN;
|
||||||
|
if (router.currentRoute.value?.name === LoginName) return;
|
||||||
|
// 到登录页
|
||||||
|
errorMsg = '登录超时,请重新登录!';
|
||||||
|
$dialog.warning({
|
||||||
|
title: '提示',
|
||||||
|
content: '登录身份已失效,请重新登录!',
|
||||||
|
positiveText: '确定',
|
||||||
|
//negativeText: '取消',
|
||||||
|
closable: false,
|
||||||
|
maskClosable: false,
|
||||||
|
onPositiveClick: () => {
|
||||||
|
storage.clear();
|
||||||
|
window.location.href = LoginPath;
|
||||||
|
},
|
||||||
|
onNegativeClick: () => {},
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
throw new Error(errorMsg);
|
||||||
// 登录超时
|
|
||||||
if (code === ResultEnum.TIMEOUT) {
|
|
||||||
if (router.currentRoute.value.name == 'login') return;
|
|
||||||
// 到登录页
|
|
||||||
const timeoutMsg = '登录超时,请重新登录!';
|
|
||||||
Modal.warning({
|
|
||||||
title: '提示',
|
|
||||||
content: '登录身份已失效,请重新登录!',
|
|
||||||
positiveText: '确定',
|
|
||||||
negativeText: '取消',
|
|
||||||
onPositiveClick: () => {
|
|
||||||
storage.clear();
|
|
||||||
router.replace({
|
|
||||||
name: 'login',
|
|
||||||
query: {
|
|
||||||
redirect: router.currentRoute.value.fullPath,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onNegativeClick: () => {},
|
|
||||||
});
|
|
||||||
return reject(new Error(timeoutMsg));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这里逻辑可以根据项目进行修改
|
|
||||||
if (!hasSuccess) {
|
|
||||||
return reject(new Error(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 请求之前处理config
|
// 请求之前处理config
|
||||||
beforeRequestHook: (config, options) => {
|
beforeRequestHook: (config, options) => {
|
||||||
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;
|
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options;
|
||||||
|
|
||||||
if (joinPrefix) {
|
const isUrlStr = isUrl(config.url as string);
|
||||||
|
|
||||||
|
if (!isUrlStr && joinPrefix) {
|
||||||
config.url = `${urlPrefix}${config.url}`;
|
config.url = `${urlPrefix}${config.url}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apiUrl && isString(apiUrl)) {
|
if (!isUrlStr && apiUrl && isString(apiUrl)) {
|
||||||
config.url = `${apiUrl}${config.url}`;
|
config.url = `${apiUrl}${config.url}`;
|
||||||
}
|
}
|
||||||
const params = config.params || {};
|
const params = config.params || {};
|
||||||
|
const data = config.data || false;
|
||||||
if (config.method?.toUpperCase() === RequestEnum.GET) {
|
if (config.method?.toUpperCase() === RequestEnum.GET) {
|
||||||
if (!isString(params)) {
|
if (!isString(params)) {
|
||||||
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
|
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
|
||||||
@@ -155,10 +149,18 @@ const transform: AxiosTransform = {
|
|||||||
} else {
|
} else {
|
||||||
if (!isString(params)) {
|
if (!isString(params)) {
|
||||||
formatDate && formatRequestDate(params);
|
formatDate && formatRequestDate(params);
|
||||||
config.data = params;
|
if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) {
|
||||||
config.params = undefined;
|
config.data = data;
|
||||||
|
config.params = params;
|
||||||
|
} else {
|
||||||
|
config.data = params;
|
||||||
|
config.params = undefined;
|
||||||
|
}
|
||||||
if (joinParamsToUrl) {
|
if (joinParamsToUrl) {
|
||||||
config.url = setObjToUrlParams(config.url as string, config.data);
|
config.url = setObjToUrlParams(
|
||||||
|
config.url as string,
|
||||||
|
Object.assign({}, config.params, config.data)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 兼容restful风格
|
// 兼容restful风格
|
||||||
@@ -172,13 +174,15 @@ const transform: AxiosTransform = {
|
|||||||
/**
|
/**
|
||||||
* @description: 请求拦截器处理
|
* @description: 请求拦截器处理
|
||||||
*/
|
*/
|
||||||
requestInterceptors: (config) => {
|
requestInterceptors: (config, options) => {
|
||||||
// 请求之前处理config
|
// 请求之前处理config
|
||||||
const userStore = useUserStoreWidthOut();
|
const userStore = useUserStoreWidthOut();
|
||||||
const token = userStore.getToken;
|
const token = userStore.getToken;
|
||||||
if (token) {
|
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
|
||||||
// jwt token
|
// jwt token
|
||||||
config.headers.token = token;
|
(config as Recordable).headers.Authorization = options.authenticationScheme
|
||||||
|
? `${options.authenticationScheme} ${token}`
|
||||||
|
: token;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
@@ -187,8 +191,8 @@ const transform: AxiosTransform = {
|
|||||||
* @description: 响应错误处理
|
* @description: 响应错误处理
|
||||||
*/
|
*/
|
||||||
responseInterceptorsCatch: (error: any) => {
|
responseInterceptorsCatch: (error: any) => {
|
||||||
// @ts-ignore
|
const $dialog = window['$dialog'];
|
||||||
const { $message: Message, $dialog: Modal } = window;
|
const $message = window['$message'];
|
||||||
const { response, code, message } = error || {};
|
const { response, code, message } = error || {};
|
||||||
// TODO 此处要根据后端接口返回格式修改
|
// TODO 此处要根据后端接口返回格式修改
|
||||||
const msg: string =
|
const msg: string =
|
||||||
@@ -196,57 +200,88 @@ const transform: AxiosTransform = {
|
|||||||
const err: string = error.toString();
|
const err: string = error.toString();
|
||||||
try {
|
try {
|
||||||
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
||||||
Message.error('接口请求超时,请刷新页面重试!');
|
$message.error('接口请求超时,请刷新页面重试!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (err && err.includes('Network Error')) {
|
if (err && err.includes('Network Error')) {
|
||||||
Modal.info({
|
$dialog.info({
|
||||||
title: '网络异常',
|
title: '网络异常',
|
||||||
content: '请检查您的网络连接是否正常!',
|
content: '请检查您的网络连接是否正常',
|
||||||
positiveText: '确定',
|
positiveText: '确定',
|
||||||
|
//negativeText: '取消',
|
||||||
|
closable: false,
|
||||||
|
maskClosable: false,
|
||||||
onPositiveClick: () => {},
|
onPositiveClick: () => {},
|
||||||
|
onNegativeClick: () => {},
|
||||||
});
|
});
|
||||||
return;
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error);
|
throw new Error(error as any);
|
||||||
}
|
}
|
||||||
// 请求是否被取消
|
// 请求是否被取消
|
||||||
const isCancel = axios.isCancel(error);
|
const isCancel = axios.isCancel(error);
|
||||||
if (!isCancel) {
|
if (!isCancel) {
|
||||||
checkStatus(error.response && error.response.status, msg, Message);
|
checkStatus(error.response && error.response.status, msg);
|
||||||
} else {
|
} else {
|
||||||
console.warn(error, '请求被取消!');
|
console.warn(error, '请求被取消!');
|
||||||
}
|
}
|
||||||
return error;
|
//return Promise.reject(error);
|
||||||
|
return Promise.reject(response?.data);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const Axios = new VAxios({
|
function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
||||||
timeout: 10 * 1000,
|
return new VAxios(
|
||||||
// 接口前缀
|
deepMerge(
|
||||||
prefixUrl: urlPrefix,
|
{
|
||||||
headers: { 'Content-Type': ContentTypeEnum.JSON },
|
timeout: 10 * 1000,
|
||||||
// 数据处理方式
|
authenticationScheme: '',
|
||||||
transform,
|
// 接口前缀
|
||||||
// 配置项,下面的选项都可以在独立的接口请求中覆盖
|
prefixUrl: urlPrefix,
|
||||||
requestOptions: {
|
headers: { 'Content-Type': ContentTypeEnum.JSON },
|
||||||
// 默认将prefix 添加到url
|
// 数据处理方式
|
||||||
joinPrefix: true,
|
transform,
|
||||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
// 配置项,下面的选项都可以在独立的接口请求中覆盖
|
||||||
isReturnNativeResponse: false,
|
requestOptions: {
|
||||||
// 需要对返回数据进行处理
|
// 默认将prefix 添加到url
|
||||||
isTransformResponse: true,
|
joinPrefix: true,
|
||||||
// post请求的时候添加参数到url
|
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||||
joinParamsToUrl: false,
|
isReturnNativeResponse: false,
|
||||||
// 格式化提交参数时间
|
// 需要对返回数据进行处理
|
||||||
formatDate: true,
|
isTransformResponse: true,
|
||||||
// 消息提示类型
|
// post请求的时候添加参数到url
|
||||||
errorMessageMode: 'none',
|
joinParamsToUrl: false,
|
||||||
// 接口地址
|
// 格式化提交参数时间
|
||||||
apiUrl: globSetting.apiUrl as string,
|
formatDate: true,
|
||||||
},
|
// 消息提示类型
|
||||||
withCredentials: false,
|
errorMessageMode: 'none',
|
||||||
});
|
// 接口地址
|
||||||
|
apiUrl: globSetting.apiUrl,
|
||||||
|
// 接口拼接地址
|
||||||
|
urlPrefix: urlPrefix,
|
||||||
|
// 是否加入时间戳
|
||||||
|
joinTime: true,
|
||||||
|
// 忽略重复请求
|
||||||
|
ignoreCancelToken: true,
|
||||||
|
// 是否携带token
|
||||||
|
withToken: true,
|
||||||
|
},
|
||||||
|
withCredentials: false,
|
||||||
|
},
|
||||||
|
opt || {}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default Axios;
|
export const http = createAxios();
|
||||||
|
|
||||||
|
// 项目,多个不同 api 地址,直接在这里导出多个
|
||||||
|
// src/api ts 里面接口,就可以单独使用这个请求,
|
||||||
|
// import { httpTwo } from '@/utils/http/axios'
|
||||||
|
// export const httpTwo = createAxios({
|
||||||
|
// requestOptions: {
|
||||||
|
// apiUrl: 'http://localhost:9001',
|
||||||
|
// urlPrefix: 'api',
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|||||||
@@ -2,9 +2,22 @@ import { AxiosRequestConfig } from 'axios';
|
|||||||
import { AxiosTransform } from './axiosTransform';
|
import { AxiosTransform } from './axiosTransform';
|
||||||
|
|
||||||
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
||||||
prefixUrl?: string;
|
|
||||||
transform?: AxiosTransform;
|
transform?: AxiosTransform;
|
||||||
requestOptions?: RequestOptions;
|
requestOptions?: RequestOptions;
|
||||||
|
authenticationScheme?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
export interface UploadFileParams {
|
||||||
|
// 其他参数
|
||||||
|
data?: Recordable;
|
||||||
|
// 文件参数接口字段名
|
||||||
|
name?: string;
|
||||||
|
// 文件
|
||||||
|
file: File | Blob;
|
||||||
|
// 文件名称
|
||||||
|
filename?: string;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RequestOptions {
|
export interface RequestOptions {
|
||||||
@@ -28,6 +41,8 @@ export interface RequestOptions {
|
|||||||
joinPrefix?: boolean;
|
joinPrefix?: boolean;
|
||||||
// 接口地址, 不填则使用默认apiUrl
|
// 接口地址, 不填则使用默认apiUrl
|
||||||
apiUrl?: string;
|
apiUrl?: string;
|
||||||
|
// 请求拼接路径
|
||||||
|
urlPrefix?: string;
|
||||||
// 错误消息提示类型
|
// 错误消息提示类型
|
||||||
errorMessageMode?: 'none' | 'modal';
|
errorMessageMode?: 'none' | 'modal';
|
||||||
// 是否添加时间戳
|
// 是否添加时间戳
|
||||||
@@ -36,6 +51,10 @@ export interface RequestOptions {
|
|||||||
isTransformResponse?: boolean;
|
isTransformResponse?: boolean;
|
||||||
// 是否返回原生响应头
|
// 是否返回原生响应头
|
||||||
isReturnNativeResponse?: boolean;
|
isReturnNativeResponse?: boolean;
|
||||||
|
//忽略重复请求
|
||||||
|
ignoreCancelToken?: boolean;
|
||||||
|
// 是否携带token
|
||||||
|
withToken?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Result<T = any> {
|
export interface Result<T = any> {
|
||||||
|
|||||||
@@ -206,3 +206,10 @@ export function lighten(color: string, amount: number) {
|
|||||||
amount
|
amount
|
||||||
)}${addLight(color.substring(4, 6), amount)}`;
|
)}${addLight(color.substring(4, 6), amount)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否 url
|
||||||
|
* */
|
||||||
|
export function isUrl(url: string) {
|
||||||
|
return /(^http|https:\/\/)/g.test(url);
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,10 +77,10 @@
|
|||||||
field: 'makeDate',
|
field: 'makeDate',
|
||||||
component: 'NDatePicker',
|
component: 'NDatePicker',
|
||||||
label: '预约时间',
|
label: '预约时间',
|
||||||
|
defaultValue: 1183135260000,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
clearable: true,
|
clearable: true,
|
||||||
defaultValue: 1183135260000,
|
|
||||||
onUpdateValue: (e: any) => {
|
onUpdateValue: (e: any) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,10 +79,10 @@
|
|||||||
giProps: {
|
giProps: {
|
||||||
//span: 24,
|
//span: 24,
|
||||||
},
|
},
|
||||||
|
defaultValue: 1183135260000,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
clearable: true,
|
clearable: true,
|
||||||
defaultValue: 1183135260000,
|
|
||||||
onUpdateValue: (e: any) => {
|
onUpdateValue: (e: any) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -120,10 +120,10 @@
|
|||||||
giProps: {
|
giProps: {
|
||||||
//span: 24,
|
//span: 24,
|
||||||
},
|
},
|
||||||
|
defaultValue: 1183135260000,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
clearable: true,
|
clearable: true,
|
||||||
defaultValue: 1183135260000,
|
|
||||||
onUpdateValue: (e: any) => {
|
onUpdateValue: (e: any) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadDataTable = async (res) => {
|
const loadDataTable = async (res) => {
|
||||||
return await getTableList({...res,...params});
|
return await getTableList({ ...params, ...res });
|
||||||
};
|
};
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
function onCheckedRow(rowKeys) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadDataTable = async (res) => {
|
const loadDataTable = async (res) => {
|
||||||
return await getTableList({ ...res, ...params });
|
return await getTableList({ ...params, ...res });
|
||||||
};
|
};
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
function onCheckedRow(rowKeys) {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadDataTable = async (res) => {
|
const loadDataTable = async (res) => {
|
||||||
return await getTableList({ ...res, ...params });
|
return await getTableList({ ...params, ...res });
|
||||||
};
|
};
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
function onCheckedRow(rowKeys) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
日同比
|
日同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="visits.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="visits.rise" />
|
||||||
<n-icon size="12" color="#00ff6f">
|
<n-icon size="12" color="#00ff6f">
|
||||||
<component is="CaretUpOutlined" />
|
<CaretUpOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
周同比
|
周同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="visits.decline" />
|
<CountTo :startVal="1" suffix="%" :endVal="visits.decline" />
|
||||||
<n-icon size="12" color="#ffde66">
|
<n-icon size="12" color="#ffde66">
|
||||||
<component is="CaretDownOutlined" />
|
<CaretDownOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
日同比
|
日同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
||||||
<n-icon size="12" color="#00ff6f">
|
<n-icon size="12" color="#00ff6f">
|
||||||
<component is="CaretUpOutlined" />
|
<CaretUpOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
周同比
|
周同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
||||||
<n-icon size="12" color="#ffde66">
|
<n-icon size="12" color="#ffde66">
|
||||||
<component is="CaretDownOutlined" />
|
<CaretDownOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
月同比
|
月同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="volume.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="volume.rise" />
|
||||||
<n-icon size="12" color="#00ff6f">
|
<n-icon size="12" color="#00ff6f">
|
||||||
<component is="CaretUpOutlined" />
|
<CaretUpOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
月同比
|
月同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="volume.decline" />
|
<CountTo :startVal="1" suffix="%" :endVal="volume.decline" />
|
||||||
<n-icon size="12" color="#ffde66">
|
<n-icon size="12" color="#ffde66">
|
||||||
<component is="CaretDownOutlined" />
|
<CaretDownOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -241,12 +241,10 @@
|
|||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
} from '@vicons/antd';
|
} from '@vicons/antd';
|
||||||
|
|
||||||
const cardHeaderStyle = ref({ 'border-bottom': '1px solid #eee', 'font-size': '16px' });
|
|
||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const visits = ref({});
|
const visits = ref<any>({});
|
||||||
const saleroom = ref({});
|
const saleroom = ref<any>({});
|
||||||
const orderLarge = ref({});
|
const orderLarge = ref<any>({});
|
||||||
const volume = ref({});
|
const volume = ref({});
|
||||||
|
|
||||||
// 图标列表
|
// 图标列表
|
||||||
|
|||||||
@@ -141,10 +141,10 @@
|
|||||||
field: 'makeDate',
|
field: 'makeDate',
|
||||||
component: 'NDatePicker',
|
component: 'NDatePicker',
|
||||||
label: '预约时间',
|
label: '预约时间',
|
||||||
|
defaultValue: 1183135260000,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
clearable: true,
|
clearable: true,
|
||||||
defaultValue: 1183135260000,
|
|
||||||
onUpdateValue: (e: any) => {
|
onUpdateValue: (e: any) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
},
|
},
|
||||||
@@ -296,7 +296,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadDataTable = async (res) => {
|
const loadDataTable = async (res) => {
|
||||||
return await getTableList({...res, ...formParams, ...params.value});
|
return await getTableList({ ...formParams, ...params.value, ...res });
|
||||||
};
|
};
|
||||||
|
|
||||||
function onCheckedRow(rowKeys) {
|
function onCheckedRow(rowKeys) {
|
||||||
|
|||||||
@@ -179,7 +179,7 @@
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let formParams = reactive({
|
const formParams = reactive({
|
||||||
type: 1,
|
type: 1,
|
||||||
label: '',
|
label: '',
|
||||||
subtitle: '',
|
subtitle: '',
|
||||||
@@ -203,7 +203,7 @@
|
|||||||
const treeItem = getTreeItem(unref(treeData), keys[0]);
|
const treeItem = getTreeItem(unref(treeData), keys[0]);
|
||||||
treeItemKey.value = keys;
|
treeItemKey.value = keys;
|
||||||
treeItemTitle.value = treeItem.label;
|
treeItemTitle.value = treeItem.label;
|
||||||
formParams = Object.assign(formParams, treeItem);
|
Object.assign(formParams, treeItem);
|
||||||
isEditMenu.value = true;
|
isEditMenu.value = true;
|
||||||
} else {
|
} else {
|
||||||
isEditMenu.value = false;
|
isEditMenu.value = false;
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
|
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
const treeItem = getTreeItem(unref(treeData), treeItemKey[0]);
|
const treeItem = getTreeItem(unref(treeData), treeItemKey[0]);
|
||||||
formParams = Object.assign(formParams, treeItem);
|
Object.assign(formParams, treeItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formSubmit() {
|
function formSubmit() {
|
||||||
@@ -237,7 +237,8 @@
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const treeMenuList = await getMenuList();
|
const treeMenuList = await getMenuList();
|
||||||
formParams = treeMenuList.list.map((item) => item.key);
|
const keys = treeMenuList.list.map((item) => item.key);
|
||||||
|
Object.assign(formParams, keys);
|
||||||
treeData.value = treeMenuList.list;
|
treeData.value = treeMenuList.list;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
:checked-keys="checkedKeys"
|
:checked-keys="checkedKeys"
|
||||||
style="max-height: 950px; overflow: hidden"
|
style="max-height: 950px; overflow: hidden"
|
||||||
@update:checked-keys="checkedTree"
|
@update:checked-keys="checkedTree"
|
||||||
|
@update:expanded-keys="onExpandedKeys"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<template #action>
|
<template #action>
|
||||||
@@ -135,8 +136,8 @@
|
|||||||
|
|
||||||
const loadDataTable = async (res: any) => {
|
const loadDataTable = async (res: any) => {
|
||||||
let _params = {
|
let _params = {
|
||||||
...res,
|
|
||||||
...unref(params),
|
...unref(params),
|
||||||
|
...res,
|
||||||
};
|
};
|
||||||
return await getRoleList(_params);
|
return await getRoleList(_params);
|
||||||
};
|
};
|
||||||
@@ -186,6 +187,10 @@
|
|||||||
checkedKeys.value = [checkedKeys.value, ...keys];
|
checkedKeys.value = [checkedKeys.value, ...keys];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onExpandedKeys(keys) {
|
||||||
|
expandedKeys.value = keys;
|
||||||
|
}
|
||||||
|
|
||||||
function packHandle() {
|
function packHandle() {
|
||||||
if (expandedKeys.value.length) {
|
if (expandedKeys.value.length) {
|
||||||
expandedKeys.value = [];
|
expandedKeys.value = [];
|
||||||
|
|||||||
@@ -14,19 +14,31 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": false,
|
"noUnusedParameters": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": ["dom", "esnext"],
|
"lib": [
|
||||||
"types": ["vite/client", "jest"],
|
"dom",
|
||||||
"typeRoots": ["./node_modules/@types/", "./types"],
|
"esnext"
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
"vite/client"
|
||||||
|
],
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types/",
|
||||||
|
"./types"
|
||||||
|
],
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"],
|
"@/*": [
|
||||||
"/#/*": ["types/*"]
|
"src/*"
|
||||||
|
],
|
||||||
|
"/#/*": [
|
||||||
|
"types/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"includes": [
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"src/**/*.tsx",
|
"src/**/*.tsx",
|
||||||
@@ -36,7 +48,12 @@
|
|||||||
"build/**/*.ts",
|
"build/**/*.ts",
|
||||||
"build/**/*.d.ts",
|
"build/**/*.d.ts",
|
||||||
"mock/**/*.ts",
|
"mock/**/*.ts",
|
||||||
|
"components.d.ts",
|
||||||
"vite.config.ts"
|
"vite.config.ts"
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules", "dist", "**/*.js"]
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"**/*.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
5
types/config.d.ts
vendored
5
types/config.d.ts
vendored
@@ -17,6 +17,10 @@ export interface ProjectSettingState {
|
|||||||
permissionMode: string;
|
permissionMode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IbodySetting {
|
||||||
|
fixed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IheaderSetting {
|
export interface IheaderSetting {
|
||||||
bgColor: string;
|
bgColor: string;
|
||||||
fixed: boolean;
|
fixed: boolean;
|
||||||
@@ -28,6 +32,7 @@ export interface ImenuSetting {
|
|||||||
menuWidth: number;
|
menuWidth: number;
|
||||||
fixed: boolean;
|
fixed: boolean;
|
||||||
mixMenu: boolean;
|
mixMenu: boolean;
|
||||||
|
collapsed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IcrumbsSetting {
|
export interface IcrumbsSetting {
|
||||||
|
|||||||
5
types/utils.d.ts
vendored
Normal file
5
types/utils.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
|
||||||
|
export type DynamicProps<T> = {
|
||||||
|
[P in keyof T]: Ref<T[P]> | T[P] | ComputedRef<T[P]>;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user