Commit 50688879 authored by “yiyousong”'s avatar “yiyousong”

feat: 添加动态菜单

parent 5beea730
#开发环境
NODE_ENV = "development"
VUE_APP_API_BASE_URL=http://192.168.0.98:11078
# VUE_APP_API_BASE_URL=http://192.168.0.98:11078
VUE_APP_API_BASE_URL=http://192.168.0.250:11078
......@@ -10,6 +10,7 @@
"dependencies": {
"@ianwalter/vuex-reset": "^4.3.4",
"@jiaminghi/data-view": "^2.10.0",
"@riophae/vue-treeselect": "^0.4.0",
"axios": "^1.4.0",
"core-js": "^3.8.3",
"crypto-js": "^4.1.1",
......
......@@ -227,6 +227,15 @@ export const addRoleResource = (data) => {
});
};
// 添加角色菜单
export const addRoleMenu = (data) => {
return request({
url: `/bill/role/auth/distributionMenu`,
method: "post",
data,
});
};
/**
* 用户管理
*/
......@@ -347,3 +356,12 @@ export const changeMenuSort = (data) => {
data,
});
};
// 获取菜单树列表
export const getMenuTreeselect = (data) => {
return request({
url: `/bill/menu/treeselect`,
method: "post",
data,
});
};
<template>
<div class="flex h-full w-full flex-col bg-white">
<el-tabs :value="activeKey" @tab-click="changeRouter">
<el-tab-pane v-for="v in secondaryRoutes" :key="v.path" :name="v.path">
<template slot="label">
<i
v-if="v.meta.icon"
:class="['mr-[5px]', 'primary', v.meta.icon]"
></i>
<span class="tab-label">{{ v.meta.title }}</span>
</template>
</el-tab-pane>
</el-tabs>
<div class="flex-1 overflow-y-auto p-[15px]">
<router-view></router-view>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "TabMenuBar",
data() {
return {
subMenus: [],
};
},
computed: {
...mapGetters("user", ["secondaryRoutes"]),
activeKey() {
return this.$route.path;
},
},
created() {},
methods: {
changeRouter(e) {
this.$router.push(e.name);
},
},
};
</script>
<style lang="less" scoped></style>
......@@ -3,8 +3,8 @@ import store from "@/store";
export const permission = {
inserted: function (el, binding) {
const { value } = binding;
const roles = store.getters["user/userId"];
if (value) {
const roles = store.getters["user/userInfo"].id;
if (value && value instanceof Array && value.length > 0) {
const permissionRoles = value;
const hasPermission = permissionRoles.includes(roles);
if (!hasPermission) {
......@@ -15,3 +15,25 @@ export const permission = {
}
},
};
// 按钮鉴权
export const hasPermi = {
inserted: function (el, binding) {
const { value } = binding;
const permissions = store.getters["user/permissions"];
if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value;
const hasPermissions = permissions.some((permission) => {
return permissionFlag.includes(permission);
});
if (!hasPermissions) {
el.remove();
}
} else {
throw new Error(`请设置操作权限标签值`);
}
},
};
......@@ -17,8 +17,7 @@
:default-active="activeMenu"
mode="horizontal"
router
text-color="rgba(254, 254, 254, 0.65)"
background-color="#0000"
@select="selectMenu"
>
<template v-for="v in menus">
<el-submenu
......@@ -55,7 +54,7 @@
<script>
import HeaderSite from "./HeaderSite.vue";
import { mapState } from "vuex";
import { mapState, mapActions } from "vuex";
export default {
components: {
HeaderSite,
......@@ -75,20 +74,57 @@ export default {
}
return path;
},
...mapState("user", ["menus", "sysName", "sysLogo", "path"]),
...mapState("user", ["menus", "sysName", "sysLogo", "path", "menus"]),
},
created() {
document.title = this.sysName ? this.sysName : this.systemName; // 设置项目标题
},
methods: {
...mapActions("user", ["setSecondaryRoutes"]),
selectMenu(index) {
this.setSecondaryRoutes(index);
},
handleGoHome() {
this.$router.push("/home");
let path = this.menus[0].path;
this.$router.push(path);
},
},
};
</script>
<style lang="less">
.el-menu--popup {
.el-menu-item {
display: flex;
align-items: center;
&:hover {
color: var(--primary) !important;
i {
color: var(--primary);
}
}
}
.is-active {
color: var(--primary) !important;
}
}
</style>
<style lang="less" scoped>
@text-color: #fefefea5;
.mixins(@l,@t) {
content: "";
display: inline-block;
height: 4px;
width: 30%;
background: #ffffff;
border-radius: 2px;
position: absolute;
bottom: 0px;
left: @l;
transform: translateX(@t);
}
.header {
height: 72px;
width: 100%;
......@@ -136,49 +172,67 @@ export default {
:deep(.el-menu) {
height: 100% !important;
border: none !important;
background: #0000;
.el-menu-item {
.el-menu-item:not(.el-submenu) {
height: 100%;
font-size: 16px;
color: #fff;
display: flex;
align-items: center;
border: none !important;
letter-spacing: 1px;
color: @text-color;
i {
color: #fff;
// color: #fff;
color: @text-color;
}
&:hover {
background: #0000 !important;
color: @text-color !important;
&::after {
content: "";
display: inline-block;
height: 4px;
width: 30%;
background: #ffffff;
border-radius: 2px;
position: absolute;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
.mixins(50%,-50%);
}
}
}
.is-active {
.el-submenu {
height: 100%;
font-size: 16px;
.el-submenu__title {
height: 100%;
display: flex;
font-size: 16px;
align-items: center;
border: none !important;
color: @text-color;
&:hover {
background: #0000 !important;
color: #fff !important;
&::after {
.mixins(calc(50% - 20px),-(50% - 20px));
}
}
}
.el-submenu__icon-arrow {
color: @text-color;
}
}
.is-active:not(.el-submenu),
.is-active .el-submenu__title {
color: #fff !important;
background: #0000 !important;
font-weight: 600;
i {
color: #fff;
}
&::after {
content: "";
display: inline-block;
height: 4px;
width: 30%;
background: #ffffff;
border-radius: 2px;
position: absolute;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
.mixins(50%,-50%);
}
}
.is-active .el-submenu__title {
&::after {
left: calc(50% - 20px);
transform: translateX(-(50% - 20px));
}
}
}
......
......@@ -4,19 +4,19 @@
<div class="tab-box flex items-end gap-5">
<router-link
:class="['tab-item', 'top-radius']"
to="/engine/queueupsystem"
v-for="item in secondaryRoutes"
:key="item.path"
:to="item.path"
>
排队取号系统
</router-link>
<router-link
:class="['tab-item', 'top-radius']"
to="/engine/evaluatesystem"
>
评价系统
<i v-if="item.meta.icon" :class="['mr-2', item.meta.icon]"></i>
{{ item.meta.title }}
</router-link>
</div>
<div class="flex gap-5">
<div class="search-box top-radius flex h-full items-center gap-5">
<div
class="search-box top-radius flex h-full items-center gap-5"
v-hasPermi="['engine:query']"
>
<div class="text-[14px] text-[#395EBF]">
统计时段:{{ time[0] }}~{{ time[1] }}
</div>
......@@ -35,6 +35,7 @@
<div
class="engine-btn top-radius"
@click="$router.push('/enginesearch')"
v-hasPermi="['engine:enginesearch']"
>
<img src="@/assets/img/engine.png" class="engine-img mr-2 w-[24px]" />
数据搜索引擎
......@@ -48,6 +49,7 @@
</template>
<script>
import { mapGetters } from "vuex";
export default {
data() {
return {
......@@ -64,6 +66,9 @@ export default {
});
},
},
computed: {
...mapGetters("user", ["secondaryRoutes"]),
},
created() {
this.$nextTick(() => {
this.handleDate();
......
......@@ -13,6 +13,7 @@
:loading="hallLoading"
type="hall"
@export="exportHallEva"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......@@ -37,6 +38,8 @@
type="pjOption"
@export="exportPjOptionEva"
@search="handleSearch"
hasPermiQuery="engine:queueupsystem:query"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......@@ -61,6 +64,8 @@
type="dept"
@export="exportDeptEva"
@search="handleSearch"
hasPermiQuery="engine:queueupsystem:query"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......@@ -85,6 +90,8 @@
type="window"
@export="exportWindowEva"
@search="handleSearch"
hasPermiQuery="engine:queueupsystem:query"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......
......@@ -13,6 +13,7 @@
:loading="hallLoading"
type="hall"
@export="exportHallQueue"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......@@ -37,6 +38,8 @@
type="business"
@export="exportbusinessQueue"
@search="handleSearch"
hasPermiQuery="engine:queueupsystem:query"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......@@ -61,6 +64,8 @@
type="dept"
@export="exportDeptQueue"
@search="handleSearch"
hasPermiQuery="engine:queueupsystem:query"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......@@ -85,6 +90,8 @@
type="window"
@export="exportWindowQueue"
@search="handleSearch"
hasPermiQuery="engine:queueupsystem:query"
hasPermiExport="engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
......
......@@ -5,7 +5,11 @@
{{ title }}
</div>
<div class="flex gap-4">
<el-button type="primary" size="small" @click="handleExport"
<el-button
type="primary"
size="small"
@click="handleExport"
v-hasPermi="[hasPermiExport]"
>导出</el-button
>
......@@ -16,6 +20,7 @@
v-model="form.pjOption"
placeholder="请选择评价选项"
clearable
v-hasPermi="[hasPermiQuery]"
>
<el-option
v-for="(v, i) in dict.pjOption"
......@@ -32,6 +37,7 @@
v-model="form.businessName"
placeholder="请选择业务"
clearable
v-hasPermi="[hasPermiQuery]"
>
<el-option
v-for="(v, i) in getTopKeyList(dict.businessList)"
......@@ -48,6 +54,7 @@
v-model="form.deptName"
placeholder="请选择部门"
clearable
v-hasPermi="[hasPermiQuery]"
>
<el-option
v-for="(v, i) in getTopKeyList(dict.sectionNameList)"
......@@ -64,6 +71,7 @@
v-model="form.windowNum"
placeholder="请选择窗口"
clearable
v-hasPermi="[hasPermiQuery]"
>
<el-option
v-for="(v, i) in getTopKeyList(dict.windowFromnumList)"
......@@ -78,6 +86,7 @@
size="small"
v-if="type != 'hall'"
@click="handleSearch"
v-hasPermi="[hasPermiQuery]"
>搜索</el-button
>
</div>
......@@ -153,6 +162,12 @@ export default {
type: Object,
default: () => {},
},
hasPermiQuery: {
type: String,
},
hasPermiExport: {
type: String,
},
},
data() {
return {
......
......@@ -8,6 +8,7 @@
size="small"
:loading="exportLoading"
@click="exportExcel"
v-hasPermi="['market:evaluatereport:export']"
>导出</el-button
>
<div class="text-[#909399]">
......@@ -17,7 +18,10 @@
统计时间段:{{ searchForm.time[0] }} ~ {{ searchForm.time[1] }}
</div>
</div>
<div class="flex items-center">
<div
class="flex items-center"
v-hasPermi="['market:evaluatereport:query']"
>
<el-form ref="searchForm" inline size="small" :model="searchForm">
<el-form-item>
<el-select style="width: 130px" v-model="searchForm.type">
......@@ -52,7 +56,11 @@
</el-form-item>
</el-form>
</div>
<el-popover placement="bottom" trigger="click">
<el-popover
placement="bottom"
trigger="click"
v-hasPermi="['market:evaluatereport:query']"
>
<div class="w-full">
<el-form ref="searchForm2" inline size="small" :model="searchForm2">
<el-form-item>
......
......@@ -10,7 +10,7 @@
</div>
<div class="flex h-full flex-1 flex-col bg-white">
<el-tabs :value="activeKey" @tab-click="changeRouter">
<el-tab-pane v-for="v in subMenus" :key="v.path" :name="v.path">
<el-tab-pane v-for="v in secondaryRoutes" :key="v.path" :name="v.path">
<template slot="label">
<i
v-if="v.meta.icon"
......@@ -28,37 +28,25 @@
</template>
<script>
import { findBottomSubarrays } from "@/utils";
import { mapGetters } from "vuex";
export default {
data() {
return {
subMenus: [],
curTreeData: {}, // 当前选择的站点
};
},
computed: {
...mapGetters("user", ["secondaryRoutes"]),
activeKey() {
return this.$route.path;
},
},
created() {
this.getSubMenus();
},
created() {},
methods: {
changeRouter(e) {
this.$router.push(e.name);
},
// 获取当前顶层路由下的所有子路由
getSubMenus() {
let path = this.$route?.meta.activeMenu
? this.$route.meta.activeMenu
: this.$route.path;
let options = this.$router.options.routes[0].children;
let curRouters = options.filter((v) => v.path == path);
this.subMenus = findBottomSubarrays(curRouters).filter(
(v) => !v.meta.hidden
);
},
// 改变站点选择
changeSite(data) {
this.curTreeData = data;
......
......@@ -8,6 +8,7 @@
size="small"
:loading="exportLoading"
@click="exportExcel"
v-hasPermi="['market:queueupreport:export']"
>导出</el-button
>
<div class="text-[#909399]">
......@@ -17,7 +18,10 @@
统计时间段:{{ searchForm.time[0] }} ~ {{ searchForm.time[1] }}
</div>
</div>
<div class="flex items-center">
<div
class="flex items-center"
v-hasPermi="['market:queueupreport:query']"
>
<el-form ref="searchForm" inline size="small" :model="searchForm">
<el-form-item>
<el-select style="width: 130px" v-model="searchForm.type">
......@@ -52,7 +56,11 @@
</el-form-item>
</el-form>
</div>
<el-popover placement="bottom" trigger="click">
<el-popover
placement="bottom"
trigger="click"
v-hasPermi="['market:queueupreport:query']"
>
<div class="w-full">
<el-form ref="searchForm2" inline size="small" :model="searchForm2">
<!-- <el-form-item>
......
......@@ -7,9 +7,14 @@
<script>
import storage from "@/utils/storage";
import { mapMutations } from "vuex";
import { getHomeData } from "@/api/home";
import { generateRoutes, filterBtn } from "@/utils";
import { calcMenu } from "@/router";
export default {
data() {
return {};
return {
menuList: [],
};
},
created() {
this.getToken();
......@@ -21,9 +26,12 @@ export default {
"SET_sysLogo",
"SET_path",
"SET_userInfo",
"SET_permissions",
"SET_routes",
"SET_menusList",
]),
// 获取token
getToken() {
async getToken() {
let { token, userInfo, siteid, siteName, sysName, sysLogo, path } =
this.$route.query;
if (token && userInfo) {
......@@ -35,7 +43,7 @@ export default {
this.SET_path(path);
storage.set(2, "siteId", siteid);
storage.set(2, "siteName", siteName);
this.$router.push("/home");
await this.getIndixData();
} else {
this.$message.warning("跳转失败,请重新登录");
setTimeout(() => {
......@@ -43,6 +51,32 @@ export default {
}, 2000);
}
},
// 获取菜单列表
async getIndixData() {
let res = await getHomeData();
if (res.data.code == 1) {
let { menuList } = res.data.data;
// 过滤掉按钮
let menus = filterBtn(menuList, false);
let routes = generateRoutes(menus);
// this.SET_routes(routes);
this.SET_menusList(menus);
this.setBtnPermissions(menuList);
calcMenu();
if (routes.length) {
let path = routes[0].path;
this.$router.push(path);
}
}
},
// 添加按钮权限字符
setBtnPermissions(menuList) {
let btnPermissions = filterBtn(menuList)
.filter((v) => v.perms)
.map((v) => v.perms);
this.SET_permissions(btnPermissions);
},
},
};
</script>
......
<template>
<div class="system flex flex-col bg-white">
<el-tabs :value="activeKey" @tab-click="changeRouter">
<el-tab-pane v-for="v in subMenus" :key="v.path" :name="v.path">
<template slot="label">
<i
v-if="v.meta.icon"
:class="['mr-[5px]', 'primary', v.meta.icon]"
></i>
<span class="tab-label">{{ v.meta.title }}</span>
</template>
</el-tab-pane>
</el-tabs>
<div class="system-out-box flex-1">
<router-view></router-view>
</div>
<div class="system">
<TabMenuBar></TabMenuBar>
</div>
</template>
<script>
import { findBottomSubarrays } from "@/utils";
export default {
data() {
return {
subMenus: [],
};
},
computed: {
activeKey() {
return this.$route.path;
},
},
created() {
this.getSubMenus();
},
methods: {
changeRouter(e) {
this.$router.push(e.name);
},
// 获取当前顶层路由下的所有子路由
getSubMenus() {
let path = this.$route?.meta.activeMenu
? this.$route.meta.activeMenu
: this.$route.path;
let options = this.$router.options.routes[0].children;
let curRouters = options.filter((v) => v.path == path);
this.subMenus = findBottomSubarrays(curRouters).filter(
(v) => !v.meta.hidden
);
},
},
computed: {},
created() {},
methods: {},
};
</script>
<style lang="less" scoped>
// :deep(.el-tabs__nav-scroll) {
// padding-left: 15px;
// }
.system {
width: 100%;
height: 100%;
.system-out-box {
padding: 15px;
overflow-y: auto;
}
}
</style>
<template>
<div>
<el-popover placement="bottom-start" trigger="click">
<el-popover placement="bottom-start" trigger="click" width="100%">
<el-tree
:data="treeData"
:props="defaultProps"
......@@ -20,11 +19,11 @@
@clear="handleClear"
></el-input>
</el-popover>
</div>
</template>
<script>
export default {
name: "InputTree",
props: {
treeData: {
type: Array,
......@@ -35,15 +34,19 @@ export default {
value: {
default: "",
},
},
data() {
return {
defaultProps: {
type: Object,
default: () => {
return {
children: "children",
label: "areaName",
},
};
},
},
},
data() {
return {};
},
methods: {
handleClear() {
this.$emit("input", "");
......
......@@ -107,7 +107,7 @@ export default {
{
label: "菜单名称",
prop: "name",
align: "center",
// align: "center",
},
{
label: "ID",
......@@ -242,7 +242,7 @@ export default {
this.current -= 1;
this.getMenuList();
}
this.menuList = [...this.menuList, ...data];
this.menuList = [...this.menuList, ...buildTree(data)];
this.tableData = buildTree(data);
this.total = total;
this.dict = dict;
......
......@@ -4,7 +4,7 @@
:title="title"
:destroy-on-close="true"
:visible.sync="Visible"
width="610px"
width="650px"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
......@@ -14,31 +14,44 @@
:model="form"
:rules="rules"
size="small"
label-width="100px"
label-width="130px"
>
<el-form-item label="父级菜单" prop="parentId">
<treeselect
v-model="form.parentId"
:options="menuList"
:normalizer="normalizer"
:show-count="true"
placeholder="选择父级菜单"
/>
</el-form-item>
<el-form-item label="菜单类型" prop="menuType">
<el-radio-group v-model="form.menuType">
<el-radio
v-for="(item, key) in dict.menuType"
:key="key"
:label="Number(key)"
>{{ item }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单名称" prop="name">
<el-input
placeholder="请输入系统名称"
placeholder="请输入菜单名称"
v-model="form.name"
clearable
></el-input>
</el-form-item>
<el-form-item label="父级菜单" prop="parentId">
<el-select
clearable
v-model="form.parentId"
placeholder="请选择父级菜单"
>
<el-option
v-for="item in menuList"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
<el-form-item label="菜单图标" prop="imgPath" v-if="form.menuType != 2">
<IconSelect v-model="form.imgPath"></IconSelect>
</el-form-item>
<el-form-item label="权限类型" prop="authType">
<el-form-item
label="权限类型"
prop="authType"
v-if="form.menuType != 2"
>
<el-select
clearable
v-model="form.authType"
......@@ -53,24 +66,124 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item label="访问地址" prop="url">
<el-form-item prop="url" v-if="form.menuType != 2">
<span slot="label">
<el-tooltip content="访问的路由地址,如:`system`" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
路由地址
</span>
<el-input
clearable
placeholder="请输入菜单访问地址"
placeholder="请输入菜单路由地址"
v-model="form.url"
></el-input>
</el-form-item>
<el-form-item label="类型" prop="menuType">
<el-radio-group v-model="form.menuType">
<el-form-item prop="component" v-if="form.menuType != 2">
<span slot="label">
<el-tooltip
content="访问的组件路径,如:`system/menu/Menu`,默认在`pages`目录下"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
组件路径
</span>
<el-input
clearable
placeholder="请输入组件路径"
v-model="form.component"
></el-input>
</el-form-item>
<el-form-item prop="activeDir" v-if="form.menuType != 2">
<span slot="label">
<el-tooltip content="顶部菜单栏激活路由" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
激活菜单
</span>
<el-input
clearable
placeholder="请输入激活菜单地址"
v-model="form.activeDir"
></el-input>
</el-form-item>
<el-form-item prop="perms" v-if="form.menuType == 2">
<span slot="label">
<el-tooltip
content="控制器中定义的权限字符,如:'system:menu:add'"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
权限字符
</span>
<el-input
clearable
placeholder="请输入权限字符"
v-model="form.perms"
></el-input>
</el-form-item>
<el-row>
<el-col :span="12" v-if="form.menuType != 2">
<el-form-item prop="visible">
<span slot="label">
<el-tooltip
content="控制路由和子路由是否显示在菜单栏"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
显示状态
</span>
<el-radio-group v-model="form.visible">
<el-radio
v-for="(item, key) in dict.menuType"
v-for="(item, key) in dict.visible"
:key="key"
:label="Number(key)"
>{{ item }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item label="状态" prop="status">
</el-col>
<el-col :span="12" v-if="form.menuType != 2">
<el-form-item prop="cache">
<span slot="label">
<el-tooltip
content="选择是则会被`keep-alive`缓存"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
是否缓存
</span>
<el-radio-group v-model="form.cache">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" v-if="form.menuType != 2">
<el-form-item prop="hideChildrenInMenu">
<span slot="label">
<el-tooltip
content="强制菜单显示为Item而不是SubItem"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
是否隐藏子菜单
</span>
<el-radio-group v-model="form.hideChildrenInMenu">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="(item, key) in dict.status"
......@@ -80,35 +193,8 @@
>
</el-radio-group>
</el-form-item>
<el-form-item label="图标" prop="imgPath">
<IconSelect v-model="form.imgPath"></IconSelect>
<!-- <div class="icon-box grid grid-cols-2 gap-1">
<div
:class="[
'icon-item',
'cursor-pointer',
{ active: form.imgPath == '' },
]"
@click="form.imgPath = ''"
>
不需要图标
</div>
<div
:class="[
'icon-item',
'cursor-pointer',
{ active: form.imgPath == v },
]"
v-for="(v, i) in iconJson"
:key="i"
@click="form.imgPath = v"
>
<i :class="v"></i>
<span class="ml-2">{{ v }}</span>
</div>
</div> -->
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="handleRest">重 置</el-button>
......@@ -124,9 +210,12 @@
import { saveMenu } from "@/api/system";
import IconSelect from "./IconSelect.vue";
import iconJson from "@/assets/icon.json";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
components: {
IconSelect,
Treeselect,
},
props: {
title: {
......@@ -153,20 +242,40 @@ export default {
data() {
return {
iconJson,
defaultProps: {
children: "childList",
label: "name",
},
form: {
name: "",
parentId: 0,
menuType: 0,
status: 1,
url: "",
authType: "",
imgPath: "",
name: "", // 菜单名称
url: "", // 路由地址
ancestors: "", // 当前激活根目录
parentId: 0, // 父菜单ID,一级菜单的该字段值为-1
linkType: 0, // 链接方式 (0.普通,1.弹出,2.脚本)
imgPath: "", // 主菜单图标,主菜单图标的css样式名
buttonImgPath: "", // 按钮图标,按钮图标的css样式名
imgCommPath: "", // 常用菜单图标,常用菜单图标的css样式名
commMenu: 1, // 是否常用菜单 (0.非常用,1.常用)
component: "", // vue组件路径
menuType: 0, // 菜单类型 (0.目录,1.菜单,2.按钮)
authType: 0, // 权限类型 (0.无限制,1.无需登录查看,2.需要登录查看,3.需要角色权限查看)
visible: 0, // 菜单显示状态 (0.显示,1.隐藏)
perms: "", // 权限标识,多个逗号分割
remark: "", // 备注信息
orderId: "", // 排序编号
status: 1, // 菜单状态 (0.停用,1.启用)
cache: 0, // 是否缓存
activeDir: "", // 激活菜单
hideChildrenInMenu: 1, // 是否隐藏子菜单
},
rules: {
name: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
url: [
{ required: true, message: "请输入菜单访问地址", trigger: "blur" },
],
component: [
{ required: true, message: "请输入组件路径", trigger: "blur" },
],
authType: [
{ required: true, message: "请输入选择权限类型", trigger: "change" },
],
......@@ -218,6 +327,20 @@ export default {
this.$resetForm("form");
this.Visible = false;
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.childList && !node.childList.length) {
delete node.childList;
}
return {
id: node.id,
label: node.name,
children: node.childList,
};
},
changeParent(row) {
console.log(row);
},
},
};
</script>
......@@ -230,7 +353,4 @@ export default {
:deep(.el-select) {
width: 100%;
}
.active {
color: var(--primary);
}
</style>
......@@ -3,12 +3,6 @@
<div
class="content grid max-h-[300px] w-full grid-cols-2 gap-x-4 gap-y-2 overflow-auto"
>
<div
:class="['cursor-pointer indent-8', { active: value === '' }]"
@click="handleChange('')"
>
不需要图标
</div>
<div v-for="(v, i) in iconJson" :key="i">
<div
:class="[
......@@ -30,8 +24,8 @@
v-bind="$attrs"
v-on="$listeners"
:value="value"
readonly
:placeholder="placeholder"
clearable
>
<i v-if="value" slot="prefix" :class="value" />
<i v-else slot="prefix" class="el-icon-search" />
......
......@@ -2,6 +2,7 @@ import Vue from "vue";
import VueRouter from "vue-router";
import Layouts from "@/layouts/Layouts.vue";
import store from "@/store";
import { generateRoutes } from "@/utils";
// import local from "@/utils/local";
// 解决重复点击同一个路由报错
const originalPush = VueRouter.prototype.push;
......@@ -9,62 +10,53 @@ VueRouter.prototype.push = function (location) {
return originalPush.call(this, location).catch((err) => err);
};
Vue.use(VueRouter);
/**
* Route 对象配置:
* hidden:控制路由是否显示在在菜单
* hideChildrenInMenu:强制菜单显示为Item而不是SubItem
* meta对象配置:
* title:标题
* keepAlive:缓存该路由
* activeMenu:当前的激活路由
* icon:图标
* hidden:控制路由是否显示在在菜单
*/
const routes = [
{
path: "/",
name: "/",
component: Layouts,
redirect: "/sso",
children: [
{
path: "/home",
hideChildrenInMenu: true,
component: () => import("@/pages/home/Home"),
meta: {
title: "数仓工作台",
},
},
{
path: "/engine",
hideChildrenInMenu: true,
component: () => import("@/pages/engine/Engine"),
meta: {
title: "数据引擎",
},
redirect: "/engine/queueupsystem",
children: [
{
path: "/engine/queueupsystem",
hideChildrenInMenu: true,
hidden: true,
component: () => import("@/pages/engine/QueueUpSystem"),
meta: {
title: "排队取号系统",
activeMenu: "/engine",
},
},
{
path: "/engine/evaluatesystem",
hideChildrenInMenu: true,
hidden: true,
component: () => import("@/pages/engine/EvaluateSystem"),
meta: {
title: "评价系统",
activeMenu: "/engine",
},
},
],
},
// {
// path: "/home",
// hideChildrenInMenu: true,
// component: () => import("@/pages/home/Home"),
// meta: {
// title: "数仓工作台",
// },
// },
// {
// path: "/engine",
// hideChildrenInMenu: true,
// component: () => import("@/pages/engine/Engine"),
// meta: {
// title: "数据引擎",
// },
// redirect: "/engine/queueupsystem",
// children: [
// {
// path: "/engine/queueupsystem",
// hideChildrenInMenu: true,
// hidden: true,
// component: () => import("@/pages/engine/QueueUpSystem"),
// meta: {
// title: "排队取号系统",
// activeMenu: "/engine",
// },
// },
// {
// path: "/engine/evaluatesystem",
// hideChildrenInMenu: true,
// hidden: true,
// component: () => import("@/pages/engine/EvaluateSystem"),
// meta: {
// title: "评价系统",
// activeMenu: "/engine",
// },
// },
// ],
// },
// 数据搜索引擎
{
path: "/enginesearch",
......@@ -97,133 +89,133 @@ const routes = [
],
},
{
path: "/market",
name: "market",
hideChildrenInMenu: true,
component: () => import("@/pages/market/Market"),
meta: {
title: "数据集市",
},
redirect: "/market/queueupreport",
children: [
{
path: "/market/queueupreport",
name: "queueupreport",
hideChildrenInMenu: true,
component: () => import("@/pages/market/QueueUpReport"),
meta: {
title: "排队数据报表",
activeMenu: "/market",
icon: "el-icon-guide",
},
},
{
path: "/market/evaluatereport",
name: "evaluatereport",
hideChildrenInMenu: true,
component: () => import("@/pages/market/EvaluateReport"),
meta: {
title: "评价数据报表",
activeMenu: "/market",
icon: "el-icon-collection",
},
},
],
},
{
path: "/system",
hideChildrenInMenu: true,
component: () => import("@/pages/system/System"),
meta: {
title: "系统设置",
},
redirect: "/system/access",
children: [
{
path: "/system/access",
component: () => import("@/pages/system/access/Access.vue"),
meta: {
activeMenu: "/system",
title: "区县接入",
icon: "el-icon-set-up",
},
},
// {
// path: "/system/areasystem",
// component: () => import("@/pages/system/areaSystem/AreaSystem.vue"),
// path: "/market",
// name: "market",
// hideChildrenInMenu: true,
// component: () => import("@/pages/market/Market"),
// meta: {
// title: "数据集市",
// },
// redirect: "/market/queueupreport",
// children: [
// {
// path: "/market/queueupreport",
// name: "queueupreport",
// hideChildrenInMenu: true,
// component: () => import("@/pages/market/QueueUpReport"),
// meta: {
// title: "排队数据报表",
// activeMenu: "/market",
// icon: "el-icon-guide",
// },
// },
// {
// path: "/market/evaluatereport",
// name: "evaluatereport",
// hideChildrenInMenu: true,
// component: () => import("@/pages/market/EvaluateReport"),
// meta: {
// title: "评价数据报表",
// activeMenu: "/market",
// icon: "el-icon-collection",
// },
// },
// ],
// },
// {
// path: "/system",
// hideChildrenInMenu: true,
// component: () => import("@/pages/system/System"),
// meta: {
// title: "系统设置",
// },
// redirect: "/system/access",
// children: [
// {
// path: "/system/access",
// component: () => import("@/pages/system/access/Access.vue"),
// meta: {
// activeMenu: "/system",
// title: "区县系统",
// icon: "el-icon-monitor",
// title: "区县接入",
// icon: "el-icon-set-up",
// },
// },
{
path: "/system/user",
component: () => import("@/pages/system/user/User.vue"),
meta: {
activeMenu: "/system",
title: "用户信息",
icon: "el-icon-user",
},
},
{
path: "/system/role",
component: () => import("@/pages/system/role/Role.vue"),
meta: {
activeMenu: "/system",
title: "角色信息",
icon: "el-icon-postcard",
},
},
{
path: "/system/resourcemanage",
component: () =>
import("@/pages/system/resourceManage/ResourceManage.vue"),
meta: {
activeMenu: "/system",
title: "资源信息",
icon: "el-icon-box",
},
},
{
path: "/system/menu",
component: () => import("@/pages/system/menu/Menu.vue"),
meta: {
activeMenu: "/system",
title: "菜单管理",
icon: "el-icon-guide",
},
},
{
path: "/system/parameter",
component: () => import("@/pages/system/parameter/Parameter.vue"),
meta: {
activeMenu: "/system",
title: "系统参数",
icon: "el-icon-cpu",
},
},
{
path: "/system/task",
component: () => import("@/pages/system/task/TaskSet.vue"),
meta: {
activeMenu: "/system",
title: "任务信息",
icon: "el-icon-bank-card",
},
},
{
path: "/system/systemlogs",
component: () => import("@/pages/system/systemlogs/SystemLogs.vue"),
meta: {
activeMenu: "/system",
title: "系统日志",
icon: "el-icon-notebook-1",
},
},
],
},
// // {
// // path: "/system/areasystem",
// // component: () => import("@/pages/system/areaSystem/AreaSystem.vue"),
// // meta: {
// // activeMenu: "/system",
// // title: "区县系统",
// // icon: "el-icon-monitor",
// // },
// // },
// {
// path: "/system/user",
// component: () => import("@/pages/system/user/User.vue"),
// meta: {
// activeMenu: "/system",
// title: "用户信息",
// icon: "el-icon-user",
// },
// },
// {
// path: "/system/role",
// component: () => import("@/pages/system/role/Role.vue"),
// meta: {
// activeMenu: "/system",
// title: "角色信息",
// icon: "el-icon-postcard",
// },
// },
// {
// path: "/system/resourcemanage",
// component: () =>
// import("@/pages/system/resourceManage/ResourceManage.vue"),
// meta: {
// activeMenu: "/system",
// title: "资源信息",
// icon: "el-icon-box",
// },
// },
// {
// path: "/system/menu",
// component: () => import("@/pages/system/menu/Menu.vue"),
// meta: {
// activeMenu: "/system",
// title: "菜单管理",
// icon: "el-icon-guide",
// },
// },
// {
// path: "/system/parameter",
// component: () => import("@/pages/system/parameter/Parameter.vue"),
// meta: {
// activeMenu: "/system",
// title: "系统参数",
// icon: "el-icon-cpu",
// },
// },
// {
// path: "/system/task",
// component: () => import("@/pages/system/task/TaskSet.vue"),
// meta: {
// activeMenu: "/system",
// title: "任务信息",
// icon: "el-icon-bank-card",
// },
// },
// {
// path: "/system/systemlogs",
// component: () => import("@/pages/system/systemlogs/SystemLogs.vue"),
// meta: {
// activeMenu: "/system",
// title: "系统日志",
// icon: "el-icon-notebook-1",
// },
// },
// ],
// },
],
},
{
......@@ -277,10 +269,12 @@ function menusFilter(arr) {
}
// 动态菜单
export function calcMenu() {
// dynamicRouter.forEach((v) => {
// router.addRoute(v);
// });
let menus = menusFilter(routes[0].children);
let menusList = store.getters["user/menusList"];
let dynamicRouter = generateRoutes(menusList);
dynamicRouter.forEach((v) => {
router.addRoute("/", v);
});
let menus = menusFilter(dynamicRouter);
store.commit("user/SET_menus", menus);
}
calcMenu();
......
import { getSiteBusiness, getDepartment, getWindow } from "@/api/site";
import { getHomeData } from "@/api/home";
import { findInTree } from "@/utils";
export default {
namespaced: true,
state: {
menus: [], // 菜单
menusList: [], // 原始菜单列表
menus: [], // 格式化菜单列表
routes: [], // 路由列表
secondaryRoutes: [], // 二级路由
barList: [], // 登录返回菜单
homeData: {}, // 首页数据
token: "",
......@@ -16,6 +20,7 @@ export default {
businessList: [], // 站点业务列表
deptList: [], // 站点部门列表
windowList: [], // 站点窗口列表
permissions: [], // 按钮权限字符列表
},
getters: {
siteId(state) {
......@@ -37,8 +42,35 @@ export default {
let { barList } = state.homeData;
return barList || [];
},
routes(state) {
return state.routes;
},
menus(state) {
return state.menus;
},
permissions(state) {
return state.permissions;
},
menusList(state) {
return state.menusList;
},
secondaryRoutes(state) {
return state.secondaryRoutes;
},
},
mutations: {
SET_menusList(state, menusList) {
state.menusList = menusList;
},
SET_routes(state, routes) {
state.routes = routes;
},
SET_permissions(state, permissions) {
state.permissions = permissions;
},
SET_secondaryRoutes(state, secondaryRoutes) {
state.secondaryRoutes = secondaryRoutes;
},
SET_path(state, path) {
state.path = path;
},
......@@ -127,5 +159,11 @@ export default {
context.commit("SET_windowList", data);
}
},
// 设置二级路由
setSecondaryRoutes(context, value) {
let routes = findInTree(context.state.menus, "path", value);
let secondaryRoutes = routes.children || [];
context.commit("SET_secondaryRoutes", secondaryRoutes);
},
},
};
import Vue from "vue";
import CryptoJS from "crypto-js";
import moment from "moment";
import { find, get } from "lodash-es";
// 加密数据
export let encrypt = (str, keyStr, ivStr) => {
......@@ -205,3 +206,95 @@ export const getFieldFromArray = (arr, field, treeField) => {
return result;
};
// 生成路由
export const generateRoutes = (menuList) => {
let routers = menuList.map((item) => {
// 构造符合要求的结构
let path = item.url.charAt(0) === "/" ? item.url : "/" + item.url;
let name = item.url.charAt(0) === "/" ? item.url.slice(1) : item.url;
let activeMenu = item.activeDir
? item.activeDir.charAt(0) === "/"
? item.activeDir
: "/" + item.activeDir
: "";
let component = item.component
? item.component.charAt(0) === "/"
? item.component
: "/" + item.component
: null;
const newItem = {
path,
name,
hidden: !!item.visible,
hideChildrenInMenu: !!item.hideChildrenInMenu,
component: () => import(`@/pages${component}`),
meta: {
title: item.name,
icon: item.imgPath,
keepAlive: !!item.cache,
activeMenu,
},
};
// 递归处理子节点
if (item.children && item.children.length > 0) {
newItem.children = generateRoutes(item.children);
}
return newItem;
});
routers.forEach((v) => {
if (v.children && v.children.length) {
v.redirect = v.children[0].path;
}
});
return routers;
};
/**
* 过滤菜单按钮项并提取 menuType = 2 的项
* @param {Array} menuList - 菜单列表
* @param {Boolean} menuType - true 获取 menuType = 2 的项并返回为一维数组, false 剔除 menuType = 2 的项
* @param {Array} btnItems - 用于存储 menuType = 2 的项(递归使用)
* @returns {Array} - 返回提取到的 menuType = 2 的项(如果 menuType 为 true)或剔除 menuType = 2 的菜单
*/
export const filterBtn = (menuList, menuType = true, btnItems = []) => {
const result = menuList
.map((menu) => {
// 深拷贝对象,避免修改原数据
const newMenu = { ...menu };
if (newMenu.children && newMenu.children.length > 0) {
newMenu.children = filterBtn(newMenu.children, menuType, btnItems);
}
const btnItem = newMenu.menuType == 2;
if (menuType) {
if (btnItem) {
btnItems.push(newMenu);
}
return newMenu;
} else {
// 剔除 menuType = 2 的项
return !btnItem ? newMenu : null;
}
})
.filter((menu) => menu !== null); // 过滤掉 null 项
return menuType ? btnItems : result;
};
export function findInTree(data, key, value) {
// 递归遍历树形结构
function recursiveSearch(nodes) {
return find(nodes, (node) => {
if (get(node, key) === value) {
return true;
}
if (node.children) {
return recursiveSearch(node.children);
}
return false;
});
}
return recursiveSearch(data);
}
......@@ -989,6 +989,13 @@
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.3.1":
version "7.25.6"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.22.5":
version "7.22.5"
resolved "https://registry.npmmirror.com/@babel/template/-/template-7.22.5.tgz"
......@@ -1222,6 +1229,20 @@
resolved "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.21.tgz"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@riophae/vue-treeselect@^0.4.0":
version "0.4.0"
resolved "https://registry.npmmirror.com/@riophae/vue-treeselect/-/vue-treeselect-0.4.0.tgz#0baed5a794cffc580b63591f35c125e51c0df241"
integrity sha512-J4atYmBqXQmiPFK/0B5sXKjtnGc21mBJEiyKIDZwk0Q9XuynVFX6IJ4EpaLmUgL5Tve7HAS7wkiGGSti6Uaxcg==
dependencies:
"@babel/runtime" "^7.3.1"
babel-helper-vue-jsx-merge-props "^2.0.3"
easings-css "^1.0.0"
fuzzysearch "^1.0.3"
is-promise "^2.1.0"
lodash "^4.0.0"
material-colors "^1.2.6"
watch-size "^2.0.0"
"@sideway/address@^4.1.3":
version "4.1.4"
resolved "https://registry.npmmirror.com/@sideway/address/-/address-4.1.4.tgz"
......@@ -2140,7 +2161,7 @@ axios@^1.4.0:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
babel-helper-vue-jsx-merge-props@^2.0.0:
babel-helper-vue-jsx-merge-props@^2.0.0, babel-helper-vue-jsx-merge-props@^2.0.3:
version "2.0.3"
resolved "https://registry.npmmirror.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
integrity sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==
......@@ -3104,6 +3125,11 @@ duplexer@^0.1.2:
resolved "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
easings-css@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/easings-css/-/easings-css-1.0.0.tgz#dde569003bb7a4a0c0b77878f5db3e0be5679c81"
integrity sha512-7Uq7NdazNfVtr0RNmPAys8it0zKCuaqxJStYKEl72D3j4gbvXhhaM7iWNbqhA4C94ygCye6VuyhzBRQC4szeBg==
easy-stack@1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/easy-stack/-/easy-stack-1.0.1.tgz"
......@@ -3684,6 +3710,11 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
fuzzysearch@^1.0.3:
version "1.0.3"
resolved "https://registry.npmmirror.com/fuzzysearch/-/fuzzysearch-1.0.3.tgz#dffc80f6d6b04223f2226aa79dd194231096d008"
integrity sha512-s+kNWQuI3mo9OALw0HJ6YGmMbLqEufCh2nX/zzV5CrICQ/y4AwPxM+6TIiF9ItFCHXFCyM/BfCCmN57NTIJuPg==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz"
......@@ -4173,6 +4204,11 @@ is-plain-object@^2.0.4:
dependencies:
isobject "^3.0.1"
is-promise@^2.1.0:
version "2.2.2"
resolved "https://registry.npmmirror.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz"
......@@ -4485,7 +4521,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz"
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21:
lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
......@@ -4556,6 +4592,11 @@ make-dir@^3.0.2, make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
material-colors@^1.2.6:
version "1.2.6"
resolved "https://registry.npmmirror.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz"
......@@ -5714,6 +5755,11 @@ regenerator-runtime@^0.13.11:
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
regenerator-runtime@^0.14.0:
version "0.14.1"
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regenerator-transform@^0.15.1:
version "0.15.1"
resolved "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz"
......@@ -6688,6 +6734,11 @@ vuex@^3.6.2:
resolved "https://registry.npmmirror.com/vuex/-/vuex-3.6.2.tgz"
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==
watch-size@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/watch-size/-/watch-size-2.0.0.tgz#096ee28d0365bd7ea03d9c8bf1f2f50a73be1474"
integrity sha512-M92R89dNoTPWyCD+HuUEDdhaDnh9jxPGOwlDc0u51jAgmjUvzqaEMynXSr3BaWs+QdHYk4KzibPy1TFtjLmOZQ==
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment