update
This commit is contained in:
parent
33fda82dd9
commit
bbf03e66fb
46
.eslintrc.js
46
.eslintrc.js
@ -1,22 +1,52 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
env: {
|
env: {
|
||||||
|
browser: true,
|
||||||
node: true,
|
node: true,
|
||||||
|
es6: true,
|
||||||
},
|
},
|
||||||
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
|
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
"parser": "babel-eslint"
|
"parser": "babel-eslint",
|
||||||
|
"sourceType": 'module',
|
||||||
|
"ecmaVersion": 2020,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
"no-console": 0,
|
||||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
'no-use-before-define': 'off',
|
||||||
|
'no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'no-prototype-builtins': 'off',
|
||||||
|
'space-before-function-paren': 'off',
|
||||||
|
'vue/custom-event-name-casing': 'off',
|
||||||
|
'vue/attributes-order': 'off',
|
||||||
|
'vue/one-component-per-file': 'off',
|
||||||
|
'vue/html-closing-bracket-newline': 'off',
|
||||||
|
'vue/max-attributes-per-line': 'off',
|
||||||
|
'vue/multiline-html-element-content-newline': 'off',
|
||||||
|
'vue/singleline-html-element-content-newline': 'off',
|
||||||
|
'vue/attribute-hyphenation': 'off',
|
||||||
|
'vue/require-default-prop': 'off',
|
||||||
|
'vue/no-unused-components': 'warn',
|
||||||
|
'vue/no-setup-props-destructure': 'off',
|
||||||
"prettier/prettier": [
|
"prettier/prettier": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
// singleQuote: none,
|
'printWidth': 80, // 每行代码长度(默认80)
|
||||||
// semi: false,
|
'tabWidth': 2, // 每个tab相当于多少个空格(默认2)
|
||||||
trailingComma: "es5",
|
'useTabs': false, // 是否使用tab进行缩进(默认false)
|
||||||
},
|
'singleQuote': true, // 使用单引号(默认false)
|
||||||
],
|
'semi': true, // 声明结尾使用分号(默认true)
|
||||||
|
'trailingComma': 'es5', // 多行使用拖尾逗号(默认none)
|
||||||
|
'bracketSpacing': true, // 对象字面量的大括号间使用空格(默认true)
|
||||||
|
'jsxBracketSameLine': false, // 多行JSX中的>放置在最后一行的结尾,而不是另起一行(默认false)
|
||||||
|
'arrowParens': 'avoid', // 只有一个参数的箭头函数的参数是否带括号(默认avoid)
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build:mock": "vite build --mode mock",
|
"build:mock": "vite build --mode mock",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
"lint": "eslint --ext .js,.vue src"
|
"lint": "eslint --fix --ext .js,.vue src"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
printWidth: 80, // 每行代码长度(默认80)
|
|
||||||
tabWidth: 2, // 每个tab相当于多少个空格(默认2)
|
|
||||||
useTabs: false, // 是否使用tab进行缩进(默认false)
|
|
||||||
singleQuote: false, // 使用单引号(默认false)
|
|
||||||
semi: true, // 声明结尾使用分号(默认true)
|
|
||||||
trailingComma: 'es5', // 多行使用拖尾逗号(默认none)
|
|
||||||
bracketSpacing: true, // 对象字面量的大括号间使用空格(默认true)
|
|
||||||
jsxBracketSameLine: false, // 多行JSX中的>放置在最后一行的结尾,而不是另起一行(默认false)
|
|
||||||
arrowParens: "avoid", // 只有一个参数的箭头函数的参数是否带圆括号(默认avoid)
|
|
||||||
};
|
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request';
|
||||||
|
|
||||||
// 登录接口
|
// 登录接口
|
||||||
export const Login = data => {
|
export const Login = data => {
|
||||||
return request({
|
return request({
|
||||||
url: "/api/login",
|
url: '/api/login',
|
||||||
method: "post",
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -12,7 +12,7 @@ export const Login = data => {
|
|||||||
// 获取登录用户信息
|
// 获取登录用户信息
|
||||||
export const GetUserinfo = () => {
|
export const GetUserinfo = () => {
|
||||||
return request({
|
return request({
|
||||||
url: "/api/userinfo",
|
url: '/api/userinfo',
|
||||||
method: "get"
|
method: 'get',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -1,10 +1,9 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
|
||||||
// 获取菜单
|
// 获取菜单
|
||||||
export const GetMenus = () => {
|
export const GetMenus = () => {
|
||||||
return request({
|
return request({
|
||||||
url: "/api/menus",
|
url: '/api/menus',
|
||||||
method: "get"
|
method: 'get',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -212,42 +212,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, reactive, toRefs, onBeforeMount } from "vue";
|
import { defineComponent, reactive, toRefs, onBeforeMount } from 'vue';
|
||||||
const formatDate = (date, format) => {
|
const formatDate = (date, format) => {
|
||||||
var obj = {
|
var obj = {
|
||||||
"M+": date.getMonth() + 1,
|
'M+': date.getMonth() + 1,
|
||||||
"D+": date.getDate(),
|
'D+': date.getDate(),
|
||||||
"H+": date.getHours(),
|
'H+': date.getHours(),
|
||||||
"m+": date.getMinutes(),
|
'm+': date.getMinutes(),
|
||||||
"s+": date.getSeconds(),
|
's+': date.getSeconds(),
|
||||||
"q+": Math.floor((date.getMonth() + 3) / 3),
|
'q+': Math.floor((date.getMonth() + 3) / 3),
|
||||||
"S+": date.getMilliseconds(),
|
'S+': date.getMilliseconds(),
|
||||||
};
|
};
|
||||||
if (/(y+)/i.test(format)) {
|
if (/(y+)/i.test(format)) {
|
||||||
format = format.replace(
|
format = format.replace(
|
||||||
RegExp.$1,
|
RegExp.$1,
|
||||||
(date.getFullYear() + "").substr(4 - RegExp.$1.length)
|
(date.getFullYear() + '').substr(4 - RegExp.$1.length)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (var k in obj) {
|
for (var k in obj) {
|
||||||
if (new RegExp("(" + k + ")").test(format)) {
|
if (new RegExp('(' + k + ')').test(format)) {
|
||||||
format = format.replace(
|
format = format.replace(
|
||||||
RegExp.$1,
|
RegExp.$1,
|
||||||
RegExp.$1.length == 1
|
RegExp.$1.length == 1
|
||||||
? obj[k]
|
? obj[k]
|
||||||
: ("00" + obj[k]).substr(("" + obj[k]).length)
|
: ('00' + obj[k]).substr(('' + obj[k]).length)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return format;
|
return format;
|
||||||
};
|
};
|
||||||
const getSearchModel = (search) => {
|
const getSearchModel = search => {
|
||||||
const searchModel = {};
|
const searchModel = {};
|
||||||
if (search && search.fields) {
|
if (search && search.fields) {
|
||||||
search.fields.forEach((item) => {
|
search.fields.forEach(item => {
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case "checkbox":
|
case 'checkbox':
|
||||||
case "checkbox-button":
|
case 'checkbox-button':
|
||||||
searchModel[item.name] = [];
|
searchModel[item.name] = [];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -257,7 +257,7 @@ const getSearchModel = (search) => {
|
|||||||
searchModel[item.name] = item.defaultValue;
|
searchModel[item.name] = item.defaultValue;
|
||||||
// 日期范围和时间范围真实变量默认值
|
// 日期范围和时间范围真实变量默认值
|
||||||
if (
|
if (
|
||||||
(item.type === "daterange" || item.type === "datetimerange") &&
|
(item.type === 'daterange' || item.type === 'datetimerange') &&
|
||||||
!!item.trueNames &&
|
!!item.trueNames &&
|
||||||
Array.isArray(item.defaultValue)
|
Array.isArray(item.defaultValue)
|
||||||
) {
|
) {
|
||||||
@ -279,7 +279,7 @@ export default defineComponent({
|
|||||||
// 表格标题
|
// 表格标题
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: '',
|
||||||
},
|
},
|
||||||
// 是否隐藏标题栏
|
// 是否隐藏标题栏
|
||||||
hideTitleBar: {
|
hideTitleBar: {
|
||||||
@ -298,14 +298,12 @@ export default defineComponent({
|
|||||||
// 表头配置
|
// 表头配置
|
||||||
columns: {
|
columns: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: function (params) {
|
default: () => [],
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// 行数据的Key,同elementUI的table组件的row-key
|
// 行数据的Key,同elementUI的table组件的row-key
|
||||||
rowKey: {
|
rowKey: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "id",
|
default: 'id',
|
||||||
},
|
},
|
||||||
// 分页配置,false表示不显示分页
|
// 分页配置,false表示不显示分页
|
||||||
pagination: {
|
pagination: {
|
||||||
@ -317,18 +315,18 @@ export default defineComponent({
|
|||||||
// 优化搜索字段,
|
// 优化搜索字段,
|
||||||
// 1、如果搜索配置有transform处理函数,执行transform
|
// 1、如果搜索配置有transform处理函数,执行transform
|
||||||
// 2、删除日期范围默认的name字段
|
// 2、删除日期范围默认的name字段
|
||||||
const optimizeFields = (search) => {
|
const optimizeFields = search => {
|
||||||
const searchModel = JSON.parse(JSON.stringify(state.searchModel));
|
const searchModel = JSON.parse(JSON.stringify(state.searchModel));
|
||||||
if (search && search.fields) {
|
if (search && search.fields) {
|
||||||
search.fields.forEach((item) => {
|
search.fields.forEach(item => {
|
||||||
if (!searchModel.hasOwnProperty(item.name)) {
|
if (!searchModel.hasOwnProperty(item.name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!!item.transform) {
|
if (item.transform) {
|
||||||
searchModel[item.name] = item.transform(searchModel[item.name]);
|
searchModel[item.name] = item.transform(searchModel[item.name]);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(item.type === "daterange" || item.type === "datetimerange") &&
|
(item.type === 'daterange' || item.type === 'datetimerange') &&
|
||||||
!!item.trueNames
|
!!item.trueNames
|
||||||
) {
|
) {
|
||||||
delete searchModel[item.name];
|
delete searchModel[item.name];
|
||||||
@ -373,7 +371,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
// 重置函数
|
// 重置函数
|
||||||
handleReset() {
|
handleReset() {
|
||||||
if (JSON.stringify(state.searchModel) === "{}") {
|
if (JSON.stringify(state.searchModel) === '{}') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.pageNum = 1;
|
state.pageNum = 1;
|
||||||
@ -386,52 +384,52 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 当前页变化
|
// 当前页变化
|
||||||
handleCurrentChange(page) {
|
handleCurrentChange() {
|
||||||
getTableData();
|
getTableData();
|
||||||
},
|
},
|
||||||
// 改变每页size数量
|
// 改变每页size数量
|
||||||
handleSizeChange(value) {
|
handleSizeChange() {
|
||||||
state.pageNum = 1;
|
state.pageNum = 1;
|
||||||
getTableData();
|
getTableData();
|
||||||
},
|
},
|
||||||
// 全选
|
// 全选
|
||||||
handleSelectionChange(arr) {
|
handleSelectionChange(arr) {
|
||||||
emit("selectionChange", arr);
|
emit('selectionChange', arr);
|
||||||
},
|
},
|
||||||
// 过滤方法
|
// 过滤方法
|
||||||
filterHandler(value, row, column) {
|
filterHandler(value, row, column) {
|
||||||
const property = column["property"];
|
const property = column['property'];
|
||||||
return row[property] === value;
|
return row[property] === value;
|
||||||
},
|
},
|
||||||
// 日期范围
|
// 日期范围
|
||||||
handleDateChange(date, item, format) {
|
handleDateChange(date, item, format) {
|
||||||
state.searchModel[item.name] = !!date ? formatDate(date, format) : "";
|
state.searchModel[item.name] = date ? formatDate(date, format) : '';
|
||||||
},
|
},
|
||||||
handleRangeChange(date, item, format) {
|
handleRangeChange(date, item, format) {
|
||||||
const arr = !!date && date.map((d) => formatDate(d, format));
|
const arr = !!date && date.map(d => formatDate(d, format));
|
||||||
state.searchModel[item.name] = !!arr ? arr : [];
|
state.searchModel[item.name] = arr ? arr : [];
|
||||||
|
|
||||||
if (!item.trueNames) {
|
if (!item.trueNames) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!arr) {
|
if (arr) {
|
||||||
arr.forEach((val, index) => {
|
arr.forEach((val, index) => {
|
||||||
state.searchModel[item.trueNames[index]] = val;
|
state.searchModel[item.trueNames[index]] = val;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
item.trueNames.forEach((key) => {
|
item.trueNames.forEach(key => {
|
||||||
delete state.searchModel[key];
|
delete state.searchModel[key];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof props.pagination === "object") {
|
if (typeof props.pagination === 'object') {
|
||||||
const { layout, pageSizes, style } = props.pagination;
|
const { layout, pageSizes, style } = props.pagination;
|
||||||
state.paginationConfig = {
|
state.paginationConfig = {
|
||||||
show: true,
|
show: true,
|
||||||
layout: layout || "total, sizes, prev, pager, next, jumper",
|
layout: layout || 'total, sizes, prev, pager, next, jumper',
|
||||||
pageSizes: pageSizes || [10, 20, 30, 40, 50, 100],
|
pageSizes: pageSizes || [10, 20, 30, 40, 50, 100],
|
||||||
style: style || {},
|
style: style || {},
|
||||||
};
|
};
|
||||||
@ -491,4 +489,3 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg
|
<svg class="icon" aria-hidden="true">
|
||||||
class="icon"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<use :xlink:href="symbolId" />
|
<use :xlink:href="symbolId" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, computed } from "vue";
|
import { defineComponent, computed } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "SvgIcon",
|
name: 'SvgIcon',
|
||||||
props: {
|
props: {
|
||||||
prefix: {
|
prefix: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "icon",
|
default: 'icon',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export { default as SvgIcon } from "@/components/SvgIcon/index.vue";
|
export { default as SvgIcon } from '@/components/SvgIcon/index.vue';
|
||||||
export { default as ProTable } from "@/components/ProTable/index.vue";
|
export { default as ProTable } from '@/components/ProTable/index.vue';
|
||||||
|
|||||||
@ -6,9 +6,9 @@
|
|||||||
</router-view>
|
</router-view>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { computed, defineComponent } from "vue";
|
import { computed, defineComponent } from 'vue';
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from 'vue-router';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
|
|||||||
@ -1,23 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<i
|
<i v-if="isElementIcon" :class="`icon ${icon}`" />
|
||||||
v-if="isElementIcon"
|
<svg-icon class="icon" v-else-if="!!icon" :name="icon" />
|
||||||
:class="`icon ${icon}`"
|
|
||||||
/>
|
|
||||||
<svg-icon
|
|
||||||
class="icon"
|
|
||||||
v-else-if="!!icon"
|
|
||||||
:name="icon"
|
|
||||||
/>
|
|
||||||
<span>{{ title }}</span>
|
<span>{{ title }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, defineComponent } from "vue";
|
import { computed, defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: ["title", "icon"],
|
props: ['title', 'icon'],
|
||||||
setup({ icon }) {
|
setup({ icon }) {
|
||||||
const isElementIcon = computed(() => icon && icon.startsWith("el-icon"));
|
const isElementIcon = computed(() => icon && icon.startsWith('el-icon'));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isElementIcon,
|
isElementIcon,
|
||||||
|
|||||||
@ -1,22 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
<img
|
<img class="logo" src="~@/assets/logo.svg" @click="goHome" />
|
||||||
class="logo"
|
|
||||||
src="~@/assets/logo.svg"
|
|
||||||
@click="goHome"
|
|
||||||
>
|
|
||||||
<div class="title">Vue3 Element Admin</div>
|
<div class="title">Vue3 Element Admin</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const goHome = () => {
|
const goHome = () => {
|
||||||
router.push("/");
|
router.push('/');
|
||||||
};
|
};
|
||||||
return { goHome };
|
return { goHome };
|
||||||
},
|
},
|
||||||
@ -44,4 +40,3 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -15,11 +15,11 @@
|
|||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { computed, defineComponent } from "vue";
|
import { computed, defineComponent } from 'vue';
|
||||||
import Submenu from "./Submenu.vue";
|
import Submenu from './Submenu.vue';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from 'vue-router';
|
||||||
import config from "./config/menu.module.scss";
|
import config from './config/menu.module.scss';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -35,7 +35,7 @@ export default defineComponent({
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
"menu/generateMenus",
|
'menu/generateMenus',
|
||||||
store.state.account.userinfo && store.state.account.userinfo.role
|
store.state.account.userinfo && store.state.account.userinfo.role
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ export default defineComponent({
|
|||||||
background-color: $collapseMenuActiveBg !important;
|
background-color: $collapseMenuActiveBg !important;
|
||||||
color: $collapseMenuActiveColor !important;
|
color: $collapseMenuActiveColor !important;
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|||||||
@ -1,23 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-menu-item
|
<el-menu-item v-if="!menu.children" :index="menu.url">
|
||||||
v-if="!menu.children"
|
<item :icon="menu.icon" :title="menu.title" />
|
||||||
:index="menu.url"
|
|
||||||
>
|
|
||||||
<item
|
|
||||||
:icon="menu.icon"
|
|
||||||
:title="menu.title"
|
|
||||||
/>
|
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-submenu
|
<el-submenu v-else :index="menu.url">
|
||||||
v-else
|
|
||||||
:index="menu.url"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<item
|
<item :icon="menu.icon" :title="menu.title" />
|
||||||
:icon="menu.icon"
|
|
||||||
:title="menu.title"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<submenu
|
<submenu
|
||||||
v-for="submenu in menu.children"
|
v-for="submenu in menu.children"
|
||||||
@ -28,10 +15,10 @@
|
|||||||
</el-submenu>
|
</el-submenu>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
import Item from "./Item.vue";
|
import Item from './Item.vue';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Submenu",
|
name: 'Submenu',
|
||||||
components: {
|
components: {
|
||||||
Item,
|
Item,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -10,10 +10,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, computed } from "vue";
|
import { defineComponent, computed } from 'vue';
|
||||||
import Logo from "./Logo.vue";
|
import Logo from './Logo.vue';
|
||||||
import Menus from "./Menus.vue";
|
import Menus from './Menus.vue';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -26,7 +26,7 @@ export default defineComponent({
|
|||||||
const device = computed(() => store.state.app.device);
|
const device = computed(() => store.state.app.device);
|
||||||
|
|
||||||
const closeSidebar = () => {
|
const closeSidebar = () => {
|
||||||
store.commit("app/setCollapse", 1);
|
store.commit('app/setCollapse', 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { onMounted, onBeforeUnmount, reactive, toRefs, nextTick } from 'vue';
|
import { onMounted, onBeforeUnmount, reactive, toRefs, nextTick } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex';
|
||||||
import { isAffix } from './useTags'
|
import { isAffix } from './useTags';
|
||||||
|
|
||||||
export const useContextMenu = (tagList) => {
|
export const useContextMenu = tagList => {
|
||||||
const store = useStore()
|
const store = useStore();
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -23,11 +23,11 @@ export const useContextMenu = (tagList) => {
|
|||||||
state.visible = false;
|
state.visible = false;
|
||||||
},
|
},
|
||||||
refreshSelectedTag(tag) {
|
refreshSelectedTag(tag) {
|
||||||
store.dispatch("tags/delCacheList", tag)
|
store.dispatch('tags/delCacheList', tag);
|
||||||
const { fullPath } = tag;
|
const { fullPath } = tag;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
router.replace({
|
router.replace({
|
||||||
path: "/redirect" + fullPath,
|
path: '/redirect' + fullPath,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -35,64 +35,68 @@ export const useContextMenu = (tagList) => {
|
|||||||
if (isAffix(tag)) return;
|
if (isAffix(tag)) return;
|
||||||
|
|
||||||
const closedTagIndex = tagList.value.findIndex(
|
const closedTagIndex = tagList.value.findIndex(
|
||||||
(item) => item.fullPath === tag.fullPath
|
item => item.fullPath === tag.fullPath
|
||||||
);
|
);
|
||||||
store.dispatch("tags/delTag", tag)
|
store.dispatch('tags/delTag', tag);
|
||||||
if (isActive(tag)) {
|
if (isActive(tag)) {
|
||||||
toLastTag(closedTagIndex - 1);
|
toLastTag(closedTagIndex - 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeOtherTags() {
|
closeOtherTags() {
|
||||||
store.dispatch("tags/delOtherTags", state.selectedTag)
|
store.dispatch('tags/delOtherTags', state.selectedTag);
|
||||||
router.push(state.selectedTag);
|
router.push(state.selectedTag);
|
||||||
},
|
},
|
||||||
closeLeftTags() {
|
closeLeftTags() {
|
||||||
state.closeSomeTags('left')
|
state.closeSomeTags('left');
|
||||||
|
|
||||||
},
|
},
|
||||||
closeRightTags() {
|
closeRightTags() {
|
||||||
state.closeSomeTags('right')
|
state.closeSomeTags('right');
|
||||||
|
|
||||||
},
|
},
|
||||||
closeSomeTags(direction) {
|
closeSomeTags(direction) {
|
||||||
const index = tagList.value.findIndex(
|
const index = tagList.value.findIndex(
|
||||||
(item) => item.fullPath === state.selectedTag.fullPath
|
item => item.fullPath === state.selectedTag.fullPath
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((direction === 'left' && index <= 0) || (direction === 'right' && index >= tagList.value.length - 1)) {
|
if (
|
||||||
|
(direction === 'left' && index <= 0) ||
|
||||||
|
(direction === 'right' && index >= tagList.value.length - 1)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const needToClose = direction === 'left' ? tagList.value.slice(0, index) : tagList.value.slice(index + 1)
|
const needToClose =
|
||||||
store.dispatch("tags/delSomeTags", needToClose)
|
direction === 'left'
|
||||||
|
? tagList.value.slice(0, index)
|
||||||
|
: tagList.value.slice(index + 1);
|
||||||
|
store.dispatch('tags/delSomeTags', needToClose);
|
||||||
router.push(state.selectedTag);
|
router.push(state.selectedTag);
|
||||||
},
|
},
|
||||||
closeAllTags() {
|
closeAllTags() {
|
||||||
store.dispatch("tags/delAllTags")
|
store.dispatch('tags/delAllTags');
|
||||||
router.push("/");
|
router.push('/');
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const isActive = (tag) => {
|
const isActive = tag => {
|
||||||
return tag.fullPath === route.fullPath;
|
return tag.fullPath === route.fullPath;
|
||||||
}
|
};
|
||||||
|
|
||||||
const toLastTag = (lastTagIndex) => {
|
const toLastTag = lastTagIndex => {
|
||||||
const lastTag = tagList.value[lastTagIndex];
|
const lastTag = tagList.value[lastTagIndex];
|
||||||
if (!!lastTag) {
|
if (lastTag) {
|
||||||
router.push(lastTag.fullPath);
|
router.push(lastTag.fullPath);
|
||||||
} else {
|
} else {
|
||||||
router.push("/");
|
router.push('/');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener("click", state.closeMenu);
|
document.addEventListener('click', state.closeMenu);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
document.removeEventListener("click", state.closeMenu);
|
document.removeEventListener('click', state.closeMenu);
|
||||||
});
|
});
|
||||||
|
|
||||||
return toRefs(state)
|
return toRefs(state);
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue';
|
||||||
|
|
||||||
export const useScrollbar = (tagsItem) => {
|
export const useScrollbar = tagsItem => {
|
||||||
const scrollContainer = ref(null);
|
const scrollContainer = ref(null);
|
||||||
|
|
||||||
const handleScroll = (e) => {
|
const handleScroll = e => {
|
||||||
const eventDelta = e.wheelDelta || -e.deltaY;
|
const eventDelta = e.wheelDelta || -e.deltaY;
|
||||||
scrollContainer.value.wrap.scrollLeft -= eventDelta / 4;
|
scrollContainer.value.wrap.scrollLeft -= eventDelta / 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const moveToTarget = currentTag => {
|
||||||
const moveToTarget = (currentTag) => {
|
|
||||||
const containerWidth = scrollContainer.value.scrollbar.offsetWidth;
|
const containerWidth = scrollContainer.value.scrollbar.offsetWidth;
|
||||||
const scrollWrapper = scrollContainer.value.wrap;
|
const scrollWrapper = scrollContainer.value.wrap;
|
||||||
const tagList = tagsItem.value;
|
const tagList = tagsItem.value;
|
||||||
@ -26,8 +25,11 @@ export const useScrollbar = (tagsItem) => {
|
|||||||
} else if (lastTag === currentTag) {
|
} else if (lastTag === currentTag) {
|
||||||
scrollWrapper.scrollLeft = scrollWrapper.scrollWidth - containerWidth;
|
scrollWrapper.scrollLeft = scrollWrapper.scrollWidth - containerWidth;
|
||||||
} else {
|
} else {
|
||||||
const el = currentTag.$el.nextElementSibling
|
const el = currentTag.$el.nextElementSibling;
|
||||||
scrollWrapper.scrollLeft = el.offsetLeft + el.offsetWidth > containerWidth ? el.offsetLeft - el.offsetWidth : 0
|
scrollWrapper.scrollLeft =
|
||||||
|
el.offsetLeft + el.offsetWidth > containerWidth
|
||||||
|
? el.offsetLeft - el.offsetWidth
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,4 +38,4 @@ export const useScrollbar = (tagsItem) => {
|
|||||||
handleScroll,
|
handleScroll,
|
||||||
moveToTarget,
|
moveToTarget,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,69 +1,71 @@
|
|||||||
import { useScrollbar } from "./useScrollbar";
|
import { useScrollbar } from './useScrollbar';
|
||||||
import { watch, computed, ref, nextTick, onBeforeMount } from 'vue';
|
import { watch, computed, ref, nextTick, onBeforeMount } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export const isAffix = (tag) => {
|
export const isAffix = tag => {
|
||||||
return !!tag.meta && !!tag.meta.affix;
|
return !!tag.meta && !!tag.meta.affix;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTags = () => {
|
export const useTags = () => {
|
||||||
const store = useStore()
|
const store = useStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = router.currentRoute;
|
const route = router.currentRoute;
|
||||||
const routes = computed(() => router.getRoutes());
|
const routes = computed(() => router.getRoutes());
|
||||||
const tagList = computed(() => store.state.tags.tagList);
|
const tagList = computed(() => store.state.tags.tagList);
|
||||||
|
|
||||||
const tagsItem = ref([])
|
const tagsItem = ref([]);
|
||||||
|
|
||||||
const setItemRef = (i, el) => {
|
const setItemRef = (i, el) => {
|
||||||
tagsItem.value[i] = el
|
tagsItem.value[i] = el;
|
||||||
}
|
};
|
||||||
|
|
||||||
const scrollbar = useScrollbar(tagsItem);
|
const scrollbar = useScrollbar(tagsItem);
|
||||||
|
|
||||||
watch(() => tagList.value.length, () => {
|
watch(
|
||||||
tagsItem.value = []
|
() => tagList.value.length,
|
||||||
})
|
() => {
|
||||||
|
tagsItem.value = [];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const filterAffixTags = routes => {
|
||||||
const filterAffixTags = (routes) => {
|
return routes.filter(route => isAffix(route));
|
||||||
return routes.filter((route) => isAffix(route));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const initTags = () => {
|
const initTags = () => {
|
||||||
const affixTags = filterAffixTags(routes.value);
|
const affixTags = filterAffixTags(routes.value);
|
||||||
|
|
||||||
for (const tag of affixTags) {
|
for (const tag of affixTags) {
|
||||||
if (!!tag.name) {
|
if (tag.name) {
|
||||||
store.dispatch("tags/addTagList", tag);
|
store.dispatch('tags/addTagList', tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const addTag = () => {
|
const addTag = () => {
|
||||||
const tag = route.value;
|
const tag = route.value;
|
||||||
if (!!tag.name && tag.matched[0].components.default.name === "layout") {
|
if (!!tag.name && tag.matched[0].components.default.name === 'layout') {
|
||||||
store.dispatch("tags/addTag", tag);
|
store.dispatch('tags/addTag', tag);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveActivePosition = (tag) => {
|
const saveActivePosition = tag => {
|
||||||
const index = tagList.value.findIndex(
|
const index = tagList.value.findIndex(
|
||||||
(item) => item.fullPath === tag.fullPath
|
item => item.fullPath === tag.fullPath
|
||||||
);
|
);
|
||||||
|
|
||||||
store.dispatch("tags/saveActivePosition", Math.max(0, index));
|
store.dispatch('tags/saveActivePosition', Math.max(0, index));
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveToCurrentTag = () => {
|
const moveToCurrentTag = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
for (const tag of tagsItem.value) {
|
for (const tag of tagsItem.value) {
|
||||||
if (!!tag && (tag.to.path === route.value.path)) {
|
if (!!tag && tag.to.path === route.value.path) {
|
||||||
scrollbar.moveToTarget(tag);
|
scrollbar.moveToTarget(tag);
|
||||||
|
|
||||||
if (tag.to.fullPath !== route.value.fullPath) {
|
if (tag.to.fullPath !== route.value.fullPath) {
|
||||||
store.dispatch("tags/updateTagList", route.value);
|
store.dispatch('tags/updateTagList', route.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -71,8 +73,6 @@ export const useTags = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initTags();
|
initTags();
|
||||||
addTag();
|
addTag();
|
||||||
@ -89,6 +89,6 @@ export const useTags = () => {
|
|||||||
tagList,
|
tagList,
|
||||||
setItemRef,
|
setItemRef,
|
||||||
isAffix,
|
isAffix,
|
||||||
...scrollbar
|
...scrollbar,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
v-for="(tag, i) in tagList"
|
v-for="(tag, i) in tagList"
|
||||||
:key="tag.fullPath"
|
:key="tag.fullPath"
|
||||||
:to="tag"
|
:to="tag"
|
||||||
:ref="(el) => setItemRef(i, el)"
|
:ref="el => setItemRef(i, el)"
|
||||||
custom
|
custom
|
||||||
v-slot="{ navigate, isExactActive }"
|
v-slot="{ navigate, isExactActive }"
|
||||||
>
|
>
|
||||||
@ -46,17 +46,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
import { useTags } from "./hooks/useTags";
|
import { useTags } from './hooks/useTags';
|
||||||
import { useContextMenu } from "./hooks/useContextMenu";
|
import { useContextMenu } from './hooks/useContextMenu';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Tagsbar",
|
name: 'Tagsbar',
|
||||||
setup() {
|
setup() {
|
||||||
const tags = useTags();
|
const tags = useTags();
|
||||||
const contextMenu = useContextMenu(tags.tagList);
|
const contextMenu = useContextMenu(tags.tagList);
|
||||||
|
|
||||||
const onScroll = (e) => {
|
const onScroll = e => {
|
||||||
tags.handleScroll(e);
|
tags.handleScroll(e);
|
||||||
contextMenu.closeMenu.value();
|
contextMenu.closeMenu.value();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,9 +15,9 @@
|
|||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, computed, ref, onBeforeMount, watch } from "vue";
|
import { defineComponent, computed, ref, onBeforeMount, watch } from 'vue';
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
@ -27,13 +27,13 @@ export default defineComponent({
|
|||||||
const route = router.currentRoute; // 这里不使用useRoute获取当前路由,否则下面watch监听路由的时候会有警告
|
const route = router.currentRoute; // 这里不使用useRoute获取当前路由,否则下面watch监听路由的时候会有警告
|
||||||
const breadcrumbs = ref([]);
|
const breadcrumbs = ref([]);
|
||||||
|
|
||||||
const getBreadcrumbs = (route) => {
|
const getBreadcrumbs = route => {
|
||||||
const home = [{ path: "/", meta: { title: "首页" } }];
|
const home = [{ path: '/', meta: { title: '首页' } }];
|
||||||
if (route.name === "home") {
|
if (route.name === 'home') {
|
||||||
return home;
|
return home;
|
||||||
} else {
|
} else {
|
||||||
const matched = route.matched.filter(
|
const matched = route.matched.filter(
|
||||||
(item) => !!item.meta && !!item.meta.title
|
item => !!item.meta && !!item.meta.title
|
||||||
);
|
);
|
||||||
|
|
||||||
return [...home, ...matched];
|
return [...home, ...matched];
|
||||||
@ -44,7 +44,7 @@ export default defineComponent({
|
|||||||
breadcrumbs.value = getBreadcrumbs(route.value);
|
breadcrumbs.value = getBreadcrumbs(route.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(route, (newRoute) => {
|
watch(route, newRoute => {
|
||||||
breadcrumbs.value = getBreadcrumbs(newRoute);
|
breadcrumbs.value = getBreadcrumbs(newRoute);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -6,15 +6,15 @@
|
|||||||
></i>
|
></i>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, computed } from "vue";
|
import { defineComponent, computed } from 'vue';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const collapse = computed(() => !!store.state.app.sidebar.collapse);
|
const collapse = computed(() => !!store.state.app.sidebar.collapse);
|
||||||
const handleToggleMenu = () => {
|
const handleToggleMenu = () => {
|
||||||
store.commit("app/setCollapse", +!collapse.value);
|
store.commit('app/setCollapse', +!collapse.value);
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
collapse,
|
collapse,
|
||||||
|
|||||||
@ -21,19 +21,19 @@
|
|||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { computed, defineComponent } from "vue";
|
import { computed, defineComponent } from 'vue';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from 'vue-router';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const userinfo = computed(() => store.state.account.userinfo);
|
const userinfo = computed(() => store.state.account.userinfo);
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
store.commit("app/clearToken");
|
store.commit('app/clearToken');
|
||||||
store.commit("account/clearUserinfo");
|
store.commit('account/clearUserinfo');
|
||||||
store.dispatch("tags/delAllTags");
|
store.dispatch('tags/delAllTags');
|
||||||
router.push("/login");
|
router.push('/login');
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
userinfo,
|
userinfo,
|
||||||
|
|||||||
@ -11,12 +11,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, computed } from "vue";
|
import { defineComponent, computed } from 'vue';
|
||||||
import Logo from "@/layout/components/Sidebar/Logo.vue";
|
import Logo from '@/layout/components/Sidebar/Logo.vue';
|
||||||
import Hamburger from "./Hamburger.vue";
|
import Hamburger from './Hamburger.vue';
|
||||||
import Breadcrumbs from "./Breadcrumbs.vue";
|
import Breadcrumbs from './Breadcrumbs.vue';
|
||||||
import Userinfo from "./Userinfo.vue";
|
import Userinfo from './Userinfo.vue';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
|||||||
@ -1,38 +1,38 @@
|
|||||||
import { onBeforeMount, onBeforeUnmount, watch } from "vue"
|
import { onBeforeMount, onBeforeUnmount /*watch*/ } from 'vue';
|
||||||
import { useRouter } from "vue-router"
|
// import { useRouter } from 'vue-router';
|
||||||
import { useStore } from "vuex"
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
const WIDTH = 768
|
const WIDTH = 768;
|
||||||
export const useResizeHandler = () => {
|
export const useResizeHandler = () => {
|
||||||
const store = useStore()
|
const store = useStore();
|
||||||
const router = useRouter()
|
// const router = useRouter();
|
||||||
const route = router.currentRoute
|
// const route = router.currentRoute;
|
||||||
|
|
||||||
const isMobile = () => {
|
const isMobile = () => {
|
||||||
return window.innerWidth < WIDTH
|
return window.innerWidth < WIDTH;
|
||||||
}
|
};
|
||||||
|
|
||||||
const resizeHandler = () => {
|
const resizeHandler = () => {
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
store.commit('app/setDevice', 'mobile')
|
store.commit('app/setDevice', 'mobile');
|
||||||
store.commit('app/setCollapse', 1)
|
store.commit('app/setCollapse', 1);
|
||||||
} else {
|
} else {
|
||||||
store.commit('app/setDevice', 'desktop')
|
store.commit('app/setDevice', 'desktop');
|
||||||
store.commit('app/setCollapse', 0)
|
store.commit('app/setCollapse', 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
store.commit('app/setDevice', 'mobile')
|
store.commit('app/setDevice', 'mobile');
|
||||||
store.commit('app/setCollapse', 1)
|
store.commit('app/setCollapse', 1);
|
||||||
}
|
}
|
||||||
window.addEventListener('resize', resizeHandler)
|
window.addEventListener('resize', resizeHandler);
|
||||||
})
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener('resize', resizeHandler)
|
window.removeEventListener('resize', resizeHandler);
|
||||||
})
|
});
|
||||||
|
|
||||||
// // 监听路由的时候不能使用useRoute获取路由,否则会有警告
|
// // 监听路由的时候不能使用useRoute获取路由,否则会有警告
|
||||||
// watch(route, () => {
|
// watch(route, () => {
|
||||||
@ -40,7 +40,4 @@ export const useResizeHandler = () => {
|
|||||||
// store.commit('app/setCollapse', 1)
|
// store.commit('app/setCollapse', 1)
|
||||||
// }
|
// }
|
||||||
// })
|
// })
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -7,21 +7,21 @@
|
|||||||
<tagsbar />
|
<tagsbar />
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<content />
|
<Content />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
import Sidebar from "./components/Sidebar/index.vue";
|
import Sidebar from './components/Sidebar/index.vue';
|
||||||
import Topbar from "./components/Topbar/index.vue";
|
import Topbar from './components/Topbar/index.vue';
|
||||||
import Tagsbar from "./components/Tagsbar/index.vue";
|
import Tagsbar from './components/Tagsbar/index.vue';
|
||||||
import Content from "./components/Content/index.vue";
|
import Content from './components/Content/index.vue';
|
||||||
import { useResizeHandler } from "./hooks/useResizeHandler";
|
import { useResizeHandler } from './hooks/useResizeHandler';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "layout",
|
name: 'layout',
|
||||||
components: {
|
components: {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
Topbar,
|
Topbar,
|
||||||
|
|||||||
24
src/main.js
24
src/main.js
@ -1,29 +1,29 @@
|
|||||||
import { createApp } from "vue";
|
import { createApp } from 'vue';
|
||||||
import App from "./App.vue";
|
import App from './App.vue';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
// 引入element-plus
|
// 引入element-plus
|
||||||
import ElementPlus from "element-plus";
|
import ElementPlus from 'element-plus';
|
||||||
import "./assets/style/element-variables.scss";
|
import './assets/style/element-variables.scss';
|
||||||
// 引入中文语言包
|
// 引入中文语言包
|
||||||
import "dayjs/locale/zh-cn";
|
import 'dayjs/locale/zh-cn';
|
||||||
import locale from "element-plus/lib/locale/lang/zh-cn";
|
import locale from 'element-plus/lib/locale/lang/zh-cn';
|
||||||
|
|
||||||
// 引入路由
|
// 引入路由
|
||||||
import router from "./router";
|
import router from './router';
|
||||||
|
|
||||||
// 引入store
|
// 引入store
|
||||||
import store from "./store";
|
import store from './store';
|
||||||
|
|
||||||
// 权限控制
|
// 权限控制
|
||||||
import "./permission";
|
import './permission';
|
||||||
|
|
||||||
// 引入svg图标注册脚本
|
// 引入svg图标注册脚本
|
||||||
import "vite-plugin-svg-icons/register";
|
import 'vite-plugin-svg-icons/register';
|
||||||
|
|
||||||
// 注册全局组件
|
// 注册全局组件
|
||||||
import * as Components from "./global-components";
|
import * as Components from './global-components';
|
||||||
Object.entries(Components).forEach(([key, component]) => {
|
Object.entries(Components).forEach(([key, component]) => {
|
||||||
app.component(key, component);
|
app.component(key, component);
|
||||||
});
|
});
|
||||||
@ -32,4 +32,4 @@ app
|
|||||||
.use(ElementPlus, { locale })
|
.use(ElementPlus, { locale })
|
||||||
.use(store)
|
.use(store)
|
||||||
.use(router)
|
.use(router)
|
||||||
.mount("#app");
|
.mount('#app');
|
||||||
|
|||||||
@ -1,49 +1,50 @@
|
|||||||
import router from '@/router'
|
import router from '@/router';
|
||||||
import store from '@/store'
|
import store from '@/store';
|
||||||
import { TOKEN } from '@/store/modules/app' // TOKEN变量名
|
import { TOKEN } from '@/store/modules/app'; // TOKEN变量名
|
||||||
|
|
||||||
const getPageTitle = title => {
|
const getPageTitle = title => {
|
||||||
const appTitle = store.state.app.title;
|
const appTitle = store.state.app.title;
|
||||||
if (title) {
|
if (title) {
|
||||||
return `${title} - ${appTitle}`
|
return `${title} - ${appTitle}`;
|
||||||
}
|
|
||||||
return appTitle
|
|
||||||
}
|
}
|
||||||
|
return appTitle;
|
||||||
|
};
|
||||||
|
|
||||||
// 白名单,里面是路由对象的name
|
// 白名单,里面是路由对象的name
|
||||||
const WhiteList = ['login', 'forbidden', 'server-error', 'not-found']
|
const WhiteList = ['login', 'forbidden', 'server-error', 'not-found'];
|
||||||
|
|
||||||
// vue-router4的路由守卫不再是通过next放行,而是通过return返回true或false或者一个路由地址
|
// vue-router4的路由守卫不再是通过next放行,而是通过return返回true或false或者一个路由地址
|
||||||
router.beforeEach(async (to) => {
|
router.beforeEach(async to => {
|
||||||
|
document.title = getPageTitle(!!to.meta && to.meta.title);
|
||||||
document.title = getPageTitle(!!to.meta && to.meta.title)
|
|
||||||
|
|
||||||
if (WhiteList.includes(to.name)) {
|
if (WhiteList.includes(to.name)) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
if (!window.localStorage[TOKEN]) {
|
if (!window.localStorage[TOKEN]) {
|
||||||
return {
|
return {
|
||||||
name: 'login',
|
name: 'login',
|
||||||
query: {
|
query: {
|
||||||
redirect: to.path // redirect是指登录之后可以跳回到redirect指定的页面
|
redirect: to.path, // redirect是指登录之后可以跳回到redirect指定的页面
|
||||||
},
|
},
|
||||||
replace: true
|
replace: true,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
let userinfo = store.state.account.userinfo
|
let userinfo = store.state.account.userinfo;
|
||||||
if (!userinfo) {
|
if (!userinfo) {
|
||||||
try {
|
try {
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
userinfo = await store.dispatch("account/getUserinfo");
|
userinfo = await store.dispatch('account/getUserinfo');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// 如果没有权限,跳转到403页面
|
// 如果没有权限,跳转到403页面
|
||||||
if (!!to.meta && !!to.meta.roles && !to.meta.roles.includes(userinfo.role)) {
|
if (
|
||||||
return { path: '/403', replace: true }
|
!!to.meta &&
|
||||||
|
!!to.meta.roles &&
|
||||||
|
!to.meta.roles.includes(userinfo.role)
|
||||||
|
) {
|
||||||
|
return { path: '/403', replace: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
// index.js
|
// index.js
|
||||||
import { createRouter, createWebHashHistory } from "vue-router"
|
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||||
|
|
||||||
import redirect from './modules/redirect'
|
|
||||||
import error from './modules/error'
|
|
||||||
import login from './modules/login'
|
|
||||||
import home from './modules/home'
|
|
||||||
import test from './modules/test'
|
|
||||||
|
|
||||||
|
import redirect from './modules/redirect';
|
||||||
|
import error from './modules/error';
|
||||||
|
import login from './modules/login';
|
||||||
|
import home from './modules/home';
|
||||||
|
import test from './modules/test';
|
||||||
|
|
||||||
// 左侧菜单
|
// 左侧菜单
|
||||||
export const allMenus = [
|
export const allMenus = [...home, ...test];
|
||||||
...home,
|
|
||||||
...test,
|
|
||||||
]
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
@ -24,13 +20,13 @@ const router = createRouter({
|
|||||||
...redirect, // 统一的重定向配置
|
...redirect, // 统一的重定向配置
|
||||||
...login,
|
...login,
|
||||||
...allMenus,
|
...allMenus,
|
||||||
...error
|
...error,
|
||||||
],
|
],
|
||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to, from, savedPosition) {
|
||||||
if (savedPosition) {
|
if (savedPosition) {
|
||||||
return savedPosition
|
return savedPosition;
|
||||||
} else {
|
} else {
|
||||||
return { left: 0, top: 0 }
|
return { left: 0, top: 0 };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,18 +1,15 @@
|
|||||||
import store from '@/store'
|
import store from '@/store';
|
||||||
|
|
||||||
const checkUserinfo = (code) => {
|
const checkUserinfo = code => {
|
||||||
const userinfo = store.state.account.userinfo
|
const userinfo = store.state.account.userinfo;
|
||||||
if (!!userinfo) {
|
if (userinfo) {
|
||||||
return `/error/${code}`
|
return `/error/${code}`;
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const Layout = () => import('@/layout/index.vue')
|
const Layout = () => import('@/layout/index.vue');
|
||||||
const Error = () => import("@/views/error/index.vue");
|
const Error = () => import('@/views/error/index.vue');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@ -25,8 +22,8 @@ export default [
|
|||||||
component: Error,
|
component: Error,
|
||||||
meta: { title: '403' },
|
meta: { title: '403' },
|
||||||
props: {
|
props: {
|
||||||
error: '403'
|
error: '403',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '500',
|
path: '500',
|
||||||
@ -34,8 +31,8 @@ export default [
|
|||||||
component: Error,
|
component: Error,
|
||||||
meta: { title: '500' },
|
meta: { title: '500' },
|
||||||
props: {
|
props: {
|
||||||
error: '500'
|
error: '500',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '404',
|
path: '404',
|
||||||
@ -43,42 +40,42 @@ export default [
|
|||||||
component: Error,
|
component: Error,
|
||||||
meta: { title: '404' },
|
meta: { title: '404' },
|
||||||
props: {
|
props: {
|
||||||
error: '404'
|
error: '404',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/403',
|
path: '/403',
|
||||||
name: 'forbidden',
|
name: 'forbidden',
|
||||||
component: Error,
|
component: Error,
|
||||||
props: {
|
props: {
|
||||||
error: '403'
|
error: '403',
|
||||||
},
|
},
|
||||||
beforeEnter() {
|
beforeEnter() {
|
||||||
return checkUserinfo('403')
|
return checkUserinfo('403');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/500',
|
path: '/500',
|
||||||
name: 'server-error',
|
name: 'server-error',
|
||||||
component: Error,
|
component: Error,
|
||||||
props: {
|
props: {
|
||||||
error: '500'
|
error: '500',
|
||||||
},
|
},
|
||||||
beforeEnter() {
|
beforeEnter() {
|
||||||
return checkUserinfo('500')
|
return checkUserinfo('500');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)',
|
path: '/:pathMatch(.*)',
|
||||||
name: 'not-found',
|
name: 'not-found',
|
||||||
component: Error,
|
component: Error,
|
||||||
props: {
|
props: {
|
||||||
error: '404'
|
error: '404',
|
||||||
},
|
},
|
||||||
beforeEnter() {
|
beforeEnter() {
|
||||||
return checkUserinfo('404')
|
return checkUserinfo('404');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
|
];
|
||||||
|
|||||||
@ -1,27 +1,26 @@
|
|||||||
// home.js
|
// home.js
|
||||||
const Layout = () => import('@/layout/index.vue')
|
const Layout = () => import('@/layout/index.vue');
|
||||||
const Home = () => import("@/views/home/index.vue");
|
const Home = () => import('@/views/home/index.vue');
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: '/home',
|
path: '/home',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
name: "Dashboard",
|
name: 'Dashboard',
|
||||||
meta: {
|
meta: {
|
||||||
title: "Dashboard",
|
title: 'Dashboard',
|
||||||
},
|
},
|
||||||
icon: 'home',
|
icon: 'home',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "",
|
path: '',
|
||||||
name: "home",
|
name: 'home',
|
||||||
component: Home,
|
component: Home,
|
||||||
meta: {
|
meta: {
|
||||||
title: "首页",
|
title: '首页',
|
||||||
affix: true
|
affix: true,
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
]
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
// login.js
|
// login.js
|
||||||
const Login = () => import("@/views/login/index.vue");
|
const Login = () => import('@/views/login/index.vue');
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: "/login",
|
path: '/login',
|
||||||
name: "login",
|
name: 'login',
|
||||||
component: Login,
|
component: Login,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const Layout = () => import('@/layout/index.vue')
|
const Layout = () => import('@/layout/index.vue');
|
||||||
const Redirect = () => import("@/views/redirect/index.vue");
|
const Redirect = () => import('@/views/redirect/index.vue');
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@ -9,7 +9,7 @@ export default [
|
|||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: Redirect,
|
component: Redirect,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|||||||
@ -1,112 +1,112 @@
|
|||||||
const Layout = () => import('@/layout/index.vue')
|
const Layout = () => import('@/layout/index.vue');
|
||||||
const List = () => import("@/views/test/index.vue");
|
const List = () => import('@/views/test/index.vue');
|
||||||
const Add = () => import("@/views/test/Add.vue");
|
const Add = () => import('@/views/test/Add.vue');
|
||||||
const Auth = () => import("@/views/test/Auth.vue");
|
const Auth = () => import('@/views/test/Auth.vue');
|
||||||
const NoAuth = () => import("@/views/test/NoAuth.vue");
|
const NoAuth = () => import('@/views/test/NoAuth.vue');
|
||||||
const Nest = () => import("@/views/test/Nest.vue");
|
const Nest = () => import('@/views/test/Nest.vue');
|
||||||
const NestPage1 = () => import("@/views/test/nest/Page1.vue");
|
const NestPage1 = () => import('@/views/test/nest/Page1.vue');
|
||||||
const NestPage2 = () => import("@/views/test/nest/Page2.vue");
|
const NestPage2 = () => import('@/views/test/nest/Page2.vue');
|
||||||
const Iscache = () => import("@/views/test/Cache.vue");
|
const Iscache = () => import('@/views/test/Cache.vue');
|
||||||
const Nocache = () => import("@/views/test/Nocache.vue");
|
const Nocache = () => import('@/views/test/Nocache.vue');
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: '/test',
|
path: '/test',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
name: "test",
|
name: 'test',
|
||||||
meta: {
|
meta: {
|
||||||
title: "测试页面",
|
title: '测试页面',
|
||||||
},
|
},
|
||||||
icon: 'el-icon-location',
|
icon: 'el-icon-location',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "",
|
path: '',
|
||||||
name: "testList",
|
name: 'testList',
|
||||||
component: List,
|
component: List,
|
||||||
meta: {
|
meta: {
|
||||||
title: "列表",
|
title: '列表',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "add",
|
path: 'add',
|
||||||
name: "testAdd",
|
name: 'testAdd',
|
||||||
component: Add,
|
component: Add,
|
||||||
meta: {
|
meta: {
|
||||||
title: "添加",
|
title: '添加',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
},
|
},
|
||||||
hidden: true, // 不在菜单中显示
|
hidden: true, // 不在菜单中显示
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "auth",
|
path: 'auth',
|
||||||
name: "testAuth",
|
name: 'testAuth',
|
||||||
component: Auth,
|
component: Auth,
|
||||||
meta: {
|
meta: {
|
||||||
title: "权限测试",
|
title: '权限测试',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "noauth",
|
path: 'noauth',
|
||||||
name: "testNoAuth",
|
name: 'testNoAuth',
|
||||||
component: NoAuth,
|
component: NoAuth,
|
||||||
meta: {
|
meta: {
|
||||||
title: "权限页面",
|
title: '权限页面',
|
||||||
roles: ["admin"],
|
roles: ['admin'],
|
||||||
},
|
},
|
||||||
hidden: true
|
hidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "cache",
|
path: 'cache',
|
||||||
name: "test-cache",
|
name: 'test-cache',
|
||||||
component: Iscache,
|
component: Iscache,
|
||||||
meta: {
|
meta: {
|
||||||
title: "该页面可缓存",
|
title: '该页面可缓存',
|
||||||
roles: ["admin", "visitor"]
|
roles: ['admin', 'visitor'],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "nocache",
|
path: 'nocache',
|
||||||
name: "test-no-cache",
|
name: 'test-no-cache',
|
||||||
component: Nocache,
|
component: Nocache,
|
||||||
meta: {
|
meta: {
|
||||||
title: "该页面不缓存",
|
title: '该页面不缓存',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
noCache: true, // 不缓存页面
|
noCache: true, // 不缓存页面
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "nest",
|
path: 'nest',
|
||||||
name: "nest",
|
name: 'nest',
|
||||||
component: Nest,
|
component: Nest,
|
||||||
redirect: '/test/nest/page1',
|
redirect: '/test/nest/page1',
|
||||||
meta: {
|
meta: {
|
||||||
title: "二级菜单",
|
title: '二级菜单',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "page1",
|
path: 'page1',
|
||||||
name: "nestPage1",
|
name: 'nestPage1',
|
||||||
component: NestPage1,
|
component: NestPage1,
|
||||||
meta: {
|
meta: {
|
||||||
title: "page1",
|
title: 'page1',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "page2",
|
path: 'page2',
|
||||||
name: "nestPage2",
|
name: 'nestPage2',
|
||||||
component: NestPage2,
|
component: NestPage2,
|
||||||
meta: {
|
meta: {
|
||||||
title: "page2",
|
title: 'page2',
|
||||||
roles: ["admin", "visitor"],
|
roles: ['admin', 'visitor'],
|
||||||
},
|
},
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
//index.js
|
//index.js
|
||||||
import { createStore } from "vuex";
|
import { createStore } from 'vuex';
|
||||||
import app from "./modules/app";
|
import app from './modules/app';
|
||||||
import account from "./modules/account";
|
import account from './modules/account';
|
||||||
import menu from "./modules/menu";
|
import menu from './modules/menu';
|
||||||
import tags from "./modules/tags";
|
import tags from './modules/tags';
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
modules: {
|
modules: {
|
||||||
app,
|
app,
|
||||||
account,
|
account,
|
||||||
menu,
|
menu,
|
||||||
tags
|
tags,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { GetUserinfo } from '@/api/login'
|
import { GetUserinfo } from '@/api/login';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: {
|
state: {
|
||||||
userinfo: null
|
userinfo: null,
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
// 保存用户信息
|
// 保存用户信息
|
||||||
@ -13,16 +13,16 @@ export default {
|
|||||||
// 清除用户信息
|
// 清除用户信息
|
||||||
clearUserinfo(state) {
|
clearUserinfo(state) {
|
||||||
state.userinfo = null;
|
state.userinfo = null;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
async getUserinfo({ commit }) {
|
async getUserinfo({ commit }) {
|
||||||
const { code, data } = await GetUserinfo();
|
const { code, data } = await GetUserinfo();
|
||||||
if (+code === 200) {
|
if (+code === 200) {
|
||||||
commit("setUserinfo", data);
|
commit('setUserinfo', data);
|
||||||
return Promise.resolve(data)
|
return Promise.resolve(data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { getItem, setItem, removeItem } from "@/utils/storage"; //getItem和setItem是封装的操作localStorage的方法
|
import { getItem, setItem, removeItem } from '@/utils/storage'; //getItem和setItem是封装的操作localStorage的方法
|
||||||
export const TOKEN = "VEA-TOKEN";
|
export const TOKEN = 'VEA-TOKEN';
|
||||||
const COLLAPSE = "VEA-COLLAPSE";
|
const COLLAPSE = 'VEA-COLLAPSE';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
@ -8,7 +8,7 @@ export default {
|
|||||||
title: 'Vue3 Element Admin',
|
title: 'Vue3 Element Admin',
|
||||||
authorization: getItem(TOKEN),
|
authorization: getItem(TOKEN),
|
||||||
sidebar: {
|
sidebar: {
|
||||||
collapse: getItem(COLLAPSE)
|
collapse: getItem(COLLAPSE),
|
||||||
},
|
},
|
||||||
device: 'desktop',
|
device: 'desktop',
|
||||||
},
|
},
|
||||||
@ -34,7 +34,7 @@ export default {
|
|||||||
removeItem(COLLAPSE);
|
removeItem(COLLAPSE);
|
||||||
},
|
},
|
||||||
setDevice(state, device) {
|
setDevice(state, device) {
|
||||||
state.device = device
|
state.device = device;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {},
|
actions: {},
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
import { allMenus } from '@/router'
|
import { allMenus } from '@/router';
|
||||||
import { GetMenus } from '@/api/menu'
|
// import { GetMenus } from '@/api/menu';
|
||||||
|
|
||||||
const hasPermission = (role, route) => {
|
const hasPermission = (role, route) => {
|
||||||
if (!!route.meta && !!route.meta.roles && !route.meta.roles.includes(role)) {
|
if (!!route.meta && !!route.meta.roles && !route.meta.roles.includes(role)) {
|
||||||
return false
|
return false;
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const generateUrl = (path, parentPath) => {
|
const generateUrl = (path, parentPath) => {
|
||||||
return path.startsWith('/') ? path : (!!path ? `${parentPath}/${path}` : parentPath)
|
return path.startsWith('/')
|
||||||
}
|
? path
|
||||||
|
: path
|
||||||
|
? `${parentPath}/${path}`
|
||||||
|
: parentPath;
|
||||||
|
};
|
||||||
|
|
||||||
const getFilterMenus = (arr, role, parentPath = '') => {
|
const getFilterMenus = (arr, role, parentPath = '') => {
|
||||||
const menus = [];
|
const menus = [];
|
||||||
@ -21,43 +25,42 @@ const getFilterMenus = (arr, role, parentPath = '') => {
|
|||||||
url: generateUrl(item.path, parentPath),
|
url: generateUrl(item.path, parentPath),
|
||||||
title: item.meta.title,
|
title: item.meta.title,
|
||||||
icon: item.icon,
|
icon: item.icon,
|
||||||
}
|
};
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
if (item.children.length === 1) {
|
if (item.children.length === 1) {
|
||||||
menu.url = generateUrl(item.children[0].path, menu.url)
|
menu.url = generateUrl(item.children[0].path, menu.url);
|
||||||
} else {
|
} else {
|
||||||
menu.children = getFilterMenus(item.children, role, menu.url)
|
menu.children = getFilterMenus(item.children, role, menu.url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menus.push(menu)
|
menus.push(menu);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return menus
|
return menus;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: {
|
state: {
|
||||||
menus: []
|
menus: [],
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
SET_MENUS(state, data) {
|
SET_MENUS(state, data) {
|
||||||
state.menus = data;
|
state.menus = data;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async generateMenus({ commit }, role) {
|
async generateMenus({ commit }, role) {
|
||||||
// 方式一:根据角色生成菜单
|
// 方式一:根据角色生成菜单
|
||||||
const menus = getFilterMenus(allMenus, role)
|
const menus = getFilterMenus(allMenus, role);
|
||||||
commit('SET_MENUS', menus)
|
commit('SET_MENUS', menus);
|
||||||
|
|
||||||
// // 方式二:从后台获取菜单
|
// // 方式二:从后台获取菜单
|
||||||
// const { code, data } = await GetMenus();
|
// const { code, data } = await GetMenus();
|
||||||
// if (+code === 200) {
|
// if (+code === 200) {
|
||||||
// commit('SET_MENUS', data)
|
// commit('SET_MENUS', data)
|
||||||
// }
|
// }
|
||||||
|
},
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import { getItem, setItem, removeItem } from "@/utils/storage"; //getItem和setItem是封装的操作localStorage的方法
|
import { getItem, setItem, removeItem } from '@/utils/storage'; //getItem和setItem是封装的操作localStorage的方法
|
||||||
|
|
||||||
const TAGLIST = 'VEA-TAGLIST'
|
const TAGLIST = 'VEA-TAGLIST';
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
tagList: getItem(TAGLIST) || [],
|
tagList: getItem(TAGLIST) || [],
|
||||||
cacheList: [],
|
cacheList: [],
|
||||||
activePosition: 0
|
activePosition: 0,
|
||||||
}
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
ADD_TAG_LIST: (state, { path, fullPath, name, meta }) => {
|
ADD_TAG_LIST: (state, { path, fullPath, name, meta }) => {
|
||||||
@ -15,138 +15,144 @@ const mutations = {
|
|||||||
state.tagList.splice(
|
state.tagList.splice(
|
||||||
state.activePosition + 1,
|
state.activePosition + 1,
|
||||||
0,
|
0,
|
||||||
Object.assign({}, { path, fullPath, name, meta }, {
|
Object.assign(
|
||||||
|
{},
|
||||||
|
{ path, fullPath, name, meta },
|
||||||
|
{
|
||||||
title: meta.title || '未命名',
|
title: meta.title || '未命名',
|
||||||
fullPath: fullPath || path
|
fullPath: fullPath || path,
|
||||||
})
|
}
|
||||||
)
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// 保存到localStorage
|
// 保存到localStorage
|
||||||
setItem(TAGLIST, state.tagList);
|
setItem(TAGLIST, state.tagList);
|
||||||
},
|
},
|
||||||
ADD_CACHE_LIST: (state, tag) => {
|
ADD_CACHE_LIST: (state, tag) => {
|
||||||
if (state.cacheList.includes(tag.name)) return
|
if (state.cacheList.includes(tag.name)) return;
|
||||||
if (!tag.meta.noCache) {
|
if (!tag.meta.noCache) {
|
||||||
state.cacheList.push(tag.name)
|
state.cacheList.push(tag.name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
DEL_TAG_LIST: (state, tag) => {
|
DEL_TAG_LIST: (state, tag) => {
|
||||||
state.tagList = state.tagList.filter(v => v.path !== tag.path)
|
state.tagList = state.tagList.filter(v => v.path !== tag.path);
|
||||||
// 保存到localStorage
|
// 保存到localStorage
|
||||||
setItem(TAGLIST, state.tagList);
|
setItem(TAGLIST, state.tagList);
|
||||||
},
|
},
|
||||||
DEL_CACHE_LIST: (state, tag) => {
|
DEL_CACHE_LIST: (state, tag) => {
|
||||||
state.cacheList = state.cacheList.filter(v => v !== tag.name)
|
state.cacheList = state.cacheList.filter(v => v !== tag.name);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
DEL_OTHER_TAG_LIST: (state, tag) => {
|
DEL_OTHER_TAG_LIST: (state, tag) => {
|
||||||
state.tagList = state.tagList.filter(v => !!v.meta.affix || v.path === tag.path)
|
state.tagList = state.tagList.filter(
|
||||||
|
v => !!v.meta.affix || v.path === tag.path
|
||||||
|
);
|
||||||
// 保存到localStorage
|
// 保存到localStorage
|
||||||
setItem(TAGLIST, state.tagList);
|
setItem(TAGLIST, state.tagList);
|
||||||
},
|
},
|
||||||
DEL_OTHER_CACHE_LIST: (state, tag) => {
|
DEL_OTHER_CACHE_LIST: (state, tag) => {
|
||||||
state.cacheList = state.cacheList.filter(v => v === tag.name)
|
state.cacheList = state.cacheList.filter(v => v === tag.name);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
DEL_SOME_TAG_LIST: (state, tags) => {
|
DEL_SOME_TAG_LIST: (state, tags) => {
|
||||||
state.tagList = state.tagList.filter(v => !!v.meta.affix || tags.every(tag => tag.path !== v.path))
|
state.tagList = state.tagList.filter(
|
||||||
|
v => !!v.meta.affix || tags.every(tag => tag.path !== v.path)
|
||||||
|
);
|
||||||
// 保存到localStorage
|
// 保存到localStorage
|
||||||
setItem(TAGLIST, state.tagList);
|
setItem(TAGLIST, state.tagList);
|
||||||
},
|
},
|
||||||
|
|
||||||
DEL_SOME_CACHE_LIST: (state, tags) => {
|
DEL_SOME_CACHE_LIST: (state, tags) => {
|
||||||
state.cacheList = state.cacheList.filter(v => tags.every(tag => tag.name !== v))
|
state.cacheList = state.cacheList.filter(v =>
|
||||||
|
tags.every(tag => tag.name !== v)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
DEL_ALL_TAG_LIST: state => {
|
DEL_ALL_TAG_LIST: state => {
|
||||||
state.tagList = state.tagList.filter(v => !!v.meta.affix)
|
state.tagList = state.tagList.filter(v => !!v.meta.affix);
|
||||||
// 保存到localStorage
|
// 保存到localStorage
|
||||||
removeItem(TAGLIST);
|
removeItem(TAGLIST);
|
||||||
},
|
},
|
||||||
DEL_ALL_CACHE_LIST: state => {
|
DEL_ALL_CACHE_LIST: state => {
|
||||||
state.cacheList = []
|
state.cacheList = [];
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
UPDATE_TAG_LIST: (state, tag) => {
|
UPDATE_TAG_LIST: (state, tag) => {
|
||||||
const index = state.tagList.findIndex(v => v.path === tag.path);
|
const index = state.tagList.findIndex(v => v.path === tag.path);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
state.tagList[index] = Object.assign({}, state.tagList[index], tag)
|
state.tagList[index] = Object.assign({}, state.tagList[index], tag);
|
||||||
// 保存到localStorage
|
// 保存到localStorage
|
||||||
setItem(TAGLIST, state.tagList);
|
setItem(TAGLIST, state.tagList);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
SAVE_ACTIVE_POSITION: (state, index) => {
|
SAVE_ACTIVE_POSITION: (state, index) => {
|
||||||
state.activePosition = index
|
state.activePosition = index;
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
saveActivePosition({ commit }, index) {
|
saveActivePosition({ commit }, index) {
|
||||||
commit('SAVE_ACTIVE_POSITION', index)
|
commit('SAVE_ACTIVE_POSITION', index);
|
||||||
},
|
},
|
||||||
addTag({ dispatch }, tag) {
|
addTag({ dispatch }, tag) {
|
||||||
dispatch('addTagList', tag)
|
dispatch('addTagList', tag);
|
||||||
dispatch('addCacheList', tag)
|
dispatch('addCacheList', tag);
|
||||||
},
|
},
|
||||||
addTagList({ commit }, tag) {
|
addTagList({ commit }, tag) {
|
||||||
commit('ADD_TAG_LIST', tag)
|
commit('ADD_TAG_LIST', tag);
|
||||||
},
|
},
|
||||||
addCacheList({ commit }, tag) {
|
addCacheList({ commit }, tag) {
|
||||||
commit('ADD_CACHE_LIST', tag)
|
commit('ADD_CACHE_LIST', tag);
|
||||||
},
|
},
|
||||||
|
|
||||||
delTag({ dispatch }, tag) {
|
delTag({ dispatch }, tag) {
|
||||||
dispatch('delTagList', tag)
|
dispatch('delTagList', tag);
|
||||||
dispatch('delCacheList', tag)
|
dispatch('delCacheList', tag);
|
||||||
},
|
},
|
||||||
delTagList({ commit }, tag) {
|
delTagList({ commit }, tag) {
|
||||||
commit('DEL_TAG_LIST', tag)
|
commit('DEL_TAG_LIST', tag);
|
||||||
},
|
},
|
||||||
delCacheList({ commit }, tag) {
|
delCacheList({ commit }, tag) {
|
||||||
commit('DEL_CACHE_LIST', tag)
|
commit('DEL_CACHE_LIST', tag);
|
||||||
},
|
},
|
||||||
|
|
||||||
delOtherTags({ dispatch }, tag) {
|
delOtherTags({ dispatch }, tag) {
|
||||||
dispatch('delOtherTagList', tag)
|
dispatch('delOtherTagList', tag);
|
||||||
dispatch('delOtherCacheList', tag)
|
dispatch('delOtherCacheList', tag);
|
||||||
},
|
},
|
||||||
delOtherTagList({ commit }, tag) {
|
delOtherTagList({ commit }, tag) {
|
||||||
commit('DEL_OTHER_TAG_LIST', tag)
|
commit('DEL_OTHER_TAG_LIST', tag);
|
||||||
},
|
},
|
||||||
delOtherCacheList({ commit }, tag) {
|
delOtherCacheList({ commit }, tag) {
|
||||||
commit('DEL_OTHER_CACHE_LIST', tag)
|
commit('DEL_OTHER_CACHE_LIST', tag);
|
||||||
},
|
},
|
||||||
|
|
||||||
delSomeTags({ commit }, tags) {
|
delSomeTags({ commit }, tags) {
|
||||||
commit('DEL_SOME_TAG_LIST', tags)
|
commit('DEL_SOME_TAG_LIST', tags);
|
||||||
commit('DEL_SOME_CACHE_LIST', tags)
|
commit('DEL_SOME_CACHE_LIST', tags);
|
||||||
},
|
},
|
||||||
|
|
||||||
delAllTags({ dispatch }) {
|
delAllTags({ dispatch }) {
|
||||||
dispatch('delAllTagList')
|
dispatch('delAllTagList');
|
||||||
dispatch('delAllCacheList')
|
dispatch('delAllCacheList');
|
||||||
},
|
},
|
||||||
delAllTagList({ commit }) {
|
delAllTagList({ commit }) {
|
||||||
commit('DEL_ALL_TAG_LIST')
|
commit('DEL_ALL_TAG_LIST');
|
||||||
},
|
},
|
||||||
delAllCacheList({ commit }) {
|
delAllCacheList({ commit }) {
|
||||||
commit('DEL_ALL_CACHE_LIST')
|
commit('DEL_ALL_CACHE_LIST');
|
||||||
},
|
},
|
||||||
|
|
||||||
updateTagList({ commit }, tag) {
|
updateTagList({ commit }, tag) {
|
||||||
commit('UPDATE_TAG_LIST', tag)
|
commit('UPDATE_TAG_LIST', tag);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state,
|
state,
|
||||||
mutations,
|
mutations,
|
||||||
actions
|
actions,
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,24 +1,24 @@
|
|||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from 'element-plus';
|
||||||
import store from "@/store";
|
import store from '@/store';
|
||||||
import router from "@/router";
|
import router from '@/router';
|
||||||
|
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: "/",
|
baseURL: '/',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 拦截请求
|
// 拦截请求
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
(config) => {
|
config => {
|
||||||
const { authorization } = store.state.app;
|
const { authorization } = store.state.app;
|
||||||
if (authorization) {
|
if (authorization) {
|
||||||
config.headers.Authorization = `Bearer ${authorization.token}`;
|
config.headers.Authorization = `Bearer ${authorization.token}`;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => {
|
error => {
|
||||||
// console.log(error);
|
// console.log(error);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
@ -27,18 +27,18 @@ service.interceptors.request.use(
|
|||||||
// 拦截响应
|
// 拦截响应
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
// 响应成功进入第1个函数,该函数的参数是响应对象
|
// 响应成功进入第1个函数,该函数的参数是响应对象
|
||||||
(response) => {
|
response => {
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
// 响应失败进入第2个函数,该函数的参数是错误对象
|
// 响应失败进入第2个函数,该函数的参数是错误对象
|
||||||
async (error) => {
|
async error => {
|
||||||
// 如果响应码是 401 ,则请求获取新的 token
|
// 如果响应码是 401 ,则请求获取新的 token
|
||||||
// 响应拦截器中的 error 就是那个响应的错误对象
|
// 响应拦截器中的 error 就是那个响应的错误对象
|
||||||
if (error.response && error.response.status === 401) {
|
if (error.response && error.response.status === 401) {
|
||||||
// 校验是否有 refresh_token
|
// 校验是否有 refresh_token
|
||||||
const { authorization } = store.state.app;
|
const { authorization } = store.state.app;
|
||||||
if (!authorization || !authorization.refresh_token) {
|
if (!authorization || !authorization.refresh_token) {
|
||||||
router.push("/login");
|
router.push('/login');
|
||||||
|
|
||||||
// 代码不要往后执行了
|
// 代码不要往后执行了
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
@ -46,8 +46,8 @@ service.interceptors.response.use(
|
|||||||
// 如果有refresh_token,则请求获取新的 token
|
// 如果有refresh_token,则请求获取新的 token
|
||||||
try {
|
try {
|
||||||
const res = await axios({
|
const res = await axios({
|
||||||
method: "PUT",
|
method: 'PUT',
|
||||||
url: "/api/authorizations",
|
url: '/api/authorizations',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${authorization.refresh_token}`,
|
Authorization: `Bearer ${authorization.refresh_token}`,
|
||||||
@ -55,7 +55,7 @@ service.interceptors.response.use(
|
|||||||
});
|
});
|
||||||
// 如果获取成功,则把新的 token 更新到容器中
|
// 如果获取成功,则把新的 token 更新到容器中
|
||||||
// console.log('刷新 token 成功', res)
|
// console.log('刷新 token 成功', res)
|
||||||
store.commit("app/setToken", {
|
store.commit('app/setToken', {
|
||||||
token: res.data.data.token, // 最新获取的可用 token
|
token: res.data.data.token, // 最新获取的可用 token
|
||||||
refresh_token: authorization.refresh_token, // 还是原来的 refresh_token
|
refresh_token: authorization.refresh_token, // 还是原来的 refresh_token
|
||||||
});
|
});
|
||||||
@ -66,9 +66,9 @@ service.interceptors.response.use(
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 如果获取失败,直接跳转 登录页
|
// 如果获取失败,直接跳转 登录页
|
||||||
// console.log('请求刷新 token 失败', err)
|
// console.log('请求刷新 token 失败', err)
|
||||||
router.push("/login");
|
router.push('/login');
|
||||||
// 清除token
|
// 清除token
|
||||||
store.commit("app/clearToken")
|
store.commit('app/clearToken');
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export const getItem = name => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const setItem = (name, value) => {
|
export const setItem = (name, value) => {
|
||||||
if (typeof value === "object") {
|
if (typeof value === 'object') {
|
||||||
value = JSON.stringify(value);
|
value = JSON.stringify(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,14 +21,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: ["error"],
|
props: ['error'],
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.error {
|
.error {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "home",
|
name: 'home',
|
||||||
setup() {},
|
setup() {},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -43,12 +43,12 @@ import {
|
|||||||
toRefs,
|
toRefs,
|
||||||
ref,
|
ref,
|
||||||
computed,
|
computed,
|
||||||
} from "vue";
|
} from 'vue';
|
||||||
import { Login } from "@/api/login";
|
import { Login } from '@/api/login';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
import { useRouter, useRoute } from "vue-router";
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "login",
|
name: 'login',
|
||||||
setup() {
|
setup() {
|
||||||
const { ctx } = getCurrentInstance(); // 可以把ctx当成vue2中的this
|
const { ctx } = getCurrentInstance(); // 可以把ctx当成vue2中的this
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@ -56,42 +56,42 @@ export default defineComponent({
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
model: {
|
model: {
|
||||||
userName: "admin",
|
userName: 'admin',
|
||||||
password: "123456",
|
password: '123456',
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
userName: [
|
userName: [
|
||||||
{ required: true, message: "请输入用户名", trigger: "blur" },
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
min: 6,
|
min: 6,
|
||||||
max: 12,
|
max: 12,
|
||||||
message: "长度在 6 到 12 个字符",
|
message: '长度在 6 到 12 个字符',
|
||||||
trigger: "blur",
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
btnText: computed(() => (state.loading ? "登录中..." : "登录")),
|
btnText: computed(() => (state.loading ? '登录中...' : '登录')),
|
||||||
loginForm: ref(null),
|
loginForm: ref(null),
|
||||||
submit: () => {
|
submit: () => {
|
||||||
if (state.loading) {
|
if (state.loading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.loginForm.validate(async (valid) => {
|
state.loginForm.validate(async valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
state.loading = true;
|
state.loading = true;
|
||||||
const { code, data, message } = await Login(state.model);
|
const { code, data, message } = await Login(state.model);
|
||||||
if (+code === 200) {
|
if (+code === 200) {
|
||||||
ctx.$message.success({
|
ctx.$message.success({
|
||||||
message: "登录成功",
|
message: '登录成功',
|
||||||
duration: 1000,
|
duration: 1000,
|
||||||
});
|
});
|
||||||
const targetPath = route.query.redirect;
|
const targetPath = route.query.redirect;
|
||||||
router.push(!!targetPath ? targetPath : "/");
|
router.push(targetPath ? targetPath : '/');
|
||||||
store.commit("app/setToken", data);
|
store.commit('app/setToken', data);
|
||||||
} else {
|
} else {
|
||||||
ctx.$message.error(message);
|
ctx.$message.error(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
created() {
|
created() {
|
||||||
this.$router.replace(this.$route.fullPath.replace(/^\/redirect/, ""));
|
this.$router.replace(this.$route.fullPath.replace(/^\/redirect/, ''));
|
||||||
|
},
|
||||||
|
render(h) {
|
||||||
|
return h();
|
||||||
},
|
},
|
||||||
render() {},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -6,14 +6,14 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, onActivated } from "vue";
|
import { defineComponent, onActivated } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "test-cache", // 该name必须跟路由配置的name一致
|
name: 'test-cache', // 该name必须跟路由配置的name一致
|
||||||
setup() {
|
setup() {
|
||||||
console.log("cache");
|
console.log('cache');
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
console.log("onActivated");
|
console.log('onActivated');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,12 +6,12 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "test-no-cache", // 该name必须跟路由配置的name一致,不一致或者不设置name则不缓存
|
name: 'test-no-cache', // 该name必须跟路由配置的name一致,不一致或者不设置name则不缓存
|
||||||
setup() {
|
setup() {
|
||||||
console.log("nocache");
|
console.log('nocache');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -32,170 +32,170 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, reactive, ref, toRefs } from "vue";
|
import { defineComponent, reactive, ref, toRefs } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "testList",
|
name: 'testList',
|
||||||
setup() {
|
setup() {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
// 表格列配置,大部分属性跟el-table-column配置一样
|
// 表格列配置,大部分属性跟el-table-column配置一样
|
||||||
columns: [
|
columns: [
|
||||||
{ type: "selection" },
|
{ type: 'selection' },
|
||||||
{ label: "序号", type: "index" },
|
{ label: '序号', type: 'index' },
|
||||||
{ label: "名称", prop: "nickName", sortable: true, width: 180 },
|
{ label: '名称', prop: 'nickName', sortable: true, width: 180 },
|
||||||
{ label: "邮箱", prop: "userEmail" },
|
{ label: '邮箱', prop: 'userEmail' },
|
||||||
{
|
{
|
||||||
label: "操作",
|
label: '操作',
|
||||||
fixed: "right",
|
fixed: 'right',
|
||||||
width: 180,
|
width: 180,
|
||||||
align: "center",
|
align: 'center',
|
||||||
tdSlot: "operate", // 自定义单元格内容的插槽名称
|
tdSlot: 'operate', // 自定义单元格内容的插槽名称
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// 搜索配置
|
// 搜索配置
|
||||||
searchConfig: {
|
searchConfig: {
|
||||||
labelWidth: "90px", // 必须带上单位
|
labelWidth: '90px', // 必须带上单位
|
||||||
inputWidth: "360px", // 必须带上单位
|
inputWidth: '360px', // 必须带上单位
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: 'text',
|
||||||
label: "账户名称",
|
label: '账户名称',
|
||||||
name: "nickName",
|
name: 'nickName',
|
||||||
defaultValue: "abc",
|
defaultValue: 'abc',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "textarea",
|
type: 'textarea',
|
||||||
label: "描述",
|
label: '描述',
|
||||||
name: "description",
|
name: 'description',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "状态",
|
label: '状态',
|
||||||
name: "status",
|
name: 'status',
|
||||||
type: "select",
|
type: 'select',
|
||||||
defaultValue: 1,
|
defaultValue: 1,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "已发布",
|
name: '已发布',
|
||||||
value: 1,
|
value: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "未发布",
|
name: '未发布',
|
||||||
value: 0,
|
value: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "性别",
|
label: '性别',
|
||||||
name: "sex",
|
name: 'sex',
|
||||||
type: "radio",
|
type: 'radio',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "男",
|
name: '男',
|
||||||
value: 1,
|
value: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "女",
|
name: '女',
|
||||||
value: 0,
|
value: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "城市",
|
label: '城市',
|
||||||
name: "city",
|
name: 'city',
|
||||||
type: "radio-button",
|
type: 'radio-button',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "北京",
|
name: '北京',
|
||||||
value: "bj",
|
value: 'bj',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "上海",
|
name: '上海',
|
||||||
value: "sh",
|
value: 'sh',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "广州",
|
name: '广州',
|
||||||
value: "gz",
|
value: 'gz',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "深圳",
|
name: '深圳',
|
||||||
value: "sz",
|
value: 'sz',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "爱好",
|
label: '爱好',
|
||||||
name: "hobby",
|
name: 'hobby',
|
||||||
type: "checkbox",
|
type: 'checkbox',
|
||||||
defaultValue: ["吃饭"],
|
defaultValue: ['吃饭'],
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "吃饭",
|
name: '吃饭',
|
||||||
value: "吃饭",
|
value: '吃饭',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "睡觉",
|
name: '睡觉',
|
||||||
value: "睡觉",
|
value: '睡觉',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "打豆豆",
|
name: '打豆豆',
|
||||||
value: "打豆豆",
|
value: '打豆豆',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// transform: (val) => val.join(","),
|
// transform: (val) => val.join(","),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "水果",
|
label: '水果',
|
||||||
name: "fruit",
|
name: 'fruit',
|
||||||
type: "checkbox-button",
|
type: 'checkbox-button',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "苹果",
|
name: '苹果',
|
||||||
value: "苹果",
|
value: '苹果',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "香蕉",
|
name: '香蕉',
|
||||||
value: "香蕉",
|
value: '香蕉',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "橘子",
|
name: '橘子',
|
||||||
value: "橘子",
|
value: '橘子',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "葡萄",
|
name: '葡萄',
|
||||||
value: "葡萄",
|
value: '葡萄',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
transform: (val) => val.join(","),
|
transform: val => val.join(','),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "日期",
|
label: '日期',
|
||||||
name: "date",
|
name: 'date',
|
||||||
type: "date",
|
type: 'date',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "时间",
|
label: '时间',
|
||||||
name: "datetime",
|
name: 'datetime',
|
||||||
type: "datetime",
|
type: 'datetime',
|
||||||
defaultValue: "2020-10-10 8:00:00",
|
defaultValue: '2020-10-10 8:00:00',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "日期范围",
|
label: '日期范围',
|
||||||
name: "daterange",
|
name: 'daterange',
|
||||||
type: "daterange",
|
type: 'daterange',
|
||||||
trueNames: ["startDate", "endDate"],
|
trueNames: ['startDate', 'endDate'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "时间范围",
|
label: '时间范围',
|
||||||
name: "datetimerange",
|
name: 'datetimerange',
|
||||||
type: "datetimerange",
|
type: 'datetimerange',
|
||||||
trueNames: ["startTime", "endTime"],
|
trueNames: ['startTime', 'endTime'],
|
||||||
style: { width: "360px" },
|
style: { width: '360px' },
|
||||||
defaultValue: ["2020-10-10 9:00:00", "2020-10-11 18:30:00"],
|
defaultValue: ['2020-10-10 9:00:00', '2020-10-11 18:30:00'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "数量",
|
label: '数量',
|
||||||
name: "num",
|
name: 'num',
|
||||||
type: "number",
|
type: 'number',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 10,
|
max: 10,
|
||||||
},
|
},
|
||||||
@ -203,10 +203,10 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
// 分页配置
|
// 分页配置
|
||||||
paginationConfig: {
|
paginationConfig: {
|
||||||
layout: "total, prev, pager, next, sizes", // 分页组件显示哪些功能
|
layout: 'total, prev, pager, next, sizes', // 分页组件显示哪些功能
|
||||||
pageSize: 5, // 每页条数
|
pageSize: 5, // 每页条数
|
||||||
pageSizes: [5, 10, 20, 50],
|
pageSizes: [5, 10, 20, 50],
|
||||||
style: { textAlign: "left" },
|
style: { textAlign: 'left' },
|
||||||
},
|
},
|
||||||
selectedItems: [],
|
selectedItems: [],
|
||||||
batchDelete() {
|
batchDelete() {
|
||||||
@ -220,7 +220,7 @@ export default defineComponent({
|
|||||||
async getList(params) {
|
async getList(params) {
|
||||||
console.log(params);
|
console.log(params);
|
||||||
// params是从组件接收的,包含分页和搜索字段。
|
// params是从组件接收的,包含分页和搜索字段。
|
||||||
const { data } = await new Promise((rs) => {
|
const { data } = await new Promise(rs => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
rs({
|
rs({
|
||||||
code: 200,
|
code: 200,
|
||||||
@ -228,13 +228,13 @@ export default defineComponent({
|
|||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
nickName: "zhangsan",
|
nickName: 'zhangsan',
|
||||||
userEmail: "zhangsan@xx.com",
|
userEmail: 'zhangsan@xx.com',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
nickName: "lisi",
|
nickName: 'lisi',
|
||||||
userEmail: "lisi@xx.com",
|
userEmail: 'lisi@xx.com',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
total: 100,
|
total: 100,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { defineConfig } from "vite";
|
import { defineConfig } from 'vite';
|
||||||
import vue from "@vitejs/plugin-vue";
|
import vue from '@vitejs/plugin-vue';
|
||||||
import path from "path";
|
import path from 'path';
|
||||||
import { viteMockServe } from "vite-plugin-mock";
|
import { viteMockServe } from 'vite-plugin-mock';
|
||||||
import viteSvgIcons from "vite-plugin-svg-icons";
|
import viteSvgIcons from 'vite-plugin-svg-icons';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default env => {
|
export default env => {
|
||||||
@ -13,11 +13,11 @@ export default env => {
|
|||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
viteMockServe({
|
viteMockServe({
|
||||||
ignore: /^\_/, // 忽略以下划线`_`开头的文件
|
ignore: /^_/, // 忽略以下划线`_`开头的文件
|
||||||
mockPath: "mock", // 指定mock目录中的文件全部是mock接口
|
mockPath: 'mock', // 指定mock目录中的文件全部是mock接口
|
||||||
supportTs: false, // mockPath目录中的文件是否支持ts文件,现在我们不使用ts,所以设为false
|
supportTs: false, // mockPath目录中的文件是否支持ts文件,现在我们不使用ts,所以设为false
|
||||||
localEnabled: env.mode === "mock", // 开发环境是否开启mock功能(可以在package.json的启动命令中指定mode为mock)
|
localEnabled: env.mode === 'mock', // 开发环境是否开启mock功能(可以在package.json的启动命令中指定mode为mock)
|
||||||
prodEnabled: env.mode === "mock", // 生产环境是否开启mock功能
|
prodEnabled: env.mode === 'mock', // 生产环境是否开启mock功能
|
||||||
injectCode: `
|
injectCode: `
|
||||||
import { setupProdMockServer } from '../mock/_createProductionServer';
|
import { setupProdMockServer } from '../mock/_createProductionServer';
|
||||||
setupProdMockServer();
|
setupProdMockServer();
|
||||||
@ -25,9 +25,9 @@ export default env => {
|
|||||||
}),
|
}),
|
||||||
viteSvgIcons({
|
viteSvgIcons({
|
||||||
// 指定需要缓存的图标文件夹
|
// 指定需要缓存的图标文件夹
|
||||||
iconDirs: [path.resolve(__dirname, "src/assets/svg")],
|
iconDirs: [path.resolve(__dirname, 'src/assets/svg')],
|
||||||
// 指定symbolId格式
|
// 指定symbolId格式
|
||||||
symbolId: "icon-[dir]-[name]",
|
symbolId: 'icon-[dir]-[name]',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
css: {
|
css: {
|
||||||
@ -40,14 +40,14 @@ export default env => {
|
|||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": path.resolve(__dirname, "src"),
|
'@': path.resolve(__dirname, 'src'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
open: true,
|
open: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api": {
|
'/api': {
|
||||||
target: "http://dev.erp.com", // 后端接口的域名
|
target: 'http://dev.erp.com', // 后端接口的域名
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -67,8 +67,8 @@ export default env => {
|
|||||||
output: {
|
output: {
|
||||||
// 拆分单独模块
|
// 拆分单独模块
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
"element-plus": ["element-plus"],
|
'element-plus': ['element-plus'],
|
||||||
mockjs: ["mockjs"],
|
mockjs: ['mockjs'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user