This commit is contained in:
huzhushan 2021-04-19 18:50:34 +08:00
parent 33fda82dd9
commit bbf03e66fb
53 changed files with 719 additions and 726 deletions

View File

@ -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
}
]
}, },
}; };

View File

@ -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%",

View File

@ -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
};

View File

@ -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',
}); });
}; };

View File

@ -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',
}); });
}; };

View File

@ -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 [];
},
}, },
// KeyelementUItablerow-key // KeyelementUItablerow-key
rowKey: { rowKey: {
type: String, type: String,
default: "id", default: 'id',
}, },
// false // false
pagination: { pagination: {
@ -317,18 +315,18 @@ export default defineComponent({
// //
// 1transformtransform // 1transformtransform
// 2name // 2name
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>

View File

@ -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,

View File

@ -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';

View File

@ -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() {

View File

@ -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,

View File

@ -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>

View File

@ -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;

View File

@ -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,
}, },

View File

@ -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 {

View File

@ -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);
} };

View File

@ -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,
}; };
} };

View File

@ -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,
} };
} };

View File

@ -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();
}; };

View File

@ -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; // 使useRoutewatch const route = router.currentRoute; // 使useRoutewatch
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);
}); });

View File

@ -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,

View File

@ -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,

View File

@ -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: {

View File

@ -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)
// } // }
// }) // })
};
}

View File

@ -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,

View File

@ -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');

View File

@ -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 };
} }
} }
}) });

View File

@ -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 };
} }
}, },
}); });

View File

@ -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');
}
}, },
] },
];

View File

@ -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,
}
}
]
}, },
},
] ],
},
];

View File

@ -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,
} },
] ];

View File

@ -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,
} },
] ],
} },
] ];

View File

@ -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'],
}, },
}
]
}, },
] ],
} },
] ],
},
];

View File

@ -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,
}, },
}); });

View File

@ -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);
}
} }
}, },
},
}; };

View File

@ -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: {},

View File

@ -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)
// } // }
},
}
}, },
}; };

View File

@ -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,
} };

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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;

View File

@ -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>

View File

@ -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(); // ctxvue2this const { ctx } = getCurrentInstance(); // ctxvue2this
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);
} }

View File

@ -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>

View File

@ -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", // namename name: 'test-cache', // namename
setup() { setup() {
console.log("cache"); console.log('cache');
onActivated(() => { onActivated(() => {
console.log("onActivated"); console.log('onActivated');
}); });
}, },
}); });

View File

@ -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", // namenamename name: 'test-no-cache', // namenamename
setup() { setup() {
console.log("nocache"); console.log('nocache');
}, },
}); });
</script> </script>

View File

@ -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,

View File

@ -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'],
}, },
}, },
}, },