mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-11 08:42:28 +08:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad5ba18a9 | ||
|
|
536e16f166 | ||
|
|
42f2256ea1 | ||
|
|
bf0d294322 | ||
|
|
51f5c64755 | ||
|
|
b49d9e8bd2 | ||
|
|
12e62d1179 | ||
|
|
6558e1597c | ||
|
|
7bf1e1265a | ||
|
|
1213de598e | ||
|
|
20c9dbbfe1 | ||
|
|
6dab2ab35b | ||
|
|
a424788c45 | ||
|
|
b31d5c2bd6 | ||
|
|
b979d9db32 | ||
|
|
a53c86e41b | ||
|
|
b16b5c8992 | ||
|
|
58dadbb95a | ||
|
|
4ebdbc7203 | ||
|
|
0729e56ed4 | ||
|
|
a50cbfa44d | ||
|
|
65d6d4d21e | ||
|
|
c5bb818f13 | ||
|
|
9e255da5d7 | ||
|
|
e2b5086be3 | ||
|
|
caaca83f78 | ||
|
|
91de971636 | ||
|
|
5fb005d5ae | ||
|
|
b42e0a2fef | ||
|
|
097dda5aa1 | ||
|
|
16714d4bdb | ||
|
|
a5438b4f50 | ||
|
|
4f5bbb0673 | ||
|
|
24cbde8b95 | ||
|
|
7222398cf0 | ||
|
|
261e27c139 | ||
|
|
8288f0a84b | ||
|
|
c0ff8985ea | ||
|
|
a8400ac475 | ||
|
|
d4b173e3c8 |
@@ -15,7 +15,7 @@ VITE_DROP_CONSOLE = true
|
|||||||
|
|
||||||
# 跨域代理,可以配置多个,请注意不要换行
|
# 跨域代理,可以配置多个,请注意不要换行
|
||||||
#VITE_PROXY = [["/appApi","http://localhost:8001"],["/upload","http://localhost:8001/upload"]]
|
#VITE_PROXY = [["/appApi","http://localhost:8001"],["/upload","http://localhost:8001/upload"]]
|
||||||
# VITE_PROXY=[["/api","https://naive-ui-admin"]]
|
#VITE_PROXY=[["/api","https://naive-ui-admin"]]
|
||||||
|
|
||||||
# API 接口地址
|
# API 接口地址
|
||||||
VITE_GLOB_API_URL =
|
VITE_GLOB_API_URL =
|
||||||
|
|||||||
32
CHANGELOG.md
32
CHANGELOG.md
@@ -1,5 +1,37 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 1.8.0 (2022-04-01)
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 新增 `多页签` 支持配置 `affix` 固定属性
|
||||||
|
- 新增 `usePage` Hooks
|
||||||
|
- 表格列支持 `draggable` 配置拖拽 合并 [#114](https://github.com/jekip/naive-ui-admin/pull/114)
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 修复 `多页签` 关闭全部缺陷
|
||||||
|
- 修复 `多页签` 跳转缺陷(记得清空多页签缓存)
|
||||||
|
## 1.7.0 (2022-02-14)
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 移除 `登录页面` 滑动验证组件
|
||||||
|
- 修复 `BasicUpload` 组件,回显问题
|
||||||
|
- 修复 `ts类型` 配置缺陷
|
||||||
|
- 修复 `登录页面` message 交互缺陷
|
||||||
|
- 修复 `表格编辑` 时间格式化异常 [#92](https://github.com/jekip/naive-ui-admin/issues/92)
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
|
## 1.6.1 (2022-01-06)
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
- 修复 `项目配置` 打开空白
|
||||||
|
- 修复 `多标签` 背景和字体色变量丢失
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
## 1.6.0 (2021-12-24)
|
## 1.6.0 (2021-12-24)
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -1,6 +1,3 @@
|
|||||||
## 留步
|
|
||||||
少侠留步,早知如此绊人心,何如当初莫相识,右上角免费的 `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/) 的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目, 相信不管是从新技术使用还是其他方面,都能帮助到你。
|
||||||
@@ -32,20 +29,28 @@
|
|||||||
|
|
||||||
### Antd vue
|
### Antd vue
|
||||||
|
|
||||||
千呼万唤 `Naive Admin Antd` 也迎来了第一个版本,同时具备 `Naive Ui Admin` 优点,如果您选的技术栈是 `Antd` 的话,不妨看看。
|
新产品,如果您选的技术栈是 `Antd` 的话,不妨看看
|
||||||
|
|
||||||
[NaiveAdmin Antd 预览](https://antd.naiveadmin.com)
|
[NaiveAdmin Antd 预览](https://antd.naiveadmin.com)
|
||||||
|
|
||||||
### Arco vue
|
### Arco vue
|
||||||
|
|
||||||
新产品,新生态,智能设计体系,连接轻盈体验,一如既往、开箱即用,欢迎前往查看。
|
新产品,智能设计体系,连接轻盈体验
|
||||||
|
|
||||||
[NaiveAdmin Arco 预览](https://arco.naiveadmin.com)
|
[NaiveAdmin Arco 预览](https://arco.naiveadmin.com)
|
||||||
|
|
||||||
|
### Element Plus
|
||||||
|
|
||||||
|
新产品,面向设计师和开发者的组件库
|
||||||
|
|
||||||
|
[Element Plus Admin 预览](https://element.naiveadmin.com)
|
||||||
|
|
||||||
|
以上版本同时具备 `NaiveAdmin v2` 功能/组件/页面,一如既往、开箱即用,欢迎前往查看。
|
||||||
|
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
[v1文档地址](https://naive-ui-admin-docs.vercel.app)
|
[v1文档地址](https://naive-ui-admin-docs.vercel.app)
|
||||||
|
|
||||||
## 准备
|
## 准备
|
||||||
|
|
||||||
@@ -137,11 +142,13 @@ yarn build
|
|||||||
|
|
||||||
## 交流
|
## 交流
|
||||||
|
|
||||||
`Naive Ui Admin` 在帮助开发者更方便地进行中大型管理系统开发,同时也提供 QQ 交流群使用问题欢迎在群内提问。
|
`Naive Ui Admin` 使用或者其他问题,都可以在群内讨论或提问。
|
||||||
|
|
||||||
- QQ 群 `328347666`
|

|
||||||
|
|
||||||
## 赞助
|
## 赞助
|
||||||
#### 如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 🍹。
|
#### 如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 🍹。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
[Paypal Me](https://www.paypal.com/paypalme/majunping)
|
||||||
|
|||||||
93
package.json
93
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "naive-ui-admin",
|
"name": "naive-ui-admin",
|
||||||
"version": "1.6.0",
|
"version": "1.8.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Ahjung",
|
"name": "Ahjung",
|
||||||
"email": "735878602@qq.com",
|
"email": "735878602@qq.com",
|
||||||
@@ -27,72 +27,71 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vicons/antd": "^0.10.0",
|
"@vicons/antd": "^0.10.0",
|
||||||
"@vicons/ionicons5": "^0.10.0",
|
"@vicons/ionicons5": "^0.10.0",
|
||||||
"@vueup/vue-quill": "^1.0.0-beta.7",
|
"@vueup/vue-quill": "^1.0.0-beta.8",
|
||||||
"@vueuse/core": "^5.0.3",
|
"@vueuse/core": "^5.3.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.4",
|
||||||
"blueimp-md5": "^2.18.0",
|
"blueimp-md5": "^2.19.0",
|
||||||
"date-fns": "^2.23.0",
|
"date-fns": "^2.28.0",
|
||||||
"echarts": "^5.1.2",
|
"echarts": "^5.3.1",
|
||||||
"element-resize-detector": "^1.2.3",
|
"element-resize-detector": "^1.2.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"makeit-captcha": "^1.2.5",
|
|
||||||
"mitt": "^2.1.0",
|
"mitt": "^2.1.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"naive-ui": "^2.23.1",
|
"naive-ui": "^2.27.0",
|
||||||
"pinia": "^2.0.0-rc.4",
|
"pinia": "^2.0.13",
|
||||||
"qs": "^6.10.1",
|
"qs": "^6.10.3",
|
||||||
"vfonts": "^0.1.0",
|
"vfonts": "^0.1.0",
|
||||||
"vue": "^3.2.16",
|
"vue": "^3.2.31",
|
||||||
"vue-router": "^4.0.11",
|
"vue-router": "^4.0.14",
|
||||||
"vue-types": "^4.1.0",
|
"vue-types": "^4.1.1",
|
||||||
"vuedraggable": "^4.0.3"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"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.181",
|
||||||
"@types/node": "^15.12.2",
|
"@types/node": "^15.14.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.31.2",
|
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||||
"@typescript-eslint/parser": "^4.31.2",
|
"@typescript-eslint/parser": "^4.33.0",
|
||||||
"@vitejs/plugin-vue": "^1.9.1",
|
"@vitejs/plugin-vue": "^1.10.2",
|
||||||
"@vitejs/plugin-vue-jsx": "^1.1.8",
|
"@vitejs/plugin-vue-jsx": "^1.3.9",
|
||||||
"@vue/compiler-sfc": "^3.2.16",
|
"@vue/compiler-sfc": "^3.2.31",
|
||||||
"@vue/eslint-config-typescript": "^7.0.0",
|
"@vue/eslint-config-typescript": "^7.0.0",
|
||||||
"autoprefixer": "^10.3.1",
|
"autoprefixer": "^10.4.4",
|
||||||
"commitizen": "^4.2.4",
|
"commitizen": "^4.2.4",
|
||||||
"core-js": "^3.14.0",
|
"core-js": "^3.21.1",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-define-config": "^1.0.9",
|
"eslint-define-config": "1.0.9",
|
||||||
"eslint-plugin-jest": "^24.4.0",
|
"eslint-plugin-jest": "^24.7.0",
|
||||||
"eslint-plugin-prettier": "^3.4.0",
|
"eslint-plugin-prettier": "^3.4.1",
|
||||||
"eslint-plugin-vue": "^7.18.0",
|
"eslint-plugin-vue": "^7.20.0",
|
||||||
"esno": "^0.7.3",
|
"esno": "^0.7.3",
|
||||||
"gh-pages": "^3.2.0",
|
"gh-pages": "^3.2.3",
|
||||||
"husky": "^6.0.0",
|
"husky": "^6.0.0",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.5.1",
|
||||||
"less": "^4.1.1",
|
"less": "^4.1.2",
|
||||||
"less-loader": "^9.0.0",
|
"less-loader": "^9.1.0",
|
||||||
"lint-staged": "^11.0.0",
|
"lint-staged": "^11.2.6",
|
||||||
"postcss": "^8.3.5",
|
"postcss": "^8.4.12",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.6.1",
|
||||||
"pretty-quick": "^3.1.0",
|
"pretty-quick": "^3.1.3",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"stylelint": "^13.13.1",
|
"stylelint": "^13.13.1",
|
||||||
"stylelint-config-prettier": "^8.0.2",
|
"stylelint-config-prettier": "^8.0.2",
|
||||||
"stylelint-config-standard": "^22.0.0",
|
"stylelint-config-standard": "^22.0.0",
|
||||||
"stylelint-order": "^4.1.0",
|
"stylelint-order": "^4.1.0",
|
||||||
"stylelint-scss": "^3.19.0",
|
"stylelint-scss": "^3.21.0",
|
||||||
"tailwindcss": "^2.2.7",
|
"tailwindcss": "^2.2.19",
|
||||||
"typescript": "^4.4.3",
|
"typescript": "^4.6.3",
|
||||||
"unplugin-vue-components": "^0.17.2",
|
"unplugin-vue-components": "^0.17.21",
|
||||||
"vite": "^2.5.10",
|
"vite": "^2.9.1",
|
||||||
"vite-plugin-compression": "^0.3.1",
|
"vite-plugin-compression": "^0.3.6",
|
||||||
"vite-plugin-html": "^2.0.7",
|
"vite-plugin-html": "^2.1.2",
|
||||||
"vite-plugin-mock": "^2.9.3",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
"vite-plugin-style-import": "^1.0.1",
|
"vite-plugin-style-import": "^1.4.1",
|
||||||
"vue-eslint-parser": "^7.11.0"
|
"vue-eslint-parser": "^7.11.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|||||||
7548
pnpm-lock.yaml
generated
Normal file
7548
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, onUnmounted } from 'vue';
|
import { computed, onMounted, onUnmounted } from 'vue';
|
||||||
import { zhCN, dateZhCN, createTheme, inputDark, datePickerDark, darkTheme } from 'naive-ui';
|
import { zhCN, dateZhCN, darkTheme } from 'naive-ui';
|
||||||
import { LockScreen } from '@/components/Lockscreen';
|
import { LockScreen } from '@/components/Lockscreen';
|
||||||
import { AppProvider } from '@/components/Application';
|
import { AppProvider } from '@/components/Application';
|
||||||
import { useLockscreenStore } from '@/store/modules/lockscreen';
|
import { useLockscreenStore } from '@/store/modules/lockscreen';
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
subLoading.value = true;
|
subLoading.value = true;
|
||||||
console.log(subLoading.value)
|
console.log(subLoading.value);
|
||||||
emit('on-ok');
|
emit('on-ok');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { ModalMethods, UseModalReturnType } from '../type';
|
|||||||
import { getDynamicProps } from '@/utils';
|
import { getDynamicProps } from '@/utils';
|
||||||
import { tryOnUnmounted } from '@vueuse/core';
|
import { tryOnUnmounted } from '@vueuse/core';
|
||||||
export function useModal(props): UseModalReturnType {
|
export function useModal(props): UseModalReturnType {
|
||||||
|
|
||||||
const modalRef = ref<Nullable<ModalMethods>>(null);
|
const modalRef = ref<Nullable<ModalMethods>>(null);
|
||||||
const currentInstance = getCurrentInstance();
|
const currentInstance = getCurrentInstance();
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ export interface ModalMethods {
|
|||||||
/**
|
/**
|
||||||
* 支持修改,DialogOptions 參數
|
* 支持修改,DialogOptions 參數
|
||||||
*/
|
*/
|
||||||
export interface ModalProps extends DialogOptions { }
|
export type ModalProps = DialogOptions;
|
||||||
|
|
||||||
export type RegisterFn = (ModalInstance: ModalMethods) => void;
|
export type RegisterFn = (ModalInstance: ModalMethods) => void;
|
||||||
|
|
||||||
export type UseModalReturnType = [RegisterFn, ModalMethods];
|
export type UseModalReturnType = [RegisterFn, ModalMethods];
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
<CellComponent
|
<CellComponent
|
||||||
v-bind="getComponentProps"
|
v-bind="getComponentProps"
|
||||||
:component="getComponent"
|
:component="getComponent"
|
||||||
:style="getWrapperStyle"
|
|
||||||
:popoverVisible="getRuleVisible"
|
:popoverVisible="getRuleVisible"
|
||||||
:ruleMessage="ruleMessage"
|
:ruleMessage="ruleMessage"
|
||||||
:rule="getRule"
|
:rule="getRule"
|
||||||
@@ -33,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { CSSProperties, PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import type { BasicColumn } from '../../types/table';
|
import type { BasicColumn } from '../../types/table';
|
||||||
import type { EditRecordRow } from './index';
|
import type { EditRecordRow } from './index';
|
||||||
|
|
||||||
@@ -51,7 +50,8 @@
|
|||||||
import { set, omit } from 'lodash-es';
|
import { set, omit } from 'lodash-es';
|
||||||
import { EventEnum } from '@/components/Table/src/componentMap';
|
import { EventEnum } from '@/components/Table/src/componentMap';
|
||||||
|
|
||||||
import { milliseconds, format } from 'date-fns';
|
import { parseISO, format } from 'date-fns';
|
||||||
|
import { Fn, LabelValueOptions } from '/#/index';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'EditableCell',
|
name: 'EditableCell',
|
||||||
@@ -105,16 +105,28 @@
|
|||||||
|
|
||||||
const isCheckValue = unref(getIsCheckComp);
|
const isCheckValue = unref(getIsCheckComp);
|
||||||
|
|
||||||
const valueField = isCheckValue ? 'checked' : 'value';
|
let valueField = isCheckValue ? 'checked' : 'value';
|
||||||
const val = unref(currentValueRef);
|
const val = unref(currentValueRef);
|
||||||
|
|
||||||
let value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
|
let value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
|
||||||
|
|
||||||
if (isString(value) && component === 'NDatePicker') {
|
//TODO 特殊处理 NDatePicker 可能要根据项目 规范自行调整代码
|
||||||
value = milliseconds(value as Duration);
|
if (component === 'NDatePicker') {
|
||||||
} else if (isArray(value) && component === 'NDatePicker') {
|
if (isString(value)) {
|
||||||
value = value.map((item) => milliseconds(item));
|
if (compProps.valueFormat) {
|
||||||
|
valueField = 'formatted-value';
|
||||||
|
} else {
|
||||||
|
value = parseISO(value as any).getTime();
|
||||||
|
}
|
||||||
|
} else if (isArray(value)) {
|
||||||
|
if (compProps.valueFormat) {
|
||||||
|
valueField = 'formatted-value';
|
||||||
|
} else {
|
||||||
|
value = value.map((item) => parseISO(item).getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onEvent: any = editComponent ? EventEnum[editComponent] : undefined;
|
const onEvent: any = editComponent ? EventEnum[editComponent] : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -146,15 +158,6 @@
|
|||||||
return option?.label ?? value;
|
return option?.label ?? value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getWrapperStyle = computed((): CSSProperties => {
|
|
||||||
// if (unref(getIsCheckComp) || unref(getRowEditable)) {
|
|
||||||
// return {};
|
|
||||||
// }
|
|
||||||
return {
|
|
||||||
width: 'calc(100% - 48px)',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getWrapperClass = computed(() => {
|
const getWrapperClass = computed(() => {
|
||||||
const { align = 'center' } = props.column;
|
const { align = 'center' } = props.column;
|
||||||
return `edit-cell-align-${align}`;
|
return `edit-cell-align-${align}`;
|
||||||
@@ -188,6 +191,7 @@
|
|||||||
|
|
||||||
async function handleChange(e: any) {
|
async function handleChange(e: any) {
|
||||||
const component = unref(getComponent);
|
const component = unref(getComponent);
|
||||||
|
const compProps = props.column?.editComponentProps ?? {};
|
||||||
if (!e) {
|
if (!e) {
|
||||||
currentValueRef.value = e;
|
currentValueRef.value = e;
|
||||||
} else if (e?.target && Reflect.has(e.target, 'value')) {
|
} else if (e?.target && Reflect.has(e.target, 'value')) {
|
||||||
@@ -198,10 +202,20 @@
|
|||||||
currentValueRef.value = e;
|
currentValueRef.value = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO 根据组件格式化值
|
//TODO 特殊处理 NDatePicker 可能要根据项目 规范自行调整代码
|
||||||
// if (component === 'NDatePicker') {
|
if (component === 'NDatePicker') {
|
||||||
// currentValueRef.value = format(currentValueRef.value,'yyyy-MM-dd HH:mm:ss');
|
if (isNumber(currentValueRef.value)) {
|
||||||
// }
|
if (compProps.valueFormat) {
|
||||||
|
currentValueRef.value = format(currentValueRef.value, compProps.valueFormat);
|
||||||
|
}
|
||||||
|
} else if (isArray(currentValueRef.value)) {
|
||||||
|
if (compProps.valueFormat) {
|
||||||
|
currentValueRef.value = currentValueRef.value.map((item) => {
|
||||||
|
format(item, compProps.valueFormat);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onChange = props.column?.editComponentProps?.onChange;
|
const onChange = props.column?.editComponentProps?.onChange;
|
||||||
if (onChange && isFunction(onChange)) onChange(...arguments);
|
if (onChange && isFunction(onChange)) onChange(...arguments);
|
||||||
@@ -303,104 +317,103 @@
|
|||||||
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle: Fn) {
|
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle: Fn) {
|
||||||
if (props.record) {
|
if (props.record) {
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
isArray(props.record[cbs])
|
isArray(props.record[cbs])
|
||||||
? props.record[cbs]?.push(handle)
|
? props.record[cbs]?.push(handle)
|
||||||
: (props.record[cbs] = [handle]);
|
: (props.record[cbs] = [handle]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (props.record) {
|
|
||||||
initCbs('submitCbs', handleSubmit);
|
|
||||||
initCbs('validCbs', handleSubmiRule);
|
|
||||||
initCbs('cancelCbs', handleCancel);
|
|
||||||
|
|
||||||
if (props.column.key) {
|
|
||||||
if (!props.record.editValueRefs) props.record.editValueRefs = {};
|
|
||||||
props.record.editValueRefs[props.column.key] = currentValueRef;
|
|
||||||
}
|
|
||||||
/* eslint-disable */
|
|
||||||
props.record.onCancelEdit = () => {
|
|
||||||
isArray(props.record?.cancelCbs) && props.record?.cancelCbs.forEach((fn) => fn());
|
|
||||||
};
|
|
||||||
/* eslint-disable */
|
|
||||||
props.record.onSubmitEdit = async() => {
|
|
||||||
if (isArray(props.record?.submitCbs)) {
|
|
||||||
const validFns = (props.record?.validCbs || []).map((fn) => fn());
|
|
||||||
|
|
||||||
const res = await Promise.all(validFns);
|
|
||||||
|
|
||||||
const pass = res.every((item) => !!item);
|
|
||||||
|
|
||||||
if (!pass) return;
|
|
||||||
const submitFns = props.record?.submitCbs || [];
|
|
||||||
submitFns.forEach((fn) => fn(false, false));
|
|
||||||
table.emit?.('edit-row-end');
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
if (props.record) {
|
||||||
isEdit,
|
initCbs('submitCbs', handleSubmit);
|
||||||
handleEdit,
|
initCbs('validCbs', handleSubmiRule);
|
||||||
currentValueRef,
|
initCbs('cancelCbs', handleCancel);
|
||||||
handleSubmit,
|
|
||||||
handleChange,
|
if (props.column.key) {
|
||||||
handleCancel,
|
if (!props.record.editValueRefs) props.record.editValueRefs = {};
|
||||||
elRef,
|
props.record.editValueRefs[props.column.key] = currentValueRef;
|
||||||
getComponent,
|
}
|
||||||
getRule,
|
/* eslint-disable */
|
||||||
onClickOutside,
|
props.record.onCancelEdit = () => {
|
||||||
ruleMessage,
|
isArray(props.record?.cancelCbs) && props.record?.cancelCbs.forEach((fn) => fn());
|
||||||
getRuleVisible,
|
};
|
||||||
getComponentProps,
|
/* eslint-disable */
|
||||||
handleOptionsChange,
|
props.record.onSubmitEdit = async () => {
|
||||||
getWrapperStyle,
|
if (isArray(props.record?.submitCbs)) {
|
||||||
getWrapperClass,
|
const validFns = (props.record?.validCbs || []).map((fn) => fn());
|
||||||
getRowEditable,
|
|
||||||
getValues,
|
const res = await Promise.all(validFns);
|
||||||
handleEnter,
|
|
||||||
// getSize,
|
const pass = res.every((item) => !!item);
|
||||||
};
|
|
||||||
},
|
if (!pass) return;
|
||||||
|
const submitFns = props.record?.submitCbs || [];
|
||||||
|
submitFns.forEach((fn) => fn(false, false));
|
||||||
|
table.emit?.('edit-row-end');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isEdit,
|
||||||
|
handleEdit,
|
||||||
|
currentValueRef,
|
||||||
|
handleSubmit,
|
||||||
|
handleChange,
|
||||||
|
handleCancel,
|
||||||
|
elRef,
|
||||||
|
getComponent,
|
||||||
|
getRule,
|
||||||
|
onClickOutside,
|
||||||
|
ruleMessage,
|
||||||
|
getRuleVisible,
|
||||||
|
getComponentProps,
|
||||||
|
handleOptionsChange,
|
||||||
|
getWrapperClass,
|
||||||
|
getRowEditable,
|
||||||
|
getValues,
|
||||||
|
handleEnter,
|
||||||
|
// getSize,
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.editable-cell {
|
.editable-cell {
|
||||||
&-content {
|
&-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
&-comp{
|
&-comp {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
//position: absolute;
|
||||||
|
//top: 4px;
|
||||||
|
//right: 0;
|
||||||
|
display: none;
|
||||||
|
width: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.edit-icon {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-action {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-icon {
|
|
||||||
font-size: 14px;
|
|
||||||
//position: absolute;
|
|
||||||
//top: 4px;
|
|
||||||
//right: 0;
|
|
||||||
display: none;
|
|
||||||
width: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.edit-icon {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-action {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -25,13 +25,26 @@
|
|||||||
</template>
|
</template>
|
||||||
<div class="table-toolbar-inner">
|
<div class="table-toolbar-inner">
|
||||||
<n-checkbox-group v-model:value="checkList" @update:value="onChange">
|
<n-checkbox-group v-model:value="checkList" @update:value="onChange">
|
||||||
<Draggable v-model="columnsList" animation="300" item-key="key" @end="draggableEnd">
|
<Draggable
|
||||||
|
v-model="columnsList"
|
||||||
|
animation="300"
|
||||||
|
item-key="key"
|
||||||
|
filter=".no-draggable"
|
||||||
|
:move="onMove"
|
||||||
|
@end="draggableEnd"
|
||||||
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<div
|
<div
|
||||||
class="table-toolbar-inner-checkbox"
|
class="table-toolbar-inner-checkbox"
|
||||||
:class="{ 'table-toolbar-inner-checkbox-dark': getDarkTheme === true }"
|
:class="{
|
||||||
|
'table-toolbar-inner-checkbox-dark': getDarkTheme === true,
|
||||||
|
'no-draggable': element.draggable === false,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<span class="drag-icon">
|
<span
|
||||||
|
class="drag-icon"
|
||||||
|
:class="{ 'drag-icon-hidden': element.draggable === false }"
|
||||||
|
>
|
||||||
<n-icon size="18">
|
<n-icon size="18">
|
||||||
<DragOutlined />
|
<DragOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
@@ -211,6 +224,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onMove(e) {
|
||||||
|
if (e.draggedContext.element.draggable === false) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//固定
|
//固定
|
||||||
function fixedColumn(item, fixed) {
|
function fixedColumn(item, fixed) {
|
||||||
if (!state.checkList.includes(item.key)) return;
|
if (!state.checkList.includes(item.key)) return;
|
||||||
@@ -232,6 +250,7 @@
|
|||||||
onChange,
|
onChange,
|
||||||
onCheckAll,
|
onCheckAll,
|
||||||
onSelection,
|
onSelection,
|
||||||
|
onMove,
|
||||||
resetColumns,
|
resetColumns,
|
||||||
fixedColumn,
|
fixedColumn,
|
||||||
draggableEnd,
|
draggableEnd,
|
||||||
@@ -275,6 +294,10 @@
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
|
&-hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-item {
|
.fixed-item {
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export function useDataSource(
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { request, pagination }: any = unref(propsRef);
|
const { request, pagination }: any = unref(propsRef);
|
||||||
|
if (!request) return;
|
||||||
//组装分页信息
|
//组装分页信息
|
||||||
const pageField = APISETTING.pageField;
|
const pageField = APISETTING.pageField;
|
||||||
const sizeField = APISETTING.sizeField;
|
const sizeField = APISETTING.sizeField;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const basicProps = {
|
|||||||
type: String,
|
type: String,
|
||||||
default: 'medium',
|
default: 'medium',
|
||||||
},
|
},
|
||||||
tableData: {
|
dataSource: {
|
||||||
type: [Object],
|
type: [Object],
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
@@ -28,7 +28,6 @@ export const basicProps = {
|
|||||||
request: {
|
request: {
|
||||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||||
default: null,
|
default: null,
|
||||||
required: true,
|
|
||||||
},
|
},
|
||||||
rowKey: {
|
rowKey: {
|
||||||
type: [String, Function] as PropType<string | ((record) => string)>,
|
type: [String, Function] as PropType<string | ((record) => string)>,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export interface BasicColumn extends TableBaseColumn {
|
|||||||
auth?: string[];
|
auth?: string[];
|
||||||
// 业务控制是否显示
|
// 业务控制是否显示
|
||||||
ifShow?: boolean | ((column: BasicColumn) => boolean);
|
ifShow?: boolean | ((column: BasicColumn) => boolean);
|
||||||
|
// 控制是否支持拖拽,默认支持
|
||||||
|
draggable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableActionType {
|
export interface TableActionType {
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
<img :src="item" />
|
<img :src="item" />
|
||||||
</div>
|
</div>
|
||||||
<div class="img-box-actions">
|
<div class="img-box-actions">
|
||||||
<n-icon size="18" class="action-icon mx-2" @click="preview(item)">
|
<n-icon size="18" class="mx-2 action-icon" @click="preview(item)">
|
||||||
<EyeOutlined />
|
<EyeOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
<n-icon size="18" class="action-icon mx-2" @click="remove(index)">
|
<n-icon size="18" class="mx-2 action-icon" @click="remove(index)">
|
||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
@before-upload="beforeUpload"
|
@before-upload="beforeUpload"
|
||||||
@finish="finish"
|
@finish="finish"
|
||||||
>
|
>
|
||||||
<div class="flex justify-center flex-col">
|
<div class="flex flex-col justify-center">
|
||||||
<n-icon size="18" class="m-auto">
|
<n-icon size="18" class="m-auto">
|
||||||
<PlusOutlined />
|
<PlusOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, toRefs, reactive, computed } from 'vue';
|
import { defineComponent, toRefs, reactive, computed, watch } from 'vue';
|
||||||
import { EyeOutlined, DeleteOutlined, PlusOutlined } from '@vicons/antd';
|
import { EyeOutlined, DeleteOutlined, PlusOutlined } from '@vicons/antd';
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { useMessage, useDialog } from 'naive-ui';
|
import { useMessage, useDialog } from 'naive-ui';
|
||||||
@@ -106,11 +106,14 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
//赋值默认图片显示
|
//赋值默认图片显示
|
||||||
if (props.value.length) {
|
watch(
|
||||||
state.imgList = props.value.map((item) => {
|
() => props.value,
|
||||||
return getImgUrl(item);
|
() => {
|
||||||
});
|
imgList.value = props.value.map((item) => {
|
||||||
}
|
return getImgUrl(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
//预览
|
//预览
|
||||||
function preview(url: string) {
|
function preview(url: string) {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export function useProjectSetting() {
|
|||||||
|
|
||||||
const getNavTheme = computed(() => projectStore.navTheme);
|
const getNavTheme = computed(() => projectStore.navTheme);
|
||||||
|
|
||||||
|
const getIsMobile = computed(() => projectStore.isMobile);
|
||||||
|
|
||||||
const getHeaderSetting = computed(() => projectStore.headerSetting);
|
const getHeaderSetting = computed(() => projectStore.headerSetting);
|
||||||
|
|
||||||
const getMultiTabsSetting = computed(() => projectStore.multiTabsSetting);
|
const getMultiTabsSetting = computed(() => projectStore.multiTabsSetting);
|
||||||
@@ -27,6 +29,7 @@ export function useProjectSetting() {
|
|||||||
return {
|
return {
|
||||||
getNavMode,
|
getNavMode,
|
||||||
getNavTheme,
|
getNavTheme,
|
||||||
|
getIsMobile,
|
||||||
getHeaderSetting,
|
getHeaderSetting,
|
||||||
getMultiTabsSetting,
|
getMultiTabsSetting,
|
||||||
getMenuSetting,
|
getMenuSetting,
|
||||||
|
|||||||
62
src/hooks/web/usePage.ts
Normal file
62
src/hooks/web/usePage.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import type { RouteLocationRaw, Router } from 'vue-router';
|
||||||
|
|
||||||
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
import { RedirectName } from '@/router/constant';
|
||||||
|
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { isString } from '@/utils/is';
|
||||||
|
import { unref } from 'vue';
|
||||||
|
|
||||||
|
export type RouteLocationRawEx = Omit<RouteLocationRaw, 'path'> & { path: PageEnum };
|
||||||
|
|
||||||
|
function handleError(e: Error) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面切换
|
||||||
|
*/
|
||||||
|
export function useGo(_router?: Router) {
|
||||||
|
let router;
|
||||||
|
if (!_router) {
|
||||||
|
router = useRouter();
|
||||||
|
}
|
||||||
|
const { push, replace } = _router || router;
|
||||||
|
function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) {
|
||||||
|
if (!opt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isString(opt)) {
|
||||||
|
isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError);
|
||||||
|
} else {
|
||||||
|
const o = opt as RouteLocationRaw;
|
||||||
|
isReplace ? replace(o).catch(handleError) : push(o).catch(handleError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return go;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重做当前页面
|
||||||
|
*/
|
||||||
|
export const useRedo = (_router?: Router) => {
|
||||||
|
const { push, currentRoute } = _router || useRouter();
|
||||||
|
const { query, params = {}, name, fullPath } = unref(currentRoute.value);
|
||||||
|
function redo(): Promise<boolean> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (name === RedirectName) {
|
||||||
|
resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (name && Object.keys(params).length > 0) {
|
||||||
|
params['_redirect_type'] = 'name';
|
||||||
|
params['path'] = String(name);
|
||||||
|
} else {
|
||||||
|
params['_redirect_type'] = 'path';
|
||||||
|
params['path'] = fullPath;
|
||||||
|
}
|
||||||
|
push({ name: RedirectName, params, query }).then(() => resolve(true));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return redo;
|
||||||
|
};
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-drawer v-model:show="isDrawer" :width="width" :placement="placement" :native-scrollbar="false">
|
<n-drawer v-model:show="isDrawer" :width="width" :placement="placement">
|
||||||
<n-drawer-content :title="title">
|
<n-drawer-content :title="title" :native-scrollbar="false">
|
||||||
<div class="drawer">
|
<div class="drawer">
|
||||||
<n-divider title-placement="center">主题</n-divider>
|
<n-divider title-placement="center">主题</n-divider>
|
||||||
|
|
||||||
<div class="drawer-setting-item justify-center dark-switch">
|
<div class="justify-center drawer-setting-item dark-switch">
|
||||||
<n-tooltip placement="bottom">
|
<n-tooltip placement="bottom">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<n-switch v-model:value="designStore.darkTheme" class="dark-theme-switch">
|
<n-switch v-model:value="designStore.darkTheme" class="dark-theme-switch">
|
||||||
@@ -116,9 +116,7 @@
|
|||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
<n-badge dot color="#19be6b" v-if="settingStore.navTheme === 'light'" />
|
<n-badge dot color="#19be6b" v-if="settingStore.navTheme === 'light'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-setting-item align-items-top">
|
|
||||||
<div class="drawer-setting-item-style">
|
<div class="drawer-setting-item-style">
|
||||||
<n-tooltip placement="top">
|
<n-tooltip placement="top">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
@@ -133,7 +131,6 @@
|
|||||||
<n-badge dot color="#19be6b" v-if="settingStore.navTheme === 'header-dark'" />
|
<n-badge dot color="#19be6b" v-if="settingStore.navTheme === 'header-dark'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<n-divider title-placement="center">界面功能</n-divider>
|
<n-divider title-placement="center">界面功能</n-divider>
|
||||||
|
|
||||||
<div class="drawer-setting-item">
|
<div class="drawer-setting-item">
|
||||||
@@ -361,6 +358,7 @@
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
margin: 0 5px 5px 0;
|
margin: 0 5px 5px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
line-height: 14px;
|
||||||
|
|
||||||
.n-icon {
|
.n-icon {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|||||||
@@ -125,6 +125,7 @@
|
|||||||
} else {
|
} else {
|
||||||
router.push({ name: key });
|
router.push({ name: key });
|
||||||
}
|
}
|
||||||
|
emit('clickMenuItem' as any, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
//展开菜单
|
//展开菜单
|
||||||
|
|||||||
@@ -40,11 +40,7 @@
|
|||||||
@contextmenu="handleContextMenu($event, element)"
|
@contextmenu="handleContextMenu($event, element)"
|
||||||
>
|
>
|
||||||
<span>{{ element.meta.title }}</span>
|
<span>{{ element.meta.title }}</span>
|
||||||
<n-icon
|
<n-icon size="14" @click.stop="closeTabItem(element)" v-if="!element.meta.affix">
|
||||||
size="14"
|
|
||||||
@click.stop="closeTabItem(element)"
|
|
||||||
v-if="element.path !== baseHome"
|
|
||||||
>
|
|
||||||
<CloseOutlined />
|
<CloseOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,6 +111,8 @@
|
|||||||
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';
|
||||||
|
import { useThemeVars } from 'naive-ui';
|
||||||
|
import { useGo } from '@/hooks/web/usePage';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'TabsView',
|
name: 'TabsView',
|
||||||
@@ -132,7 +130,7 @@
|
|||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { getDarkTheme, getAppTheme } = useDesignSetting();
|
const { getDarkTheme, getAppTheme } = useDesignSetting();
|
||||||
const { getNavMode, getHeaderSetting, getMenuSetting, getMultiTabsSetting } =
|
const { getNavMode, getHeaderSetting, getMenuSetting, getMultiTabsSetting, getIsMobile } =
|
||||||
useProjectSetting();
|
useProjectSetting();
|
||||||
const settingStore = useProjectSettingStore();
|
const settingStore = useProjectSettingStore();
|
||||||
|
|
||||||
@@ -144,6 +142,17 @@
|
|||||||
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);
|
||||||
|
const go = useGo();
|
||||||
|
|
||||||
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
|
const getCardColor = computed(() => {
|
||||||
|
return themeVars.value.cardColor;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getBaseColor = computed(() => {
|
||||||
|
return themeVars.value.textColor1;
|
||||||
|
});
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeKey: route.fullPath,
|
activeKey: route.fullPath,
|
||||||
@@ -181,6 +190,13 @@
|
|||||||
: collapsed
|
: collapsed
|
||||||
? `${minMenuWidth}px`
|
? `${minMenuWidth}px`
|
||||||
: `${menuWidth}px`;
|
: `${menuWidth}px`;
|
||||||
|
|
||||||
|
if (getIsMobile.value) {
|
||||||
|
return {
|
||||||
|
left: '0px',
|
||||||
|
width: '100%',
|
||||||
|
};
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
left: lenNum,
|
left: lenNum,
|
||||||
width: `calc(100% - ${!fixed ? '0px' : lenNum})`,
|
width: `calc(100% - ${!fixed ? '0px' : lenNum})`,
|
||||||
@@ -247,8 +263,8 @@
|
|||||||
window.pageYOffset ||
|
window.pageYOffset ||
|
||||||
document.body.scrollTop; // 滚动条偏移量
|
document.body.scrollTop; // 滚动条偏移量
|
||||||
state.isMultiHeaderFixed = !!(
|
state.isMultiHeaderFixed = !!(
|
||||||
!getHeaderSetting.fixed &&
|
!getHeaderSetting.value.fixed &&
|
||||||
getMultiTabsSetting.fixed &&
|
getMultiTabsSetting.value.fixed &&
|
||||||
scrollTop >= 64
|
scrollTop >= 64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -345,7 +361,6 @@
|
|||||||
|
|
||||||
// 关闭全部
|
// 关闭全部
|
||||||
const closeAll = () => {
|
const closeAll = () => {
|
||||||
localStorage.removeItem('routes');
|
|
||||||
tabsViewStore.closeAllTabs();
|
tabsViewStore.closeAllTabs();
|
||||||
router.replace(PageEnum.BASE_HOME);
|
router.replace(PageEnum.BASE_HOME);
|
||||||
updateNavScroll();
|
updateNavScroll();
|
||||||
@@ -462,7 +477,7 @@
|
|||||||
const { fullPath } = e;
|
const { fullPath } = e;
|
||||||
if (fullPath === route.fullPath) return;
|
if (fullPath === route.fullPath) return;
|
||||||
state.activeKey = fullPath;
|
state.activeKey = fullPath;
|
||||||
router.push({ path: fullPath });
|
go(e, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//删除tab
|
//删除tab
|
||||||
@@ -488,7 +503,6 @@
|
|||||||
navScroll,
|
navScroll,
|
||||||
route,
|
route,
|
||||||
tabsList,
|
tabsList,
|
||||||
baseHome: PageEnum.BASE_HOME_REDIRECT,
|
|
||||||
goPage,
|
goPage,
|
||||||
closeTabItem,
|
closeTabItem,
|
||||||
closeLeft,
|
closeLeft,
|
||||||
@@ -505,6 +519,8 @@
|
|||||||
onClickOutside,
|
onClickOutside,
|
||||||
getDarkTheme,
|
getDarkTheme,
|
||||||
getAppTheme,
|
getAppTheme,
|
||||||
|
getCardColor,
|
||||||
|
getBaseColor,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -565,8 +581,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
background: var(--color);
|
background: v-bind(getCardColor);
|
||||||
color: var(--text-color);
|
color: v-bind(getBaseColor);
|
||||||
height: 32px;
|
height: 32px;
|
||||||
padding: 6px 16px 4px;
|
padding: 6px 16px 4px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-layout class="layout" :position="fixedMenu" has-sider>
|
<n-layout class="layout" :position="fixedMenu" has-sider>
|
||||||
<n-layout-sider
|
<n-layout-sider
|
||||||
v-if="isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')"
|
v-if="
|
||||||
|
!isMobile && isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')
|
||||||
|
"
|
||||||
show-trigger="bar"
|
show-trigger="bar"
|
||||||
@collapse="collapsed = true"
|
@collapse="collapsed = true"
|
||||||
:position="fixedMenu"
|
:position="fixedMenu"
|
||||||
@@ -18,6 +20,16 @@
|
|||||||
<AsideMenu v-model:collapsed="collapsed" v-model:location="getMenuLocation" />
|
<AsideMenu v-model:collapsed="collapsed" v-model:location="getMenuLocation" />
|
||||||
</n-layout-sider>
|
</n-layout-sider>
|
||||||
|
|
||||||
|
<n-drawer
|
||||||
|
v-model:show="showSideDrawder"
|
||||||
|
:width="menuWidth"
|
||||||
|
:placement="'left'"
|
||||||
|
class="layout-side-drawer"
|
||||||
|
>
|
||||||
|
<Logo :collapsed="collapsed" />
|
||||||
|
<AsideMenu @clickMenuItem="collapsed = false" />
|
||||||
|
</n-drawer>
|
||||||
|
|
||||||
<n-layout :inverted="inverted">
|
<n-layout :inverted="inverted">
|
||||||
<n-layout-header :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" />
|
||||||
@@ -71,7 +83,7 @@
|
|||||||
|
|
||||||
const { getDarkTheme } = useDesignSetting();
|
const { getDarkTheme } = useDesignSetting();
|
||||||
const {
|
const {
|
||||||
getShowFooter,
|
// getShowFooter,
|
||||||
getNavMode,
|
getNavMode,
|
||||||
getNavTheme,
|
getNavTheme,
|
||||||
getHeaderSetting,
|
getHeaderSetting,
|
||||||
@@ -85,6 +97,13 @@
|
|||||||
|
|
||||||
const collapsed = ref<boolean>(false);
|
const collapsed = ref<boolean>(false);
|
||||||
|
|
||||||
|
const { mobileWidth, menuWidth } = unref(getMenuSetting);
|
||||||
|
|
||||||
|
const isMobile = computed<boolean>({
|
||||||
|
get: () => settingStore.getIsMobile,
|
||||||
|
set: (val) => settingStore.setIsMobile(val),
|
||||||
|
});
|
||||||
|
|
||||||
const fixedHeader = computed(() => {
|
const fixedHeader = computed(() => {
|
||||||
const { fixed } = unref(getHeaderSetting);
|
const { fixed } = unref(getHeaderSetting);
|
||||||
return fixed ? 'absolute' : 'static';
|
return fixed ? 'absolute' : 'static';
|
||||||
@@ -127,25 +146,44 @@
|
|||||||
return collapsed.value ? minMenuWidth : menuWidth;
|
return collapsed.value ? minMenuWidth : menuWidth;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getChangeStyle = computed(() => {
|
// const getChangeStyle = computed(() => {
|
||||||
const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
// const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
||||||
return {
|
// return {
|
||||||
'padding-left': collapsed.value ? `${minMenuWidth}px` : `${menuWidth}px`,
|
// 'padding-left': collapsed.value ? `${minMenuWidth}px` : `${menuWidth}px`,
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
|
|
||||||
const getMenuLocation = computed(() => {
|
const getMenuLocation = computed(() => {
|
||||||
return 'left';
|
return 'left';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 控制显示或隐藏移动端侧边栏
|
||||||
|
const showSideDrawder = computed({
|
||||||
|
get: () => isMobile.value && collapsed.value,
|
||||||
|
set: (val) => (collapsed.value = val),
|
||||||
|
});
|
||||||
|
|
||||||
|
//判断是否触发移动端模式
|
||||||
|
const checkMobileMode = () => {
|
||||||
|
if (document.body.clientWidth <= mobileWidth) {
|
||||||
|
isMobile.value = true;
|
||||||
|
} else {
|
||||||
|
isMobile.value = false;
|
||||||
|
}
|
||||||
|
collapsed.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
const watchWidth = () => {
|
const watchWidth = () => {
|
||||||
const Width = document.body.clientWidth;
|
const Width = document.body.clientWidth;
|
||||||
if (Width <= 950) {
|
if (Width <= 950) {
|
||||||
collapsed.value = true;
|
collapsed.value = true;
|
||||||
} else collapsed.value = false;
|
} else collapsed.value = false;
|
||||||
|
|
||||||
|
checkMobileMode();
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
checkMobileMode();
|
||||||
window.addEventListener('resize', watchWidth);
|
window.addEventListener('resize', watchWidth);
|
||||||
//挂载在 window 方便与在js中使用
|
//挂载在 window 方便与在js中使用
|
||||||
window['$loading'] = useLoadingBar();
|
window['$loading'] = useLoadingBar();
|
||||||
@@ -153,6 +191,19 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.layout-side-drawer {
|
||||||
|
background-color: rgb(0, 20, 40);
|
||||||
|
|
||||||
|
.layout-sider {
|
||||||
|
min-height: 100vh;
|
||||||
|
box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
|
||||||
|
position: relative;
|
||||||
|
z-index: 13;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.layout {
|
.layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -213,7 +264,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fluid-header {
|
.fluid-header {
|
||||||
padding-top: 0px;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-view-fix {
|
.main-view-fix {
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import { createApp } from 'vue';
|
|||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router, { setupRouter } from './router';
|
import router, { setupRouter } from './router';
|
||||||
import { setupStore } from '@/store';
|
import { setupStore } from '@/store';
|
||||||
import MakeitCaptcha from 'makeit-captcha';
|
|
||||||
import 'makeit-captcha/dist/captcha.min.css';
|
|
||||||
import { setupNaive, setupDirectives } from '@/plugins';
|
import { setupNaive, setupDirectives } from '@/plugins';
|
||||||
import { AppProvider } from '@/components/Application';
|
import { AppProvider } from '@/components/Application';
|
||||||
|
|
||||||
@@ -13,8 +11,6 @@ async function bootstrap() {
|
|||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
app.use(MakeitCaptcha);
|
|
||||||
|
|
||||||
// 注册全局常用的 naive-ui 组件
|
// 注册全局常用的 naive-ui 组件
|
||||||
setupNaive(app);
|
setupNaive(app);
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: '主控台',
|
title: '主控台',
|
||||||
permissions: ['dashboard_console'],
|
permissions: ['dashboard_console'],
|
||||||
|
affix: true,
|
||||||
},
|
},
|
||||||
component: () => import('@/views/dashboard/console/console.vue'),
|
component: () => import('@/views/dashboard/console/console.vue'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
icon: renderIcon(DesktopOutline),
|
icon: renderIcon(DesktopOutline),
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
path: 'naive-admin',
|
||||||
|
name: 'naive-admin',
|
||||||
|
meta: {
|
||||||
|
title: 'NaiveAdmin',
|
||||||
|
frameSrc: 'https://www.naiveadmin.com',
|
||||||
|
},
|
||||||
|
component: IFrame,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'docs',
|
path: 'docs',
|
||||||
name: 'frame-docs',
|
name: 'frame-docs',
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ const setting = {
|
|||||||
navMode: 'vertical',
|
navMode: 'vertical',
|
||||||
//导航风格 dark 暗色侧边栏 light 白色侧边栏 header-dark 暗色顶栏
|
//导航风格 dark 暗色侧边栏 light 白色侧边栏 header-dark 暗色顶栏
|
||||||
navTheme: 'dark',
|
navTheme: 'dark',
|
||||||
|
// 是否处于移动端模式
|
||||||
|
isMobile: false,
|
||||||
//顶部
|
//顶部
|
||||||
headerSetting: {
|
headerSetting: {
|
||||||
//背景色
|
//背景色
|
||||||
@@ -33,6 +35,8 @@ const setting = {
|
|||||||
fixed: true,
|
fixed: true,
|
||||||
//分割菜单
|
//分割菜单
|
||||||
mixMenu: false,
|
mixMenu: false,
|
||||||
|
//触发移动端侧边栏的宽度
|
||||||
|
mobileWidth: 800,
|
||||||
},
|
},
|
||||||
//面包屑
|
//面包屑
|
||||||
crumbsSetting: {
|
crumbsSetting: {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type { IheaderSetting, ImenuSetting, ImultiTabsSetting, IcrumbsSetting }
|
|||||||
const {
|
const {
|
||||||
navMode,
|
navMode,
|
||||||
navTheme,
|
navTheme,
|
||||||
|
isMobile,
|
||||||
headerSetting,
|
headerSetting,
|
||||||
showFooter,
|
showFooter,
|
||||||
menuSetting,
|
menuSetting,
|
||||||
@@ -27,6 +28,7 @@ interface ProjectSettingState {
|
|||||||
permissionMode: string; //权限模式
|
permissionMode: string; //权限模式
|
||||||
isPageAnimate: boolean; //是否开启路由动画
|
isPageAnimate: boolean; //是否开启路由动画
|
||||||
pageAnimateType: string; //路由动画类型
|
pageAnimateType: string; //路由动画类型
|
||||||
|
isMobile: boolean; // 是否处于移动端模式
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useProjectSettingStore = defineStore({
|
export const useProjectSettingStore = defineStore({
|
||||||
@@ -34,6 +36,7 @@ export const useProjectSettingStore = defineStore({
|
|||||||
state: (): ProjectSettingState => ({
|
state: (): ProjectSettingState => ({
|
||||||
navMode: navMode,
|
navMode: navMode,
|
||||||
navTheme,
|
navTheme,
|
||||||
|
isMobile,
|
||||||
headerSetting,
|
headerSetting,
|
||||||
showFooter,
|
showFooter,
|
||||||
menuSetting,
|
menuSetting,
|
||||||
@@ -50,6 +53,9 @@ export const useProjectSettingStore = defineStore({
|
|||||||
getNavTheme(): string {
|
getNavTheme(): string {
|
||||||
return this.navTheme;
|
return this.navTheme;
|
||||||
},
|
},
|
||||||
|
getIsMobile(): boolean {
|
||||||
|
return this.isMobile;
|
||||||
|
},
|
||||||
getHeaderSetting(): object {
|
getHeaderSetting(): object {
|
||||||
return this.headerSetting;
|
return this.headerSetting;
|
||||||
},
|
},
|
||||||
@@ -79,6 +85,9 @@ export const useProjectSettingStore = defineStore({
|
|||||||
setNavTheme(value: string): void {
|
setNavTheme(value: string): void {
|
||||||
this.navTheme = value;
|
this.navTheme = value;
|
||||||
},
|
},
|
||||||
|
setIsMobile(value: boolean): void {
|
||||||
|
this.isMobile = value;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,23 @@ const whiteList = ['Redirect', 'login'];
|
|||||||
|
|
||||||
export type RouteItem = Partial<RouteLocationNormalized> & {
|
export type RouteItem = Partial<RouteLocationNormalized> & {
|
||||||
fullPath: string;
|
fullPath: string;
|
||||||
|
path: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
hash: string;
|
||||||
|
meta: object;
|
||||||
|
params: object;
|
||||||
|
query: object;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ITabsViewState = {
|
export type ITabsViewState = {
|
||||||
tabsList: RouteItem[]; // 标签页
|
tabsList: RouteItem[]; // 标签页
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//保留固定路由
|
||||||
|
function retainAffixRoute(list: any[]) {
|
||||||
|
return list.filter((item) => item?.meta?.affix ?? false);
|
||||||
|
}
|
||||||
|
|
||||||
export const useTabsViewStore = defineStore({
|
export const useTabsViewStore = defineStore({
|
||||||
id: 'app-tabs-view',
|
id: 'app-tabs-view',
|
||||||
state: (): ITabsViewState => ({
|
state: (): ITabsViewState => ({
|
||||||
@@ -55,8 +65,8 @@ export const useTabsViewStore = defineStore({
|
|||||||
},
|
},
|
||||||
closeAllTabs() {
|
closeAllTabs() {
|
||||||
// 关闭全部
|
// 关闭全部
|
||||||
this.tabsList = [];
|
console.log(retainAffixRoute(this.tabsList));
|
||||||
localStorage.removeItem(TABS_ROUTES);
|
this.tabsList = retainAffixRoute(this.tabsList);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#app, body, html {
|
#app,
|
||||||
|
body,
|
||||||
|
html {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, "\5FAE\8F6F\96C5\9ED1", Arial, sans-serif;
|
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei,
|
||||||
|
'\5FAE\8F6F\96C5\9ED1', Arial, sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #515a6e;
|
color: #515a6e;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -15,7 +18,7 @@ body {
|
|||||||
//重置样式
|
//重置样式
|
||||||
.anticon {
|
.anticon {
|
||||||
svg {
|
svg {
|
||||||
vertical-align: initial
|
vertical-align: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,10 +28,11 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color .2s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:active, a:hover {
|
a:active,
|
||||||
|
a:hover {
|
||||||
outline-width: 0;
|
outline-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +44,8 @@ a:active {
|
|||||||
color: #2b85e4;
|
color: #2b85e4;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:active, a:hover {
|
a:active,
|
||||||
|
a:hover {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@@ -91,7 +96,7 @@ a:active, a:hover {
|
|||||||
|
|
||||||
//antd 卡片样式定制
|
//antd 卡片样式定制
|
||||||
body .n-card {
|
body .n-card {
|
||||||
transition: all .2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
body .n-icon {
|
body .n-icon {
|
||||||
@@ -110,7 +115,7 @@ body .proCard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body .n-modal{
|
body .n-modal {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export const columns = [
|
|||||||
editComponentProps: {
|
editComponentProps: {
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
format: 'yyyy-MM-dd HH:mm:ss',
|
format: 'yyyy-MM-dd HH:mm:ss',
|
||||||
|
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||||
},
|
},
|
||||||
ellipsis: false,
|
ellipsis: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export const columns = [
|
|||||||
editComponentProps: {
|
editComponentProps: {
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
format: 'yyyy-MM-dd HH:mm:ss',
|
format: 'yyyy-MM-dd HH:mm:ss',
|
||||||
|
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||||
},
|
},
|
||||||
ellipsis: false,
|
ellipsis: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
init();
|
init();
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<n-input
|
<n-input
|
||||||
v-model:value="formInline.password"
|
v-model:value="formInline.password"
|
||||||
type="password"
|
type="password"
|
||||||
show-password-toggle
|
showPasswordOn="click"
|
||||||
placeholder="请输入密码"
|
placeholder="请输入密码"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
@@ -39,11 +39,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</n-input>
|
</n-input>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item path="isCaptcha">
|
|
||||||
<div class="w-full">
|
|
||||||
<mi-captcha width="384" theme-color="#2d8cf0" :logo="logo" @success="onAuthCode" />
|
|
||||||
</div>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item class="default-color">
|
<n-form-item class="default-color">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="flex-initial">
|
<div class="flex-initial">
|
||||||
@@ -95,8 +90,8 @@
|
|||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
import { ResultEnum } from '@/enums/httpEnum';
|
import { ResultEnum } from '@/enums/httpEnum';
|
||||||
import logo from '@/assets/images/logo.png';
|
|
||||||
import { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook } from '@vicons/ionicons5';
|
import { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook } from '@vicons/ionicons5';
|
||||||
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
|
||||||
interface FormState {
|
interface FormState {
|
||||||
username: string;
|
username: string;
|
||||||
@@ -107,23 +102,17 @@
|
|||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const autoLogin = ref(true);
|
const autoLogin = ref(true);
|
||||||
|
const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME;
|
||||||
|
|
||||||
const formInline = reactive({
|
const formInline = reactive({
|
||||||
username: 'admin',
|
username: 'admin',
|
||||||
password: '123456',
|
password: '123456',
|
||||||
isCaptcha: false,
|
isCaptcha: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
username: { required: true, message: '请输入用户名', trigger: 'blur' },
|
username: { required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
password: { required: true, message: '请输入密码', trigger: 'blur' },
|
password: { required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
isCaptcha: {
|
|
||||||
required: true,
|
|
||||||
type: 'boolean',
|
|
||||||
trigger: 'change',
|
|
||||||
message: '请点击按钮进行验证码校验',
|
|
||||||
validator: (_, value) => value === true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@@ -144,28 +133,26 @@
|
|||||||
password,
|
password,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { code, message: msg } = await userStore.login(params);
|
try {
|
||||||
|
const { code, message: msg } = await userStore.login(params);
|
||||||
if (code == ResultEnum.SUCCESS) {
|
message.destroyAll();
|
||||||
const toPath = decodeURIComponent((route.query?.redirect || '/') as string);
|
if (code == ResultEnum.SUCCESS) {
|
||||||
message.success('登录成功!');
|
const toPath = decodeURIComponent((route.query?.redirect || '/') as string);
|
||||||
router.replace(toPath).then((_) => {
|
message.success('登录成功,即将进入系统');
|
||||||
if (route.name == 'login') {
|
if (route.name === LOGIN_NAME) {
|
||||||
router.replace('/');
|
router.replace('/');
|
||||||
}
|
} else router.replace(toPath);
|
||||||
});
|
} else {
|
||||||
} else {
|
message.info(msg || '登录失败');
|
||||||
message.info(msg || '登录失败');
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error('请填写完整信息,并且进行验证码校验');
|
message.error('请填写完整信息,并且进行验证码校验');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onAuthCode = () => {
|
|
||||||
formInline.isCaptcha = true;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -37,10 +37,17 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useThemeVars } from 'naive-ui';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { InfoCircleOutlined } from '@vicons/antd';
|
import { InfoCircleOutlined } from '@vicons/antd';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
|
const getTableHeaderColor = computed(() => {
|
||||||
|
return themeVars.value.tableHeaderColor;
|
||||||
|
});
|
||||||
|
|
||||||
function goHome() {
|
function goHome() {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
@@ -56,7 +63,7 @@
|
|||||||
&-extra {
|
&-extra {
|
||||||
padding: 24px 40px;
|
padding: 24px 40px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: #f8f8f9;
|
background: v-bind(getTableHeaderColor);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,17 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useThemeVars } from 'naive-ui';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { CheckCircleOutlined } from '@vicons/antd';
|
import { CheckCircleOutlined } from '@vicons/antd';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
|
const getTableHeaderColor = computed(() => {
|
||||||
|
return themeVars.value.tableHeaderColor;
|
||||||
|
});
|
||||||
|
|
||||||
function goHome() {
|
function goHome() {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
@@ -60,7 +67,7 @@
|
|||||||
&-extra {
|
&-extra {
|
||||||
padding: 24px 40px;
|
padding: 24px 40px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: #f8f8f9;
|
background: v-bind(getTableHeaderColor);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,16 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { useThemeVars } from 'naive-ui';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
|
const getTableHeaderColor = computed(() => {
|
||||||
|
return themeVars.value.tableHeaderColor;
|
||||||
|
});
|
||||||
|
|
||||||
function goHome() {
|
function goHome() {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
@@ -41,7 +48,7 @@
|
|||||||
&-extra {
|
&-extra {
|
||||||
padding: 24px 40px;
|
padding: 24px 40px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: #f8f8f9;
|
background: v-bind(getTableHeaderColor);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,7 +213,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
const treeItem = getTreeItem(unref(treeData), treeItemKey[0]);
|
const treeItem = getTreeItem(unref(treeData), treeItemKey.value[0]);
|
||||||
Object.assign(formParams, treeItem);
|
Object.assign(formParams, treeItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"includes": [
|
"include": [
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"src/**/*.tsx",
|
"src/**/*.tsx",
|
||||||
|
|||||||
1
types/config.d.ts
vendored
1
types/config.d.ts
vendored
@@ -33,6 +33,7 @@ export interface ImenuSetting {
|
|||||||
fixed: boolean;
|
fixed: boolean;
|
||||||
mixMenu: boolean;
|
mixMenu: boolean;
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
|
mobileWidth: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IcrumbsSetting {
|
export interface IcrumbsSetting {
|
||||||
|
|||||||
Reference in New Issue
Block a user