Commit 634f8615 authored by “yiyousong”'s avatar “yiyousong”

feat: 添加权限

parent 254df117
src/assets
src/components/formDes
\ No newline at end of file
module.exports = {
root: true,
env: {
node: true
node: true,
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
extends: ["plugin:vue/essential", "eslint:recommended"],
parserOptions: {
parser: '@babel/eslint-parser'
parser: "@babel/eslint-parser",
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/no-mutating-props': 0,
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
"vue/no-mutating-props": 0,
},
overrides: [
{
files: ['src/**/**/*.vue'],
files: ["src/**/**/*.vue"],
rules: {
'vue/multi-word-component-names': 0
}
}
]
}
"vue/multi-word-component-names": 0,
},
},
],
};
......@@ -13,6 +13,7 @@
},
"dependencies": {
"@babel/parser": "^7.7.4",
"@riophae/vue-treeselect": "^0.4.0",
"axios": "^0.27.2",
"beautifier": "^0.1.7",
"clipboard": "^2.0.4",
......
......@@ -92,3 +92,227 @@ export const getlog = (params) => {
params,
});
};
/**
* 资源信息
*/
// 获取资源信息列表
export const getResourceList = (data) => {
return request({
url: `/sampleform/resource/list`,
method: "post",
data,
});
};
// 获取资源信息详情
export const getResourceDetail = (params) => {
return request({
url: `/sampleform/resource/info`,
method: "get",
params,
});
};
// 添加资源信息
export const saveResource = (data) => {
return request({
url: `/sampleform/resource/save`,
method: "post",
data,
});
};
// 删除资源信息
export const deleteResource = (params) => {
return request({
url: `/sampleform/resource/delete`,
method: "get",
params,
});
};
// 刷新资源
export const refreshResource = (data) => {
return request({
url: `/sampleform/resource/refreshUrl`,
method: "post",
data,
});
};
// 资源分组
export const getResourceGroup = (data) => {
return request({
url: `/sampleform/resource/group`,
method: "post",
data,
});
};
/**
* 角色
*/
// 获取角色列表
export const getRoleList = (data) => {
return request({
url: `/sampleform/role/list`,
method: "post",
data,
});
};
// 获取角色详情
export const getRole = (params) => {
return request({
url: `/sampleform/role/get`,
method: "get",
params,
});
};
// 保存角色
export const addRole = (data) => {
return request({
url: `/sampleform/role/save`,
method: "post",
data,
});
};
// 删除角色
export const deleteRole = (params) => {
return request({
url: `/sampleform/role/delete`,
method: "get",
params,
});
};
// 获取角色资源列表
export const getRoleResourceList = (data) => {
return request({
url: `/sampleform/role/auth/list`,
method: "post",
data,
});
};
// 添加角色资源
export const addRoleResource = (data) => {
return request({
url: `/sampleform/role/auth/distributionSource`,
method: "post",
data,
});
};
// 添加角色菜单
export const addRoleMenu = (data) => {
return request({
url: `/sampleform/role/auth/distributionMenu`,
method: "post",
data,
});
};
// 获取角色菜单
export const getRoleMenuList = (data) => {
return request({
url: `/sampleform/role/auth/editMenu`,
method: "post",
data,
});
};
/**
* 用户管理
*/
// 获取用户列表
export const getUserList = (data) => {
return request({
url: `/sampleform/user/list`,
method: "post",
data,
});
};
// 获取用户信息
export const getUserInfo = (params) => {
return request({
url: `/sampleform/user/info`,
method: "get",
params,
});
};
// 保存用户
export const saveUser = (data) => {
return request({
url: `/sampleform/user/save`,
method: "post",
data,
});
};
// 删除用户
export const deleteUser = (params) => {
return request({
url: `/sampleform/user/delete`,
method: "get",
params,
});
};
/**
* 菜单管理
*/
// 获取菜单列表
export const getMenuList = (data) => {
return request({
url: `/sampleform/menu/list`,
method: "post",
data,
});
};
// 获取菜单信息
export const getMenuInfo = (params) => {
return request({
url: `/sampleform/menu/info`,
method: "get",
params,
});
};
// 保存菜单
export const saveMenu = (data) => {
return request({
url: `/sampleform/menu/save`,
method: "post",
data,
});
};
// 删除菜单
export const deleteMenu = (params) => {
return request({
url: `/sampleform/menu/delete`,
method: "get",
params,
});
};
// 改变菜单排序
export const changeMenuSort = (data) => {
return request({
url: `/sampleform/menu/upOrDown`,
method: "post",
data,
});
};
// 获取菜单树列表
export const getMenuTreeselect = (data) => {
return request({
url: `/sampleform/menu/treeselect`,
method: "post",
data,
});
};
// 获取个人菜单树
export const getMenuTree = (data) => {
return request({
url: `/sampleform/login/index`,
method: "post",
data,
});
};
......@@ -430,6 +430,13 @@
.el-tabs__header{
margin: 0px !important;
}
.table-control{
display: flex;
align-items: center;
justify-content: center;
gap:8px;
}
// .el-tabs__content {
// padding: 0px 15px 15px 15px;
// }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4136233" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xeac5;</span>
<div class="name">24gf-folderOpen</div>
<div class="code-name">&amp;#xeac5;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1687661668952') format('woff2'),
url('iconfont.woff?t=1687661668952') format('woff'),
url('iconfont.ttf?t=1687661668952') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-folder"></span>
<div class="name">
24gf-folderOpen
</div>
<div class="code-name">.icon-folder
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-folder"></use>
</svg>
<div class="name">24gf-folderOpen</div>
<div class="code-name">#icon-folder</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>
<template>
<div class="pagination" v-if="total">
<el-pagination
background
layout="total,prev,pager,next,sizes,jumper"
:pager-count="5"
:total="total"
:current-page="current"
:page-size="size"
:page-sizes="pageSizes"
@current-change="changePagination"
@size-change="changeSize"
>
</el-pagination>
</div>
</template>
<script>
export default {
props: {
total: {
required: true,
type: Number,
default: 0,
},
size: {
required: true,
type: Number,
default: 10,
},
current: {
required: true,
type: Number,
default: 1,
},
},
data() {
return {
pageSizes: [10, 20, 30, 40, 50, 100, 200],
};
},
computed: {},
methods: {
changePagination(cur) {
this.$emit("currentChange", cur);
},
changeSize(size) {
this.$emit("sizeChange", size);
},
},
};
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
......@@ -20,5 +20,8 @@ export default {};
display: flex;
align-items: center;
justify-content: space-between;
:deep(.el-form-item) {
margin-bottom: 0px;
}
}
</style>
\ No newline at end of file
</style>
import store from "@/store";
// 权限渲染
export const permission = {
inserted: function (el, binding) {
const { value } = binding;
const roles = store.getters["userInfo"].id;
if (value && value instanceof Array && value.length > 0) {
const permissionRoles = value;
const hasPermission = permissionRoles.includes(roles);
if (!hasPermission) {
el.remove();
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`);
}
},
};
// 按钮鉴权
export const hasPermi = {
inserted: function (el, binding) {
const { value } = binding;
const permissions = store.getters["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(`请设置操作权限标签值`);
}
},
};
......@@ -14,6 +14,12 @@ import "@/assets/fonts/iconfont.css";
import moment from "moment";
Vue.prototype.$moment = moment;
// 引入注册全局指令
import * as directives from "@/directive";
Object.keys(directives).forEach((name) =>
Vue.directive(name, directives[name])
);
// 引入element-ui
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
......@@ -21,8 +27,10 @@ Vue.use(ElementUI);
import { message } from "@/utils/resetMessage";
Vue.prototype.$message = message;
import { resetForm } from "@/utils";
Vue.prototype.resetForm = resetForm;
// 重置表单
import { resetForm, clearSelection } from "@/utils";
Vue.prototype.$resetForm = resetForm;
Vue.prototype.$clearSelection = clearSelection;
// 注册全局组件
import customComponents from "@/components";
......
......@@ -120,13 +120,22 @@
class="primary"
>激活</span
>
<span class="primary pointer" @click="handleBound(scope.row)"
<span
class="primary pointer"
v-hasPermi="['numberwritedevice:binding']"
@click="handleBound(scope.row)"
>绑定表单</span
>
<span class="primary pointer" @click="handleEdit(scope.row)"
<span
class="primary pointer"
v-hasPermi="['numberwritedevice:edit']"
@click="handleEdit(scope.row)"
>编辑</span
>
<span class="delete pointer" @click="handleDel(scope.row.id)"
<span
class="delete pointer"
v-hasPermi="['numberwritedevice:remove']"
@click="handleDel(scope.row.id)"
>删除</span
>
</div>
......@@ -180,9 +189,7 @@ export default {
return {
typeList,
searchVal: "",
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
tableData: [],
total: 0,
page: 1,
......
......@@ -261,7 +261,7 @@ export default {
},
methods: {
handleReset() {
this.resetForm("form");
this.$resetForm("form");
},
handleOk() {
this.$refs.form.validate(async (valid) => {
......@@ -288,7 +288,7 @@ export default {
}, 10);
},
handleClose() {
this.resetForm("form");
this.$resetForm("form");
this.Visible = false;
},
},
......
......@@ -177,9 +177,7 @@ export default {
data() {
return {
loading: false,
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
department: "",
searchVal: "",
page: 1,
......
......@@ -6,7 +6,8 @@
import local from "@/utils/local";
import { mapMutations } from "vuex";
import { calcMenu } from "@/router";
// import { getSiteTree } from "@/services/businessMatter";
import { generateRoutes, filterBtn } from "@/utils";
import { getMenuTree } from "@/api/system";
export default {
data() {
return {
......@@ -17,18 +18,27 @@ export default {
this.getInfo();
},
methods: {
...mapMutations(["SET_sysName", "SET_sysLogo", "SET_token", "SET_path"]),
...mapMutations([
"SET_token",
"SET_sysName",
"SET_sysLogo",
"SET_path",
"SET_userInfo",
"SET_permissions",
"SET_routes",
"SET_menusList",
]),
// 获取token和站点信息
async getInfo() {
let { token, siteid, sysName, sysLogo, path } = this.$route.query;
if (token) {
local.setLocal("sampleSiteId", siteid);
local.setLocal("siteId", siteid);
this.SET_token(token);
this.SET_sysName(sysName);
this.SET_sysLogo(sysLogo);
this.SET_path(path);
calcMenu();
this.$router.push("/basicsset");
await this.getIndixData();
} else {
this.$message.warning("跳转失败,请重新登录");
setTimeout(() => {
......@@ -36,9 +46,36 @@ export default {
}, 2000);
}
},
// 获取菜单列表
async getIndixData() {
let res = await getMenuTree();
if (res.data.code == 1) {
let { menuList } = res.data.data;
// 过滤掉按钮
let menus = filterBtn(menuList, false);
let routes = generateRoutes(menus);
this.SET_menusList(menus);
this.setBtnPermissions(menuList);
calcMenu();
if (routes.length) {
let path = routes[0].path;
this.$router.push(path);
} else {
this.$message.warning("暂无页面权限,请联系管理员!");
}
}
},
// 添加按钮权限字符
setBtnPermissions(menuList) {
let btnPermissions = filterBtn(menuList)
.filter((v) => v.perms)
.map((v) => v.perms);
this.SET_permissions(btnPermissions);
},
},
};
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
<style lang="less" scoped></style>
......@@ -108,9 +108,7 @@ export default {
// 获取部门列表
async getdeptList() {
let res = await getdeptList({
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
page: 1,
size: -1,
});
......
<template>
<div class="system bgw flex flexc">
<div class="system">
<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" :class="['mr5', 'primary', v.meta.icon]"></i>
<i v-if="v.meta.icon" :class="['tab-icon', v.meta.icon]"></i>
<span class="tab-label">{{ v.meta.title }}</span>
</template>
</el-tab-pane>
</el-tabs>
<div class="system-out-box flex1">
<div class="system-out-box">
<router-view></router-view>
</div>
</div>
</template>
<script>
import { findBottomSubarrays } from "@/utils";
import { mapGetters } from "vuex";
export default {
data() {
return {
subMenus: [],
};
return {};
},
computed: {
activeKey() {
return this.$route.path;
},
...mapGetters(["secondaryRoutes"]),
},
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
);
},
},
};
</script>
......@@ -52,13 +38,30 @@ export default {
<style lang="less" scoped>
:deep(.el-tabs__nav-scroll) {
padding-left: 15px;
.tab-icon {
margin-right: 5px;
color: #2681e8;
}
.tab-label {
font-weight: bold;
color: rgba(0, 0, 0, 0.65);
}
.is-active {
.tab-label {
color: #2681e8;
}
}
}
.system {
width: 100%;
height: 100%;
background: #fff;
display: flex;
flex-direction: column;
.system-out-box {
flex: 1;
padding: 15px;
overflow-y: auto;
}
}
</style>
\ No newline at end of file
</style>
<template>
<div class="header flex aic jcb">
<div class="left flex aic">
<img
class="pointer mr10 logo"
:src="sysLogo ? sysLogo : require('@/assets/img/logo.png')"
alt="LOGO"
@click="handleGoHome"
/>
<h1 class="title pointer" @click="handleGoHome">
{{ sysName ? sysName : systemName }}
</h1>
<HeaderSite class="mr50 ml20"></HeaderSite>
<!-- 导航 -->
<el-menu
:default-active="activeMenu"
mode="horizontal"
router
text-color="rgba(254, 254, 254, 0.65)"
>
<template v-for="v in menus">
<!-- 有子路由 -->
<el-submenu
v-if="!v.hideChildrenInMenu && v.children && v.children.length"
:key="'a' + v.path"
:index="v.path"
>
<template slot="title">
<i v-if="v.meta && v.meta.icon" :class="v.meta.icon"></i>
{{ v.meta.title }}
</template>
<el-menu-item
v-for="item in v.children"
:key="item.path"
:index="item.path"
>
<i v-if="item.meta && item.meta.icon" :class="item.meta.icon"></i>
{{ item.meta && item.meta.title }}
</el-menu-item>
</el-submenu>
<!-- 单个路由 -->
<el-menu-item v-else :key="v.path" :index="v.path">
<i v-if="v.meta && v.meta.icon" :class="v.meta.icon"></i>
{{ v.meta.title }}
</el-menu-item>
</template>
<!-- <el-menu-item v-for="v in menus" :key="v.path" :index="v.path">
<i :class="v.meta.icon"></i>
{{ v.meta.title }}
</el-menu-item> -->
</el-menu>
</div>
<!-- 返回门户 -->
<div class="back-btn">
<el-tooltip effect="dark" content="返回门户" placement="bottom">
<a class="pointer" :href="portal + (path ? path : '/')">
<i class="el-icon-s-home"></i> 返回门户
</a>
</el-tooltip>
</div>
</div>
</template>
<script>
import HeaderSite from "./HeaderSite.vue";
import { systemName } from "@/config";
import { mapState } from "vuex";
export default {
components: {
HeaderSite,
},
data() {
return {
systemName,
portal: process.env.VUE_APP_API_portal_URL + "/#",
};
},
computed: {
activeMenu() {
const route = this.$route;
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
},
...mapState(["menus", "sysName", "sysLogo", "path"]),
},
created() {},
methods: {
handleGoHome() {
this.$router.push("/basicsset");
},
},
};
</script>
<style lang="less" scoped>
.header {
height: 64px;
width: 100%;
padding: 0px 24px;
// background-color: #2681e8;
background: linear-gradient(90deg, #1845c6 0%, #2999ff 100%);
color: #fff;
flex-shrink: 0;
.logo {
height: 32px;
object-fit: contain;
}
.left {
height: 100%;
}
.title {
max-width: 200px;
font-size: 18px;
}
.back-btn {
a {
color: #fff;
font-size: 14px;
}
}
}
/deep/.el-menu {
height: 100% !important;
border: none !important;
background-color: transparent;
i {
color: rgba(254, 254, 254, 0.65);
}
.el-menu-item {
height: 100% !important;
border: none !important;
display: flex;
align-items: center;
color: rgba(254, 254, 254, 0.65);
&:hover {
// background-color: transparent !important;
color: #fff !important;
background-color: #1890ff !important;
// border-bottom: 2px solid #fff !important;
}
}
}
/deep/.el-submenu {
height: 100% !important;
.el-submenu__title {
height: 100% !important;
display: flex;
align-items: center;
color: rgba(254, 254, 254, 0.65) !important;
border: none !important;
&:hover {
// background-color: transparent !important;
color: #fff !important;
background-color: #1890ff !important;
// border-bottom: 2px solid #fff !important;
}
}
}
.el-menu--horizontal .el-menu .el-menu-item {
color: #909399;
&:hover {
i {
color: #1890ff;
}
color: #1890ff;
}
}
.el-menu--horizontal .el-menu .el-menu-item.is-active {
color: #1890ff !important;
}
/deep/.is-active {
// border-bottom: 2px solid #fff !important;
color: #fff !important;
// background-color: transparent !important;
background-color: #1890ff !important;
.el-submenu__title {
border: none !important;
color: #fff !important;
// background-color: transparent !important;
background-color: #1890ff !important;
}
}
</style>
......@@ -17,6 +17,7 @@
mode="horizontal"
router
text-color="rgba(254, 254, 254, 0.65)"
@select="selectMenu"
>
<template v-for="v in menus">
<!-- 有子路由 -->
......@@ -65,7 +66,7 @@
<script>
import HeaderSite from "./HeaderSite.vue";
import { systemName } from "@/config";
import { mapState } from "vuex";
import { mapState, mapMutations } from "vuex";
export default {
components: {
HeaderSite,
......@@ -79,18 +80,27 @@ export default {
computed: {
activeMenu() {
const route = this.$route;
const { meta, path } = route;
const { meta, matched } = route;
if (meta.activeMenu) {
return meta.activeMenu;
} else {
let curMatched = matched.filter((v) => v.path);
return curMatched[0].path;
}
return path;
},
...mapState(["menus", "sysName", "sysLogo", "path"]),
},
created() {},
methods: {
...mapMutations(["SET_secondaryRoutes"]),
selectMenu(index) {
this.SET_secondaryRoutes(index);
},
handleGoHome() {
this.$router.push("/basicsset");
let path = this.menus[0].path;
if (path) {
this.$router.push(path);
}
},
},
};
......
......@@ -162,7 +162,7 @@ export default {
}
});
};
const siteid = local.getLocal("sampleSiteId");
const siteid = local.getLocal("siteId");
treeFn(siteTree);
const siteObj = arr.find((v) => v.id == siteid);
this.siteName = siteObj ? siteObj.label : "请选择站点";
......@@ -178,7 +178,7 @@ export default {
// siteName: obj.label,
// siteid: obj.id,
// };
local.setLocal("sampleSiteId", obj.id);
local.setLocal("siteId", obj.id);
this.show = false;
if (location.href.search(/token/gi) >= 0) {
setTimeout(() => {
......
......@@ -176,7 +176,7 @@ export default {
}
});
};
const siteid = local.getLocal("sampleSiteId");
const siteid = local.getLocal("siteId");
treeFn(siteTree);
const siteObj = arr.find((v) => v.id == siteid);
this.siteName = siteObj ? siteObj.label : "请选择站点";
......@@ -189,7 +189,7 @@ export default {
// siteName: obj.label,
// siteid: obj.id,
// };
local.setLocal("sampleSiteId", obj.id);
local.setLocal("siteId", obj.id);
this.show = false;
if (location.href.search(/token/gi) >= 0) {
setTimeout(() => {
......
......@@ -64,7 +64,7 @@ export default {
let siteIds = data.user.siteIds;
let siteid = siteIds.split(",")[0];
if (token) {
local.setLocal("sampleSiteId", siteid);
local.setLocal("siteId", siteid);
this.SET_token(token);
// 渲染菜单
calcMenu();
......@@ -152,4 +152,3 @@ export default {
}
}
</style>
......@@ -56,7 +56,11 @@
</div>
<div class="mt50">
<el-button size="medium" @click="handleReset"> </el-button>
<el-button size="medium" type="primary" @click="handleOk"
<el-button
size="medium"
type="primary"
v-hasPermi="['basicsset:save']"
@click="handleOk"
>
</el-button>
</div>
......@@ -74,9 +78,7 @@ export default {
},
data() {
return {
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
inputVisible: false,
inputValue: "",
newSourceEnumData: {},
......
......@@ -7,7 +7,11 @@
<!-- <el-button size="small" type="primary" @click="handleAddMaterials"
>加入材料</el-button
>-->
<el-button size="small" type="danger" @click="handleDelAll"
<el-button
size="small"
type="danger"
v-hasPermi="['librarymanage:remove']"
@click="handleDelAll"
>批量移除</el-button
>
</div>
......@@ -65,10 +69,16 @@
<template slot="action" slot-scope="scope">
<div class="flex jca">
<span class="primary pointer" @click="handlePreview(scope.row)"
<span
class="primary pointer"
v-hasPermi="['librarymanage:preview']"
@click="handlePreview(scope.row)"
>预览</span
>
<span class="delete pointer" @click="handleDel(scope.row.id)"
<span
class="delete pointer"
v-hasPermi="['librarymanage:remove']"
@click="handleDel(scope.row.id)"
>移除</span
>
</div>
......
......@@ -76,13 +76,12 @@
>
</el-table-column>
</el-table>
<Pagination
<y-pagination
:total="total"
:current="current"
:size="size"
@currentChange="changePagination"
@sizeChange="changeSize"
></Pagination>
:page="current"
:pageSize="size"
></y-pagination>
<span slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="handleOk"
> </el-button
......@@ -95,12 +94,10 @@
<script>
import TableHeader from "@/components/TableHeader.vue";
import Pagination from "@/components/Pagination.vue";
import { mapGetters } from "vuex";
export default {
components: {
TableHeader,
Pagination,
},
props: {
libVisible: {
......@@ -173,4 +170,4 @@ export default {
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
\ No newline at end of file
</style>
......@@ -84,22 +84,39 @@
<!-- 内容 -->
<TableHeader>
<div slot="left">
<el-button size="small" type="primary" @click="handleAddMaterial"
<el-button
size="small"
type="primary"
v-hasPermi="['materialsmanage:add']"
@click="handleAddMaterial"
>新增材料</el-button
>
<el-button size="small" type="primary" @click="showLib"
<el-button
size="small"
type="primary"
v-hasPermi="['materialsmanage:lib']"
@click="showLib"
>公共库选择</el-button
>
<el-button size="small" type="primary" @click="addFolder"
<el-button
size="small"
type="primary"
v-hasPermi="['materialsmanage:addFolder']"
@click="addFolder"
>新增文件夹</el-button
>
<el-button size="small" type="danger" @click="handleDelAll"
<el-button
size="small"
type="danger"
v-hasPermi="['materialsmanage:remove']"
@click="handleDelAll"
>批量删除</el-button
>
<el-button
size="small"
v-if="activeDep.id"
type="primary"
v-hasPermi="['materialsmanage:move']"
@click="addMaterialsToFolder"
>移动至</el-button
>
......@@ -159,7 +176,10 @@
<template slot="action" slot-scope="scope">
<div class="flex jcb">
<div style="width: 60px">
<div
style="width: 60px"
v-hasPermi="['materialsmanage:recommend']"
>
<span
@click="handleRecommend(scope.row.id)"
v-if="scope.row.isRecommend == 1"
......@@ -173,7 +193,10 @@
>推荐</span
>
</div>
<span class="primary pointer" @click="handleEdit(scope.row)"
<span
class="primary pointer"
v-hasPermi="['materialsmanage:edit']"
@click="handleEdit(scope.row)"
>编辑</span
>
<!-- <span
......@@ -181,10 +204,16 @@
@click="addMaterialsToFolder(scope.row)"
>移动至</span
> -->
<span class="primary pointer" @click="handlePreview(scope.row)"
<span
class="primary pointer"
v-hasPermi="['materialsmanage:preview']"
@click="handlePreview(scope.row)"
>预览</span
>
<span class="delete pointer" @click="handleDel(scope.row.id)"
<span
class="delete pointer"
v-hasPermi="['materialsmanage:remove']"
@click="handleDel(scope.row.id)"
>删除</span
>
</div>
......@@ -261,9 +290,7 @@ export default {
},
data() {
return {
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
// 样表事项表格
sampleformMatterTable: {
loading: false,
......
......@@ -123,12 +123,12 @@ export default {
},
// 重置
handleRest() {
this.resetForm("form");
this.$resetForm("form");
},
// 关闭
handleClose() {
this.loading = false;
this.resetForm("form");
this.$resetForm("form");
this.Visible = false;
},
},
......
......@@ -101,9 +101,7 @@ export default {
materiaFullName: "", // 材料全名
source: 1, // 来源
matterId: "", // 事项id
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
matterNo: "", // 事项编号
// fileName: "", // 附件名称
// fileUrl: "", // 附件地址
......@@ -189,12 +187,12 @@ export default {
},
// 重置
handleRest() {
this.resetForm("form");
this.$resetForm("form");
this.samplePathFileList = [];
},
// 关闭
handleClose() {
this.resetForm("form");
this.$resetForm("form");
// this.fileUrlFileList = [];
// this.templatePathFileList = [];
this.samplePathFileList = [];
......
......@@ -104,9 +104,7 @@ export default {
},
data() {
return {
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
department: "",
searchVal: "",
tableData: [],
......
......@@ -6,10 +6,18 @@
<div class="pd15 flex1 auto-scroll">
<TableHeader>
<div slot="left">
<el-button size="small" type="primary" @click="handleAddMatter"
<el-button
size="small"
type="primary"
v-hasPermi="['basicsset:addMatter']"
@click="handleAddMatter"
>新增事项</el-button
>
<el-button size="small" type="danger" @click="handleDelAll"
<el-button
size="small"
type="danger"
v-hasPermi="['basicsset:removeMatter']"
@click="handleDelAll"
>批量删除</el-button
>
</div>
......@@ -69,7 +77,10 @@
<!-- 操作 -->
<template slot="action" slot-scope="scope">
<div class="flex jcb">
<div style="width: 60px">
<div
style="width: 60px"
v-hasPermi="['basicsset:RecommendMatter']"
>
<span
@click="handleRecommend(scope.row.id)"
v-if="scope.row.isRecommend == 1"
......@@ -83,10 +94,16 @@
>推荐</span
>
</div>
<span class="primary pointer" @click="handleEdit(scope.row)"
<span
class="primary pointer"
v-hasPermi="['basicsset:editMatter']"
@click="handleEdit(scope.row)"
>编辑</span
>
<span class="delete pointer" @click="handleDel(scope.row.id)"
<span
class="delete pointer"
v-hasPermi="['basicsset:removeMatter']"
@click="handleDel(scope.row.id)"
>删除</span
>
</div>
......@@ -108,7 +125,11 @@
<!-- 内容 -->
<TableHeader>
<div slot="left">
<el-button size="small" type="primary" @click="handleAllJoin"
<el-button
size="small"
type="primary"
v-hasPermi="['basicsset:join']"
@click="handleAllJoin"
>批量加入</el-button
>
</div>
......@@ -168,7 +189,10 @@
<el-tag size="small" v-else>自建事项</el-tag>
</template>
<template slot="action" slot-scope="scope">
<span class="primary pointer" @click="handleJoin(scope.row.id)"
<span
v-hasPermi="['basicsset:join']"
class="primary pointer"
@click="handleJoin(scope.row.id)"
>加入</span
>
</template>
......@@ -212,9 +236,7 @@ export default {
},
data() {
return {
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
// 样表事项表格
sampleformMatterTable: {
loading: false,
......
......@@ -90,9 +90,7 @@ export default {
deptId: "", // 部门id
deptCode: "", // 部门编号
matterNo: "", // 事项编号
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
source: 1, // 1为手动添加,
deptName: "",
},
......@@ -150,11 +148,11 @@ export default {
},
// 重置
handleRest() {
this.resetForm("form");
this.$resetForm("form");
},
// 关闭
handleClose() {
this.resetForm("form");
this.$resetForm("form");
this.Visible = false;
},
handleChange(val) {
......
......@@ -21,6 +21,7 @@
/>
</div>
<el-button
v-hasPermi="['skinmanage:use']"
size="small"
:class="{ active: v.used == 1 }"
@click="changeSkin(v)"
......@@ -56,9 +57,7 @@ export default {
},
data() {
return {
siteId: local.getLocal("sampleSiteId")
? local.getLocal("sampleSiteId")
: "",
siteId: local.getLocal("siteId") ? local.getLocal("siteId") : "",
skinList: [],
previewImg: false,
previewUrl: "",
......
<template>
<div class="h-full w-full">
<table-header>
<div slot="left">
<el-button
size="small"
type="primary"
v-hasPermi="['system:menu:add']"
@click="handleAdd"
>新增</el-button
>
<!-- <el-button size="small" type="danger" @click="handleDelAll"
>批量删除</el-button
> -->
</div>
<!-- <div slot="search">
<el-form ref="searchForm" :model="searchForm" inline>
<el-form-item prop="name">
<el-input
size="small"
v-model="searchForm.name"
style="width: 200px"
class="ml10 mr10"
placeholder="请输入系统名称搜索"
@keyup.native.enter="handleSearch"
></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="handleSearch"
>搜 索</el-button
>
</el-form-item>
<el-form-item>
<el-button size="small" @click="handleReset">重 置</el-button>
</el-form-item>
</el-form>
</div> -->
</table-header>
<!-- 表格 -->
<div class="table-content">
<y-table
ref="MyTable"
:loading="loading"
:data="tableData"
:column="column"
border
tooltip-effect="dark"
:max-height="600"
:row-key="(row) => row.id"
:tree-props="{ children: 'childList', hasChildren: 'hasChildren' }"
@selection-change="handleSelectionChange"
></y-table>
</div>
<y-pagination
:total="total"
:page.sync="page"
:pageSize.sync="size"
layout="total,prev,pager,next"
@change="getMenuList"
></y-pagination>
<AddMenu
ref="AddMenu"
:show.sync="show"
:title="title"
:dict="dict"
:menuList="menuList"
@success="getMenuList"
></AddMenu>
</div>
</template>
<script>
import TableHeader from "@/components/TableHeader.vue";
import AddMenu from "./components/AddMenu.vue";
import {
getMenuList,
deleteMenu,
saveMenu,
changeMenuSort,
} from "@/api/system";
import { buildTree } from "@/utils";
export default {
components: {
TableHeader,
AddMenu,
},
data() {
return {
column: [
// {
// label: "全选",
// type: "selection",
// width: "55",
// align: "center",
// reserveSelection: true,
// },
// {
// label: "序号",
// type: "index",
// width: "55",
// align: "center",
// index: (index) => {
// return (this.page - 1) * this.size + index + 1;
// },
// },
// {
// label: "树形展开",
// width: "80",
// align: "center",
// },
{
label: "菜单名称",
prop: "name",
// align: "center",
},
// {
// label: 'ID',
// prop: 'id',
// align: 'center'
// },
{
label: "图标",
align: "center",
prop: "imgPath",
formatter: (row) => {
if (row.imgPath) {
return <i class={row.imgPath}></i>;
}
},
},
// {
// label: '权限类型',
// prop: 'authType',
// align: 'center',
// formatter: (row) => {
// return this.dict.authType[row.authType];
// }
// },
// {
// label: '父ID',
// prop: 'parentId',
// align: 'center'
// },
{
label: "地址",
prop: "url",
align: "center",
},
{
label: "类型",
prop: "menuType",
align: "center",
formatter: (row) => {
if (row.menuType === 0) {
return (
<el-tag size="small" type="info">
{this.dict.menuType[row.menuType]}
</el-tag>
);
} else if (row.menuType === 1) {
return (
<el-tag size="small" type="success">
{this.dict.menuType[row.menuType]}
</el-tag>
);
} else if (row.menuType === 2) {
return (
<el-tag size="small">{this.dict.menuType[row.menuType]}</el-tag>
);
}
},
},
{
label: "权限字符",
prop: "perms",
align: "center",
},
{
label: "状态",
prop: "status",
align: "center",
formatter: (row) => {
return (
<el-switch
active-value={1}
inactive-value={0}
value={row.status}
onChange={(val) => {
this.handleStatus(row, val);
}}
></el-switch>
);
},
},
{
label: "操作",
align: "center",
width: "180",
formatter: (row) => {
return (
<div class="table-control">
<i
v-hasPermi={["system:menu:sort"]}
class="el-icon-top primary pointer"
onClick={() => this.changeMenuSort(row.id, 0)}
></i>
<i
v-hasPermi={["system:menu:sort"]}
class="el-icon-bottom primary pointer"
onClick={() => this.changeMenuSort(row.id, 1)}
></i>
<span
v-hasPermi={["system:menu:edit"]}
class="primary pointer"
onClick={() => this.handleEdit(row)}
>
编辑
</span>
<span
v-hasPermi={["system:menu:remove"]}
class="delete pointer"
onClick={() => this.handleDel(row.id)}
>
删除
</span>
</div>
);
},
},
],
searchForm: {
name: "",
},
tableData: [],
menuList: [],
page: 1,
size: 10000,
total: 0,
loading: false,
selectRows: [],
show: false,
title: "新增",
dict: {}, // 字典
isAllSelected: false,
};
},
created() {
this.getMenuList();
},
computed: {},
methods: {
// 获取列表
async getMenuList() {
this.loading = true;
this.menuList = [
{
id: 0,
name: "",
},
];
let res = await getMenuList({
page: this.page,
size: this.size,
name: `%${this.searchForm.name}%`,
});
this.loading = false;
if (res.data.code == 1) {
let { data, total, dict } = res.data.data;
if (!data.length && this.page > 1) {
this.page -= 1;
this.getMenuList();
}
this.menuList = [...this.menuList, ...buildTree(data)];
this.tableData = buildTree(data);
this.total = total;
this.dict = dict;
}
},
// 批量移除
handleDelAll() {
if (!this.selectRows.length) {
this.$message.warning("请先勾选数据");
return;
}
let ids = this.selectRows.map((v) => v.id).join(",");
this.handleDel(ids);
},
// 搜索
handleSearch() {
this.page = 1;
this.$clearSelection("MyTable");
this.getMenuList();
},
// 重置
handleReset() {
this.page = 1;
this.$clearSelection("MyTable");
this.$resetForm("searchForm");
this.getMenuList();
},
// 选中
handleSelectionChange(selection) {
this.selectRows = selection;
},
// 新增
handleAdd() {
this.title = "新增";
this.$refs.AddMenu.onAdd();
this.show = true;
},
// 编辑
handleEdit(row) {
this.title = "编辑";
let data = { ...row };
this.$refs.AddMenu.onEdit(data);
this.show = true;
},
// 移除
handleDel(id) {
this.$confirm("此操作将删除所选数据,是否继续?", "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
cancelButtonClass: "btn-custom-cancel",
type: "warning",
})
.then(async () => {
let res = await deleteMenu({ id });
let { code, msg } = res.data;
if (code === 1) {
this.$message.success(msg);
this.getMenuList();
this.$clearSelection("MyTable");
}
})
.catch(() => {
console.log("取消成功!");
});
},
async handleStatus(row, status) {
row.status = status;
let res = await saveMenu(row);
if (res.data.code == 1) {
this.$message.success(res.data.msg);
}
this.getMenuList();
},
// 改变菜单排序
async changeMenuSort(id, type) {
let res = await changeMenuSort({ id, type });
if (res.data.code == 1) {
this.$message.success("更改排序成功");
this.getMenuList();
}
},
},
};
</script>
<style lang="less" scoped></style>
<template>
<div>
<el-dialog
:title="title"
:visible.sync="Visible"
width="650px"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
>
<el-form
ref="form"
:model="form"
:rules="rules"
size="medium"
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="请输入菜单名称"
v-model="form.name"
clearable
></el-input>
</el-form-item>
<el-form-item label="菜单图标" prop="imgPath" v-if="form.menuType != 2">
<icon-select v-model="form.imgPath"></icon-select>
</el-form-item>
<!-- <el-form-item label="权限类型" prop="authType" v-if="form.menuType != 2">
<el-select clearable v-model="form.authType" placeholder="请选择权限类型">
<el-option
v-for="(item, key) in dict.authType"
:key="key"
:label="item"
:value="Number(key)"
>
</el-option>
</el-select>
</el-form-item> -->
<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="请输入菜单路由地址"
v-model="form.url"
></el-input>
</el-form-item>
<el-form-item prop="component" v-if="form.menuType != 2">
<span slot="label">
<el-tooltip
content="访问的组件路径,如:`pages/system/menu/Menu`,默认在`src`目录下"
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.visible"
:key="key"
:label="Number(key)"
>{{ item }}</el-radio
>
</el-radio-group>
</el-form-item>
</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"
:key="key"
:label="Number(key)"
>{{ item }}</el-radio
>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="资源类型" prop="resourceType">
<el-radio-group v-model="form.resourceType">
<el-radio :label="1">从资源列表获取</el-radio>
<el-radio :label="2">自定义资源地址</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24" v-show="form.resourceType == 1">
<el-form-item label="资源" prop="resourceUrl">
<select-res
v-model="form.resourceUrl"
:clearable="false"
></select-res>
</el-form-item>
</el-col>
<el-col :span="24" v-show="form.resourceType == 2">
<el-form-item class="url-params-box" label="资源">
<el-form-item
class="url-params"
v-for="(v, i) in form.urls"
:key="i"
:prop="`urls.${i}.value`"
:rules="[
{ required: false, validator: validatorUrl, trigger: 'blur' },
]"
>
<el-input
class="mr-[10px]"
v-model="v.value"
placeholder="请输入链接地址"
/>
<div class="flex">
<el-button type="primary" @click="changeParams(i, 'add')">
<i class="el-icon-plus"></i>
</el-button>
<el-button
type="danger"
v-if="i > 0"
@click="changeParams(i, 'remove')"
><i class="el-icon-minus"></i
></el-button>
</div>
</el-form-item>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleRest">重 置</el-button>
<el-button
size="medium"
type="primary"
:loading="loading"
@click="handleOk"
>确 定</el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
import { saveMenu } from "@/api/system";
import IconSelect from "./IconSelect";
import SelectRes from "./SelectRes.vue";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
components: {
IconSelect,
Treeselect,
SelectRes,
},
props: {
title: {
type: String,
required: true,
default: "",
},
show: {
type: Boolean,
required: true,
default: false,
},
menuList: {
required: true,
type: Array,
default: () => [],
},
dict: {
required: true,
type: Object,
default: () => {},
},
},
data() {
return {
loading: false,
defaultProps: {
children: "childList",
label: "name",
},
form: {
name: "", // 菜单名称
url: "", // 路由地址
ancestors: "", // 当前节点父id路径,“,”分割
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: "", // 激活菜单
resourceType: 1, // 资源类型 (1.按资源id,1.链接地址)
resourceUrl: [], // 资源id或者路径
hideChildrenInMenu: 1, // 是否隐藏子菜单
urls: [
{
value: "",
},
],
},
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' }]
},
};
},
computed: {
Visible: {
get() {
return this.show;
},
set(val) {
this.$emit("update:show", val);
},
},
},
methods: {
// 确定
handleOk() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.loading = true;
let resourceUrl;
let form = { ...this.form };
if (this.form.resourceType === 1) {
resourceUrl = this.form.resourceUrl.join(",");
} else {
resourceUrl = this.form.urls.map((v) => v.value).join(",");
}
this.$delete(form, "resourceType");
this.$delete(form, "urls");
let res = await saveMenu({
...form,
resourceUrl,
});
let { code, msg } = res.data;
if (code === 1) {
this.$message.success(msg);
this.$emit("success");
this.handleClose();
}
this.loading = false;
}
});
},
// 新增
onAdd() {
Object.assign(this.form, this.$options.data().form);
this.form.id && this.$delete(this.form, "id");
},
// 编辑
onEdit(row) {
setTimeout(() => {
this.form = { ...row };
this.$set(this.form, "resourceType", 1);
this.$set(this.form, "urls", [{ value: "" }]);
this.form.resourceUrl = [];
if (row.resourceUrl) {
let arr = row.resourceUrl.split(",");
if (this.isUrl(row.resourceUrl)) {
this.form.urls = arr.map((v) => {
return {
value: v,
};
});
this.form.resourceType = 2;
this.form.resourceUrl = arr;
} else {
this.form.resourceUrl = arr.map(Number);
}
}
}, 10);
},
// 判断资源是否是链接
isUrl(val) {
return val.startsWith("/");
},
// 重置
handleRest() {
this.$resetForm("form");
},
// 关闭
handleClose() {
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,
};
},
// 判断是否存在链接
isRepeat(val) {
return this.form.urls.filter((v) => v.value == val).length > 1;
},
// 校验链接地址
validatorUrl(rule, value, callback) {
if (!value) {
if (rule.required) {
callback(new Error("请输入链接"));
} else {
callback();
}
} else if (this.isRepeat(value)) {
callback(new Error("重复的链接地址"));
} else {
callback();
}
},
changeParams(index, type) {
if (type == "add") {
let obj = {
value: "",
};
if (this.form.urls.some((v) => !v.value)) {
this.$message.warning("请先完成前面地址的填写");
return;
}
this.form.urls.splice(index + 1, 0, obj);
} else {
this.form.urls.splice(index, 1);
}
// this.$forceUpdate();
},
},
};
</script>
<style lang="less" scoped>
:deep(.el-dialog__body) {
max-height: 650px;
overflow: auto;
}
:deep(.el-select) {
width: 100%;
}
:deep(.url-params) {
margin-bottom: 22px;
.el-form-item__content {
display: flex;
}
}
</style>
<template>
<el-popover placement="bottom-start" trigger="click" width="100%">
<div class="content">
<div v-for="(v, i) in iconJson" :key="i">
<div
:class="['item', { active: v === value }]"
@click="handleChange(v)"
>
<i :class="v"></i>
<span>{{ v }}</span>
</div>
</div>
</div>
<el-input
slot="reference"
v-bind="$attrs"
v-on="$listeners"
:value="value"
:placeholder="placeholder"
clearable
>
<i v-if="value" slot="prefix" :class="value" />
<i v-else slot="prefix" class="el-icon-search" />
</el-input>
</el-popover>
</template>
<script>
import iconJson from "./icon.json";
export default {
model: {
prop: "value",
event: "change",
},
props: {
value: {
type: String,
default: "",
},
placeholder: {
type: String,
default: "点击选择图标",
},
},
data() {
return {
iconJson,
};
},
methods: {
handleChange(v) {
this.$emit("change", v);
},
},
};
</script>
<style lang="less" scoped>
.content {
width: 100%;
max-height: 300px;
display: grid;
grid-template-columns: repeat(2, 1fr);
overflow: auto;
gap: 8px 16px;
&::-webkit-scrollbar {
width: 6px;
height: 6px;
overflow-y: auto;
}
&::-webkit-scrollbar-thumb {
border-radius: 6px;
background-color: rgba(144, 147, 153, 0.5);
}
&::-webkit-scrollbar-track {
border-radius: 6px;
background: rbga(0, 0, 0, 0);
}
.active {
color: var(--primary);
}
.item {
display: flex;
align-items: center;
gap: 16px;
cursor: pointer;
}
}
</style>
<template>
<div class="select-res">
<el-cascader
clearable
filterable
:value="value"
placeholder="请选择资源"
:options="resourceList"
:props="{
value: 'id',
label: 'name',
multiple: true,
emitPath: false,
expandTrigger: 'hover',
}"
v-bind="$attrs"
v-on="$listeners"
@change="handleChange"
></el-cascader>
</div>
</template>
<script>
import { getResourceGroup } from "@/api/system";
export default {
model: {
prop: "value",
event: "change",
},
props: {
value: {
default: "",
},
dict: {
type: Object,
default: () => {},
},
form: {
type: Object,
default: () => {},
},
},
data() {
return {
resourceList: [], // 资源列表
};
},
created() {
this.getResourceGroup();
},
methods: {
// 获取资源列表
async getResourceGroup() {
this.loading = true;
let res = await getResourceGroup({
page: 1,
size: -1,
});
if (res.data.code == 1) {
let { data } = res.data.data;
this.resourceList = this.formatGroup(data);
}
},
// 格式化分组
formatGroup(data) {
let arr = [];
Object.keys(data).forEach((key, index) => {
let group = {};
group = {
name: key,
id: -index,
children: [],
};
group.children.push(...data[key]);
arr.push(group);
});
return arr;
},
handleChange(value) {
this.$emit("change", value);
},
},
};
</script>
<style lang="less" scoped>
.select-res,
:deep(.el-cascader) {
width: 100%;
}
</style>
[
"el-icon-platform-eleme",
"el-icon-eleme",
"el-icon-delete-solid",
"el-icon-delete",
"el-icon-s-tools",
"el-icon-setting",
"el-icon-user-solid",
"el-icon-user",
"el-icon-phone",
"el-icon-phone-outline",
"el-icon-more",
"el-icon-more-outline",
"el-icon-star-on",
"el-icon-star-off",
"el-icon-s-goods",
"el-icon-goods",
"el-icon-warning",
"el-icon-warning-outline",
"el-icon-question",
"el-icon-info",
"el-icon-remove",
"el-icon-circle-plus",
"el-icon-success",
"el-icon-error",
"el-icon-zoom-in",
"el-icon-zoom-out",
"el-icon-remove-outline",
"el-icon-circle-plus-outline",
"el-icon-circle-check",
"el-icon-circle-close",
"el-icon-s-help",
"el-icon-help",
"el-icon-minus",
"el-icon-plus",
"el-icon-check",
"el-icon-close",
"el-icon-picture",
"el-icon-picture-outline",
"el-icon-picture-outline-round",
"el-icon-upload",
"el-icon-upload2",
"el-icon-download",
"el-icon-camera-solid",
"el-icon-camera",
"el-icon-video-camera-solid",
"el-icon-video-camera",
"el-icon-message-solid",
"el-icon-bell",
"el-icon-s-cooperation",
"el-icon-s-order",
"el-icon-s-platform",
"el-icon-s-fold",
"el-icon-s-unfold",
"el-icon-s-operation",
"el-icon-s-promotion",
"el-icon-s-home",
"el-icon-s-release",
"el-icon-s-ticket",
"el-icon-s-management",
"el-icon-s-open",
"el-icon-s-shop",
"el-icon-s-marketing",
"el-icon-s-flag",
"el-icon-s-comment",
"el-icon-s-finance",
"el-icon-s-claim",
"el-icon-s-custom",
"el-icon-s-opportunity",
"el-icon-s-data",
"el-icon-s-check",
"el-icon-s-grid",
"el-icon-menu",
"el-icon-share",
"el-icon-d-caret",
"el-icon-caret-left",
"el-icon-caret-right",
"el-icon-caret-bottom",
"el-icon-caret-top",
"el-icon-bottom-left",
"el-icon-bottom-right",
"el-icon-back",
"el-icon-right",
"el-icon-bottom",
"el-icon-top",
"el-icon-top-left",
"el-icon-top-right",
"el-icon-arrow-left",
"el-icon-arrow-right",
"el-icon-arrow-down",
"el-icon-arrow-up",
"el-icon-d-arrow-left",
"el-icon-d-arrow-right",
"el-icon-video-pause",
"el-icon-video-play",
"el-icon-refresh",
"el-icon-refresh-right",
"el-icon-refresh-left",
"el-icon-finished",
"el-icon-sort",
"el-icon-sort-up",
"el-icon-sort-down",
"el-icon-rank",
"el-icon-loading",
"el-icon-view",
"el-icon-c-scale-to-original",
"el-icon-date",
"el-icon-edit",
"el-icon-edit-outline",
"el-icon-folder",
"el-icon-folder-opened",
"el-icon-folder-add",
"el-icon-folder-remove",
"el-icon-folder-delete",
"el-icon-folder-checked",
"el-icon-tickets",
"el-icon-document-remove",
"el-icon-document-delete",
"el-icon-document-copy",
"el-icon-document-checked",
"el-icon-document",
"el-icon-document-add",
"el-icon-printer",
"el-icon-paperclip",
"el-icon-takeaway-box",
"el-icon-search",
"el-icon-monitor",
"el-icon-attract",
"el-icon-mobile",
"el-icon-scissors",
"el-icon-umbrella",
"el-icon-headset",
"el-icon-brush",
"el-icon-mouse",
"el-icon-coordinate",
"el-icon-magic-stick",
"el-icon-reading",
"el-icon-data-line",
"el-icon-data-board",
"el-icon-pie-chart",
"el-icon-data-analysis",
"el-icon-collection-tag",
"el-icon-film",
"el-icon-suitcase",
"el-icon-suitcase-1",
"el-icon-receiving",
"el-icon-collection",
"el-icon-files",
"el-icon-notebook-1",
"el-icon-notebook-2",
"el-icon-toilet-paper",
"el-icon-office-building",
"el-icon-school",
"el-icon-table-lamp",
"el-icon-house",
"el-icon-no-smoking",
"el-icon-smoking",
"el-icon-shopping-cart-full",
"el-icon-shopping-cart-1",
"el-icon-shopping-cart-2",
"el-icon-shopping-bag-1",
"el-icon-shopping-bag-2",
"el-icon-sold-out",
"el-icon-sell",
"el-icon-present",
"el-icon-box",
"el-icon-bank-card",
"el-icon-money",
"el-icon-coin",
"el-icon-wallet",
"el-icon-discount",
"el-icon-price-tag",
"el-icon-news",
"el-icon-guide",
"el-icon-male",
"el-icon-female",
"el-icon-thumb",
"el-icon-cpu",
"el-icon-link",
"el-icon-connection",
"el-icon-open",
"el-icon-turn-off",
"el-icon-set-up",
"el-icon-chat-round",
"el-icon-chat-line-round",
"el-icon-chat-square",
"el-icon-chat-dot-round",
"el-icon-chat-dot-square",
"el-icon-chat-line-square",
"el-icon-message",
"el-icon-postcard",
"el-icon-position",
"el-icon-turn-off-microphone",
"el-icon-microphone",
"el-icon-close-notification",
"el-icon-bangzhu",
"el-icon-time",
"el-icon-odometer",
"el-icon-crop",
"el-icon-aim",
"el-icon-switch-button",
"el-icon-full-screen",
"el-icon-copy-document",
"el-icon-mic",
"el-icon-stopwatch",
"el-icon-medal-1",
"el-icon-medal",
"el-icon-trophy",
"el-icon-trophy-1",
"el-icon-first-aid-kit",
"el-icon-discover",
"el-icon-place",
"el-icon-location",
"el-icon-location-outline",
"el-icon-location-information",
"el-icon-add-location",
"el-icon-delete-location",
"el-icon-map-location",
"el-icon-alarm-clock",
"el-icon-timer",
"el-icon-watch-1",
"el-icon-watch",
"el-icon-lock",
"el-icon-unlock",
"el-icon-key",
"el-icon-service",
"el-icon-mobile-phone",
"el-icon-bicycle",
"el-icon-truck",
"el-icon-ship",
"el-icon-basketball",
"el-icon-football",
"el-icon-soccer",
"el-icon-baseball",
"el-icon-wind-power",
"el-icon-light-rain",
"el-icon-lightning",
"el-icon-heavy-rain",
"el-icon-sunrise",
"el-icon-sunrise-1",
"el-icon-sunset",
"el-icon-sunny",
"el-icon-cloudy",
"el-icon-partly-cloudy",
"el-icon-cloudy-and-sunny",
"el-icon-moon",
"el-icon-moon-night",
"el-icon-dish",
"el-icon-dish-1",
"el-icon-food",
"el-icon-chicken",
"el-icon-fork-spoon",
"el-icon-knife-fork",
"el-icon-burger",
"el-icon-tableware",
"el-icon-sugar",
"el-icon-dessert",
"el-icon-ice-cream",
"el-icon-hot-water",
"el-icon-water-cup",
"el-icon-coffee-cup",
"el-icon-cold-drink",
"el-icon-goblet",
"el-icon-goblet-full",
"el-icon-goblet-square",
"el-icon-goblet-square-full",
"el-icon-refrigerator",
"el-icon-grape",
"el-icon-watermelon",
"el-icon-cherry",
"el-icon-apple",
"el-icon-pear",
"el-icon-orange",
"el-icon-coffee",
"el-icon-ice-tea",
"el-icon-ice-drink",
"el-icon-milk-tea",
"el-icon-potato-strips",
"el-icon-lollipop",
"el-icon-ice-cream-square",
"el-icon-ice-cream-round"
]
......@@ -2,10 +2,18 @@
<div class="parameter">
<TableHeader>
<div slot="left">
<el-button size="small" type="primary" @click="handleAdd"
>新增参数</el-button
<el-button
size="small"
v-hasPermi="['system:parameter:add']"
type="primary"
@click="handleAdd"
>新增</el-button
>
<el-button size="small" type="danger" @click="handleDelAll"
<el-button
size="small"
type="danger"
v-hasPermi="['system:parameter:remove']"
@click="handleDelAll"
>批量移除</el-button
>
</div>
......@@ -44,10 +52,16 @@
<template slot="action" slot-scope="scope">
<div class="flex jca">
<span class="primary pointer" @click="handleEdit(scope.row)"
<span
class="primary pointer"
v-hasPermi="['system:parameter:edit']"
@click="handleEdit(scope.row)"
>编辑</span
>
<span class="delete pointer" @click="handleDel(scope.row.id)"
<span
class="delete pointer"
v-hasPermi="['system:parameter:remove']"
@click="handleDel(scope.row.id)"
>删除</span
>
</div>
......
......@@ -180,11 +180,11 @@ export default {
},
// 重置
handleRest() {
this.resetForm("form");
this.$resetForm("form");
},
// 关闭
handleClose() {
this.resetForm("form");
this.$resetForm("form");
this.Visible = false;
},
},
......
<template>
<div class="h-full w-full">
<table-header>
<div slot="left">
<el-button
size="small"
type="primary"
v-hasPermi="['system:resourcemanage:add']"
@click="handleAdd"
>新增</el-button
>
<el-button
size="small"
type="danger"
v-hasPermi="['system:resourcemanage:remove']"
@click="handleDelAll"
>批量删除</el-button
>
</div>
<div slot="right">
<el-form ref="searchForm" :model="searchForm" inline>
<el-form-item prop="authType">
<el-select
size="small"
style="width: 150px"
v-model="searchForm.authType"
>
<el-option label="全部认证类型" value=""></el-option>
<el-option
v-for="(v, key) in dict.authType"
:key="key"
:label="v"
:value="key"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="name">
<el-input
size="small"
v-model="searchForm.name"
style="width: 200px"
class="ml10 mr10"
placeholder="请输入关键字搜索"
@keyup.native.enter="handleSearch"
></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="handleSearch"
>搜 索</el-button
>
</el-form-item>
<el-form-item>
<el-button size="small" @click="handleReset">重 置</el-button>
</el-form-item>
</el-form>
</div>
</table-header>
<div class="table-content">
<y-table
ref="MyTable"
:loading="loading"
:data="tableData"
:column="column"
border
tooltip-effect="dark"
:max-height="600"
:row-key="(row) => row.id"
@selection-change="handleSelectionChange"
></y-table>
</div>
<y-pagination
:total="total"
:page.sync="page"
:pageSize.sync="size"
@change="getResourceList"
></y-pagination>
<!-- 新增 -->
<AddResource
ref="AddResource"
:dict="dict"
:show.sync="show"
:title="title"
@success="getResourceList"
></AddResource>
</div>
</template>
<script>
import TableHeader from "@/components/TableHeader.vue";
import { getResourceList, deleteResource } from "@/api/system";
import AddResource from "./components/AddResource.vue";
export default {
components: {
TableHeader,
AddResource,
},
data() {
return {
loading: false,
show: false,
title: "新增资源",
column: [
{
label: "全选",
type: "selection",
width: "55",
align: "center",
reserveSelection: true,
},
{
label: "序号",
type: "index",
width: "55",
align: "center",
index: (index) => {
return (this.page - 1) * this.size + index + 1;
},
},
{
label: "所属分组",
prop: "groupName",
align: "center",
},
{
label: "名称",
prop: "name",
align: "center",
},
{
label: "资源",
prop: "url",
align: "center",
formatter: (row) => {
if (row.url) {
return row.url.split(",").map((v) => {
return (
<el-tag class="mb-2 mr-2" type="info" size="mini">
{v}
</el-tag>
);
});
}
},
},
{
label: "认证类型",
prop: "authType",
align: "center",
formatter: (row) => {
return this.dict.authType[row.authType];
},
},
{
label: "操作",
align: "center",
width: "120",
formatter: (row) => {
return (
<div class="table-control">
<span
v-hasPermi={["system:resourcemanage:edit"]}
class="primary pointer"
onClick={() => this.handleEdit(row)}
>
编辑
</span>
<span
v-hasPermi={["system:resourcemanage:remove"]}
class="delete pointer"
onClick={() => this.handleDel(row.id)}
>
删除
</span>
</div>
);
},
},
],
searchForm: {
authType: "",
name: "",
},
total: 0,
size: 10,
page: 1,
tableData: [],
selectionRows: [],
dict: {},
};
},
created() {
this.getResourceList();
},
methods: {
// 获取资源列表
async getResourceList() {
this.loading = true;
let res = await getResourceList({
page: this.page,
size: this.size,
...this.searchForm,
name: `%${this.searchForm.name}%`,
});
this.loading = false;
if (res.data.code == 1) {
let { data, total, dict } = res.data.data;
if (!data.length && this.page > 1) {
this.page -= 1;
this.getResourceList();
}
this.total = total;
this.tableData = data;
this.dict = dict;
}
},
handleAdd() {
this.title = "新增资源";
this.$refs.AddResource.onAdd();
this.show = true;
},
handleSelectionChange(rows) {
this.selectionRows = rows;
},
handleDelAll() {
if (!this.selectionRows.length) {
this.$message.warning("请先勾选数据");
return;
}
let ids = this.selectionRows.map((v) => v.id).join(",");
this.handleDel(ids);
},
handleSearch() {
this.page = 1;
this.getResourceList();
},
handleReset() {
this.page = 1;
this.$resetForm("searchForm");
this.$clearSelection("MyTable");
this.getResourceList();
},
handleEdit(row) {
let data = { ...row };
this.title = "编辑资源";
this.$refs.AddResource.onEdit(data);
this.show = true;
},
handleDel(id) {
this.$confirm("此操作将删除所选数据,是否继续?", "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
cancelButtonClass: "btn-custom-cancel",
type: "warning",
})
.then(async () => {
let res = await deleteResource({ id });
let { code, msg } = res.data;
if (code === 1) {
this.$message.success(msg);
this.getResourceList();
this.$clearSelection("MyTable");
}
})
.catch(() => {
console.log("取消成功!");
});
},
},
};
</script>
<style lang="less" scoped></style>
<template>
<div>
<el-dialog
:title="title"
:destroy-on-close="true"
:visible.sync="Visible"
width="30%"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
>
<el-form ref="form" :model="form" :rules="rules" size="medium" label-width="100px">
<el-form-item label="资源名称" prop="name">
<el-input v-model="form.name" placeholder="请输入资源名称"></el-input>
</el-form-item>
<el-form-item label="权限类型" prop="authType">
<el-select v-model="form.authType">
<el-option
v-for="(v, key) in dict.authType"
:key="key"
:label="v"
:value="Number(key)"
></el-option>
</el-select>
</el-form-item>
<el-form-item class="url-params-box" label="链接地址">
<el-form-item
class="url-params"
v-for="(v, i) in form.urls"
:key="i"
:prop="`urls.${i}.value`"
:rules="[{ required: true, validator: validatorUrl, trigger: 'blur' }]"
>
<el-input class="mr-[10px]" v-model="v.value" placeholder="请输入链接地址" />
<div class="flex">
<el-button type="primary" @click="changeParams(i, 'add')">
<i class="el-icon-plus"></i>
</el-button>
<el-button type="danger" v-if="i > 0" @click="changeParams(i, 'remove')"
><i class="el-icon-minus"></i
></el-button>
</div>
</el-form-item>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleRest">重 置</el-button>
<el-button size="medium" type="primary" @click="handleOk" :loading="loading"
>确 定</el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
import { saveResource } from '@/api/system';
export default {
props: {
title: {
type: String,
required: true,
default: ''
},
show: {
type: Boolean,
required: true,
default: false
},
dict: {
type: Object,
required: true,
default: () => {
return {};
}
}
},
data() {
return {
loading: false,
form: {
name: '',
authType: '',
url: '',
urls: [
{
value: ''
}
]
},
rules: {
name: [{ required: true, message: '请输入资源名称', trigger: 'blur' }],
authType: [{ required: true, message: '请选择权限类型', trigger: 'change' }]
}
};
},
computed: {
Visible: {
get() {
return this.show;
},
set(val) {
this.$emit('update:show', val);
}
}
},
created() {},
methods: {
// 确定
handleOk() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.loading = true;
let res = await saveResource({
...this.form,
url: this.form.urls.map((v) => v.value).join(',')
});
let { code, msg } = res.data;
if (code == 1) {
this.$message.success(msg);
this.$emit('success');
this.handleClose();
}
this.loading = false;
}
});
},
// 新增
onAdd() {
Object.assign(this.form, this.$options.data().form);
this.form.id && this.$delete(this.form, 'id');
},
// 编辑
onEdit(row) {
setTimeout(() => {
this.form = { ...row };
let arr = [];
if (this.form.url) {
arr = this.form.url.split(',').map((v) => {
return {
value: v
};
});
}
this.$set(this.form, 'urls', arr);
}, 10);
},
// 重置
handleRest() {
this.$resetForm('form');
this.$set(this.form, 'urls', [{ value: '' }]);
},
// 关闭
handleClose() {
this.$resetForm('form');
this.Visible = false;
},
// 判断是否存在链接
isRepeat(val) {
return this.form.urls.filter((v) => v.value == val).length > 1;
},
// 校验链接地址
validatorUrl(rule, value, callback) {
if (!value) {
callback(new Error('请输入链接'));
} else if (this.isRepeat(value)) {
callback(new Error('重复的链接地址'));
} else {
callback();
}
},
changeParams(index, type) {
if (type == 'add') {
let obj = {
value: ''
};
if (this.form.urls.some((v) => !v.value)) {
this.$message.warning('请先完成前面地址的填写');
return;
}
this.form.urls.splice(index + 1, 0, obj);
} else {
this.form.urls.splice(index, 1);
}
// this.$forceUpdate();
}
}
};
</script>
<style lang="less" scoped>
:deep(.el-select) {
width: 100%;
}
:deep(.url-params) {
margin-bottom: 22px;
.el-form-item__content {
display: flex;
}
}
</style>
<template>
<div class="h-full w-full">
<table-header>
<div slot="left">
<el-button
size="small"
type="primary"
v-hasPermi="['system:role:add']"
@click="handleAdd"
>新增</el-button
>
<el-button
size="small"
type="danger"
v-hasPermi="['system:role:remove']"
@click="handleDelAll"
>批量删除</el-button
>
</div>
<div slot="right">
<el-form ref="searchForm" :model="searchForm" inline>
<el-form-item prop="name">
<el-input
size="small"
v-model="searchForm.name"
style="width: 200px"
class="ml10 mr10"
placeholder="请输入角色名称搜索"
@keyup.native.enter="handleSearch"
></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="handleSearch"
>搜 索</el-button
>
</el-form-item>
<el-form-item>
<el-button size="small" @click="handleReset">重 置</el-button>
</el-form-item>
</el-form>
</div>
</table-header>
<!-- 表格 -->
<div class="table-content">
<y-table
ref="MyTable"
:loading="loading"
:data="tableData"
:column="column"
border
tooltip-effect="dark"
:max-height="600"
:row-key="(row) => row.id"
@selection-change="handleSelectionChange"
></y-table>
</div>
<y-pagination
:total="total"
:page.sync="page"
:pageSize.sync="size"
@change="getRoleList"
></y-pagination>
<!-- 新增 -->
<AddRole
ref="AddRole"
:show.sync="show"
:title="title"
@success="getRoleList"
></AddRole>
<!-- 分配资源 -->
<ApportionRes
ref="ApportionRes"
:show.sync="resShow"
@success="getRoleList"
></ApportionRes>
<!-- 分配菜单 -->
<ApportionMenu
ref="ApportionMenu"
:menuTree="menuTree"
:show.sync="menuShow"
:roleInfo="roleInfo"
@success="getRoleList"
></ApportionMenu>
</div>
</template>
<script>
import TableHeader from "@/components/TableHeader.vue";
import { getRoleList, deleteRole, getMenuTreeselect } from "@/api/system";
import AddRole from "./components/AddRole.vue";
import ApportionRes from "./components/ApportionRes.vue";
import ApportionMenu from "./components/ApportionMenu.vue";
export default {
components: {
TableHeader,
AddRole,
ApportionRes,
ApportionMenu,
},
data() {
return {
column: [
{
label: "全选",
type: "selection",
width: "55",
align: "center",
reserveSelection: true,
},
{
label: "序号",
type: "index",
width: "55",
align: "center",
index: (index) => {
return (this.page - 1) * this.size + index + 1;
},
},
{
label: "角色名称",
prop: "name",
align: "center",
},
{
label: "备注",
prop: "remark",
align: "center",
},
{
label: "创建时间",
prop: "createTime",
align: "center",
formatter: (row) => {
return this.$moment(row.createTime).format("YYYY-MM-DD HH:mm:ss");
},
},
{
label: "操作",
align: "center",
width: "260",
formatter: (row) => {
return (
<div class="table-control">
<span
v-hasPermi={["system:role:roleRes"]}
class="primary pointer"
onClick={() => this.apportion(row)}
>
分配资源
</span>
<span
v-hasPermi={["system:role:roleMenu"]}
class="primary pointer"
onClick={() => this.apportionMenu(row)}
>
分配菜单
</span>
<span
v-hasPermi={["system:role:edit"]}
class="primary pointer"
onClick={() => this.handleEdit(row)}
>
编辑
</span>
<span
v-hasPermi={["system:role:remove"]}
class="delete pointer"
onClick={() => this.handleDel(row.id)}
>
删除
</span>
</div>
);
},
},
],
searchForm: {
name: "",
},
tableData: [],
menuTree: [], // 菜单树
page: 1,
size: 10,
total: 0,
loading: false,
selectRows: [],
show: false,
menuShow: false,
title: "新增",
dict: {}, // 字典
resShow: false,
roleInfo: {},
};
},
created() {
this.getRoleList();
this.getMenuTreeselect();
},
computed: {},
methods: {
// 获取菜单树
async getMenuTreeselect() {
let res = await getMenuTreeselect({
page: 1,
size: -1,
});
if (res.data.code == 1) {
let { result } = res.data.data;
this.menuTree = result;
}
},
async getRoleList() {
this.loading = true;
let res = await getRoleList({
page: this.page,
size: this.size,
name: `%${this.searchForm.name}%`,
});
this.loading = false;
if (res.data.code == 1) {
let { data, total, dict } = res.data.data;
if (!data.length && this.page > 1) {
this.page -= 1;
this.getRoleList();
}
this.tableData = data;
this.total = total;
this.dict = dict;
}
},
// 批量移除
handleDelAll() {
if (!this.selectRows.length) {
this.$message.warning("请先勾选数据");
return;
}
let ids = this.selectRows.map((v) => v.id).join(",");
this.handleDel(ids);
},
// 搜索
handleSearch() {
this.page = 1;
this.$clearSelection("MyTable");
this.getRoleList();
},
// 重置
handleReset() {
this.page = 1;
this.$clearSelection("MyTable");
this.$resetForm("searchForm");
this.getRoleList();
},
// 选中
handleSelectionChange(select) {
this.selectRows = select;
},
// 新增
handleAdd() {
this.title = "新增";
this.$refs.AddRole.onAdd();
this.show = true;
},
// 编辑
handleEdit(row) {
this.title = "编辑";
let data = { ...row };
this.$refs.AddRole.onEdit(data);
this.show = true;
},
// 移除
handleDel(id) {
this.$confirm("此操作将删除所选数据,是否继续?", "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
cancelButtonClass: "btn-custom-cancel",
type: "warning",
})
.then(async () => {
let res = await deleteRole({ id });
let { code, msg } = res.data;
if (code === 1) {
this.$message.success(msg);
this.getRoleList();
this.$clearSelection("MyTable");
}
})
.catch(() => {
console.log("取消成功!");
});
},
// 分配资源
apportion(row) {
this.$refs.ApportionRes.onAdd(row.id);
this.resShow = true;
},
// 分配菜单
apportionMenu(row) {
this.roleInfo = row;
this.$refs.ApportionMenu.onAdd(row);
this.menuShow = true;
},
},
};
</script>
<style lang="less" scoped></style>
<template>
<div>
<el-dialog
:title="title"
:destroy-on-close="true"
:visible.sync="Visible"
width="30%"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
>
<el-form ref="form" :model="form" :rules="rules" size="medium" label-width="100px">
<el-form-item label="角色名称" prop="name">
<el-input placeholder="请输入角色名称" v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
resize="none"
:autosize="{ minRows: 3, maxRows: 3 }"
type="textarea"
placeholder="请输入备注"
v-model="form.remark"
></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleRest">重 置</el-button>
<el-button size="medium" type="primary" :loading="loading" @click="handleOk"
>确 定</el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
import { addRole } from '@/api/system';
export default {
components: {},
props: {
title: {
type: String,
required: true,
default: ''
},
show: {
type: Boolean,
required: true,
default: false
}
},
data() {
return {
loading: false,
form: {
name: '',
remark: ''
},
rules: {
name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }]
}
};
},
computed: {
Visible: {
get() {
return this.show;
},
set(val) {
this.$emit('update:show', val);
}
}
},
methods: {
// 确定
handleOk() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.loading = true;
let res = await addRole(this.form);
let { code, msg } = res.data;
if (code === 1) {
this.$message.success(msg);
this.$emit('success');
this.handleClose();
}
this.loading = false;
}
});
},
// 新增
onAdd() {
Object.assign(this.form, this.$options.data().form);
this.form.id && this.$delete(this.form, 'id');
},
// 编辑
onEdit(row) {
setTimeout(() => {
this.form = row;
}, 10);
},
// 重置
handleRest() {
this.$resetForm('form');
},
// 关闭
handleClose() {
this.$resetForm('form');
this.Visible = false;
}
}
};
</script>
<style lang="less" scoped></style>
<template>
<div>
<el-dialog
title="分配角色菜单"
:destroy-on-close="true"
:visible.sync="Visible"
width="30%"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
>
<el-form ref="form" :model="form" size="medium" label-width="100px">
<el-form-item label="角色名称">
<el-input readonly :value="roleInfo.name"></el-input>
</el-form-item>
<el-form-item label="菜单权限">
<el-checkbox v-model="isExpand" @change="handleCheckedTreeExpand"
>展开/折叠</el-checkbox
>
<el-checkbox v-model="isNodeAll" @change="handleCheckedTreeNodeAll"
>全选/全不选</el-checkbox
>
<el-checkbox v-model="checkStrictly">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuTree"
show-checkbox
ref="menu"
node-key="id"
:check-strictly="!checkStrictly"
:props="defaultProps"
></el-tree>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleRest">重 置</el-button>
<el-button
size="medium"
:loading="loading"
type="primary"
@click="handleOk"
>确 定</el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
import { addRoleMenu, getRoleMenuList } from "@/api/system";
export default {
components: {},
props: {
show: {
type: Boolean,
required: true,
default: false,
},
roleInfo: {
type: Object,
required: true,
default: () => {},
},
menuTree: {
type: Array,
required: true,
default: () => [],
},
},
data() {
return {
loading: false,
userMenuList: [], // 用户资源列表
// menuTree: [], // 菜单树
isExpand: false,
isNodeAll: false,
checkStrictly: true,
defaultProps: {
label: "label",
children: "children",
},
form: {
menuIdList: [],
roleId: "",
},
};
},
computed: {
Visible: {
get() {
return this.show;
},
set(val) {
this.$emit("update:show", val);
},
},
},
methods: {
// 获取角色菜单列表
async getRoleMenuList() {
let res = await getRoleMenuList({
roleId: this.form.roleId,
page: 1,
size: -1,
});
if (res.data.code == 1) {
let { data } = res.data;
let ids = this.getRoleMenuIdList(data);
ids.forEach((v) => {
this.$nextTick(() => {
this.$refs.menu.setChecked(v, true, false);
});
});
}
},
// 确定
async handleOk() {
this.loading = true;
let res = await addRoleMenu({
roleId: this.form.roleId,
menuIdList: this.getMenuAllCheckedKeys(),
});
let { code, msg } = res.data;
if (code === 1) {
this.$message.success(msg || "添加成功");
this.$emit("success");
this.handleClose();
}
this.loading = false;
},
// 所有菜单节点数据
getMenuAllCheckedKeys() {
// 目前被选中的菜单节点
let checkedKeys = this.$refs.menu.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys();
return [...halfCheckedKeys, ...checkedKeys];
},
// 树权限(展开/折叠)
handleCheckedTreeExpand(value) {
let treeList = this.menuTree;
for (let i = 0; i < treeList.length; i++) {
this.$refs.menu.store.nodesMap[treeList[i].id].expanded = value;
}
},
// 树权限(全选/全不选)
handleCheckedTreeNodeAll(value) {
this.$refs.menu.setCheckedNodes(value ? this.menuTree : []);
},
// 新增
async onAdd(row) {
Object.assign(this.form, this.$options.data().form);
this.form.roleId = row.id;
this.getRoleMenuList();
},
// 重置
handleRest() {
this.isNodeAll = false;
this.$refs.menu.setCheckedNodes([]);
},
// 关闭
handleClose() {
this.handleRest();
this.isExpand = false;
this.isNodeAll = false;
this.checkStrictly = true;
this.Visible = false;
},
// 获取角色菜单id列表
getRoleMenuIdList(data) {
let result = [];
let getData = (list) => {
list.forEach((item) => {
item.checked && result.push(item.id);
if (item.children && item.children.length > 0) {
getData(item.children);
}
});
};
getData(data);
return result;
},
},
};
</script>
<style lang="less" scoped>
:deep(.el-dialog__body) {
max-height: 620px;
overflow: auto;
}
.tree-border {
margin-top: 5px;
border: 1px solid #e5e6e7;
background: #fff none;
border-radius: 4px;
}
</style>
<template>
<div>
<el-dialog
title="分配角色资源"
:destroy-on-close="true"
:visible.sync="Visible"
width="50%"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
>
<div class="res-item" v-for="(v, key) in resourceList" :key="key">
<div class="title-box">
<span class="title">{{ key }}</span>
<el-checkbox
:indeterminate="v.isIndeterminate"
v-model="v.checkAll"
@change="handleCheckAllChange($event, v)"
>全选</el-checkbox
>
</div>
<el-checkbox-group
v-model="form.resourceIdList"
@change="onChange($event, v)"
>
<el-row>
<el-col :span="6" v-for="item in v.list" :key="item.id">
<el-checkbox :label="item.id">{{ item.name }}</el-checkbox>
</el-col>
</el-row>
</el-checkbox-group>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleRest">重 置</el-button>
<el-button
size="medium"
type="primary"
:loading="loading"
@click="handleOk"
>确 定</el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
import {
getRoleResourceList,
addRoleResource,
getResourceGroup,
} from "@/api/system";
export default {
components: {},
props: {
show: {
type: Boolean,
required: true,
default: false,
},
},
data() {
return {
loading: false,
resourceList: {},
userResourceList: [], // 用户资源列表
form: {
resourceIdList: [],
roleId: "",
},
};
},
computed: {
Visible: {
get() {
return this.show;
},
set(val) {
this.$emit("update:show", val);
},
},
},
methods: {
// 获取资源分组
async getResourceGroup() {
let res = await getResourceGroup({
page: 1,
size: -1,
});
if (res.data.code == 1) {
let { data } = res.data.data;
let group = this.formatGroup(data);
this.resourceList = group;
}
},
// 获取角色资源权限列表
async getRoleResourceList(roleId) {
let res = await getRoleResourceList({
size: -1,
page: 1,
roleId,
});
if (res.data.code == 1) {
let { data } = res.data.data;
let arr = data.filter((v) => v.resourceId);
this.form.resourceIdList = arr.map((v) => v.resourceId);
}
},
// 权限分组
// groupByAuth(list) {
// let group = {};
// list.forEach((item) => {
// let name = item.name.split("-")[0];
// if (!group[name]) {
// group[name] = {
// isIndeterminate: false,
// checkAll: false,
// list: [],
// };
// }
// group[name].list.push(item);
// });
// return group;
// },
// 格式化分组
formatGroup(data) {
let group = {};
Object.keys(data).forEach((key) => {
group[key] = {
isIndeterminate: false,
checkAll: false,
list: [],
};
group[key].list.push(...data[key]);
});
return group;
},
// 确定
async handleOk() {
this.loading = true;
let res = await addRoleResource(this.form);
let { code } = res.data;
if (code === 1) {
this.$message.success("添加成功");
this.$emit("success");
this.handleClose();
}
this.loading = false;
},
// 新增
async onAdd(roleId) {
Object.assign(this.form, this.$options.data().form);
this.form.roleId = roleId;
await this.getResourceGroup();
this.getRoleResourceList(roleId);
},
// 重置
handleRest() {
this.form.resourceIdList = [];
Object.keys(this.resourceList).forEach((key) => {
this.resourceList[key].checkAll = false;
this.resourceList[key].indeterminate = false;
});
},
// 关闭
handleClose() {
this.handleRest();
this.Visible = false;
},
handleCheckAllChange(checked, row) {
let rowIds = row.list.map((v) => v.id);
row.isIndeterminate = false;
if (checked) {
this.form.resourceIdList = [
...new Set([...this.form.resourceIdList, ...rowIds]),
];
} else {
this.form.resourceIdList = this.form.resourceIdList.filter((v) => {
return !rowIds.includes(v);
});
}
},
onChange(checkedList, row) {
let rowIds = row.list.map((v) => v.id);
let list = checkedList.filter((v) => {
return rowIds.includes(v);
});
row.isIndeterminate = !!list.length && list.length < rowIds.length;
row.checkAll = list.length === rowIds.length;
},
},
};
</script>
<style lang="less" scoped>
:deep(.el-dialog__body) {
max-height: 620px;
overflow: auto;
}
.title-box {
border-bottom: 1px solid #e9e9e9;
}
.el-col {
margin-bottom: 10px;
}
.res-item,
.title-box {
margin-bottom: 10px;
}
.title {
margin-right: 1em;
font-size: 18px;
font-weight: bold;
}
</style>
......@@ -2,10 +2,18 @@
<div class="task-set">
<TableHeader>
<div slot="left">
<el-button size="small" type="primary" @click="handleAdd"
>新增任务</el-button
<el-button
size="small"
type="primary"
v-hasPermi="['system:task:add']"
@click="handleAdd"
>新增</el-button
>
<el-button size="small" type="danger" @click="handleDelAll"
<el-button
size="small"
type="danger"
v-hasPermi="['system:task:remove']"
@click="handleDelAll"
>批量移除</el-button
>
</div>
......@@ -49,10 +57,16 @@
<template slot="action" slot-scope="scope">
<div class="flex jca">
<span class="primary pointer" @click="handleEdit(scope.row)"
<span
class="primary pointer"
v-hasPermi="['system:task:edit']"
@click="handleEdit(scope.row)"
>编辑</span
>
<span class="delete pointer" @click="handleDel(scope.row.id)"
<span
class="delete pointer"
v-hasPermi="['system:task:remove']"
@click="handleDel(scope.row.id)"
>删除</span
>
</div>
......@@ -61,8 +75,8 @@
</div>
<y-pagination
:total="total"
:page="page"
:pageSize="size"
:page.sync="page"
:pageSize.sync="size"
@change="getTaskList"
></y-pagination>
<!-- 新增参数 -->
......
......@@ -225,11 +225,11 @@ export default {
},
// 重置
handleRest() {
this.resetForm("form");
this.$resetForm("form");
},
// 关闭
handleClose() {
this.resetForm("form");
this.$resetForm("form");
this.Visible = false;
},
// 切换策略
......
<template>
<div class="user-page">
<table-header>
<div slot="right">
<el-form ref="searchForm" :model="searchForm" inline size="small">
<el-form-item prop="type">
<el-select
style="width: 120px"
v-model="searchForm.type"
placeholder="请选择"
>
<el-option
v-for="(v, key) in typeList"
:key="key"
:label="v"
:value="key"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="keyword">
<el-input
v-model="searchForm.keyword"
style="width: 200px"
class="ml10 mr10"
placeholder="请输入关键字搜索"
@keyup.native.enter="handleSearch"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜 索</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleReset">重 置</el-button>
</el-form-item>
</el-form>
</div>
</table-header>
<!-- 表格 -->
<div class="table-content">
<y-table
ref="MyTable"
:loading="loading"
:data="tableData"
:column="column"
border
tooltip-effect="dark"
:max-height="600"
:row-key="(row) => row.id"
></y-table>
</div>
<y-pagination
:total="total"
:page.sync="page"
:pageSize.sync="size"
@change="getUserList"
></y-pagination>
<!-- 分配角色 -->
<AddUserRole
ref="AddUserRole"
:show.sync="show"
@success="getUserList"
></AddUserRole>
</div>
</template>
<script>
import TableHeader from "@/components/TableHeader.vue";
import AddUserRole from "./components/AddUserRole.vue";
import { getUserList } from "@/api/system";
let typeList = {
loginName: "按登录名",
realName: "按用户姓名",
mobile: "按手机号码",
};
export default {
components: {
TableHeader,
AddUserRole,
},
data() {
return {
typeList,
column: [
{
label: "序号",
type: "index",
width: "55",
align: "center",
index: (index) => {
return (this.page - 1) * this.size + index + 1;
},
},
{
label: "登录名",
prop: "loginName",
align: "center",
},
{
label: "用户姓名",
prop: "realName",
align: "center",
},
{
label: "手机号码",
prop: "mobile",
align: "center",
},
{
label: "所属角色",
prop: "roleIds",
align: "center",
formatter: (row) => {
if (row.roleIds) {
return (
<div class="flex justify-center gap-2">
{row.roleIds.split(",").map((v) => {
return (
<el-tag size="small" type="info">
{this.dict.roleIds[v]}
</el-tag>
);
})}
</div>
);
}
},
},
{
label: "状态",
prop: "status",
align: "center",
formatter: (row) => {
if (this.dict.status) {
return this.dict.status[row.status];
}
},
},
{
label: "创建时间",
prop: "createTime",
align: "center",
formatter: (row) => {
return this.$moment(row.createTime).format("YYYY-MM-DD HH:mm:ss");
},
},
{
label: "操作",
align: "center",
width: "120",
formatter: (row) => {
return (
<span
v-hasPermi={["system:user:userRole"]}
class="primary pointer"
onClick={() => this.apportion(row)}
>
分配角色
</span>
);
},
},
],
searchForm: {
type: "loginName",
keyword: "",
},
tableData: [],
page: 1,
size: 10,
total: 0,
loading: false,
selectRows: [],
show: false,
title: "新增",
dict: {}, // 字典
resShow: false,
};
},
created() {
this.getUserList();
},
computed: {},
methods: {
// 列表
async getUserList() {
this.loading = true;
let obj = {};
let value = `%${this.searchForm.keyword}%`;
obj[this.searchForm.type] = value;
let res = await getUserList({
page: this.page,
size: this.size,
...obj,
});
this.loading = false;
if (res.data.code == 1) {
let { data, total, dict } = res.data.data;
if (!data.length && this.page > 1) {
this.page -= 1;
this.getUserList();
}
this.tableData = data;
this.total = total;
this.dict = dict;
}
},
// 搜索
handleSearch() {
this.page = 1;
this.$clearSelection("MyTable");
this.getUserList();
},
// 重置
handleReset() {
this.page = 1;
this.$clearSelection("MyTable");
this.$resetForm("searchForm");
this.getUserList();
},
apportion(row) {
let data = { ...row };
this.$refs.AddUserRole.onEdit(data);
this.show = true;
},
},
};
</script>
<style lang="less" scoped></style>
<template>
<div>
<el-dialog
title="分配角色"
:destroy-on-close="true"
:visible.sync="Visible"
width="30%"
@close="handleClose"
:close-on-click-modal="false"
top="10vh"
>
<el-form ref="form" :model="form" :rules="rules" size="medium" label-width="100px">
<el-form-item label="角色名称" prop="roleIds">
<el-select
multiple
clearable
style="width: 100%"
v-model="form.roleIds"
placeholder="请选择角色"
>
<el-option v-for="v in roleList" :key="v.id" :label="v.name" :value="v.id"> </el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleRest">重 置</el-button>
<el-button size="medium" type="primary" @click="handleOk">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getRoleList, saveUser } from '@/api/system';
export default {
components: {},
props: {
show: {
type: Boolean,
required: true,
default: false
}
},
data() {
return {
roleList: [],
form: {
roleIds: []
},
rules: {
roleIds: [{ required: true, message: '请选择角色', trigger: 'change' }]
}
};
},
computed: {
Visible: {
get() {
return this.show;
},
set(val) {
this.$emit('update:show', val);
}
}
},
created() {
this.getRoleList();
},
methods: {
// 获取角色列表
async getRoleList() {
let res = await getRoleList({
page: 1,
size: -1
});
if (res.data.code == 1) {
let { data } = res.data.data;
this.roleList = data;
}
},
// 确定
handleOk() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.loading = true;
let { id, roleIds, lastLoginAddress, mobile } = this.form;
let res = await saveUser({
id,
lastLoginAddress,
mobile,
roleIds: roleIds.join(',')
});
let { code, msg } = res.data;
if (code == 1) {
this.$message.success(msg);
this.$emit('success');
this.handleClose();
}
this.loading = false;
}
});
},
// 新增
onAdd() {
Object.assign(this.form, this.$options.data().form);
this.form.id && this.$delete(this.form, 'id');
},
// 编辑
onEdit(row) {
setTimeout(() => {
this.form = { ...row };
if (this.form.roleIds) {
this.form.roleIds = this.form.roleIds.split(',').map(Number);
} else {
this.form.roleIds = [];
}
}, 10);
},
// 重置
handleRest() {
this.$resetForm('form');
},
// 关闭
handleClose() {
this.$resetForm('form');
this.Visible = false;
}
}
};
</script>
<style lang="less" scoped></style>
......@@ -2,6 +2,7 @@ import Vue from "vue";
import VueRouter from "vue-router";
import Layouts from "@/pages/layouts/Layouts.vue";
import store from "@/store";
import { generateRoutes } from "@/utils";
// import local from "@/utils/local";
// 解决重复点击同一个路由报错
const originalPush = VueRouter.prototype.push;
......@@ -23,109 +24,117 @@ Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "/",
component: Layouts,
redirect: "/jump",
children: [
{
path: "/basicsset",
// name: '样表基础设置',
hideChildrenInMenu: true,
component: () => import("@/pages/software/basics/BasicsSet"),
meta: {
icon: "el-icon-setting",
title: "样表基础设置",
},
},
{
path: "/mattermanage",
// name: "样表事项管理",
hideChildrenInMenu: true,
component: () => import("@/pages/software/matter/MatterManage"),
meta: {
icon: "el-icon-document",
title: "样表事项管理",
},
},
{
path: "/materialsmanage",
// name: '样表管理',
hideChildrenInMenu: true,
component: () => import("@/pages/software/materials/MaterialsManage"),
meta: {
icon: "el-icon-files",
title: "样表管理",
},
},
{
path: "/librarymanage",
// name: '公共库管理',
hideChildrenInMenu: true,
component: () => import("@/pages/software/librarymanage/LibraryManage"),
meta: {
icon: "el-icon-refrigerator",
title: "公共库管理",
},
},
{
path: "/skinmanage",
hideChildrenInMenu: true,
component: () => import("@/pages/software/skinManage/SkinManage"),
meta: {
icon: "el-icon-orange",
title: "皮肤管理",
},
},
{
path: "/numberwritedevice",
// name: '设备管理',
hideChildrenInMenu: true,
component: () => import("@/pages/hardware/NumberWriteDevice"),
meta: {
icon: "el-icon-monitor",
title: "设备管理",
},
},
{
path: "/system",
hideChildrenInMenu: true,
component: () => import("@/pages/system/System.vue"),
redirect: "/system/parameter",
meta: {
icon: "el-icon-data-board",
title: "系统设置",
},
children: [
{
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: "/basicsset",
// // name: '样表基础设置',
// hideChildrenInMenu: true,
// component: () => import("@/pages/software/basics/BasicsSet"),
// meta: {
// icon: "el-icon-setting",
// title: "样表基础设置",
// },
// },
// {
// path: "/mattermanage",
// // name: "样表事项管理",
// hideChildrenInMenu: true,
// component: () => import("@/pages/software/matter/MatterManage"),
// meta: {
// icon: "el-icon-document",
// title: "样表事项管理",
// },
// },
// {
// path: "/materialsmanage",
// // name: '样表管理',
// hideChildrenInMenu: true,
// component: () => import("@/pages/software/materials/MaterialsManage"),
// meta: {
// icon: "el-icon-files",
// title: "样表管理",
// },
// },
// {
// path: "/librarymanage",
// // name: '公共库管理',
// hideChildrenInMenu: true,
// component: () => import("@/pages/software/librarymanage/LibraryManage"),
// meta: {
// icon: "el-icon-refrigerator",
// title: "公共库管理",
// },
// },
// {
// path: "/skinmanage",
// hideChildrenInMenu: true,
// component: () => import("@/pages/software/skinManage/SkinManage"),
// meta: {
// icon: "el-icon-orange",
// title: "皮肤管理",
// },
// },
// {
// path: "/numberwritedevice",
// // name: '设备管理',
// hideChildrenInMenu: true,
// component: () => import("@/pages/hardware/NumberWriteDevice"),
// meta: {
// icon: "el-icon-monitor",
// title: "设备管理",
// },
// },
// {
// path: "/system",
// hideChildrenInMenu: true,
// component: () => import("@/pages/system/System.vue"),
// redirect: "/system/parameter",
// meta: {
// icon: "el-icon-data-board",
// title: "系统设置",
// },
// children: [
// {
// path: "/system/menu",
// component: () => import("@/pages/system/menu/Menu.vue"),
// meta: {
// activeMenu: "/system",
// title: "菜单",
// icon: "el-icon-cpu",
// },
// },
// {
// 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",
// },
// },
// ],
// },
],
},
{
......@@ -163,140 +172,6 @@ router.beforeEach((to, from, next) => {
}
});
// 动态菜单
// const dynamicRouter = [
// {
// path: "/basicsset",
// component: Layouts,
// meta: {
// icon: "el-icon-setting",
// title: "样表基础设置",
// },
// children: [
// {
// path: "",
// // name: '样表基础设置',
// component: () => import("@/pages/software/basics/BasicsSet"),
// },
// ],
// },
// {
// path: "/mattermanage",
// component: Layouts,
// meta: {
// icon: "el-icon-document",
// title: "样表事项管理",
// },
// children: [
// {
// path: "",
// name: "样表事项管理",
// component: () => import("@/pages/software/matter/MatterManage"),
// },
// ],
// },
// {
// path: "/materialsmanage",
// component: Layouts,
// meta: {
// icon: "el-icon-files",
// title: "样表管理",
// },
// children: [
// {
// path: "",
// // name: '材料管理',
// component: () => import("@/pages/software/materials/MaterialsManage"),
// },
// ],
// },
// {
// path: "/librarymanage",
// component: Layouts,
// meta: {
// icon: "el-icon-refrigerator",
// title: "公共库管理",
// },
// children: [
// {
// path: "",
// // name: '公共库管理',
// component: () => import("@/pages/software/librarymanage/LibraryManage"),
// },
// ],
// },
// {
// path: "/skinmanage",
// component: Layouts,
// meta: {
// icon: "el-icon-orange",
// title: "皮肤管理",
// },
// children: [
// {
// path: "",
// component: () => import("@/pages/software/skinManage/SkinManage"),
// },
// ],
// },
// {
// path: "/numberwritedevice",
// component: Layouts,
// meta: {
// icon: "el-icon-monitor",
// title: "数字样表设备",
// },
// children: [
// {
// path: "",
// // name: '数字样表设备',
// component: () => import("@/pages/hardware/NumberWriteDevice"),
// },
// ],
// },
// {
// path: "/system",
// component: Layouts,
// meta: {
// icon: "el-icon-data-board",
// title: "系统设置",
// },
// children: [
// {
// path: "",
// component: () => import("@/pages/system/System.vue"),
// redirect: "/system/parameter",
// children: [
// {
// path: "/system/parameter",
// component: () => import("@/pages/system/parameter/Parameter.vue"),
// meta: {
// activeMenu: "/system",
// hidden: true,
// },
// },
// {
// path: "/system/task",
// component: () => import("@/pages/system/task/TaskSet.vue"),
// meta: {
// activeMenu: "/system",
// hidden: true,
// },
// },
// {
// path: "/system/systemlogs",
// component: () => import("@/pages/system/systemlogs/SystemLogs.vue"),
// meta: {
// activeMenu: "/system",
// hidden: true,
// },
// },
// ],
// },
// ],
// },
// ];
// 过滤菜单
function menusFilter(arr) {
let router = arr.filter((v) => {
......@@ -311,11 +186,13 @@ function menusFilter(arr) {
}
// 动态菜单
export function calcMenu() {
// dynamicRouter.forEach((v) => {
// router.addRoute(v);
// });
let menus = menusFilter(routes[0].children);
store.commit("SET_MENUS", menus);
let menusList = store.getters["menusList"];
let dynamicRouter = generateRoutes(menusList);
dynamicRouter.forEach((v) => {
router.addRoute("/", v);
});
let menus = menusFilter(dynamicRouter);
store.commit("SET_menus", menus);
}
calcMenu();
......
......@@ -8,37 +8,83 @@ Vue.use(Vuex);
export default new Vuex.Store({
state: {
menus: [], // 菜单
token: "",
siteId: "", // 站点id
deptList: [], // 部门列表
sysName: "", // 系统名称
sysLogo: "", // 系统logo
path: "", // 门户跳转过来的路由
menusList: [], // 原始菜单列表
menus: [], // 格式化菜单列表
routes: [], // 路由列表
secondaryRoutes: [], // 二级路由
barList: [], // 登录返回菜单
homeData: {}, // 首页数据
userInfo: {}, // 用户信息
permissions: [], // 按钮权限字符列表
},
getters: {
token(state) {
return state.token;
},
siteId(state) {
return state.siteId;
},
deptList(state) {
return state.deptList;
},
userInfo(state) {
return state.userInfo;
},
token(state) {
return state.token;
},
path(state) {
return state.path;
},
barList(state) {
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_MENUS(state, menus) {
SET_menusList(state, menusList) {
state.menusList = menusList;
},
SET_routes(state, routes) {
state.routes = routes;
},
SET_permissions(state, permissions) {
state.permissions = permissions;
},
SET_secondaryRoutes(state, value) {
let routes = state.menus.find((v) => v.path == value);
let secondaryRoutes = routes.children || [];
state.secondaryRoutes = secondaryRoutes;
},
SET_path(state, path) {
state.path = path;
},
SET_menus(state, menus) {
state.menus = menus;
},
SET_SITEID(state, siteId) {
SET_siteId(state, siteId) {
state.siteId = siteId;
},
SET_deptList(state, deptList) {
state.deptList = deptList;
SET_userInfo(state, userInfo) {
state.userInfo = userInfo;
},
SET_sysName(state, sysName) {
state.sysName = sysName;
......@@ -49,8 +95,23 @@ export default new Vuex.Store({
SET_token(state, token) {
state.token = token;
},
SET_path(state, path) {
state.path = path;
SET_areaTree(state, areaTree) {
state.areaTree = areaTree;
},
SET_businessList(state, businessList) {
state.businessList = businessList;
},
SET_deptList(state, deptList) {
state.deptList = deptList;
},
SET_windowList(state, windowList) {
state.windowList = windowList;
},
SET_barList(state, barList) {
state.barList = barList;
},
SET_homeData(state, homeData) {
state.homeData = homeData;
},
},
actions: {},
......@@ -61,7 +122,7 @@ export default new Vuex.Store({
// storage: window.sessionStorage,
// }),
createPersistedState({
key: "sample",
key: "info",
storage: {
getItem: (key) => SessionCrypto.getItem(key),
setItem: (key, value) => SessionCrypto.setItem(key, value),
......
......@@ -103,3 +103,103 @@ export function resetForm(refName) {
this.$refs[refName].resetFields();
}
}
// 表格清除选中
export function clearSelection(refName) {
if (this.$refs[refName]) {
this.$refs[refName].clearSelection();
}
}
// 构建树形数据
export function buildTree(data, idField = "id", parentIdField = "parentId") {
const idToItem = {};
data.forEach((item) => {
idToItem[item[idField]] = { ...item, childList: [] };
});
const tree = [];
data.forEach((item) => {
const parentId = item[parentIdField];
if (parentId === null || parentId === 0) {
tree.push(idToItem[item[idField]]);
} else {
const parent = idToItem[parentId];
if (parent) {
parent.childList.push(idToItem[item[idField]]);
} else {
tree.push(idToItem[item[idField]]);
}
}
});
return tree;
}
// 生成路由
export const generateRoutes = (menuList) => {
let routers = menuList.map((item) => {
// 构造符合要求的结构
let path = item.url.charAt(0) === "/" ? item.url : "/" + item.url;
let name = item.url.replace(/^\//, "");
let activeMenu = item.activeDir
? "/" + item.activeDir.replace(/^\//, "")
: "";
let component = item.component ? item.component.replace(/^\//, "") : null;
const newItem = {
path,
name,
hidden: !!item.visible,
hideChildrenInMenu: !!item.hideChildrenInMenu,
component: () => import(`@/${component}`),
meta: {
title: item.name,
icon: item.imgPath,
keepAlive: !!item.cache,
activeMenu,
},
};
// 递归处理子节点
if (item.children && item.children.length > 0) {
newItem.children = generateRoutes(item.children);
// 如果存在子路由,默认重定向到第一个不是在菜单栏隐藏的子路由
let firstChild = newItem.children.find((v) => !v.hidden);
if (firstChild) {
newItem.redirect = firstChild.path;
}
}
return newItem;
});
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;
};
......@@ -931,6 +931,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.3.1":
version "7.27.0"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762"
integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.0.0", "@babel/template@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
......@@ -1108,6 +1115,20 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
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.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
......@@ -2081,7 +2102,7 @@ axios@^0.27.2:
follow-redirects "^1.14.9"
form-data "^4.0.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==
......@@ -3514,6 +3535,11 @@ duplexify@^3.4.2, duplexify@^3.6.0:
readable-stream "^2.0.0"
stream-shift "^1.0.0"
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.yarnpkg.com/easy-stack/-/easy-stack-1.0.1.tgz#8afe4264626988cabb11f3c704ccd0c835411066"
......@@ -4385,6 +4411,11 @@ functions-have-names@^1.2.2:
resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
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==
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.npmmirror.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
......@@ -5302,6 +5333,11 @@ is-plain-object@^2.0.3, 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-redirect@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
......@@ -5969,7 +6005,7 @@ lodash.without@~4.4.0:
resolved "https://registry.npmmirror.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
integrity sha512-M3MefBwfDhgKgINVuBJCO1YR3+gf6s9HNJsIiZ/Ru77Ws6uTb9eBuvrkpzO+9iLoAaRodGuq7tyrPCx+74QYGQ==
lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3:
lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
......@@ -6086,6 +6122,11 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.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.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
......@@ -7990,6 +8031,11 @@ regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
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.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
......@@ -9639,6 +9685,11 @@ vuex@^3.6.2:
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"
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.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
......
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