简化,适用于快速搭建项目

This commit is contained in:
Billy 2022-03-07 15:18:34 +08:00
parent 7802b85ed2
commit fc3679a5eb
47 changed files with 74 additions and 4850 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 847 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 B

View File

@ -1,70 +0,0 @@
/*
* @Author: Guanghao
* @Date: 2022-01-05 18:48:51
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-05 18:53:10
* @Description: 日志相关数据请求和处理逻辑
*/
/**
* @description 查询操作日志列表
* @returns {Array.<Log>} 日志对象数组
*/
async function findByAction() {
return [
{
user: '张三',
time: '2021-12-31 18:40:11',
module: '演示方案',
position: '101主题',
action: '编辑'
},
{
user: '张三',
time: '2021-12-31 18:40:11',
module: '演示方案',
position: '101主题',
action: '编辑'
},
{
user: '张三',
time: '2021-12-31 18:40:11',
module: '演示方案',
position: '101主题',
action: '编辑'
},
]
}
/**
* @description 查询登录日志列表
* @returns {Array.<Log>} 日志对象数组
*/
async function findByLogin() {
return [
{
user: '张三',
time: '2021-12-31 18:43:55',
result: '成功',
ip: '192.168.0.0.228'
},
{
user: '张三',
time: '2021-12-31 18:43:55',
result: '成功',
ip: '192.168.0.0.228'
},
{
user: '张三',
time: '2021-12-31 18:43:55',
result: '成功',
ip: '192.168.0.0.228'
},
]
}
export default {
findByAction,
findByLogin
}

View File

@ -1,67 +0,0 @@
/*
* @Author: Billy
* @Date: 2021-12-31 14:31:45
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 14:00:53
* @Description: 请输入
*/
import MenuItem from "../../entity/Ui/Menu/MenuItem.js";
async function getBackMenuItems() {
return [
new MenuItem({
title: '组织架构',
iconClass: 'el-icon-s-operation',
routerName: 'Org',
}),
new MenuItem({
title: '角色管理',
iconClass: 'el-icon-user',
routerName: 'Role',
}),
new MenuItem({
title: '分类管理',
iconClass: 'el-icon-film',
routerName: 'Classification',
}),
new MenuItem({
title: '数据统计',
iconClass: 'el-icon-s-data',
routerName: 'Statistics',
}),
new MenuItem({
title: '专题管理',
iconClass: 'el-icon-edit-outline',
routerName: 'Topic',
}),
new MenuItem({
title: '平台设置',
iconClass: 'el-icon-setting',
routerName: 'PlatformSetting',
}),
new MenuItem({
title: '授权管理',
iconClass: 'el-icon-finished',
routerName: 'Authorization',
children: [
new MenuItem({
title: '合作伙伴授权管理',
routerName: 'Authorization4Partner',
}),
new MenuItem({
title: '客户授权管理',
routerName: 'Authorization4Customer',
})
]
}),
new MenuItem({
title: '系统日志',
iconClass: 'el-icon-notebook-2',
routerName: 'Log',
}),
];
}
export default {
getBackMenuItems
};

View File

@ -2,7 +2,7 @@
* @Author: Billy
* @Date: 2021-12-18 02:20:09
* @LastEditors: Billy
* @LastEditTime: 2022-01-07 16:40:08
* @LastEditTime: 2022-03-07 14:36:12
* @Description: 请输入
*/
@ -10,6 +10,13 @@ import MenuItem from "../entity/Ui/Menu/MenuItem.js";
async function getMainMenuItems() {
return [
new MenuItem({
id: 'ProductAndCases',
title: '产品案例',
routerName: 'ProductAndCases',
}),
// 内部标签
new MenuItem({
id: 'ProductAndCases',
@ -51,68 +58,16 @@ async function getMainMenuItems() {
routerName: 'PersonalSpace',
}),
// popover
new MenuItem({
id: 'More',
title: '更多',
iconSrc: require("../assets/MenuIcons/Main/More1.png"),
iconSrcInactive: require("../assets/MenuIcons/Main/More2.png"),
// routerName: 'More',
}),
]
}
async function getSecondaryMenuItems() {
return [
// 抽屉
new MenuItem({
id: 'QuickFavorites',
title: '快捷收藏',
iconSrc: require("../assets/MenuIcons/Secondary/QuickFavorites.png"),
// routerName: 'QuickFavorites',
drawerName: 'QuickFavorites'
}),
// 内部标签
new MenuItem({
id: 'QuickDemonstrations',
title: '快捷演示方案',
iconSrc: require("../assets/MenuIcons/Secondary/QuickDemonstrations.png"),
routerName: 'QuickDemonstrations',
}),
// 抽屉
new MenuItem({
id: 'Clients',
title: '客户列表',
iconSrc: require("../assets/MenuIcons/Secondary/Clients.png"),
// routerName: 'Clients',
drawerName: 'Clients'
}),
// 抽屉
new MenuItem({
id: 'Partners',
title: '合作伙伴',
iconSrc: require("../assets/MenuIcons/Secondary/Partners.png"),
// routerName: 'Partners',
drawerName: 'Partners'
}),
// 抽屉
new MenuItem({
id: 'PersonalComputer',
title: '我的电脑',
iconSrc: require("../assets/MenuIcons/Secondary/PersonalComputer.png"),
// routerName: 'PersonalComputer',
drawerName: 'PersonalComputer'
}),
// 内部标签
new MenuItem({
id: 'CloudDesktop',
title: '云桌面',
iconSrc: require("../assets/MenuIcons/Secondary/CloudDesktop.png"),
routerName: 'CloudDesktop',
}),
// new MenuItem({
// id: 'More',
// title: '更多',
// iconSrc: require("../assets/MenuIcons/Main/More1.png"),
// iconSrcInactive: require("../assets/MenuIcons/Main/More2.png"),
// // routerName: 'More',
// }),
]
}
export default {
getMainMenuItems,
getSecondaryMenuItems
getMainMenuItems
};

View File

@ -1,218 +0,0 @@
<template>
<div class="header-inner" :class="arrangeMode">
<div class="header-menu"></div>
<div class="header-userinfo">
<el-popover
v-model="isUserInfoVisible"
class="userinfo-popover"
width="150"
:placement="arrangeMode === 'horizontal' ? 'bottom' : 'right'"
trigger="click"
>
<el-menu
:default-active="headerActiveIndex"
@select="handleUserMenuSelect"
>
<el-menu-item index="d">
<i class="el-icon-warning-outline"></i>
<span slot="title">系统数据</span>
</el-menu-item>
<el-menu-item index="a">
<i class="el-icon-user"></i>
<span slot="title">个人设置</span>
</el-menu-item>
<el-menu-item index="b" v-if="isAdmin">
<i class="el-icon-setting"></i>
<span slot="title">管理界面</span>
</el-menu-item>
<el-menu-item index="c">
<i class="el-icon-switch-button"></i>
<span slot="title">退出</span>
</el-menu-item>
</el-menu>
<el-avatar
class="main-avatar"
slot="reference"
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
></el-avatar>
</el-popover>
</div>
<!-- <el-dialog
class="dial-sys-info"
title="系统数据"
:visible.sync="isSysDataDialVisible"
width="50%"
:before-close="onSysDataDialClose"
>
<SysInfo :token="currUserInfo.token" :cdmsSid="currUserInfo.cdmsSid" />
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="isSysDataDialVisible = false"
> </el-button
>
</span>
</el-dialog> -->
</div>
</template>
<script>
import UserLoginApi from "../../api/Rbac/UserLogin.js";
import LoginInfo from "../../storage/login-info.js";
// import SysInfo from "./SysInfo.vue";
// import Menu from "./Menu.vue";
export default {
components: {
// SysInfo
},
props: {
//
arrangeMode: {
type: String,
default: "horizontal",
validator: function (value) {
return ["horizontal", "vertical"].indexOf(value) !== -1;
},
},
},
data() {
return {
isAdmin: false, // mounted
isUserInfoVisible: false, // popover
isSysDataDialVisible: false, //
currUserInfo: {}, //
};
},
computed: {
headerActiveIndex: function () {
return this.$route.meta.headerActiveIndex; // index
},
// menuDefaultActive: function () {
// let _routerName = this.$route.name;
// return this.mainMenuItems.findIndex(
// (item) => item.routerName === _routerName
// );
// },
},
mounted() {
let userInfo = LoginInfo.getUserInfo();
this.currUserInfo = userInfo ? userInfo : {};
},
methods: {
//
// handleHeaderMenuSelect(item, index) {
// let routerName;
// switch (index) {
// case 1:
// routerName = "Test";
// break;
// case 2:
// routerName = "Test2";
// break;
// }
// },
//
async handleUserMenuSelect(key, keyPath) {
keyPath;
switch (key) {
case "a": //
this.isUserInfoVisible = false;
break;
case "b": //
this.isUserInfoVisible = false;
break;
case "c": {
try {
await UserLoginApi.logout(); // 退退
} catch (e) {
console.log("后端退出登录失败");
}
// 退
LoginInfo.removeUser();
let currRouteName = this.$route.name;
if (currRouteName)
this.$safePush({
name: "Login",
query: {
routeName: currRouteName,
},
});
else this.$safePush({ name: "Login" });
break;
}
case "d":
//
this.isSysDataDialVisible = true;
break;
}
},
//
onSysDataDialClose(done) {
done();
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/_variables";
.header-inner {
height: 100%;
margin: 0 auto;
display: flex;
justify-content: space-between;
&.horizontal {
flex-direction: row;
.header-userinfo {
flex-direction: row;
margin-right: 36px;
}
}
&.vertical {
flex-direction: column;
.header-userinfo {
flex-direction: column;
margin-bottom: 36px;
}
}
.header-menu {
}
.header-userinfo {
display: flex;
justify-content: flex-end;
align-items: center;
.userinfo-popover {
//
display: flex;
align-items: center;
.main-avatar {
cursor: pointer;
}
}
}
.dial-sys-info {
::v-deep .el-dialog {
min-width: 530px;
}
}
}
.el-menu {
border-right: none; //
&.el-menu--horizontal {
border-bottom: none; //
}
> .el-menu-item {
height: 36px;
line-height: 36px;
}
}
</style>

View File

@ -1,195 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-12-18 16:30:05
* @LastEditors: Billy
* @LastEditTime: 2022-01-07 17:16:09
* @Description: 请输入
-->
<!--
props: 看下面注释
event:
1.select index: 选中菜单项的index, item: 选中菜单项的MenuItem类型对象
-->
<template>
<div class="menu" :class="arrangeMode">
<div class="menu-item-area" v-for="(item, index) in menuItems" :key="index">
<div
class="menu-item"
:class="[index === activeIndex ? 'active' : '']"
@click="onItemClick(item, index)"
>
<el-tooltip
v-if="displayMode === 'icon'"
class="text-tip"
effect="light"
:content="item.title"
:open-delay="750"
:placement="arrangeMode === 'horizontal' ? 'bottom' : 'right'"
>
<i v-if="iconMode === 'elementUi'" :class="item.iconClass"></i>
<img v-if="iconMode === 'img'" class="icon-img" :src="item.iconSrc" />
</el-tooltip>
<i
v-if="iconMode === 'elementUi'"
class="icon-ele"
:class="item.iconClass"
></i>
<img
v-if="iconMode === 'img' && displayMode === 'both'"
class="icon-img"
:src="item.iconSrc"
/>
<span v-if="displayMode !== 'icon'">{{ item.title }}</span>
</div>
<div class="sub-items" v-if="item.children && item.children.length">
<div
class="sub-item"
v-for="(item, index) in item.children"
:key="index"
>
{{ item.title }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
//
menuItems: {
type: Array,
default: function () {
return [];
},
},
//
arrangeMode: {
type: String,
default: "horizontal",
validator: function (value) {
return ["horizontal", "vertical"].indexOf(value) !== -1;
},
},
//
displayMode: {
type: String,
default: "both",
validator: function (value) {
return ["text", "icon", "both"].indexOf(value) !== -1;
},
},
// elementUipng jpgsvg()
iconMode: {
type: String,
default: "elementUi",
validator: function (value) {
return ["elementUi", "img", "svg"].indexOf(value) !== -1;
},
},
// index (.sync)
defaultActive: { type: Number, default: 0 },
},
computed: {
activeIndex: {
get() {
return this.activeIndex_;
},
set(val) {
// this.$emit("update:defaultActive", val); //
this.activeIndex_ = val;
},
},
},
watch: {
defaultActive: function (val, oldVal) {
this.activeIndex_ = val;
},
},
data() {
return {
activeIndex_: this.defaultActive,
};
},
mounted() {},
methods: {
onItemClick(item, index) {
this.activeIndex = index;
this.$emit("select", item, index);
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/_variables";
.menu {
height: 100%;
display: flex;
justify-content: flex-start;
align-items: stretch;
&.horizontal {
flex-direction: row;
.menu-item-area {
.menu-item {
flex-direction: row;
border-bottom: solid 2px transparent;
.icon-img {
padding-right: 4px;
}
}
}
}
&.vertical {
flex-direction: column;
.menu-item-area {
.menu-item {
flex-direction: row;
justify-content: flex-start;
// padding-left: 48px;
// border-right: solid 2px transparent;
.icon-img,
.icon-ele {
padding-right: 8px;
}
}
}
}
.menu-item-area {
.menu-item {
display: flex;
// justify-content: flex-start;
align-items: center;
cursor: pointer;
color: $font-color-dark;
padding: 8px;
margin: 8px;
border-radius: 4px;
transition: border-color 0.3s, background-color 0.3s, color 0.3s;
&.active {
// border-bottom-color: $theme-main-color;
// border-right-color: $theme-main-color;
background-color: $theme-main-color;
color: #fff;
}
.icon-img {
width: 24px;
height: 24px;
}
}
.sub-items {
.sub-item {
display: flex;
justify-content: flex-start;
align-items: center;
cursor: pointer;
padding: 8px;
padding-left: 48px;
margin: 8px;
}
}
}
}
</style>

View File

@ -1,96 +0,0 @@
<!--
* @Author: Billy
* @Date: 2022-01-04 11:46:31
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 17:40:39
* @Description: 请输入
-->
<template>
<div class="menu">
<el-menu
v-if="menuItems && menuItems.length"
:default-active="activeIndex"
@select="handleSelect"
@open="handleOpen"
@close="handleClose"
>
<template v-for="(item, index) in menuItems">
<el-submenu
v-if="item.children && item.children.length"
:index="item.routerName"
:key="index"
>
<template slot="title">
<i :class="item.iconClass"></i>
<span>{{ item.title }}</span>
</template>
<template v-for="(subItem, index2) in item.children">
<el-menu-item :index="subItem.routerName" :key="index2">
{{ subItem.title }}
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-else :index="item.routerName" :key="index">
<i :class="item.iconClass"></i>
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</template>
</el-menu>
</div>
</template>
<script>
export default {
props: {
//
menuItems: {
type: Array,
default: function () {
return [];
},
},
// index (.sync)
defaultActive: { type: String },
},
computed: {
activeIndex: {
get() {
if (this.activeIndex_) return this.activeIndex_;
else return this.menuItems[0].routerName;
},
set(val) {
// this.$emit("update:defaultActive", val); //
this.activeIndex_ = val;
},
},
},
watch: {
defaultActive: function (val, oldVal) {
this.activeIndex_ = val;
},
},
data() {
return {
activeIndex_: this.defaultActive,
};
},
methods: {
handleSelect(index, indexPath) {
// console.log("index :>> ", index);
// console.log("indexPath :>> ", indexPath);
const routerName = index;
this.$safePush({ name: routerName });
},
handleOpen(key, keyPath) {},
handleClose(key, keyPath) {},
},
};
</script>
<style lang="scss" scoped>
.el-menu {
border-right: none; //
&.el-menu--horizontal {
border-bottom: none; //
}
}
</style>

View File

@ -1,113 +0,0 @@
<!--
* @Author: Billy
* @Date: 2022-01-05 17:30:05
* @LastEditors: Billy
* @LastEditTime: 2022-01-07 16:57:02
* @Description: 右边导航栏(副栏)
-->
<template>
<div class="header-inner" :class="arrangeMode">
<div class="header-menu">
<Menu
:menuItems="secondaryMenuItems"
:arrangeMode="arrangeMode"
:displayMode="'icon'"
:defaultActive="menuDefaultActive"
:hasActiveEffect="true"
@select="handleHeaderMenuSelect"
/>
</div>
</div>
</template>
<script>
import MenuBiz from "../../biz/Menu.js";
import Menu from "./Menu.vue";
import { HIDE_DRAWER_WHEN_PUSH } from "../../const.js";
export default {
components: { Menu },
props: {
//
arrangeMode: {
type: String,
default: "horizontal",
validator: function (value) {
return ["horizontal", "vertical"].indexOf(value) !== -1;
},
},
menuDefaultActive: {
type: String,
},
},
data() {
return {
secondaryMenuItems: [], //
};
},
computed: {
// menuDefaultActive: function () {
// // let _routerName = this.$route.name;
// // return this.secondaryMenuItems.findIndex(
// // (item) => item.routerName === _routerName
// // );
// const _routerName = this.$route.name;
// const item = this.secondaryMenuItems.find(
// (item) => item.routerName === _routerName
// );
// return item ? item.id : "";
// },
},
async beforeMount() {
this.secondaryMenuItems = await MenuBiz.getSecondaryMenuItems();
},
mounted() {},
methods: {
//
handleHeaderMenuSelect(item, index) {
let routerName, drawerName;
routerName = item.routerName;
drawerName = item.drawerName;
if (routerName) {
// this.$safePush({ name: routerName });
let drawerName;
if (!HIDE_DRAWER_WHEN_PUSH) {
drawerName = this.$route.query.drawerName;
}
this.$safePush({
name: "Main",
params: { routerName },
query: { drawerName },
});
} else if (drawerName) {
this.$safePush({
name: "Main",
query: { drawerName },
});
}
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/_variables";
.header-inner {
height: 100%;
margin: 0 auto;
display: flex;
justify-content: space-between;
&.horizontal {
flex-direction: row;
}
&.vertical {
flex-direction: column;
}
.header-menu {
}
}
</style>

View File

@ -2,7 +2,7 @@
* @Author: Billy
* @Date: 2021-12-18 16:30:05
* @LastEditors: Billy
* @LastEditTime: 2022-01-10 21:19:25
* @LastEditTime: 2022-03-07 14:54:56
* @Description: 请输入
-->
<!--
@ -23,35 +23,35 @@ event:
:key="index"
@click="onItemClick(item, index)"
>
<el-tooltip
v-if="displayMode === 'icon'"
class="text-tip"
effect="light"
:content="item.title"
:open-delay="750"
:placement="arrangeMode === 'horizontal' ? 'bottom' : 'right'"
>
<template v-if="item.iconSrc && item.iconSrcInactive">
<el-tooltip
v-if="displayMode === 'icon'"
class="text-tip"
effect="light"
:content="item.title"
:open-delay="750"
:placement="arrangeMode === 'horizontal' ? 'bottom' : 'right'"
>
<img
class="icon-img"
:src="
item.id !== activeId && item.iconSrcInactive
? item.iconSrcInactive
: item.iconSrc
"
/>
</el-tooltip>
<img
class="icon-img"
v-if="displayMode === 'both'"
class="icon-img before-title"
:src="
item.id !== activeId && item.iconSrcInactive
? item.iconSrcInactive
: item.iconSrc
"
alt="无图标"
/>
</el-tooltip>
<img
v-if="displayMode === 'both'"
class="icon-img before-title"
:src="
item.id !== activeId && item.iconSrcInactive
? item.iconSrcInactive
: item.iconSrc
"
alt="无图标"
/>
</template>
<span class="title-text" v-if="displayMode !== 'icon'">{{
item.title

View File

@ -1,99 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-08-31 15:26:21
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 17:22:09
* @Description: 请输入
-->
<template>
<div class="container">
<el-form ref="form" :model="form" :rules="orgRules" label-width="100px">
<el-form-item label="上级部门名称">
<el-input :value="org.name" readonly></el-input>
</el-form-item>
<el-form-item label="部门名称" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button @click="onCancel">{{ btnCancelName }}</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import OrganizationBiz from "../../../biz/Rbac/Organization.js";
export default {
props: {
org: { type: Object, required: true }, //
},
data() {
return {
form: {
// id: 0,
name: "",
},
orgRules: {
name: [{ required: true, message: "请填写部门名称", trigger: "none" }],
},
btnCancelName: "取消",
};
},
updated() {},
methods: {
onSubmit() {
this.$refs["form"].validate(async (valid) => {
if (valid) {
this.$confirm(
`确定把在部门 ${this.org.name} 下新增 ${this.form.name} 子部门?`,
{
title: "确认新增",
showCancelButton: true,
showConfirmButton: true,
}
)
.then(async () => {
this.form.name = this.form.name.trim();
try {
let newOrg = await OrganizationBiz.add(
this.org.id < 0 ? null : this.org.id,
this.form.name
);
if (newOrg) {
this.$message.success(
`${this.org.name} 成功增加下级 ${this.form.name}`
);
this.btnCancelName = "退出";
this.$emit("success", this.org, newOrg);
}
} catch (e) {
this.$message.error(e.message);
}
})
.catch((e) => {});
}
});
},
onCancel() {
this.$emit("cancel");
},
//
updateForm() {
this.$refs["form"].clearValidate();
this.btnCancelName = "取消";
},
},
};
</script>
<style lang="scss" scoped>
.el-form-item.btns {
padding-top: 20px;
margin-bottom: 0;
::v-deep .el-form-item__content {
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -1,105 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-08-29 02:03:41
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 17:22:26
* @Description: 请输入
-->
<template>
<div class="container">
<el-form ref="form" :model="form" label-width="90px">
<el-form-item label="原部门名称">
<el-input :value="org.name" readonly></el-input>
</el-form-item>
<el-form-item label="新部门名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button @click="onCancel">{{ btnCancelName }}</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import OrganizationBiz from "../../../biz/Rbac/Organization.js";
export default {
props: {
org: { type: Object, required: true }, //
},
data() {
return {
form: {
// id: 0,
name: "",
},
btnCancelName: "取消",
};
},
updated() {},
watch: {
org: {
handler: function (newVal, oldVal) {
// this.form.id = newVal.id;
this.form.name = newVal.name;
},
immediate: true,
deep: true,
},
},
methods: {
onSubmit() {
if (this.form.name.trim() === this.org.name) {
this.$message.warning("新旧部门名称相同");
} else {
this.$confirm(
`确定把部门名称从 ${this.org.name} 修改为 ${this.form.name}?`,
{
title: "确认修改",
showCancelButton: true,
showConfirmButton: true,
}
)
.then(async () => {
this.form.name = this.form.name.trim();
try {
let count = await OrganizationBiz.update(
this.org.id < 0 ? null : this.org.id,
this.form.name
);
if (count) {
this.$message.success(
`${this.org.name} 成功修改为 ${this.form.name}`
);
this.btnCancelName = "退出";
this.org.name = this.form.name; //
}
} catch (e) {
this.$message.error(e.message);
}
})
.catch((e) => {});
}
},
onCancel() {
this.$emit("cancel");
},
//
updateForm() {
this.btnCancelName = "取消";
},
},
};
</script>
<style lang="scss" scoped>
.el-form-item.btns {
padding-top: 20px;
margin-bottom: 0;
::v-deep .el-form-item__content {
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -1,161 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-08-29 02:03:27
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 17:23:42
* @Description: 请输入
-->
<template>
<div class="container">
<LightSplit :ratios="[1, 1]" :minHeight="300">
<template v-slot:1>
<div class="tree-container">
<el-tree
ref="org-tree"
:data="treeData"
:node-key="'id'"
:props="treeProps"
:show-checkbox="false"
:highlight-current="true"
:expand-on-click-node="true"
:default-expanded-keys="defaultExpandedKeys"
@node-click="onTreeNodeClick"
@current-change="onOrgTreeCurrChange"
></el-tree>
</div>
</template>
<template v-slot:2>
<el-form
ref="form"
:model="form"
:label-position="'top'"
:rules="orgRules"
>
<el-form-item label="目标上级部门名称" prop="parentName">
<el-input
:value="form.parentName"
placeholder="请在左侧选择"
readonly
></el-input>
</el-form-item>
<el-form-item label="正在移动部门名称">
<el-input :value="org.name" readonly></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button @click="onCancel">{{ btnCancelName }}</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
</el-form>
</template>
</LightSplit>
</div>
</template>
<script>
import OrganizationBiz from "../../../biz/Rbac/Organization.js";
import LightSplit from "../../../components/_Common/LightSplit.vue";
export default {
components: { LightSplit },
props: {
treeData: { type: Array },
org: { type: Object, required: true }, //
},
data() {
return {
form: {
parentId: 0,
parentName: "",
targetParentData: null,
},
orgRules: {
parentName: [
{
required: true,
message: "请选择目标上级部门",
trigger: "none",
},
],
},
defaultExpandedKeys: [null],
treeProps: {
label: "name",
children: "Children",
},
btnCancelName: "取消",
};
},
methods: {
onSubmit() {
this.$refs["form"].validate(async (valid) => {
if (valid) {
if (this.org.id === this.form.parentId) {
this.$message.warning(`部门不能移动到自身内`);
} else {
this.$confirm(
`确定把在部门 ${this.org.name} 移动到 ${this.form.parentName} 部门下面?`,
{
title: "确认新增",
showCancelButton: true,
showConfirmButton: true,
}
)
.then(async () => {
try {
let org = OrganizationBiz.move(
this.org.id < 0 ? null : this.org.id,
this.form.parentId !== null && this.form.parentId < 1 // idnullid-1
? null
: this.form.parentId
);
if (org) {
this.$message.success(
`${this.org.name} 移动到 ${this.form.parentName} 部门下`
);
this.btnCancelName = "退出";
this.$emit("success", this.org, this.form.targetParentData);
}
} catch (e) {
this.$message.error(e.message);
}
})
.catch((e) => {});
}
}
});
},
onCancel() {
this.$emit("cancel");
},
onTreeNodeClick() {},
//
onOrgTreeCurrChange(data, node) {
this.form.parentId = data.id;
this.form.parentName = data.name;
this.form.targetParentData = data;
// this.$refs["form"].clearValidate();
},
//
updateForm() {
this.$refs["form"].clearValidate();
this.btnCancelName = "取消";
},
},
};
</script>
<style lang="scss" scoped>
.tree-container {
height: 100%;
max-height: 600px;
overflow-y: auto;
}
.el-form-item.btns {
padding-top: 20px;
margin-bottom: 0;
::v-deep .el-form-item__content {
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -1,80 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2022-01-05 11:53:19
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-05 18:21:24
* @Description: 角色新建框
-->
<template>
<div class="container">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="角色名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" />
</el-form-item>
<el-form-item label="角色说明" prop="description">
<el-input
type="textarea"
v-model="form.description"
placeholder="请输入"
/>
</el-form-item>
<el-form-item class="btns">
<el-button @click="$emit('on-cancel')">取消</el-button>
<el-button type="primary" @click="handleConfirmClick">确定</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import RoleBiz from "../../../biz/Rbac/Role.js";
export default {
data() {
return {
//
form: {
name: "",
description: "",
},
//
rules: {
name: [{ required: true, message: "请先填写角色名称" }],
},
};
},
methods: {
// -
handleConfirmClick() {
this.$refs["form"].validate(async (valid) => {
if (valid) {
const { name, description } = this.form;
try {
const res = await RoleBiz.add(name, description);
console.log("roleAdd", res);
this.$message.success("新建角色成功");
this.$emit("on-submit", res);
} catch ({ message }) {
this.$message.error(message);
}
}
});
},
},
};
</script>
<style lang="scss" scoped>
.el-form-item.btns {
padding-top: 20px;
margin-bottom: 0;
::v-deep .el-form-item__content {
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -1,93 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2022-01-05 11:53:19
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-05 18:21:17
* @Description: 角色编辑框
-->
<template>
<div class="container">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="角色名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" />
</el-form-item>
<el-form-item label="角色说明" prop="description">
<el-input
type="textarea"
v-model="form.description"
placeholder="请输入"
/>
</el-form-item>
<el-form-item class="btns">
<el-button @click="$emit('on-cancel')">取消</el-button>
<el-button type="primary" @click="handleConfirmClick">确定</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import Dialog from "../../_Common/Dialog.vue";
import RoleBiz from "../../../biz/Rbac/Role.js";
export default {
components: {
Dialog,
},
props: {
role: { type: Object, required: true }, //
},
data() {
const { id, name, description } = this.role;
return {
//
form: {
id,
name,
description,
},
//
rules: {
name: [{ required: true, message: "请先填写角色名称" }],
},
};
},
methods: {
// -
handleConfirmClick() {
this.$refs["form"].validate(async (valid) => {
if (valid) {
const { id, name, description } = this.form;
try {
const res = await RoleBiz.update(id, name, description);
console.log("roleUpdate", res);
this.$message.success("编辑角色成功");
this.$emit("on-submit", res);
} catch ({ message }) {
this.$message.error(message);
}
}
});
},
},
};
</script>
<style lang="scss" scoped>
.el-form-item.btns {
padding-top: 20px;
margin-bottom: 0;
::v-deep .el-form-item__content {
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -1,121 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-08-17 14:23:18
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 17:26:55
* @Description: 用户添加
-->
<!-- 用户添加成功后会触发user-add-success事件参数为新用户 -->
<template>
<div class="container">
<el-dialog
title="添加用户"
:visible="isVisible"
:before-close="beforeClose"
width="30%"
>
<el-form
:model="newUser"
:rules="newUserRules"
ref="newUserForm"
label-width="70px"
class="newUserForm"
>
<el-form-item label="部门名" prop="name">
<el-input :value="org.name"></el-input>
</el-form-item>
<el-form-item label="用户名" prop="name">
<el-input v-model="newUser.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="newUser.password"
autocomplete="new-password"
></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="onQuitClick">退 </el-button>
<el-button type="primary" @click="onConfirmClick"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// import SystemApi from "../../../api/Rbac/System.js";
import UserBiz from "../../../biz/Rbac/User.js";
export default {
props: {
isVisible: {
type: Boolean,
default: false,
},
org: {
type: Object,
},
},
data() {
return {
newUser: {
name: "",
password: "",
},
newUserRules: {
name: [{ required: true, message: "请填写用户名", trigger: "none" }],
password: [
{ required: true, message: "请填写密码", trigger: "none" },
{
min: 5,
max: 18,
message: "长度在 5 到 18 个字符",
trigger: "none",
},
],
},
};
},
methods: {
onQuitClick() {
this.$emit("update:isVisible", false);
},
onConfirmClick() {
this.$refs["newUserForm"].validate((valid) => {
if (valid) {
UserBiz.add({
name: this.newUser.name,
password: this.newUser.password,
orgId: this.org.id < 0 ? null : this.org.id,
})
.then((userId) => {
this.$message({
message: "添加用户成功",
type: "success",
});
this.$emit("user-add-success", userId);
console.log("userId :>> ", userId);
})
.catch((err) => {
this.$message({
message: err.message,
type: "error",
});
});
} else {
return false;
}
});
},
//
beforeClose(done) {
this.$emit("update:isVisible", false);
done();
},
},
};
</script>

View File

@ -1,381 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-06-19 00:51:47
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 17:41:04
* @Description: 用户列表
-->
<template>
<div class="user">
<el-table :data="userInfo.rows" style="width: 100%">
<el-table-column prop="id" label="ID" width="100"></el-table-column>
<el-table-column
prop="name"
label="用户名"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="Organization.name"
label="部门"
width="100"
:formatter="departmentNameFormatter"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="softDelete"
label="禁用"
width="80"
:formatter="booleanFormatter"
></el-table-column>
<el-table-column
prop="createTime"
label="创建时间"
width="180"
:formatter="timeFormatter"
></el-table-column>
<!-- <el-table-column
prop="modifyTime"
label="修改时间"
width="180"
:formatter="timeFormatter"
></el-table-column> -->
<el-table-column label="操作" width="100" fixed="right">
<template slot-scope="scope">
<el-button
class="btn-icon"
icon="el-icon-edit"
type="text"
@click="onEditBtnClick(scope.$index, scope.row)"
></el-button>
<el-button
class="btn-icon"
icon="el-icon-delete"
type="text"
@click="onDelBtnClick(scope.$index, scope.row)"
></el-button>
<el-button
class="btn-icon"
icon="el-icon-rank"
type="text"
@click="onMoveBtnClick(scope.$index, scope.row)"
></el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
layout="prev, pager, next"
:total="userInfo.totalCount"
:page-size="userInfo.pageSize"
:current-page.sync="userInfo.pageNum"
></el-pagination>
</div>
<el-dialog
v-if="editingUser"
title="修改用户"
:visible.sync="isDialEditUserVisible"
width="30%"
:before-close="onDialEditUserClose"
>
<el-form
:model="editingUser"
:rules="userRules"
ref="edit-user-form"
label-width="70px"
class="edit-user-form"
>
<el-form-item label="用户名" prop="name">
<el-input v-model="editingUser.name"></el-input>
</el-form-item>
<el-form-item label="是否禁用">
<el-radio-group v-model="editingUser.softDelete">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="isDialEditUserVisible = false">退 </el-button>
<el-button type="primary" @click="onEditUserConfirmClick"
> </el-button
>
</span>
</el-dialog>
<el-dialog
title="移动用户"
width="50%"
:visible.sync="isDialMoveUserVisible"
:before-close="onDialMoveUserClose"
@open="onDialMoveUserOpen"
>
<UserMove
ref="user-move-form"
:user="editingUser"
:treeData="orgTreeData"
@cancel="isDialMoveUserVisible = false"
@success="onUserMoveSuccess"
/>
</el-dialog>
</div>
</template>
<script>
import UserMove from "../../../components/Rbac/User/UserMove.vue";
import UserBiz from "../../../biz/Rbac/User.js";
import OrgAndUserBiz from "../../../biz/Rbac/OrgAndUser.js";
import DateHelper from "../../../util/DateHelper.js";
export default {
components: { UserMove },
props: {
orgId: { type: Number }, // orgId-1
orgTreeData: { type: Array }, //
},
data() {
return {
isDialEditUserVisible: false,
userRules: {
name: [{ required: true, message: "请填写用户名", trigger: "none" }],
password: [{ required: true, message: "请填写密码", trigger: "none" }],
},
editingUser: null,
editingUserPrototype: null,
userInfo: {
rows: [],
totalCount: 0,
pageSize: 10,
pageNum: 1,
},
isDialMoveUserVisible: false, //
};
},
computed: {
//
pageCount: function () {
return Math.ceil(this.userInfo.totalCount / this.userInfo.pageSize);
},
myOrgId: function () {
return this.orgId < 0 ? null : this.orgId;
},
},
watch: {
"userInfo.pageNum": function (newVal, oldVal) {
this.getCurrPageUsers();
},
orgId: function (newVal, oldVal) {
this.getCurrPageUsers();
},
},
mounted() {
this.getCurrPageUsers();
// this.getAllRoles();
},
methods: {
//
async getCurrPageUsers() {
// if (this.myOrgId === null) {
// //
// UserBiz.findByPage(this.userInfo.pageSize, this.userInfo.pageNum).then(
// (result) => {
// this.userInfo.rows = result.rows;
// this.userInfo.totalCount = result.count;
// }
// );
// } else {
// OrgAndUserBiz.findUsersByOrgIdAndByPage(
// this.myOrgId,
// this.userInfo.pageSize,
// this.userInfo.pageNum
// ).then((result) => {
// this.userInfo.rows = result.rows;
// this.userInfo.totalCount = result.count;
// });
// }
await OrgAndUserBiz.findUsersByOrgIdAndByPage(
this.myOrgId,
this.userInfo.pageSize,
this.userInfo.pageNum
).then((result) => {
this.userInfo.rows = result.rows;
this.userInfo.totalCount = result.count;
});
},
// tablerow
onEditBtnClick(index, row) {
this.editingUserPrototype = row;
this.editingUser = JSON.parse(JSON.stringify(row));
this.isDialEditUserVisible = true;
},
//
onEditUserConfirmClick() {
this.$refs["edit-user-form"].validate((valid) => {
if (valid) {
let user = {};
for (const key in this.editingUser) {
if (Object.hasOwnProperty.call(this.editingUser, key)) {
if (this.editingUser[key] !== this.editingUserPrototype[key]) {
user[key] = this.editingUser[key];
}
}
}
if (JSON.stringify(user) !== "{}") {
user.id = this.editingUser.id;
UserBiz.update(user)
.then((count) => {
if (count === 1) {
this.$message({
message: "用户修改成功",
type: "success",
});
this.isDialEditUserVisible = false;
this.getCurrPageUsers();
}
})
.catch((err) => {
this.$message({
message: err.message,
type: "error",
});
});
} else {
this.$message({
message: "用户信息没有任何修改",
type: "warning",
});
}
}
});
},
//
onDialEditUserClose(done) {
done();
},
// tablerow
onDelBtnClick(index, row) {
this.$confirm("此操作将永久删除该用户, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
UserBiz.delById(row.id)
.then((count) => {
this.$message({
type: "success",
message: "用户删除成功",
});
this.getCurrPageUsers();
})
.catch((err) => {
this.$message({
message: err.message,
type: "error",
});
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
onMoveBtnClick(index, row) {
this.editingUser = JSON.parse(JSON.stringify(row));
// this.editingUser = row;
this.isDialMoveUserVisible = true;
},
// ()
async goToLastPage() {
let userCount = await UserBiz.countAll();
this.userInfo.totalCount = userCount;
if (this.userInfo.pageNum === this.pageCount) {
//
this.getCurrPageUsers();
} else {
//
this.userInfo.pageNum = this.pageCount;
this.getCurrPageUsers();
}
},
//
onDialMoveUserClose(done) {
done();
},
// open
onDialMoveUserOpen() {
let $refForm = this.$refs["user-move-form"];
// dialog
if ($refForm) {
$refForm.updateForm();
}
},
//
async onUserMoveSuccess(currNodeData, targetParentData) {
// TODO: 1(await)
setTimeout(() => {
this.getCurrPageUsers();
}, 1000);
},
departmentNameFormatter(row, column, cellValue, index) {
return cellValue ? cellValue : "-";
},
//
booleanFormatter(row, column, cellValue, index) {
return cellValue ? "是" : "否";
},
//
timeFormatter(row, column, cellValue, index) {
let date = new Date(cellValue);
let dateStr = DateHelper.format(date, "yyyy-MM-dd hh:mm");
return dateStr;
},
},
};
</script>
<style lang="scss" scoped>
.user {
width: 100%;
box-sizing: border-box;
// padding: 10px;
.el-table {
.el-button {
padding: 0px;
&.btn-icon {
color: #000;
&:hover {
color: #409eff;
}
}
}
}
.pagination {
margin-top: 8px;
overflow: hidden;
.el-pagination {
float: right;
}
}
}
</style>

View File

@ -1,157 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-09-03 11:26:04
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 17:38:31
* @Description: 请输入
-->
<template>
<div class="container">
<LightSplit :ratios="[1, 1]" :minHeight="300">
<template v-slot:1>
<div class="tree-container">
<el-tree
ref="org-tree"
:data="treeData"
:node-key="'id'"
:props="treeProps"
:show-checkbox="false"
:highlight-current="true"
:expand-on-click-node="true"
:default-expanded-keys="defaultExpandedKeys"
@node-click="onTreeNodeClick"
@current-change="onOrgTreeCurrChange"
></el-tree>
</div>
</template>
<template v-slot:2>
<el-form
ref="form"
:model="form"
:label-position="'top'"
:rules="orgRules"
>
<el-form-item label="目标部门名称" prop="parentName">
<el-input
:value="form.parentName"
placeholder="请在左侧选择"
readonly
></el-input>
</el-form-item>
<el-form-item label="移动用户名称">
<el-input :value="user.name" readonly></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button @click="onCancel">{{ btnCancelName }}</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
</el-form>
</template>
</LightSplit>
</div>
</template>
<script>
// import OrganizationApi from "../../../api/Rbac/Organization.js";
import OrgAndUserBiz from "../../../biz/Rbac/OrgAndUser.js";
import LightSplit from "../../../components/_Common/LightSplit.vue";
export default {
components: { LightSplit },
props: {
treeData: { type: Array },
user: { type: Object, required: true }, //
},
data() {
return {
form: {
parentId: 0,
parentName: "",
targetParentData: null,
},
orgRules: {
parentName: [
{
required: true,
message: "请选择目标上级部门",
trigger: "none",
},
],
},
defaultExpandedKeys: [null],
treeProps: {
label: "name",
children: "Children",
},
btnCancelName: "取消",
};
},
methods: {
onSubmit() {
this.$refs["form"].validate(async (valid) => {
if (valid) {
this.$confirm(
`确定把在用户 ${this.user.name} 移动到 ${this.form.parentName} 部门下面?`,
{
title: "确认移动",
showCancelButton: true,
showConfirmButton: true,
}
)
.then(async () => {
try {
let user = OrgAndUserBiz.relateUser(
this.form.parentId < 0 ? null : this.form.parentId,
this.user.id
);
if (user) {
this.$message.success(
`${this.user.name} 移动到 ${this.form.parentName} 部门下`
);
this.btnCancelName = "退出";
this.$emit("success", user, this.form.targetParentData);
}
} catch (e) {
this.$message.error(e.message);
}
})
.catch((e) => {});
}
});
},
onCancel() {
this.$emit("cancel");
},
onTreeNodeClick() {},
//
onOrgTreeCurrChange(data, node) {
this.form.parentId = data.id;
this.form.parentName = data.name;
this.form.targetParentData = data;
// this.$refs["form"].clearValidate();
},
//
updateForm() {
this.$refs["form"].clearValidate();
this.btnCancelName = "取消";
},
},
};
</script>
<style lang="scss" scoped>
.tree-container {
height: 100%;
max-height: 600px;
overflow-y: auto;
}
.el-form-item.btns {
padding-top: 20px;
margin-bottom: 0;
::v-deep .el-form-item__content {
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -1,47 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2022-01-04 17:18:23
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-05 15:47:30
* @Description: 弹框组件
直接使用方式
<Dialog title="" visible="">
要写入的内容
</Dialog>
当页面不是直接使用时应采取以下方式比如新建/编辑框
<Dialog v-bind="$attrs" v-on="$listeners" @on-confirm.native="">
要写入的内容
</Dialog>
-->
<template>
<el-dialog :title="title" :visible="visible" :width="width">
<!-- 内容 -->
<slot />
<!-- 底部按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('update:visible', false)"> </el-button>
<el-button type="primary" @click="$emit('on-confirm')"> </el-button>
</span>
</el-dialog>
</template>
<script>
export default {
name: "Dialog",
props: {
visible: { type: Boolean, required: true }, //
title: { type: String, required: true }, //
width: { type: String, default: "30%" }, // 30%30px
},
created() {
console.log(this.$props);
},
};
</script>
<style>
</style>

View File

@ -1,386 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-12-20 09:54:19
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 13:59:12
* @Description: 请输入
-->
<template>
<div class="sliders-container" ref="sliders-container">
<Draggable
:class="[index === activeIndex ? 'active' : '']"
class="slider"
v-for="(item, index) in sliders"
ref="sliders"
:key="index"
:id="index"
:inertia="false"
:moveDirection="'horizontal'"
:isFrozen="isFrozen"
:style="{ width: perSliderWidth + 'px' }"
@drag-start="onDragStart"
@drag-move="onDragMove"
@drag-end="onDragEnd"
@drag-enter="onDragEnter"
@mousedown.native="onSliderMousedown($event, index)"
>
<slot
v-bind:item="item"
v-bind:index="index"
v-bind:isActive="index === activeIndex"
></slot>
</Draggable>
</div>
</template>
<script>
import Draggable from "./Drag/Draggable.vue";
// import Velocity from "velocity-animate";
export default {
components: { Draggable },
props: {
//
sliders: {
type: Array,
default: function () {
return [];
},
},
// index (.sync)
currentActive: { type: Number, default: 0 },
//
direction: {
type: String,
default: "horizontal",
validator: function (value) {
return ["horizontal", "vertical"].indexOf(value) !== -1;
},
},
//
millisecondOfMove: { type: Number, default: 250 },
// ()
perSliderWidth: { type: Number },
},
computed: {
// ()index
activeIndex: {
get() {
return this.currentActive;
},
set(val) {
this.calcCurrSliderKeyPoints(val);
this.activeSliderWidth = this.slidersInfo[val].width;
this.$emit("update:currentActive", val);
},
},
},
data() {
return {
slidersInfo: [], // {dom, width, midPoint}
activeSliderStartPoint: 0, // slider
activeSliderEndPoint: 0, // slider
activeSliderWidth: 0, // slider
indexOfSliderNeedToMoveCurrentlyAndActiveSliderShouldBe: 0,
isFrozen: false,
};
},
mounted() {
this.$nextTick(() => {
this.refreshSlidersInfo();
});
// this.calcAllTabsMidPoints();
// https://stackoverflow.com/questions/11700927/horizontal-scrolling-with-mouse-wheel-in-a-div
const slidersContainer = this.$refs["sliders-container"];
slidersContainer.addEventListener(
"mousewheel",
(e) => {
e = window.event || e;
var delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail));
slidersContainer.scrollLeft -= delta * 80; // Multiplied by 80
e.preventDefault();
},
false
);
},
methods: {
DoFrozen() {
this.isFrozen = true;
},
DisFrozen() {
this.isFrozen = false;
},
onDragStart(info) {},
onDragMove(info) {
// slider
const activeSliderStartPointCurr =
this.activeSliderStartPoint + info.currentX;
// slider
const activeSliderEndPointCurr =
this.activeSliderEndPoint + info.currentX;
const midPoints = this.slidersInfo.map((ti) => ti.midPoint);
// slider sliders
const midPointsBefore = midPoints.slice(0, this.activeIndex);
// slider sliders
const midPointsAfter = midPoints.slice(this.activeIndex + 1);
let index = this.activeIndex;
// slider index
function findNeedToMoveIndex() {
if (info.currentX > 0) {
for (const k in midPointsAfter) {
const point = midPointsAfter[k];
if (point > activeSliderEndPointCurr) {
index += Number(k);
return;
}
}
index = midPoints.length - 1; // slider
} else {
for (const k in midPointsBefore.reverse()) {
const point = midPointsBefore[k];
if (point < activeSliderStartPointCurr) {
index -= Number(k);
return;
}
}
index = 0; // 0 slider
}
}
findNeedToMoveIndex();
this.indexOfSliderNeedToMoveCurrentlyAndActiveSliderShouldBe = index;
// console.log(" slider index :>> ", index);
if (index !== this.activeIndex) {
const refSlider = this.$refs["sliders"][index];
let _index = index;
if (index > this.activeIndex) {
// slider slider
refSlider.MoveTo({
x: -this.activeSliderWidth,
transitionDuration: this.millisecondOfMove,
afterMoveTo: () => {},
});
// slider sliders
while (_index < midPoints.length - 1) {
_index++;
this.$refs["sliders"][_index].Rebound({
transitionDuration: this.millisecondOfMove,
afterRebound: () => {},
});
}
} else {
// slider slider
refSlider.MoveTo({
x: this.activeSliderWidth,
transitionDuration: this.millisecondOfMove,
afterMoveTo: () => {},
});
// slider sliders
while (_index > 0) {
_index--;
this.$refs["sliders"][_index].Rebound({
transitionDuration: this.millisecondOfMove,
afterRebound: () => {},
});
}
}
} else {
// slider slider
let _index = 0;
while (_index < midPoints.length - 1) {
if (_index !== this.activeIndex) {
this.$refs["sliders"][_index].Rebound({
transitionDuration: this.millisecondOfMove,
});
}
_index++;
}
}
},
onDragEnd(info) {
const index =
this.indexOfSliderNeedToMoveCurrentlyAndActiveSliderShouldBe;
const widths = this.slidersInfo.map((ti) => ti.width);
let point = 0;
if (index > this.activeIndex) {
//
for (let i = this.activeIndex + 1; i <= index; i++) {
point += widths[i];
}
} else {
//
for (let i = index; i < this.activeIndex; i++) {
point -= widths[i];
}
}
const currSlider = this.$refs["sliders"][this.activeIndex];
this.isFrozen = true;
currSlider.MoveTo({
x: point,
transitionDuration: this.millisecondOfMove,
zIndex: 1000,
afterMoveTo: () => {
this.dragAndDrop(
this.sliders,
this.activeIndex,
this.indexOfSliderNeedToMoveCurrentlyAndActiveSliderShouldBe
);
this.$nextTick(() => {
this.$refs["sliders"].forEach((slider) => {
slider.Clear();
});
this.refreshSlidersInfo();
// this.calcAllTabsMidPoints();
this.activeIndex =
this.indexOfSliderNeedToMoveCurrentlyAndActiveSliderShouldBe;
this.isFrozen = false;
});
},
});
},
onDragEnter(info) {},
onSliderMousedown(event, index) {
switch (event.button) {
case 0: //
if (!this.isFrozen) this.activeIndex = index;
break;
case 1: //
break;
case 2: //
break;
default:
break;
}
},
// handleMoveEnd(Rebound) {
// Rebound({});
// },
// slider
refreshSlidersInfo() {
const slidersRef = this.$refs["sliders"];
this.slidersInfo = [];
// slider
for (const sliderRef of slidersRef) {
const dom = sliderRef.$el;
const width = dom.getBoundingClientRect().width;
const rectSlider = dom.getBoundingClientRect();
const rectContainer =
this.$refs["sliders-container"].getBoundingClientRect();
const startPoint = rectSlider.left - rectContainer.left;
const endPoint = rectSlider.right - rectContainer.left;
const midPoint = startPoint + width / 2;
this.slidersInfo.push({
dom,
width,
startPoint,
endPoint,
midPoint,
});
}
},
// slider
calcCurrSliderKeyPoints(activeIndex) {
// ----------------------------------------------------
// const widths = this.slidersInfo.map((ti) => ti.width);
// const widthsLess = widths.slice(0, activeIndex);
// const widthsMore = widths.slice(0, activeIndex + 1);
// let sumStartPoint = 0,
// sumEndPoint = 0;
// widthsLess.forEach((el) => (sumStartPoint += el));
// widthsMore.forEach((el) => (sumEndPoint += el));
// this.activeSliderStartPoint = sumStartPoint;
// this.activeSliderEndPoint = sumEndPoint;
// ----------------------------------------------------
const doms = this.slidersInfo.map((ti) => ti.dom);
const rectActive = doms[activeIndex].getBoundingClientRect();
const rectContainer =
this.$refs["sliders-container"].getBoundingClientRect();
const startPoint = rectActive.left - rectContainer.left;
const endPoint = rectActive.right - rectContainer.left;
this.activeSliderStartPoint = startPoint;
this.activeSliderEndPoint = endPoint;
},
// slider ()
calcAllTabsMidPoints() {
for (const key in this.slidersInfo) {
if (Object.hasOwnProperty.call(this.slidersInfo, key)) {
const ti = this.slidersInfo[key];
if (key - 1 >= 0) {
ti.midPoint =
this.slidersInfo[key - 1].midPoint +
this.slidersInfo[key - 1].width / 2 +
ti.width / 2;
} else {
ti.midPoint = ti.width / 2;
}
// ti.title = this.sliders[key].title;
}
}
},
swap(arr, i1, i2) {
arr[i1] = arr.splice(i2, 1, arr[i1])[0];
return arr;
},
dragAndDrop(arr, i1, i2) {
let o = arr.splice(i1, 1)[0];
arr.splice(i2, 0, o);
return arr;
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/_variables.scss";
.sliders-container {
width: 100%;
height: 100%;
display: flex;
overflow: auto;
scrollbar-width: none; /* For Firefox */
-ms-overflow-style: none; /* For Internet Explorer and Edge */
&::-webkit-scrollbar {
/* For Chrome, Safari, and Opera */
// width: 0px;
height: 0px;
}
.slider {
// flex-grow: 1;
flex-shrink: 0;
user-select: none;
}
}
</style>

View File

@ -1,162 +0,0 @@
<!--
* @Author: Billy
* @Date: 2022-01-01 05:27:31
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 14:32:19
* @Description: 请输入
-->
<template>
<div class="tabs-container">
<Sliders
class="tabs-sliders"
ref="tabs-sliders"
:sliders="tabs"
:currentActive.sync="currentActive"
>
<template v-slot="{ item, index, isActive }">
<div
class="tab"
:class="{ active: isActive }"
:style="{
width: `${perTabWidth}px`,
maxWidth: `${perTabMaxWidth}px`,
padding: `0 ${perTabPadding}px`,
}"
@mouseenter="onTabMouseenter(item, index)"
>
<span
class="title"
:style="{
width: `${titleWidth}px`,
}"
>
{{ item.title }}
</span>
<span
class="close"
:style="{ width: `${tabCloseWidth}px` }"
@click="onTabCloseClick(item, index)"
@mousedown="onTabCloseMousedown(item, index)"
@mouseup="onTabCloseMouseup(item, index)"
@mouseenter="onTabCloseMouseenter(item, index)"
@mouseleave="onTabCloseMouseleave(item, index)"
><i class="el-icon-close icon"></i
></span>
</div>
</template>
</Sliders>
</div>
</template>
<script>
import Sliders from "../Sliders.vue";
export default {
components: { Sliders },
props: {
// @/entity/Ui/Tab/Tab.js
tabs: {
type: Array,
default: function () {
return [];
},
},
// index (.sync)
tabsCurrActiveIndex: { type: Number, default: 0 },
},
computed: {
currentActive: {
get() {
return this.tabsCurrActiveIndex;
},
set(val) {
this.$emit("update:tabsCurrActiveIndex", val);
},
},
titleWidth: function () {
return (
Math.min(this.perTabWidth, this.perTabMaxWidth) -
this.tabCloseWidth -
this.perTabPadding * 2
);
},
},
data() {
return {
isTabCloseMousedown: false,
tabCloseWidth: 18,
perTabPadding: 8,
perTabMaxWidth: 200,
perTabWidth: this.perTabMaxWidth,
};
},
mounted() {
const rectSliders = this.$refs["tabs-sliders"].$el.getBoundingClientRect();
this.perTabWidth = rectSliders.width / this.tabs.length;
},
methods: {
onTabCloseClick(item, index) {},
onTabMouseenter(item, index) {
// if (!this.isTabCloseMousedown) {
// this.$refs["tabs-sliders"].DisFrozen();
// }
},
onTabCloseMousedown(item, index) {
// this.$refs["tabs-sliders"].DoFrozen();
// this.isTabCloseMousedown = true;
},
onTabCloseMouseup(item, index) {
// this.$refs["tabs-sliders"].DisFrozen();
// this.isTabCloseMousedown = false;
},
onTabCloseMouseenter(item, index) {
// this.$refs["tabs-sliders"].DoFrozen();
// console.log("onTabCloseMouseenter");
},
onTabCloseMouseleave(item, index) {
// this.$refs["tabs-sliders"].DisFrozen();
// if (!this.isTabCloseMousedown) {
// this.$refs["tabs-sliders"].DisFrozen();
// }
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/_variables.scss";
.tabs-container {
width: 100%;
height: 36px;
line-height: 36px;
background-color: $theme-background-dark;
.tabs-sliders {
.tab {
height: 100%;
box-sizing: border-box;
background-color: $theme-background-dark;
cursor: default;
&.active {
background-color: #fff;
}
.title {
display: block;
float: left;
overflow: hidden;
}
.close {
display: block;
box-sizing: border-box;
float: left;
padding-left: 4px;
cursor: pointer;
.icon {
border-radius: 50%;
padding: 1px;
&:hover {
background-color: #bbb;
}
}
}
}
}
}
</style>

View File

@ -2,10 +2,10 @@
* @Author: Billy
* @Date: 2020-09-10 09:49:13
* @LastEditors: Billy
* @LastEditTime: 2022-01-11 10:47:12
* @LastEditTime: 2022-03-07 15:17:54
* @Description: 配置文件
*/
export const PROJECT_NAME = '销售';
export const PROJECT_NAME = '示例';
export const LOGIN_PAGE_TITLE = '前端示例 2';
export const TOKEY_ATTR_NAME = 'X-Access-Token'; // TOKEN的属性名(即客户端传token到服务端token的属性名)
export const IS_LOGIN_NEEDED = true; // 系统是否需要登录后使用
@ -13,11 +13,11 @@ export const IS_LOGIN_NEEDED = true; // 系统是否需要登录后使用
let baseUrl; // 基础API地址
switch (process.env.NODE_ENV) {
case "production": // 发布到服务器 npm run build
baseUrl = 'http://ty.y68.fun/sales-expo-saas'; // swagger http://ty.y68.fun/sales-expo-saas/#/
break;
case "preview": // 发布前预览 npm run preview
{
baseUrl = 'http://ty.y68.fun/sales-expo-saas'; // swagger http://ty.y68.fun/sales-expo-saas/#/
break;
}
case "development": // 本机前端开发调试 npm run serve
default:
baseUrl = 'http://ty.y68.fun/sales-show-3'; // swagger http://ty.y68.fun/sales-expo-saas/#/
@ -53,11 +53,4 @@ export const UPLOAD_TIMEOUT = 0; // 指定文件上传请求超时的毫秒数(0
export const DEFAULT_HOME_LAYOUT = ['top-bottom', 'left-right'][0]; // 网站前台是上下布局还是左右布局
export const DEFAULT_BACK_LAYOUT = ['top-bottom', 'left-right'][0]; // 网站后台是上下布局还是左右布局
export const HEADER_THICKNESS = 48; // 首页头部尺寸(单位:像素)
export const HIDE_DRAWER_WHEN_PUSH = false; // 当跳转页面时,抽屉是否隐藏
// 弹框类型
export const DIALOG_TYPE = {
ADD: 'add', // 添加(新建)
EDIT: 'edit', // 编辑(更新)
}
export const HEADER_THICKNESS = 48; // 首页头部尺寸(单位:像素)

View File

@ -1,21 +0,0 @@
/*
* @Author: Billy
* @Date: 2021-12-23 01:22:12
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 22:02:35
* @Description: 请输入
*/
class Tab {
/**
* @description 标签栏的每个标签
* @param {string} title 标题
*/
constructor({
title
}) {
this.title = title;
}
}
export default Tab;

View File

@ -2,7 +2,7 @@
* @Author: Billy
* @Date: 2020-09-10 09:12:00
* @LastEditors: Billy
* @LastEditTime: 2022-01-01 05:26:15
* @LastEditTime: 2022-03-07 15:03:20
* @Description: 请输入
*/
import Vue from 'vue';
@ -13,7 +13,7 @@ import ElementUI from 'element-ui';
import './scss/element-variables.scss';
import "./svgicon/index.js";
import Event from './util/Event';
import AuthHelper from "./auth/AuthHelper.js";
// import AuthHelper from "./auth/AuthHelper.js";
import SafePush from './util/SafePush';
Vue.config.productionTip = false;
@ -24,31 +24,31 @@ Vue.use(ElementUI, {
Vue.prototype.$safePush = SafePush;
// 注册一个全局自定义指令 `v-auth`,用于验证权限
Vue.directive('auth', {
bind: function (el, param) { },
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el, param) {
let pass = AuthHelper.checkAuth(param.value);
if (!pass) {
el.remove()
}
},
update: function (el, param) { },
componentUpdated: function (el, param) { },
unbind: function (el, param) { }
});
// Vue.directive('auth', {
// bind: function (el, param) { },
// // 当被绑定的元素插入到 DOM 中时……
// inserted: function (el, param) {
// let pass = AuthHelper.checkAuth(param.value);
// if (!pass) {
// el.remove()
// }
// },
// update: function (el, param) { },
// componentUpdated: function (el, param) { },
// unbind: function (el, param) { }
// });
// 全局事件总线
// 参考https://zhuanlan.zhihu.com/p/72777951
// 不到必要时,不建议使用,否则容易增加全局代码复杂度
let EventBus = new Vue();
Object.defineProperties(Vue.prototype, {
$bus: {
get: function () {
return EventBus;
}
}
});
// let EventBus = new Vue();
// Object.defineProperties(Vue.prototype, {
// $bus: {
// get: function () {
// return EventBus;
// }
// }
// });
new Vue({
router,

View File

@ -2,7 +2,7 @@
* @Author: Billy
* @Date: 2020-09-10 09:12:00
* @LastEditors: Billy
* @LastEditTime: 2022-01-10 20:27:12
* @LastEditTime: 2022-03-07 13:35:34
* @Description: 静态路由
*/
import Vue from 'vue'
@ -16,8 +16,6 @@ import {
import LoginInfo from "../storage/login-info.js";
import TestChildren from "./test.js";
import MainChildren from "./main.js";
import SecondaryChildren from "./secondary.js";
import BackChildren from "./back.js";
Vue.use(VueRouter)
@ -40,22 +38,8 @@ const routes = [{
},
children: [
...MainChildren,
...SecondaryChildren,
...TestChildren
]
}, {
path: '/back',
name: 'Back',
redirect: {
name: 'Org'
},
component: () => import( /* webpackChunkName: "Back" */ '../views/Back.vue'),
meta: {
title: ''
},
children: [
...BackChildren
]
}, {
path: '/login',
name: 'Login',

View File

@ -1,117 +0,0 @@
/*
* @Author: Billy
* @Date: 2021-12-29 17:34:21
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 13:59:15
* @Description: 请输入
*/
export default [{
path: 'org',
name: 'Org',
component: () => import(
/* webpackChunkName: "Org" */
'../views/BackViews/Org.vue'
),
meta: {
title: '组织架构',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'role',
name: 'Role',
component: () => import(
/* webpackChunkName: "Role" */
'../views/BackViews/Role.vue'
),
meta: {
title: '角色管理',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'classification',
name: 'Classification',
component: () => import(
/* webpackChunkName: "Classification" */
'../views/BackViews/Classification.vue'
),
meta: {
title: '分类管理',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'statistics',
name: 'Statistics',
component: () => import(
/* webpackChunkName: "Statistics" */
'../views/BackViews/Statistics.vue'
),
meta: {
title: '数据统计',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'topic',
name: 'Topic',
component: () => import(
/* webpackChunkName: "Topic" */
'../views/BackViews/Topic.vue'
),
meta: {
title: '专题管理',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'platformsetting',
name: 'PlatformSetting',
component: () => import(
/* webpackChunkName: "PlatformSetting" */
'../views/BackViews/PlatformSetting.vue'
),
meta: {
title: '平台设置',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'authorization-for-partner',
name: 'Authorization4Partner',
component: () => import(
/* webpackChunkName: "Authorization4Partner" */
'../views/BackViews/Authorization4Partner.vue'
),
meta: {
title: '合作伙伴授权管理',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'authorization-for-customer',
name: 'Authorization4Customer',
component: () => import(
/* webpackChunkName: "Authorization4Customer" */
'../views/BackViews/Authorization4Customer.vue'
),
meta: {
title: '客户授权管理',
// headerActiveIndex: '1',
// keepAlive: false
}
}, {
path: 'log',
name: 'Log',
component: () => import(
/* webpackChunkName: "Log" */
'../views/BackViews/Log.vue'
),
meta: {
title: '系统日志',
// headerActiveIndex: '1',
// keepAlive: false
}
}]

View File

@ -1,33 +0,0 @@
/*
* @Author: Billy
* @Date: 2022-01-06 18:23:05
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 18:28:19
* @Description: 请输入
*/
export default [{
path: '/quick-demonstrations',
name: 'QuickDemonstrations',
component: () => import(
/* webpackChunkName: "QuickDemonstrations" */
'../views/HomeSubViews/Secondary/QuickDemonstrations.vue'
),
meta: {
title: '快捷演示方案',
// headerActiveIndex: '1',
keepAlive: true
}
}, {
path: '/cloud-desktop',
name: 'CloudDesktop',
component: () => import(
/* webpackChunkName: "CloudDesktop" */
'../views/HomeSubViews/Secondary/CloudDesktop.vue'
),
meta: {
title: '云桌面',
// headerActiveIndex: '1',
keepAlive: true
}
}]

View File

@ -1,61 +0,0 @@
@import "../variables.scss";
// 自定义类
// 水平两列结构左列溢出可垂直滚动右列溢出隐藏
.back-column-two {
display: flex;
height: 100%;
.column-left {
width: calc(100% * 0.186);
min-width: 300px;
padding: 20px;
box-sizing: border-box;
overflow: hidden;
overflow-y: auto;
}
.column-right {
flex: 1;
padding: 20px;
border-left: 2px solid $theme-background-light;
box-sizing: border-box;
}
}
// 水平一列结构
.back-column-one {
padding: 20px;
}
// 标题区域变量
$title-height: 36; // 标题区域高度不包含外边距
$title-margin-bottom: 20; // 标题下外边距
// 标题区域样式
.back-title {
height: #{$title-height + px}; // 减掉外边距
margin-bottom: #{$title-margin-bottom + px};
font-size: 16px;
font-weight: 700;
line-height: 16px;
color: #25262b;
box-sizing: border-box;
overflow: hidden;
}
.pagination {
margin-top: 20px;
overflow: hidden;
.el-pagination {
float: right;
}
}
// 清除默认样式
ul {
list-style: none;
margin: 0;
padding: 0;
}

View File

@ -1,38 +0,0 @@
@import "./back.scss";
// 暗色背景输入框
.bg-dark.el-input::v-deep {
.el-input__icon {
line-height: 36px;
}
.el-input__inner {
height: 36px;
background-color: #e5e7ed;
}
}
.back-title-el-tabs.el-tabs::v-deep {
height: 100%;
.el-tabs__header {
margin-bottom: #{$title-margin-bottom + px};
}
.el-tabs__nav-wrap::after {
background-color: $theme-background-light;
}
.el-tabs__item {
height: #{$title-height + px};
font-size: 16px;
line-height: 16px;
box-sizing: border-box;
// 取消当前tab默认样式否则电脑切换应用后会显示
&.is-active {
box-shadow: none !important;
border-radius: 0 !important;
}
}
}

View File

@ -1,136 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-12-29 17:24:10
* @LastEditors: Billy
* @LastEditTime: 2022-01-07 17:16:12
* @Description: 请输入
-->
<template>
<div class="back">
<el-container>
<el-header
v-if="DEFAULT_BACK_LAYOUT === 'top-bottom'"
:height="HEADER_THICKNESS + 'px'"
>
<Header :arrangeMode="'horizontal'" />
</el-header>
<el-aside
v-else-if="DEFAULT_BACK_LAYOUT === 'left-right'"
:width="HEADER_THICKNESS + 'px'"
>
<Header :arrangeMode="'vertical'" />
</el-aside>
<el-container>
<el-aside width="200px">
<!-- <Menu
:menuItems="backMenuItems"
:arrangeMode="'vertical'"
:displayMode="'both'"
:defaultActive="menuDefaultActive"
@select="handleMenuSelect"
/> -->
<Menu2
:menuItems="backMenuItems"
:defaultActive="menuDefaultActive"
/>
</el-aside>
<el-main>
<div class="main">
<router-view></router-view>
</div>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
// @ is an alias to /src
import MenuBiz from "../biz/Back/_Menu.js";
import Header from "../components/Back/Header.vue";
// import Menu from "../components/Back/Menu(backup).vue";
import Menu2 from "../components/Back/Menu.vue";
// import TreeHelper from "../util/TreeHelper.js";
import { DEFAULT_BACK_LAYOUT, HEADER_THICKNESS } from "../const.js";
export default {
name: "Back",
components: {
Header,
// Menu,
Menu2,
},
data() {
return {
DEFAULT_BACK_LAYOUT,
HEADER_THICKNESS,
backMenuItems: [], //
};
},
computed: {
menuDefaultActive: function () {
const _routerName = this.$route.name;
// let index = this.backMenuItems.findIndex(
// (item) => item.routerName && item.routerName === _routerName
// );
return _routerName;
},
},
async beforeMount() {
this.backMenuItems = await MenuBiz.getBackMenuItems();
},
methods: {
//
handleMenuSelect(item, index) {
let routerName;
// switch (index) {
// case 1:
// routerName = "Test";
// break;
// case 2:
// routerName = "Test2";
// break;
// }
routerName = item.routerName;
if (routerName) this.$safePush({ name: routerName });
},
},
};
</script>
<style lang="scss">
.back {
height: 100%;
}
</style>
<style lang="scss" scoped>
@import "~@/scss/_variables.scss";
.el-container {
height: 100%;
//
.el-header {
// height: $header-thin + px !important;
padding: 0;
box-sizing: content-box;
border-bottom: solid 1px #e6e6e6;
}
//
.el-aside {
// width: $header-thin + px !important;
border-right: solid 1px #e6e6e6;
}
.el-container {
.el-main {
height: 100%;
padding: 16px;
background-color: $theme-background-light;
.main {
background-color: #fff;
height: 100%;
border-radius: 8px;
}
}
}
}
</style>

View File

@ -1,211 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-04 09:49:49
* @Description: 后台管理-授权管理页面
-->
<template>
<div class="authorization back-column-two">
<!-- 左侧-列表 -->
<div class="column-left">
<div class="title back-title">
{{ $route.meta.title }}
<el-button class="authorization-new" icon="el-icon-circle-plus">
新建身份
</el-button>
</div>
<el-input
v-model="inputauthorization"
prefix-icon="el-icon-search"
placeholder="请输入"
/>
<div class="authorization-list">
<ul class="list-ul">
<li
class="list-li"
v-for="authorization in authorizationList"
:key="authorization"
>
{{ authorization }}
</li>
</ul>
</div>
</div>
<!-- 右侧-内容 -->
<div class="column-right">
<ul class="auth-first-ul">
<li v-for="firstAuth in authList" :key="firstAuth.text">
<el-checkbox v-model="firstAuth.checked">
{{ firstAuth.text }}
</el-checkbox>
<ul class="auth-second-ul">
<li v-for="secondAuth in firstAuth.children" :key="secondAuth.text">
<el-checkbox v-model="secondAuth.checked">
{{ secondAuth.text }}
</el-checkbox>
</li>
</ul>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: "Authorization",
data() {
return {
inputauthorization: "", //
authorizationList: ["普通用户", "一级用户", "二级用户"],
titleList: [
{
prop: "name",
label: "伙伴名称",
},
{
prop: "department",
label: "部门",
},
{
prop: "authorization",
label: "角色",
},
{
prop: "status",
label: "账号状态",
},
],
dataList: [
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "正常",
},
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "正常",
},
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "正常",
},
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "异常",
},
],
authList: [
{
text: "全部",
checked: false,
children: [],
},
{
text: "产品",
children: [
{
text: "查看",
checked: true,
},
{
text: "新建产品",
checked: false,
},
],
},
],
};
},
methods: {
// tab
handleTabClick(tab, event) {
console.log(tab, event);
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
.authorization {
.title {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid $theme-background-light;
margin-bottom: 20px;
.authorization-new {
padding: 0;
border: none;
color: #347eff;
&:hover {
background-color: transparent;
}
}
}
.authorization-list {
.list-ul {
margin-top: 20px;
.list-li {
height: 36px;
padding-left: 20px;
line-height: 36px;
cursor: pointer;
&:hover {
background-color: rgba(52, 126, 255, 0.1);
// opacity: 0.1;
color: #347eff;
}
}
}
}
.content-top {
display: flex;
justify-content: space-between;
}
.auth-first-ul {
& > li {
margin-bottom: 20px;
& > .el-checkbox {
font-weight: 700;
}
}
}
.auth-second-ul {
display: flex;
li {
margin-left: 20px;
&:first-child {
margin-left: 0;
}
}
}
}
</style>

View File

@ -1,211 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-04 15:36:55
* @Description: 后台管理-授权管理页面
-->
<template>
<div class="authorization back-column-two">
<!-- 左侧-列表 -->
<div class="column-left">
<div class="title back-title">
{{ $route.meta.title }}
<el-button class="authorization-new" icon="el-icon-circle-plus">
新建身份
</el-button>
</div>
<el-input
v-model="inputauthorization"
prefix-icon="el-icon-search"
placeholder="请输入"
/>
<div class="authorization-list">
<ul class="list-ul">
<li
class="list-li"
v-for="authorization in authorizationList"
:key="authorization"
>
{{ authorization }}
</li>
</ul>
</div>
</div>
<!-- 右侧-内容 -->
<div class="column-right">
<ul class="auth-first-ul">
<li v-for="firstAuth in authList" :key="firstAuth.text">
<el-checkbox v-model="firstAuth.checked">
{{ firstAuth.text }}
</el-checkbox>
<ul class="auth-second-ul">
<li v-for="secondAuth in firstAuth.children" :key="secondAuth.text">
<el-checkbox v-model="secondAuth.checked">
{{ secondAuth.text }}
</el-checkbox>
</li>
</ul>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: "Authorization",
data() {
return {
inputauthorization: "", //
authorizationList: ["普通用户", "一级用户", "二级用户"],
titleList: [
{
prop: "name",
label: "伙伴名称",
},
{
prop: "department",
label: "部门",
},
{
prop: "authorization",
label: "角色",
},
{
prop: "status",
label: "账号状态",
},
],
dataList: [
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "正常",
},
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "正常",
},
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "正常",
},
{
name: "李杰",
department: "战略支持部",
authorization: "系统管理员",
status: "异常",
},
],
authList: [
{
text: "全部",
checked: false,
children: [],
},
{
text: "产品",
children: [
{
text: "查看",
checked: true,
},
{
text: "新建产品",
checked: false,
},
],
},
],
};
},
methods: {
// tab
handleTabClick(tab, event) {
console.log(tab, event);
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
.authorization {
.title {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid $theme-background-light;
margin-bottom: 20px;
.authorization-new {
padding: 0;
border: none;
color: #347eff;
&:hover {
background-color: transparent;
}
}
}
.authorization-list {
.list-ul {
margin-top: 20px;
.list-li {
height: 36px;
padding-left: 20px;
line-height: 36px;
cursor: pointer;
&:hover {
background-color: rgba(52, 126, 255, 0.1);
// opacity: 0.1;
color: #347eff;
}
}
}
}
.content-top {
display: flex;
justify-content: space-between;
}
.auth-first-ul {
& > li {
margin-bottom: 20px;
& > .el-checkbox {
font-weight: 700;
}
}
}
.auth-second-ul {
display: flex;
li {
margin-left: 20px;
&:first-child {
margin-left: 0;
}
}
}
}
</style>

View File

@ -1,84 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-04 09:49:29
* @Description: 后台管理-角色管理页面
-->
<template>
<div class="classification back-column-one">
<div class="back-title">{{ $route.meta.title }}</div>
<el-tabs value="product" type="card" @tab-click="handleClick">
<el-tab-pane label="产品案例" name="product">
<el-tabs value="role-remember" @tab-click="handleTabClick">
<el-tab-pane label="软硬件产品" name="role-remember">
<el-button type="primary" round>新建分类</el-button>
<el-table :data="dataList" style="width: 100%">
<el-table-column
v-for="title in titleList"
:key="title.prop"
:prop="title.prop"
:label="title.label"
show-overflow-tooltip
/>
</el-table>
</el-tab-pane>
<el-tab-pane label="技术服务" name="role-remember2"></el-tab-pane>
<el-tab-pane label="软件服务" name="role-remember3"></el-tab-pane>
<el-tab-pane label="应用案例" name="role-remember4"></el-tab-pane>
<el-tab-pane label="培训服务" name="role-remember5"></el-tab-pane>
</el-tabs>
</el-tab-pane>
<el-tab-pane label="解决方案" name="solution">解决方案</el-tab-pane>
<el-tab-pane label="演示方案" name="demo">演示方案</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
export default {
name: "Classification",
data() {
return {
titleList: [
{
prop: "type",
label: "分类名称",
},
{
prop: "dest",
label: "说明",
},
{
prop: "num",
label: "统计数量",
},
],
dataList: [
{
type: "品牌",
dest: "-",
num: 26,
},
{
type: "品牌",
dest: "-",
num: 26,
},
{
type: "品牌",
dest: "-",
num: 26,
},
],
};
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
</style>

View File

@ -1,108 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-05 18:56:12
* @Description: 后台管理-角色管理页面
-->
<template>
<div class="log back-column-one">
<div class="back-title">{{ $route.meta.title }}</div>
<el-tabs value="role-remember">
<el-tab-pane label="操作日志" name="role-remember">
<el-table :data="actionList" style="width: 100%">
<el-table-column
v-for="title in actionTitleList"
:key="title.prop"
:prop="title.prop"
:label="title.label"
show-overflow-tooltip
/>
</el-table>
</el-tab-pane>
<el-tab-pane label="登录日志" name="role-remember2">
<el-table :data="loginList" style="width: 100%">
<el-table-column
v-for="title in loginTitleList"
:key="title.prop"
:prop="title.prop"
:label="title.label"
show-overflow-tooltip
/>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import LogBiz from "../../biz/Back/Log.js";
export default {
name: "Log",
data() {
return {
//
actionTitleList: [
{
prop: "user",
label: "用户",
},
{
prop: "time",
label: "时间",
},
{
prop: "module",
label: "模块",
},
{
prop: "position",
label: "所在位置",
},
{
prop: "action",
label: "行为",
},
],
actionList: [], //
//
loginTitleList: [
{
prop: "user",
label: "用户",
},
{
prop: "time",
label: "登录时间",
},
{
prop: "result",
label: "认证结果",
},
{
prop: "ip",
label: "IP地址",
},
],
loginList: [], //
};
},
async created() {
const [actionList, loginList] = await Promise.all([
LogBiz.findByAction(),
LogBiz.findByLogin(),
]);
this.actionList = actionList;
this.loginList = loginList;
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
</style>

View File

@ -1,390 +0,0 @@
<!--
* @Author: Billy
* @Date: 2021-12-29 17:34:35
* @LastEditors: Billy
* @LastEditTime: 2022-01-04 21:51:32
* @Description: 请输入
-->
<template>
<PageSplit
class="split-pane"
:distribute="0.15"
:lineThickness="6"
:firstMinValue="200"
:isVertical="true"
@resizeLineStartMove="onResizeLineStartMove"
@resizeLineMove="onResizeLineMove"
@resizeLineEndMove="onResizeLineEndMove"
>
<template v-slot:first>
<div class="container">
<div class="title title-flex-both">
<span class="title-inner">组织架构</span>
</div>
<div class="content">
<el-tree
ref="org-tree"
v-loading="vloadingOrgTree"
:data="orgTreeData"
:node-key="'id'"
:props="treeProps"
:highlight-current="true"
:expand-on-click-node="false"
:default-expanded-keys="defaultExpandedKeys"
:render-content="renderTreeNodeContent"
@node-click="onTreeNodeClick"
@current-change="onOrgTreeCurrChange"
></el-tree>
</div>
</div>
</template>
<template v-slot:second>
<div class="container">
<div class="title title-flex-right">
<el-button size="mini" type="primary" @click="onAddUserBtnClick"
>新建用户</el-button
>
</div>
<div class="content">
<UserList
ref="user-list"
:orgId="currSelectedOrg.id"
:orgTreeData="orgTreeData"
/>
</div>
</div>
</template>
<div class="others">
<UserAdd
:org="currSelectedOrg"
:isVisible.sync="isDialAddUserVisible"
@user-add-success="onUserAddSuccess"
/>
<el-dialog
title="新建部门"
width="30%"
:visible.sync="isDialAddDeptVisible"
:before-close="onDialAddDeptClose"
@open="onDialAddDeptOpen"
>
<OrgAdd
ref="org-add-form"
:org="currEditingOrg"
@cancel="isDialAddDeptVisible = false"
@success="onOrgAddSuccess"
/>
</el-dialog>
<el-dialog
title="编辑部门"
width="30%"
:visible.sync="isDialEditDeptVisible"
:before-close="onDialEditDeptClose"
@open="onDialEditDeptOpen"
>
<OrgEdit
ref="org-edit-form"
:org="currEditingOrg"
@cancel="isDialEditDeptVisible = false"
/>
</el-dialog>
<el-dialog
title="移动部门"
width="50%"
:visible.sync="isDialMoveDeptVisible"
:before-close="onDialMoveDeptClose"
@open="onDialMoveDeptOpen"
>
<OrgMove
ref="org-move-form"
:org="currEditingOrg"
:treeData="orgTreeData"
@cancel="isDialMoveDeptVisible = false"
@success="onOrgMoveSuccess"
/>
</el-dialog>
</div>
</PageSplit>
</template>
<script>
import PageSplit from "vue-page-split";
import UserList from "../../components/Rbac/User/UserList4Org.vue";
import UserAdd from "../../components/Rbac/User/UserAdd.vue";
import OrgAdd from "../../components/Rbac/Organization/OrgAdd.vue";
import OrgEdit from "../../components/Rbac/Organization/OrgEdit.vue";
import OrgMove from "../../components/Rbac/Organization/OrgMove.vue";
import TreeNodeWith3Dots from "../../components/_Common/Tree/TreeNodeWith3Dots.vue";
import OrganizationBiz from "../../biz/Rbac/Organization.js";
//
const ORG_ROOT = {
name: "COMPANY",
id: -1,
};
export default {
components: { PageSplit, UserList, UserAdd, OrgEdit, OrgAdd, OrgMove },
data() {
return {
treeProps: {
label: "name",
children: "Children",
},
orgTreeData: [], //
vloadingOrgTree: false, // loading
defaultExpandedKeys: [ORG_ROOT.id], // id()
isDialAddUserVisible: false, //
isDialEditDeptVisible: false, //
isDialAddDeptVisible: false, //
isDialMoveDeptVisible: false, //
currSelectedOrg: ORG_ROOT, // id
currEditingOrg: {
id: ORG_ROOT.id, // id
name: ORG_ROOT.name, //
},
};
},
async mounted() {
//
this.orgTreeData = await this.getAllNodesWithRoot();
this.$nextTick(() => {
// let rootNode = this.$refs["org-tree"].getNode(this.orgTreeData[0]);
// console.log("rootNode :>> ", rootNode);
this.$refs["org-tree"].setCurrentKey(ORG_ROOT.id);
});
},
methods: {
//
onAddUserBtnClick() {
this.isDialAddUserVisible = true;
},
//
onUserAddSuccess(userId) {
this.$refs["user-list"].goToLastPage();
},
//
onNewDeptConfirmClick() {
this.$refs["new-org-form"].validate(async (valid) => {
if (valid) {
try {
let orgs = await OrganizationBiz.findByName(this.newOrg.name);
let _org = orgs.find(
(org) =>
org.name === this.newOrg.name &&
org.parentId === this.newOrg.parentNode.id
);
if (_org) {
this.$message({ type: "error", message: "不能有同名节点" });
} else {
let newOrg = await OrganizationBiz.add(
this.newOrg.parentNode.id,
this.newOrg.name
);
this.orgTreeData = await this.getAllNodesWithRoot();
this.defaultExpandedKeys[0] = newOrg.id;
}
} catch (e) {
this.$message({ type: "error", message: e.message });
}
}
});
},
// 退
onNewDeptQuitClick() {
this.isDialNewDeptVisible = false;
},
//
onDialAddDeptClose(done) {
done();
},
//
onDialEditDeptClose(done) {
done();
},
//
onDialMoveDeptClose(done) {
done();
},
onTreeNodeClick() {},
//
onOrgTreeCurrChange(data, node) {
this.currSelectedOrg = data;
},
// open
onDialAddDeptOpen() {
let $refForm = this.$refs["org-add-form"];
// dialog
if ($refForm) {
$refForm.updateForm();
}
},
// open
onDialEditDeptOpen() {
let $refForm = this.$refs["org-edit-form"];
// dialog
if ($refForm) {
$refForm.updateForm();
}
},
// open
onDialMoveDeptOpen() {
let $refForm = this.$refs["org-move-form"];
// dialog
if ($refForm) {
$refForm.updateForm();
}
},
//
async onOrgAddSuccess(currNodeData, newSubNodeData) {
let treeNode = this.$refs["org-tree"].getNode(currNodeData); //
this.$refs["org-tree"].append(newSubNodeData, treeNode); //
// this.$refs["org-tree"].append(newSubNodeData, currNodeData.id); //
this.defaultExpandedKeys = [newSubNodeData.id]; //
},
//
onOrgMoveSuccess(currNodeData, targetParentData) {
// console.log("currNodeData :>> ", currNodeData);
// console.log("targetParentData :>> ", targetParentData);
// let treeNode = this.$refs["org-tree"].getNode(currNodeData.id); //
let parentTreeNode = this.$refs["org-tree"].getNode(targetParentData); //
let subTreeNode = this.$refs["org-tree"].getNode(currNodeData); //
this.$refs["org-tree"].remove(subTreeNode);
this.$refs["org-tree"].append(currNodeData, parentTreeNode);
},
// root
async getAllNodesWithRoot() {
this.vloadingOrgTree = true;
let allTreeData = await OrganizationBiz.getAllNodes(null);
this.vloadingOrgTree = false;
let treeRoot = { ...ORG_ROOT };
treeRoot.Children = allTreeData;
return [treeRoot];
},
//
renderTreeNodeContent(h, { node, data, store }) {
return (
<TreeNodeWith3Dots
data={data}
btns={data.id ? ["edit", "add", "move", "delete"] : ["add"]}
addBtnName={"新增子部门"}
on-menu-select={(index, indexPath, data) => {
switch (index) {
case "add":
this.isDialAddDeptVisible = true;
this.currEditingOrg = data;
break;
case "edit":
this.isDialEditDeptVisible = true;
this.currEditingOrg = data; // OrgEdit
// this.currEditingOrg.id = data.id;
// this.currEditingOrg.name = data.name;
break;
case "move":
this.currEditingOrg = data;
this.isDialMoveDeptVisible = true;
break;
case "delete":
this.currEditingOrg = data;
this.$confirm(`确定删除部门 ${this.currEditingOrg.name}?`, {
title: "确认删除",
showCancelButton: true,
showConfirmButton: true,
})
.then(async () => {
try {
let count = await OrganizationBiz.delById(
this.currEditingOrg.id
);
if (count) {
this.$message.success(
`部门 ${this.currEditingOrg.name} 删除成功`
);
this.$refs["org-tree"].remove(this.currEditingOrg);
} else {
this.$message.success(
`部门 ${this.currEditingOrg.name} 删除失败`
);
}
} catch (e) {
this.$message.success(
`部门 ${this.currEditingOrg.name} 删除失败,原因:${e.message}`
);
}
})
.catch(() => {});
break;
}
}}
/>
);
},
onResizeLineStartMove: function () {},
onResizeLineMove: function (e) {},
onResizeLineEndMove: function () {},
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/_variables.scss";
$line-height: 28px;
.split-pane {
// background-color: #fff;
// border-radius: 8px;
// border: solid 1px $theme-background-light;
box-sizing: border-box;
.pane {
.container {
box-sizing: border-box;
height: 100%;
padding: 16px;
.title {
padding-bottom: 16px;
border-bottom: 1px solid $theme-background-dark;
height: $line-height;
&.title-flex-right {
display: flex;
flex-direction: row;
justify-content: flex-end;
}
&.title-flex-both {
// display: flex;
// flex-direction: row;
// justify-content: space-between;
}
.title-inner {
line-height: $line-height;
}
.el-button.el-button--text {
// padding: 0;
}
}
.content {
padding-top: 16px;
}
}
}
}
</style>

View File

@ -1,112 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-04 09:49:56
* @Description: 后台管理-角色管理页面
-->
<template>
<div class="platformSetting back-column-one">
<div class="back-title">{{$route.meta.title}}</div>
<el-button type="primary" round>新建模块</el-button>
<el-table :data="dataList" style="width: 100%">
<el-table-column
v-for="title in titleList"
:key="title.prop"
:prop="title.prop"
:label="title.label"
show-overflow-tooltip
/>
<el-table-column label="操作">
<template v-slot="scope">
<el-tooltip
class="item"
effect="light"
content="恢复"
placement="top"
>
<el-button
icon="el-icon-edit"
type="text"
@click="handleEditClick(scope.row)"
/>
</el-tooltip>
<el-divider direction="vertical" />
<el-tooltip
class="item"
effect="light"
content="删除"
placement="top"
>
<el-button
icon="el-icon-delete"
type="text"
@click="handleDeleteClick(scope.row)"
/>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "PlatformSetting",
data() {
return {
titleList: [
{
prop: 'type',
label: '分类名称'
},
{
prop: 'moduleType',
label: '模块类型'
},
{
prop: 'dest',
label: '说明'
},
{
prop: 'status',
label: '状态'
},
{
prop: 'sort',
label: '排序'
},
],
dataList: [
{
type: '产品及演示方案',
moduleType: '演示方案',
dest: '-',
status: '启用',
sort: '',
},
{
type: '产品及演示方案',
moduleType: '演示方案',
dest: '-',
status: '启用',
sort: '',
},
{
type: '产品及演示方案',
moduleType: '演示方案',
dest: '-',
status: '启用',
sort: '',
},
]
}
}
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
</style>

View File

@ -1,519 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-05 18:47:10
* @Description: 后台管理-角色管理页面
-->
<template>
<div class="role back-column-two">
<!-- 左侧-角色列表 -->
<div class="column-left">
<div class="title back-title">
{{ $route.meta.title }}
<el-button
class="role-new"
icon="el-icon-circle-plus"
@click="roleDialogAddVisible = true"
>
新建角色
</el-button>
</div>
<el-input
class="bg-dark"
v-model="roleInput"
prefix-icon="el-icon-search"
placeholder="请输入"
@change="handleRoleInput"
/>
<div class="role-list">
<ul class="list-ul">
<li
v-for="role in roleList"
:key="role.id"
class="list-li"
:class="{ selected: role === selectedRole }"
@click="handleRoleClick(role)"
>
<!-- {{ role.name }} -->
<TreeNodeWith3Dots
:data="role"
:btns="['edit', 'delete']"
@menu-select="handleRoleOperate"
/>
</li>
</ul>
</div>
<el-dialog
title="新建角色"
width="30%"
:visible.sync="roleDialogAddVisible"
>
<RoleAdd
@on-cancel="roleDialogAddVisible = false"
@on-submit="handleRoleAddSubmit"
/>
</el-dialog>
<el-dialog
title="编辑角色"
width="30%"
:visible.sync="roleDialogEditVisible"
>
<RoleUpdate
:role="selectedRole"
@on-cancel="roleDialogEditVisible = false"
@on-submit="handleRoleEditSubmit"
/>
</el-dialog>
</div>
<!-- 右侧-角色内容 -->
<div class="column-right">
<el-tabs
class="back-title-el-tabs"
value="role-remember"
@tab-click="handleTabClick"
>
<el-tab-pane label="角色成员2" name="role-remember">
<div class="form-box">
<el-button type="primary" round>关联用户</el-button>
<el-input
class="bg-dark"
v-model="userInput"
prefix-icon="el-icon-search"
placeholder="请输入"
@change="handleUserInput"
/>
</div>
<div class="text-box">
<div>共132个伙伴</div>
<div>
<el-dropdown class="sort" @command="ff">
<span class="el-dropdown-link">
{{ sortType }}
<i class="el-icon-arrow-down el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>创建时间正序</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-dropdown class="filter">
<span class="el-dropdown-link">
{{ filteType }}
<i class="el-icon-arrow-down el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>角色</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<el-table :data="userList" style="width: 100%">
<el-table-column
v-for="title in titleList"
:key="title.prop"
:prop="title.prop"
:label="title.label"
show-overflow-tooltip
/>
<el-table-column label="操作">
<template v-slot="scope">
<el-tooltip
class="item"
effect="light"
content="编辑"
placement="top"
>
<el-button
icon="el-icon-edit"
type="text"
@click="handleEditClick(scope.row)"
/>
</el-tooltip>
<el-divider direction="vertical" />
<el-tooltip
class="item"
effect="light"
content="删除"
placement="top"
>
<el-button
icon="el-icon-delete"
type="text"
@click="handleDeleteClick(scope.row)"
/>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="prev, pager, next" :total="1000">
</el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="角色权限" name="role-auth">
<ul class="auth-first-ul">
<li v-for="firstAuth in authList" :key="firstAuth.text">
<el-checkbox v-model="firstAuth.checked">
{{ firstAuth.text }}
</el-checkbox>
<ul class="auth-second-ul">
<li
v-for="secondAuth in firstAuth.children"
:key="secondAuth.text"
>
<el-checkbox v-model="secondAuth.checked">
{{ secondAuth.text }}
</el-checkbox>
</li>
</ul>
</li>
</ul>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import Dialog from "../../components/_Common/Dialog.vue";
import RoleAdd from "../../components/Rbac/Role/RoleAdd.vue";
import RoleUpdate from "../../components/Rbac/Role/RoleEdit.vue";
import TreeNodeWith3Dots from "../../components/_Common/Tree/TreeNodeWith3Dots.vue";
import RoleBiz from "../../biz/Rbac/Role.js";
import UserBiz from "../../biz/Rbac/User.js";
import { DIALOG_TYPE } from "../../const.js";
export default {
name: "Role",
components: {
RoleAdd,
RoleUpdate,
TreeNodeWith3Dots,
},
data() {
return {
roleDialogAddVisible: false, //
roleDialogEditVisible: false, //
roleAction: DIALOG_TYPE.ADD, //
roleInput: "", //
userInput: "", //
roleList: [], //
selectedRole: null, //
//
titleList: [
{
prop: "name",
label: "伙伴名称",
},
{
prop: "department",
label: "部门",
},
{
prop: "role",
label: "角色",
},
{
prop: "status",
label: "账号状态",
},
],
userList: [], //
//
authList: [
{
text: "全部",
checked: false,
children: [],
},
{
text: "产品",
children: [
{
text: "查看",
checked: true,
},
{
text: "下架产品",
checked: false,
},
{
text: "编辑产品",
checked: false,
},
{
text: "分享产品",
checked: false,
},
{
text: "删除产品",
checked: false,
},
{
text: "收藏",
checked: false,
},
],
},
{
text: "行业解决方案",
children: [
{
text: "查看",
checked: true,
},
],
},
{
text: "个人空间",
children: [
{
text: "开启",
checked: true,
},
],
},
{
text: "后台管理",
children: [
{
text: "组织架构",
checked: true,
},
],
},
],
sortType: "排序", //
filteType: "筛选", //
};
},
computed: {
//
roleTitle() {
switch (this.roleAction) {
case DIALOG_TYPE.EDIT:
return "编辑角色";
case DIALOG_TYPE.ADD:
default:
return "新建角色";
}
},
},
watch: {
async selectedRole() {
this.refreshUserList();
},
},
methods: {
// tab
handleTabClick(tab, event) {
console.log(tab, event);
},
ff(a, b) {
console.log(a, b);
},
// -
handleRoleInput() {
console.log("searchRole >>> ");
this.refreshRoleList();
},
// -
handleUserInput() {
console.log("searchUser");
this.refreshUserList();
},
// -
handleRoleClick(role) {
this.selectedRole = role;
},
// -
handleRoleAddSubmit(newRole) {
console.log("newRole >>> ", newRole);
this.roleDialogAddVisible = false;
},
// -
handleRoleEditSubmit() {
this.roleDialogEditVisible = false;
},
// -
handleRoleOperate(index, _, data) {
switch (index) {
case "edit":
this.roleDialogEditVisible = true;
break;
case "delete":
this.$confirm(`确定删除角色 ${data.name} ?`, { title: "确认删除" })
.then(async () => {
try {
const count = await RoleBiz.delById(data.id);
if (count) {
this.$message.success("角色删除成功");
} else {
this.$message.error("角色删除失败");
}
} catch ({ message }) {
this.$message.error(message);
}
})
.catch(() => {});
}
},
// -
handleDeleteClick(user) {
this.$confirm(`确定移除用户 ${user.name} ?`, { title: "确认移除" })
.then(async () => {
try {
const count = await UserBiz.delById(user.id);
if (count) {
this.$message.success("用户移除成功");
} else {
this.$message.error("角色移除失败");
}
} catch ({ message }) {
this.$message.error(message);
}
})
.catch(() => {});
},
//
async refreshRoleList() {
this.roleList = await RoleBiz.findByName(this.roleInput);
if (this.roleList) {
this.selectedRole = this.roleList[0];
}
},
//
async refreshUserList() {
this.userList = await UserBiz.findByName(this.userInput);
},
},
created() {
this.refreshRoleList();
},
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/element-ui-reset.scss";
.role {
.title {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: #{$title-height - 20 + px};
border-bottom: 2px solid $theme-background-light;
.role-new {
padding: 0;
border: none;
color: #347eff;
&:hover {
background-color: transparent;
}
}
}
.role-list {
.list-ul {
margin-top: 20px;
.list-li {
height: 36px;
padding-left: 20px;
line-height: 36px;
cursor: pointer;
&:hover {
background-color: rgba(52, 126, 255, 0.1);
// opacity: 0.1;
color: #347eff;
}
&.selected {
background-color: rgba(52, 126, 255, 0.1);
color: #347eff;
}
}
}
}
.form-box,
.text-box {
display: flex;
justify-content: space-between;
}
.form-box {
.el-input {
width: 274px;
}
}
.text-box {
margin: 20px 0;
.sort {
margin-right: 20px;
cursor: pointer;
}
.filter {
cursor: pointer;
}
}
.auth-first-ul {
& > li {
margin-bottom: 30px;
& > .el-checkbox::v-deep {
margin-bottom: 10px;
font-weight: 700;
.el-checkbox__label {
font-size: 16px;
}
}
}
}
.auth-second-ul {
display: flex;
li {
margin-left: 20px;
&:first-child {
margin-left: 0;
}
}
}
}
</style>

View File

@ -1,23 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-04 09:50:07
* @Description: 后台管理-角色管理页面
-->
<template>
<div class="statistics back-column-one">
<div class="back-title">{{ $route.meta.title }}</div>
</div>
</template>
<script>
export default {
name: "Statistics",
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
</style>

View File

@ -1,23 +0,0 @@
<!--
* @Author: Guanghao
* @Date: 2021-12-31 14:29:34
* @LastEditors: Guanghao
* @LastEditTime: 2022-01-04 09:50:10
* @Description: 后台管理-角色管理页面
-->
<template>
<div class="topic back-column-one">
<div class="back-title">{{$route.meta.title}}</div>
</div>
</template>
<script>
export default {
name: "Topic",
};
</script>
<style lang="scss" scoped>
@import "~@/scss/Back/back.scss";
</style>

View File

@ -2,7 +2,7 @@
* @Author: Billy
* @Date: 2020-09-10 09:12:00
* @LastEditors: Billy
* @LastEditTime: 2022-01-10 21:10:42
* @LastEditTime: 2022-03-07 14:32:23
* @Description: 首页框架
-->
<template>
@ -31,24 +31,18 @@
<keep-alive v-if="$route.meta.keepAlive">
<router-view></router-view>
</keep-alive>
<!-- <el-aside class="right" :width="HEADER_THICKNESS + 'px'">
<Header2 :arrangeMode="'vertical'" />
</el-aside> -->
</el-container>
</div>
</template>
<script>
import Header from "../components/Home/Header.vue";
import Header2 from "../components/Home/Header2.vue";
import { DEFAULT_HOME_LAYOUT, HEADER_THICKNESS } from "../const.js";
export default {
name: "Home",
components: {
Header,
Header2,
},
data() {
return {

View File

@ -2,62 +2,18 @@
* @Author: Billy
* @Date: 2021-12-20 11:05:48
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 14:18:06
* @Description: 请输入
-->
<!--
* @Author: Billy
* @Date: 2021-12-20 11:05:48
* @LastEditors: Billy
* @LastEditTime: 2021-12-20 11:07:46
* @LastEditTime: 2022-03-07 15:00:04
* @Description: 请输入
-->
<template>
<div class="container">
aa
<input type="text" />
<!-- <TabViewer
:tabs="tabs"
:tabsCurrActiveIndex.sync="tabsCurrActiveIndex"
></TabViewer> -->
</div>
<div class="container"></div>
</template>
<script>
import TabViewer from "../../../components/_Common/Tab/TabViewer2.vue";
import Tab from "../../../entity/Ui/Tab/Tab.js";
export default {
components: { TabViewer },
components: {},
data() {
return {
//
tabs: [
new Tab({ title: "000000000a" }),
new Tab({ title: "111111111b" }),
new Tab({ title: "222222222c" }),
new Tab({ title: "333333333d" }),
new Tab({ title: "444444444e" }),
new Tab({ title: "555555555f" }),
new Tab({ title: "000000000000000000000000000000000000a" }),
new Tab({ title: "111111111b" }),
new Tab({ title: "222c" }),
new Tab({ title: "333333333d" }),
new Tab({ title: "444444444e" }),
new Tab({ title: "555555555f" }),
new Tab({ title: "000000000a" }),
new Tab({ title: "111111111b" }),
new Tab({ title: "222222222c" }),
new Tab({ title: "333333333d" }),
new Tab({ title: "444444444e" }),
new Tab({ title: "555555555f" }),
new Tab({ title: "000000000000000000000000000000000000a" }),
new Tab({ title: "111111111b" }),
new Tab({ title: "222c" }),
new Tab({ title: "333333333d" }),
new Tab({ title: "444444444e" }),
new Tab({ title: "555555555f" }),
],
tabsCurrActiveIndex: 2,
};
return {};
},
mounted() {},
};

View File

@ -1,10 +0,0 @@
<!--
* @Author: Billy
* @Date: 2022-01-06 15:22:46
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 15:22:46
* @Description: 请输入
-->
<template>
<div></div>
</template>

View File

@ -1,10 +0,0 @@
<!--
* @Author: Billy
* @Date: 2022-01-06 15:22:46
* @LastEditors: Billy
* @LastEditTime: 2022-01-06 15:22:46
* @Description: 请输入
-->
<template>
<div></div>
</template>