Commit 98dfe263 authored by 白舜's avatar 白舜 🎱

Merge branch 'dev0217' of ssh://cloud.wodcloud.com:10022/apaas/apaas-system-ui into dev

parents 30a86f9a 679d75dd
kind: pipeline kind: pipeline
name: dev name: dev0217
trigger: trigger:
branch: branch:
- dev - dev0217
clone: clone:
disable: true disable: true
...@@ -17,6 +17,7 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行 ...@@ -17,6 +17,7 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
image: registry.cn-qingdao.aliyuncs.com/wod/devops-git:1.0 image: registry.cn-qingdao.aliyuncs.com/wod/devops-git:1.0
network_mode: host network_mode: host
- name: s3-cache - name: s3-cache
image: registry.cn-qingdao.aliyuncs.com/wod/devops-s3-cache:1.0 image: registry.cn-qingdao.aliyuncs.com/wod/devops-s3-cache:1.0
network_mode: host network_mode: host
......
...@@ -12,7 +12,7 @@ module.exports = { ...@@ -12,7 +12,7 @@ module.exports = {
htmlWhitespaceSensitivity: "css", htmlWhitespaceSensitivity: "css",
insertPragma: false, insertPragma: false,
jsxSingleQuote: false, jsxSingleQuote: false,
printWidth: 120, // 如果属性过多需要换行,减少该值 printWidth: 100, // 如果属性过多需要换行,减少该值
proseWrap: "preserve", proseWrap: "preserve",
quoteProps: "as-needed", quoteProps: "as-needed",
requirePragma: false, requirePragma: false,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,17 +4,33 @@ ...@@ -4,17 +4,33 @@
<bg-menu :path="nowParent.path" v-if="menuShow" @openMsg="openMsg"></bg-menu> <bg-menu :path="nowParent.path" v-if="menuShow" @openMsg="openMsg"></bg-menu>
<div class="container" :class="menuShow ? '' : 'full_screen'" v-if="pageShow"> <div class="container" :class="menuShow ? '' : 'full_screen'" v-if="pageShow">
<!-- <bg-nav :highlightParentRule="highlightParentRule" :title="nowParent.menuName" width="208px" :list="nowParent.children" v-show="navShow" class="con-nav" /> --> <!-- <bg-nav :highlightParentRule="highlightParentRule" :title="nowParent.menuName" width="208px" :list="nowParent.children" v-show="navShow" class="con-nav" /> -->
<bg-nav :highlightParentRule="highlightParentRule" width="208px" :list="nowParent.children" v-show="navShow" class="con-nav" /> <bg-nav
v-if="nowParent.children"
:highlightParentRule="highlightParentRule"
width="208px"
:list="nowParent.children"
v-show="navShow"
class="con-nav" />
<div class="bg-main view"> <div class="bg-main view">
<router-view /> <router-view />
</div> </div>
</div> </div>
<div class="container" v-else-if="$route.path=='/login'"> <div class="container" v-else-if="$route.path == '/login'">
<div class="bg-main view"> <div class="bg-main view">
<login></login> <login></login>
</div> </div>
</div> </div>
<div class="container" v-else-if="$route.path=='/404'"> <div class="container" v-else-if="$route.path == '/register'">
<div class="bg-main view">
<register></register>
</div>
</div>
<div class="container" v-else-if="$route.path == '/password'">
<div class="bg-main view">
<password></password>
</div>
</div>
<div class="container" v-else-if="$route.path == '/404'">
<div class="bg-main view"> <div class="bg-main view">
<page404></page404> <page404></page404>
</div> </div>
...@@ -25,128 +41,126 @@ ...@@ -25,128 +41,126 @@
</template> </template>
<script> <script>
import bgMenu from '@/components/bg-menu.vue' import bgMenu from "@/components/bg-menu.vue";
import login from '@/page/login/index.vue' import login from "@/page/login/index.vue";
import page404 from '@/page/404.vue' import page404 from "@/page/404.vue";
import register from "@/page/register/index.vue";
import password from "@/page/password/index.vue";
export default { export default {
components:{ components: {
bgMenu, bgMenu,
login, login,
page404, page404,
register,
password,
}, },
computed:{ computed: {
msgBoxFlag(){ msgBoxFlag() {
return this.$store.state.msgBoxFlag return this.$store.state.msgBoxFlag;
}, },
userInfo() { userInfo() {
return this.$store.state.userInfo || {}; return this.$store.state.userInfo || {};
}, },
navMenu(){ navMenu() {
return this.$store.state.menu return this.$store.state.menu;
}, },
menuObj(){ menuObj() {
return this.$store.state.menuObj return this.$store.state.menuObj;
}, },
navShow(){ navShow() {
return false||!['/','/404','/login'].includes(this.$route.path) return false || !["/", "/404", "/login", "/register", "/password"].includes(this.$route.path);
}, },
pageShow(){ pageShow() {
return false||!['/404','/login'].includes(this.$route.path) return false || !["/404", "/login", "/register", "/password"].includes(this.$route.path);
}, },
rowPath(){ rowPath() {
if(this.pageShow&&this.$store.state.userInfo){ if (this.pageShow && this.$store.state.userInfo) {
return this.menuObj[this.$route.path]&&this.menuObj[this.$route.path].rowPath return this.menuObj[this.$route.path] && this.menuObj[this.$route.path].rowPath;
}else{ } else {
return '' return "";
} }
}, },
nowParent(){ nowParent() {
if(this.pageShow&&this.$store.state.userInfo){ if (this.pageShow && this.$store.state.userInfo) {
return this.rowPath?this.navMenu[this.rowPath.slice(1,2)]:'' return this.rowPath ? this.navMenu[this.rowPath.slice(1, 2)] : "";
} else {
}else{ return "";
return ''
} }
}, },
menuShow() { menuShow() {
return false||!["/ui-example"].includes(this.$route.path) return false || !["/ui-example"].includes(this.$route.path);
} },
}, },
watch:{ watch: {
msgBoxFlag(n,o){ msgBoxFlag(n, o) {
this.readFlag = !this.readFlag this.readFlag = !this.readFlag;
}, },
userInfo: { userInfo: {
handler() { handler() {
this.initMsg() this.initMsg();
}, },
deep: true, deep: true,
} },
}, },
data(){ data() {
return{ return {
readFlag:false, readFlag: false,
menuIndex:'', menuIndex: "",
} };
}, },
created(){ created() {
// this.initMsg() // this.initMsg()
}, },
mounted() { mounted() {},
}, methods: {
methods:{
openMsg(data) { openMsg(data) {
this.readFlag = !this.readFlag; this.readFlag = !this.readFlag;
}, },
initMsg() { initMsg() {
if(this.userInfo && this.userInfo.system_id) { if (this.userInfo && this.userInfo.system_id) {
this.$trace.setOptionValue('userId',this.userInfo.system_id) this.$trace.setOptionValue("userId", this.userInfo.system_id);
// this.$trace.setOptionValue('userType',this.userInfo.userType) // this.$trace.setOptionValue('userType',this.userInfo.userType)
// this.$trace.setOptionValue('roleId',this.userInfo.roleIds.join(',')) // this.$trace.setOptionValue('roleId',this.userInfo.roleIds.join(','))
this.$trace.setOptionValue('organization',this.userInfo.organization_id) this.$trace.setOptionValue("organization", this.userInfo.organization_id);
} }
}, },
pathToData(data,path){ pathToData(data, path) {
let arr = path.split(".");
let arr = path.split('.') let temp = null;
let temp = null let tempName = "";
let tempName = '' let tempPath = "";
let tempPath = '' arr.forEach((e, idx) => {
arr.forEach((e,idx) => { if (idx == 1) {
temp = data[e];
if(idx==1){ tempName = data[e].menuName;
temp = data[e] tempPath = data[e].path;
tempName = data[e].menuName data = data[e];
tempPath = data[e].path
data = data[e]
} }
if(idx==2){ if (idx == 2) {
if(data.children&&data.children.length){ if (data.children && data.children.length) {
temp = data.children[e] temp = data.children[e];
data = data.children[e] data = data.children[e];
} }
} }
}); });
return { return {
menuName:tempName, menuName: tempName,
path:tempPath, path: tempPath,
children:[temp] children: [temp],
} };
}, },
highlightParentRule(pathArr){ highlightParentRule(pathArr) {
return pathArr.includes(this.$route.path) return pathArr.includes(this.$route.path);
}, },
ada(){ ada() {},
},
} };
}
}
</script> </script>
<style> <style>
#app{ #app {
height: 100%; height: 100%;
} }
.container{ .container {
width: 100%; width: 100%;
height: calc(100% - 56px); height: calc(100% - 56px);
overflow: hidden; overflow: hidden;
...@@ -157,10 +171,10 @@ export default { ...@@ -157,10 +171,10 @@ export default {
.full_screen .bg-main { .full_screen .bg-main {
overflow-x: hidden; overflow-x: hidden;
} }
.con-nav{ .con-nav {
float: left; float: left;
} }
.view{ .view {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
background-color: #ebedf2; background-color: #ebedf2;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
} }
/* 返回按钮颜色 */ /* 返回按钮颜色 */
.from_return>.el-button--primary { .from_return > .el-button--primary {
background-color: #edf0ff !important; background-color: #edf0ff !important;
border-color: #edf0ff !important; border-color: #edf0ff !important;
color: #264dd9 !important; color: #264dd9 !important;
...@@ -71,12 +71,15 @@ ...@@ -71,12 +71,15 @@
cursor: pointer; cursor: pointer;
} }
.space_bet {} .space_bet {
}
/* reset */ /* reset */
html {} html {
}
html,body { html,
body {
margin: 0; margin: 0;
font-family: Microsoft YaHei, sans-serif; font-family: Microsoft YaHei, sans-serif;
/* font-size: 17px; */ /* font-size: 17px; */
...@@ -101,16 +104,16 @@ h5 { ...@@ -101,16 +104,16 @@ h5 {
font-weight: normal; font-weight: normal;
} }
h1{ h1 {
font-size: 32px; font-size: 32px;
} }
h2{ h2 {
font-size: 24px; font-size: 24px;
} }
h3{ h3 {
font-size: 18.7px; font-size: 18.7px;
} }
h4{ h4 {
font-size: 16px; font-size: 16px;
} }
...@@ -154,7 +157,7 @@ div { ...@@ -154,7 +157,7 @@ div {
align-items: flex-start; align-items: flex-start;
} }
.ss_card>.sc_left_container { .ss_card > .sc_left_container {
width: 6rem; width: 6rem;
height: 6rem; height: 6rem;
flex-shrink: 0; flex-shrink: 0;
...@@ -163,19 +166,19 @@ div { ...@@ -163,19 +166,19 @@ div {
font-size: 0; font-size: 0;
} }
.ss_card>.sc_right_container { .ss_card > .sc_right_container {
width: calc(100% - 7rem); width: calc(100% - 7rem);
flex-grow: 1; flex-grow: 1;
margin-left: 1.2rem; margin-left: 1.2rem;
} }
.ss_card>.sc_right_container>.sc_title { .ss_card > .sc_right_container > .sc_title {
font-size: 1.6rem; font-size: 1.6rem;
font-weight: bold; font-weight: bold;
line-height: 2.6rem; line-height: 2.6rem;
} }
.ss_card>.sc_right_container>.sc_info { .ss_card > .sc_right_container > .sc_info {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
...@@ -202,13 +205,13 @@ div { ...@@ -202,13 +205,13 @@ div {
position: relative; position: relative;
} }
.from_return>.el-button--primary { .from_return > .el-button--primary {
position: absolute; position: absolute;
top: 15px; top: 15px;
left: 20px; left: 20px;
} }
.from_return>span { .from_return > span {
color: #1a2236; color: #1a2236;
font-size: 16px; font-size: 16px;
} }
...@@ -279,6 +282,7 @@ div { ...@@ -279,6 +282,7 @@ div {
color: #404a62; color: #404a62;
text-align: center; text-align: center;
padding: 0 16px; padding: 0 16px;
line-height: 1;
} }
.dialog_box .el-dialog__body { .dialog_box .el-dialog__body {
padding: 24px; padding: 24px;
...@@ -337,8 +341,8 @@ div { ...@@ -337,8 +341,8 @@ div {
height: 36px; height: 36px;
} }
.el-tree-node__content:hover { .el-tree-node__content:hover {
background-image: linear-gradient(90deg, background-image: linear-gradient(90deg,
rgba(255, 255, 255, 0.05) 83%, rgba(255, 255, 255, 0.05) 83%,
rgba(0, 0, 0, 0.05) 86%); rgba(0, 0, 0, 0.05) 86%);
} */ } */
/* .usrrole .el-tree-node:focus>.el-tree-node__content{ /* .usrrole .el-tree-node:focus>.el-tree-node__content{
...@@ -566,7 +570,7 @@ border-radius:8px; ...@@ -566,7 +570,7 @@ border-radius:8px;
z-index: 20000 !important; z-index: 20000 !important;
} }
/* /*
下拉选样式 下拉选样式
此处勿删,apaasV3下拉选择样式统一用这个 此处勿删,apaasV3下拉选择样式统一用这个
*/ */
...@@ -621,7 +625,7 @@ border-radius:8px; ...@@ -621,7 +625,7 @@ border-radius:8px;
background-color: #fff; background-color: #fff;
} }
.el-radio__input.is-checked+.el-radio__label { .el-radio__input.is-checked + .el-radio__label {
color: #1a2236; color: #1a2236;
font-weight: 700; font-weight: 700;
} }
...@@ -674,18 +678,18 @@ border-radius:8px; ...@@ -674,18 +678,18 @@ border-radius:8px;
} }
/* common */ /* common */
.apass_breadcrumb>.el-breadcrumb { .apass_breadcrumb > .el-breadcrumb {
padding: 10px 0; padding: 10px 0;
} }
.apass_breadcrumb>.el-breadcrumb .el-breadcrumb__inner { .apass_breadcrumb > .el-breadcrumb .el-breadcrumb__inner {
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
color: #898d9e; color: #898d9e;
line-height: 23px; line-height: 23px;
} }
.apass_breadcrumb>.el-breadcrumb .el-breadcrumb__item:last-child .el-breadcrumb__inner { .apass_breadcrumb > .el-breadcrumb .el-breadcrumb__item:last-child .el-breadcrumb__inner {
color: #242c43; color: #242c43;
font-weight: normal; font-weight: normal;
} }
...@@ -771,8 +775,7 @@ border-radius:8px; ...@@ -771,8 +775,7 @@ border-radius:8px;
border-color: #ebeef5; border-color: #ebeef5;
} }
.apass_table .el-table th > .cell {
.apass_table .el-table th>.cell {
color: #1a2236; color: #1a2236;
} }
...@@ -851,7 +854,7 @@ border-radius:8px; ...@@ -851,7 +854,7 @@ border-radius:8px;
border-color: #515fe7; border-color: #515fe7;
} }
.apass_checkbox .el-checkbox__input.is-checked+.el-checkbox__label { .apass_checkbox .el-checkbox__input.is-checked + .el-checkbox__label {
color: #58617a; color: #58617a;
} }
...@@ -934,7 +937,7 @@ border-radius:8px; ...@@ -934,7 +937,7 @@ border-radius:8px;
margin-top: 50px; margin-top: 50px;
} }
.apaas_detail_container .detail_action .el-button+.el-button { .apaas_detail_container .detail_action .el-button + .el-button {
margin-left: 30px; margin-left: 30px;
} }
...@@ -1005,7 +1008,7 @@ border-radius:8px; ...@@ -1005,7 +1008,7 @@ border-radius:8px;
width: 124px; width: 124px;
} }
.apaas_steps .apaas_step .apaas_step_action .el-button+.el-button { .apaas_steps .apaas_step .apaas_step_action .el-button + .el-button {
margin-left: 20px; margin-left: 20px;
} }
...@@ -1017,7 +1020,7 @@ border-radius:8px; ...@@ -1017,7 +1020,7 @@ border-radius:8px;
flex-grow: 1; flex-grow: 1;
font-size: 0; font-size: 0;
} }
.filter_list>.filter_item { .filter_list > .filter_item {
display: flex; display: flex;
align-items: center; align-items: center;
margin: 0 34px 16px 0; margin: 0 34px 16px 0;
...@@ -1028,7 +1031,7 @@ border-radius:8px; ...@@ -1028,7 +1031,7 @@ border-radius:8px;
vertical-align: middle; vertical-align: middle;
} */ } */
.filter_list>.filter_item>.filter_title { .filter_list > .filter_item > .filter_title {
text-align: right; text-align: right;
font-size: 14px; font-size: 14px;
color: #242c43; color: #242c43;
...@@ -1058,14 +1061,14 @@ border-radius:8px; ...@@ -1058,14 +1061,14 @@ border-radius:8px;
text-align: right; text-align: right;
} }
.filter_action>.el-button { .filter_action > .el-button {
/* min-width: 90px; */ /* min-width: 90px; */
height: 36px; height: 36px;
margin-top: 16px; margin-top: 16px;
padding: 12px 17px; padding: 12px 17px;
} }
.filter_action>.el-button+.el-button { .filter_action > .el-button + .el-button {
margin-left: 10px; margin-left: 10px;
} }
...@@ -1104,7 +1107,7 @@ border-radius:8px; ...@@ -1104,7 +1107,7 @@ border-radius:8px;
margin-top: 5px; margin-top: 5px;
} }
.meassage_detail_dialog .detail_item .full_content>.apaas_scroll { .meassage_detail_dialog .detail_item .full_content > .apaas_scroll {
height: 176px; height: 176px;
overflow: auto; overflow: auto;
} }
...@@ -1122,7 +1125,7 @@ border-radius:8px; ...@@ -1122,7 +1125,7 @@ border-radius:8px;
/* 详情页公共样式 by xuyiming ~~~end */ /* 详情页公共样式 by xuyiming ~~~end */
/* /*
form_content form_content
*/ */
.from_content1 { .from_content1 {
...@@ -1279,11 +1282,11 @@ border-radius:8px; ...@@ -1279,11 +1282,11 @@ border-radius:8px;
.el-date-table td.in-range div:hover, .el-date-table td.in-range div:hover,
.el-date-table.is-week-mode .el-date-table__row.current div, .el-date-table.is-week-mode .el-date-table__row.current div,
.el-date-table.is-week-mode .el-date-table__row:hover div { .el-date-table.is-week-mode .el-date-table__row:hover div {
background-color: #eff2fa!important; background-color: #eff2fa !important;
} }
.el-date-table td.end-date .el-date-table-cell__text, .el-date-table td.end-date .el-date-table-cell__text,
.el-date-table td.start-date .el-date-table-cell__text { .el-date-table td.start-date .el-date-table-cell__text {
background-color: #3759be!important; background-color: #3759be !important;
} }
.el-date-table td.end-date span, .el-date-table td.end-date span,
.el-date-table td.start-date span { .el-date-table td.start-date span {
...@@ -1463,8 +1466,6 @@ border-radius:8px; ...@@ -1463,8 +1466,6 @@ border-radius:8px;
padding-right: 10px; padding-right: 10px;
} }
.page_container { .page_container {
width: 100%; width: 100%;
padding: 0 24px; padding: 0 24px;
...@@ -1476,11 +1477,10 @@ border-radius:8px; ...@@ -1476,11 +1477,10 @@ border-radius:8px;
align-items: stretch; align-items: stretch;
} }
.page_content { .page_content {
background-color: #fff; background-color: #fff;
height: calc(100% - 46px - 20px); height: calc(100% - 46px - 20px);
box-shadow: 0px 1px 4px 0px box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
rgba(0, 7, 101, 0.15); border-radius: 6px;
border-radius: 6px;
} }
.flex_row { .flex_row {
...@@ -1496,19 +1496,16 @@ border-radius:8px; ...@@ -1496,19 +1496,16 @@ border-radius:8px;
overflow: hidden; overflow: hidden;
} }
.flex_right { .flex_right {
height: calc(100% - 16px); height: calc(100% - 16px);
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.bgc_white { .bgc_white {
box-shadow: 0px 1px 4px 0px box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
rgba(0, 7, 101, 0.15); border-radius: 6px;
border-radius: 6px;
background-color: #fff; background-color: #fff;
} }
.tree::-webkit-scrollbar { .tree::-webkit-scrollbar {
...@@ -1532,7 +1529,7 @@ border-radius:8px; ...@@ -1532,7 +1529,7 @@ border-radius:8px;
} }
.header_info { .header_info {
font-size: 14px; font-size: 14px;
color: #404a62; color: #404a62;
padding-left: 20px; padding-left: 20px;
} }
.fr { .fr {
...@@ -1546,8 +1543,8 @@ border-radius:8px; ...@@ -1546,8 +1543,8 @@ border-radius:8px;
color: #404a62; color: #404a62;
} }
.icon_eye { .icon_eye {
font-size: 12px; font-size: 12px;
color: #a9b1c7; color: #a9b1c7;
margin-right: 8px; margin-right: 8px;
vertical-align: baseline; vertical-align: baseline;
cursor: pointer; cursor: pointer;
...@@ -1567,7 +1564,7 @@ border-radius:8px; ...@@ -1567,7 +1564,7 @@ border-radius:8px;
.warning_info { .warning_info {
background-color: #f7f7f9; background-color: #f7f7f9;
font-size: 14px; font-size: 14px;
color: #404a62; color: #404a62;
padding: 5px; padding: 5px;
text-align: left; text-align: left;
margin: 20px 0; margin: 20px 0;
...@@ -1576,3 +1573,36 @@ border-radius:8px; ...@@ -1576,3 +1573,36 @@ border-radius:8px;
color: #d75138; color: #d75138;
} }
.register_btn {
display: flex;
align-items: center;
background-color: #eff2fa;
border-radius: 4px;
border: solid 1px #b0bee8;
color: #3759be;
}
.register_btn .icon-arrow-right {
margin-left: 39px;
}
.forget_psd {
font-size: 14px;
color: #3759be;
cursor: pointer;
}
.select-empty {
color: #616f94;
text-align: center;
padding: 20px;
}
.tip-image {
position: absolute;
right: -24px;
bottom: 9px;
width: 16px;
height: 16px;
margin-left: 8px;
background-image: url("../imgs/ic_tips.png");
background-size: contain;
}
<template>
<div class="gap-title">
<span>{{ title }}</span>
</div>
</template>
<script setup>
const props = defineProps({
title: {
type: [Number, String],
default: "",
},
});
</script>
<style scoped>
.gap-title {
font-size: 18px;
font-weight: 600;
color: #1a1a1a;
display: flex;
align-items: center;
margin-bottom: 20px;
}
.gap-title span {
margin-right: 8px;
}
.gap-title::before {
content: "";
display: inline-block;
margin-right: 8px;
width: 4px;
height: 14px;
background-color: #3759be;
border-radius: 2px;
}
/* .gap-title::after {
content: "";
display: inline-block;
flex: 1;
border-top: 1px dashed #dadee7;
} */
</style>
...@@ -50,9 +50,17 @@ ...@@ -50,9 +50,17 @@
</template> </template>
<script setup> <script setup>
import { watch, ref } from "vue"; import { watch, ref, nextTick } from "vue";
import { selectTableMixin } from "./hook/mixin-select-table"; import { selectTableMixin } from "./hook/mixin-select-table";
let { nowSelectData, allSelectData, selectData, initSelectTableData, runPage, dealSelectData } = selectTableMixin(); const {
nowSelectData,
allSelectData,
initAllSelectData,
selectData,
initSelectTableData,
runPage,
dealSelectData,
} = selectTableMixin();
const props = defineProps({ const props = defineProps({
height: { height: {
...@@ -71,9 +79,6 @@ const props = defineProps({ ...@@ -71,9 +79,6 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
// selectable: {
// type: Function,
// },
isIndex: { isIndex: {
type: Boolean, type: Boolean,
default: false, default: false,
...@@ -95,18 +100,34 @@ const props = defineProps({ ...@@ -95,18 +100,34 @@ const props = defineProps({
default: false, default: false,
}, // 多选框是否禁用 }, // 多选框是否禁用
canEditFlag: { canEditFlag: {
typr: Boolean, type: String,
default: "", default: "",
}, // 决定多选框是否禁用的字段 }, // 决定多选框是否禁用的字段
indexWidth: { indexWidth: {
type: Number, type: Number,
default: 54, default: 54,
}, },
//初始表格选中数据
originSelectedData: {
type: Array,
default: () => [],
},
}); });
const table = ref(null); const table = ref(null);
const emit = defineEmits(["selectAc", "select"]); const emit = defineEmits(["selectAc", "select"]);
watch(
() => props.originSelectedData,
(val) => {
if (val.length) {
initAllSelectData(props.originSelectedData);
}
},
{
immediate: true,
}
);
watch( watch(
() => props.rows, () => props.rows,
(n, o) => { (n, o) => {
...@@ -120,6 +141,9 @@ watch( ...@@ -120,6 +141,9 @@ watch(
} }
}); });
} }
},
{
immediate: true,
} }
); );
...@@ -127,14 +151,19 @@ const toggleRowSelection = (row, flag = true) => { ...@@ -127,14 +151,19 @@ const toggleRowSelection = (row, flag = true) => {
table.value.toggleRowSelection(row, flag); table.value.toggleRowSelection(row, flag);
}; };
const selectAction = (selection) => { const selectAction = (selection) => {
emit("selectAc", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection }); nextTick(() => {
emit("selectAc", {
allLength: Object.keys(allSelectData.value).length + nowSelectData.value.length,
selection,
});
});
}; };
const clearSelection = () => { const clearSelection = () => {
table.value.clearSelection(); table.value.clearSelection();
emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection: [] }); emit("select", {
}; allLength: Object.keys(allSelectData.value).length + nowSelectData.value.length,
const setSelectedRow = (row) => { selection: [],
toggleRowSelection(row); });
}; };
const toggleRowArrSelection = (arr, flag = true) => { const toggleRowArrSelection = (arr, flag = true) => {
arr.forEach((e) => { arr.forEach((e) => {
...@@ -143,16 +172,22 @@ const toggleRowArrSelection = (arr, flag = true) => { ...@@ -143,16 +172,22 @@ const toggleRowArrSelection = (arr, flag = true) => {
}; };
const selectActionRow = (selection, row) => { const selectActionRow = (selection, row) => {
selectData(selection); selectData(selection);
emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection }); emit("select", {
allLength: Object.keys(allSelectData.value).length + nowSelectData.value.length,
selection,
});
}; };
const selectActionAll = (selection) => { const selectActionAll = (selection) => {
selectData(selection); selectData(selection);
emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection }); emit("select", {
allLength: Object.keys(allSelectData.value).length + nowSelectData.value.length,
selection,
});
}; };
const clearTable = () => { const clearTable = () => {
//清除选中数据,在页面状态更新时使用 //清除选中数据,在页面状态更新时使用
allSelectData = {}; allSelectData.value = {};
nowSelectData = []; nowSelectData.value = [];
clearSelection(); clearSelection();
}; };
const tableRowClassName = ({ row, rowIndex }) => { const tableRowClassName = ({ row, rowIndex }) => {
...@@ -176,5 +211,6 @@ const selectable = (row, index) => { ...@@ -176,5 +211,6 @@ const selectable = (row, index) => {
defineExpose({ defineExpose({
clearTable, clearTable,
toggleRowSelection, toggleRowSelection,
dealSelectData,
}); });
</script> </script>
...@@ -11,9 +11,7 @@ ...@@ -11,9 +11,7 @@
@click="changeActiveName(item, index)"> @click="changeActiveName(item, index)">
{{ item.label }} {{ item.label }}
</li> </li>
<li>
<!-- empty -->
</li>
</ul> </ul>
</div> </div>
<div class="bg-tabs-content"> <div class="bg-tabs-content">
......
import { reactive, toRefs,useAttrs } from 'vue' import { reactive, toRefs, useAttrs } from "vue";
export function selectTableMixin(){ export function selectTableMixin() {
const state = reactive({ const state = reactive({
nowSelectData:[], nowSelectData: [],
allSelectData:{} allSelectData: {},
}) });
const attrs = useAttrs()
// const nowSelectData = reactive([])
// const allSelectData = reactive({})
const selectData = (val)=>{ const attrs = useAttrs();
console.log(val); // const nowSelectData = reactive([])
state.nowSelectData = val // const allSelectData = reactive({})
console.log('allSelectData');
console.log(state.allSelectData);
console.log(Object.keys(state.allSelectData).length);
}
const initSelectTableData = (data)=>{ const selectData = (val) => {
return new Promise((reslove,reject)=>{ state.nowSelectData = val;
data.forEach(e => { };
if(state.allSelectData[e[attrs.rowKey||'id']]){ //当某些表格有原始的选中数据时,初始化allSelectData
delete state.allSelectData[e[attrs.rowKey||'id']] const initAllSelectData = (list) => {
state.nowSelectData.push(e) list.forEach((e) => {
} state.allSelectData[e[attrs.rowKey || "id"]] = e;
}); });
};
console.log(state.nowSelectData); const initSelectTableData = (data) => {
reslove(state.nowSelectData) return new Promise((reslove, reject) => {
}) data.forEach((e) => {
} if (state.allSelectData[e[attrs.rowKey || "id"]]) {
delete state.allSelectData[e[attrs.rowKey || "id"]];
const runPage=()=>{//翻页数据推进 state.nowSelectData.push(e);
state.nowSelectData.forEach(e => { }
state.allSelectData[e[attrs.rowKey||'id']] = e });
}); reslove(state.nowSelectData);
state.nowSelectData = [] });
} };
const clearTable=()=>{//清除选中数据,在页面状态更新时使用 const runPage = () => {
state.allSelectData={} //翻页数据推进
state.nowSelectData=[] state.nowSelectData.forEach((e) => {
clearSelection(); state.allSelectData[e[attrs.rowKey || "id"]] = e;
} });
state.nowSelectData = [];
};
const dealSelectData=()=>{//最后提交处理数据 // const clearTable = () => {
state.nowSelectData.forEach(e => { // //清除选中数据,在页面状态更新时使用
state.allSelectData[e[attrs.rowKey||'id']] = e // state.allSelectData = {};
}); // state.nowSelectData = [];
return state.allSelectData // clearSelection();
} // };
const { nowSelectData, allSelectData } = toRefs(state) const dealSelectData = () => {
//最后提交处理数据
const submitData = { ...state.allSelectData };
state.nowSelectData.forEach((e) => {
submitData[e[attrs.rowKey || "id"]] = e;
});
return submitData;
};
return{ const { nowSelectData, allSelectData } = toRefs(state);
nowSelectData,
allSelectData,
selectData,
initSelectTableData,
runPage,
clearTable,
dealSelectData
}
return {
nowSelectData,
allSelectData,
initAllSelectData,
selectData,
initSelectTableData,
runPage,
// clearTable,
dealSelectData,
};
} }
// export const selectTableMixin = { // export const selectTableMixin = {
...@@ -88,7 +91,7 @@ return{ ...@@ -88,7 +91,7 @@ return{
// this.nowSelectData.push(e) // this.nowSelectData.push(e)
// } // }
// }); // });
// console.log(this.nowSelectData); // console.log(this.nowSelectData);
// if(this.nowSelectData.length){ // if(this.nowSelectData.length){
// setTimeout(()=>{ // setTimeout(()=>{
...@@ -115,4 +118,4 @@ return{ ...@@ -115,4 +118,4 @@ return{
// return this.allSelectData // return this.allSelectData
// } // }
// }, // },
// } // }
\ No newline at end of file
/** /**
* 全局组件 * 全局组件
*/ */
import BgIcon from './bg-icon.vue' import BgIcon from "./bg-icon.vue";
import BgNav from './bg-nav.vue' import BgNav from "./bg-nav.vue";
import BgList from './bg-list.vue' import BgList from "./bg-list.vue";
import BgDetail from './bg-detail.vue' import BgDetail from "./bg-detail.vue";
import BgFiltrate from './bg-filtrate.vue' import BgFiltrate from "./bg-filtrate.vue";
import BgTable from './bg-table.vue' import BgTable from "./bg-table.vue";
import BgTablePro from './bg-table-pro.vue' import BgTablePro from "./bg-table-pro.vue";
import BgTableBtn from './bg-table-btn.vue' import BgTableBtn from "./bg-table-btn.vue";
import BgTabs from './bg-tabs.vue' import BgTabs from "./bg-tabs.vue";
import BgTab from './bg-tab.vue' import BgTab from "./bg-tab.vue";
import BgLayoutCard from './bg-layout-card.vue' import BgLayoutCard from "./bg-layout-card.vue";
import BgCard from './bg-card.vue' import BgCard from "./bg-card.vue";
import BgInfo from './bg-info.vue' import BgInfo from "./bg-info.vue";
import BgBtns from './bg-btns.vue' import BgBtns from "./bg-btns.vue";
import BgUpload from './bg-upload.vue' import BgUpload from "./bg-upload.vue";
import BgUploadImage from './bg-upload-image.vue' import BgUploadImage from "./bg-upload-image.vue";
import BgTags from './bg-tags.vue' import BgTags from "./bg-tags.vue";
import BgSwitch from './bg-switch.vue' import BgSwitch from "./bg-switch.vue";
import BgRichText from './bg-rich-text.vue' import BgRichText from "./bg-rich-text.vue";
import BgCodeEditor from './bg-code-editor.vue' import BgCodeEditor from "./bg-code-editor.vue";
import BgFilter from './bg-filter.vue' import BgFilter from "./bg-filter.vue";
import BgSort from './bg-sort.vue' import BgSort from "./bg-sort.vue";
import BgFilterDate from './bg-filter-date.vue' import BgFilterDate from "./bg-filter-date.vue";
import bgUserUploadImage from './bg-user-upload-image.vue' import bgUserUploadImage from "./bg-user-upload-image.vue";
import bgDetailTable from './bg-detail-table.vue' import bgDetailTable from "./bg-detail-table.vue";
import bgDetailTable2 from './bg-detail-table2.vue' import bgDetailTable2 from "./bg-detail-table2.vue";
import debounce from './debounce' import debounce from "./debounce";
import BgPagination from './bg-pagination.vue' import BgPagination from "./bg-pagination.vue";
import BgInnerTabs from './bg-inner-tabs.vue' import BgInnerTabs from "./bg-inner-tabs.vue";
import BgFilterGroup from './bg-filter-group.vue' import BgFilterGroup from "./bg-filter-group.vue";
import BgSwitchEle from './bg-switch-ele.vue' import BgSwitchEle from "./bg-switch-ele.vue";
import BgTableBtns from './bg-table-btns.vue' import BgTableBtns from "./bg-table-btns.vue";
import BgTableBtns2 from './bg-table-btns2.vue' import BgTableBtns2 from "./bg-table-btns2.vue";
import BgPermission from './bg-permission.vue' import BgPermission from "./bg-permission.vue";
import BgFormGap from "./bg-form-gap.vue";
const components = { const components = {
BgIcon,//字体图标 BgIcon, //字体图标
BgNav, // 左侧导航 BgNav, // 左侧导航
BgList, // 列表页布局 BgList, // 列表页布局
BgDetail, // 详情页布局 BgDetail, // 详情页布局
...@@ -56,21 +57,22 @@ const components = { ...@@ -56,21 +57,22 @@ const components = {
BgTags, // 标签 BgTags, // 标签
BgSwitch, // 开关 BgSwitch, // 开关
BgRichText, // 富文本 BgRichText, // 富文本
BgCodeEditor,//代码输入 BgCodeEditor, //代码输入
BgFilter, // 首页筛选 BgFilter, // 首页筛选
BgSort, // 首页排序 BgSort, // 首页排序
BgFilterDate, BgFilterDate,
bgUserUploadImage, bgUserUploadImage,
bgDetailTable,//详情展示组件1 bgDetailTable, //详情展示组件1
bgDetailTable2,//详情展示组件2 bgDetailTable2, //详情展示组件2
debounce,//防抖组件 debounce, //防抖组件
BgPagination,// 分页组件 BgPagination, // 分页组件
BgInnerTabs,//内部tab BgInnerTabs, //内部tab
BgFilterGroup,//高级搜索 BgFilterGroup, //高级搜索
BgSwitchEle,// 基于element-plus封装的switch BgSwitchEle, // 基于element-plus封装的switch
BgTableBtns,// 表格按钮组 BgTableBtns, // 表格按钮组
BgPermission,// 菜单选择 BgPermission, // 菜单选择
BgTableBtns2, // 表格按钮组-新 BgTableBtns2, // 表格按钮组-新
BgFormGap,
}; };
const install = (Vue) => { const install = (Vue) => {
......
...@@ -840,7 +840,7 @@ a { ...@@ -840,7 +840,7 @@ a {
.bg-tabs { .bg-tabs {
background-color: #ffffff; background-color: #ffffff;
box-shadow: 0px 6px 12px 0px rgba(0, 20, 53, 0.3); box-shadow: 0px 4px 16px 0px rgba(18, 30, 0.03, 0.08);
border-radius: 12px; border-radius: 12px;
overflow: hidden; overflow: hidden;
...@@ -865,9 +865,10 @@ a { ...@@ -865,9 +865,10 @@ a {
align-items: center; align-items: center;
padding: 8px; padding: 8px;
border-bottom: 1px solid #e6e9ef; border-bottom: 1px solid #e6e9ef;
font-size: 16px; font-size: 20px;
line-height: 25px; line-height: 25px;
color: #404a62; color: #616f94;
background: #f7f7f9;
cursor: pointer; cursor: pointer;
&.current { &.current {
...@@ -877,18 +878,19 @@ a { ...@@ -877,18 +878,19 @@ a {
border-right: 1px solid #e6e9ef; border-right: 1px solid #e6e9ef;
border-bottom: 1px solid #fff; border-bottom: 1px solid #fff;
border-left: 1px solid #e6e9ef; border-left: 1px solid #e6e9ef;
color: #e56600; color: #3759be;
background-color: #fff;
overflow: hidden; overflow: hidden;
&::before { // &::before {
content: ""; // content: "";
position: absolute; // position: absolute;
top: 0; // top: 0;
left: 0; // left: 0;
width: 100%; // width: 100%;
height: 4px; // height: 4px;
background-color: #e56600; // background-color: #e56600;
} // }
} }
&:first-child { &:first-child {
......
...@@ -4,34 +4,36 @@ ...@@ -4,34 +4,36 @@
:class="{ :class="{
transparent: transparentBg, transparent: transparentBg,
'is-front': isFront, 'is-front': isFront,
}" }">
>
<!-- LOGO --> <!-- LOGO -->
<div @click="gotoPage" class="bg-logo"> <div @click="gotoPage" class="bg-logo">
<img style="width:140px;height:22px;" src="../assets/imgs/img_logo.png"/> <img
style="width: 140px; height: 22px"
:src="systemLogo ? JSON.parse(systemLogo)[0].url : getImageUrl('img_logo.png')" />
</div> </div>
<div class="person-menu" v-if="userInfo&& userInfo.system_id"> <div class="person-menu" v-if="userInfo && userInfo.system_id">
<!-- 用户中心 --> <!-- 用户中心 -->
<div class="user-center nav-item"> <div class="user-center nav-item">
<span class="user-icon"> <span class="user-icon">
<img style="width:24px;height:24px;border-radius:50%;vertical-align:middle;" v-if="userInfo&&userInfo.logo" :src="userInfo&&userInfo.logo" /> <img
<img style="width:24px;height:24px;border-radius:50%;vertical-align:middle;" v-else src="../assets/imgs/home_ic_user.png" /> style="width: 24px; height: 24px; border-radius: 50%; vertical-align: middle"
v-if="userInfo && userInfo.logo"
:src="userInfo && userInfo.logo" />
<img
style="width: 24px; height: 24px; border-radius: 50%; vertical-align: middle"
v-else
src="../assets/imgs/home_ic_user.png" />
</span> </span>
<span class="user-name" v-if="userInfo && userInfo.system_id"> <span class="user-name" v-if="userInfo && userInfo.system_id">
{{ userInfo.system_account || userInfo.system_id }} {{ userInfo.system_account || userInfo.system_id }}
<bg-icon icon="#bg-ic-arrow-down" style="font-size:8px;margin-left: 3px;"></bg-icon> <bg-icon icon="#bg-ic-arrow-down" style="font-size: 8px; margin-left: 3px"></bg-icon>
</span>
<span class="user-name" v-else>
请登录
</span> </span>
<span class="user-name" v-else> 请登录 </span>
<div class="menu-virtual"></div> <div class="menu-virtual"></div>
<div v-if="userInfo && userInfo.system_id" class="menu-list"> <div v-if="userInfo && userInfo.system_id" class="menu-list">
<div class="menu-item text_clip" @click.stop="menuAction('logout')"> <div class="menu-item text_clip" @click.stop="menuAction('logout')">退出登录</div>
退出登录
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -41,34 +43,36 @@ ...@@ -41,34 +43,36 @@
<script> <script>
import { mapState, mapMutations } from "vuex"; import { mapState, mapMutations } from "vuex";
import { clearCookie } from "../services/cookie.js"; import { clearCookie } from "../services/cookie.js";
import {resetRouter} from '../router/index' import { resetRouter } from "../router/index";
import { normalizeProps } from 'vue-demi'; import { normalizeProps } from "vue-demi";
import { getImageUrl } from "@/services/helper.js";
export default { export default {
name: "BgMenu", name: "BgMenu",
components: { }, components: {},
props:{ props: {
path:{ path: {
type:String, type: String,
default:'' default: "",
}, },
}, },
data() { data() {
return { return {
getImageUrl,
documentScrollTop: 0, documentScrollTop: 0,
cartList: [], cartList: [],
showCart: true, showCart: true,
showShopMenu: false, showShopMenu: false,
logo:'../assets/imgs/img_logo.png', logo: "../assets/imgs/img_logo.png",
name:'' name: "",
}; };
}, },
computed: { computed: {
msgUnreadNum(){ msgUnreadNum() {
return this.$store.state.msgUnreadNum return this.$store.state.msgUnreadNum;
}, },
nameFlag(){ nameFlag() {
return this.$store.state.nameFlag return this.$store.state.nameFlag;
}, },
userInfo() { userInfo() {
return this.$store.state.userInfo || {}; return this.$store.state.userInfo || {};
...@@ -79,56 +83,57 @@ export default { ...@@ -79,56 +83,57 @@ export default {
transparentBg() { transparentBg() {
return ( return (
this.documentScrollTop < 180 && this.documentScrollTop < 180 &&
(this.$route.name === "shopRecommend" || (this.$route.name === "shopRecommend" || this.$route.name === "shopSearch")
this.$route.name === "shopSearch")
); );
}, },
isFront() { isFront() {
let path = this.$route.path; let path = this.$route.path;
return false return false;
},
systemLogo() {
return this.$store.state.systemLogo;
}, },
...mapState({ ...mapState({
fontMenu (state) { fontMenu(state) {
let temp = [] let temp = [];
// state.menu.forEach(e => { // state.menu.forEach(e => {
// if(e.dict_group_id=='2cb4f767-fad7-44f2-afa3-f055e15dd2b6'){//font // if(e.dict_group_id=='2cb4f767-fad7-44f2-afa3-f055e15dd2b6'){//font
// temp.push(e) // temp.push(e)
// } // }
// }); // });
return temp return temp;
}, },
managerMenu(state){ managerMenu(state) {
let temp = [] let temp = [];
// state.menu.forEach(e => { // state.menu.forEach(e => {
// if(e.dict_group_id=='64c156e0-bfff-4bfc-a63a-56effe130a25'){//system // if(e.dict_group_id=='64c156e0-bfff-4bfc-a63a-56effe130a25'){//system
// // 暂时处理运营管控中心-调用日志,后期规划位置后修改 // // 暂时处理运营管控中心-调用日志,后期规划位置后修改
// if (e.menuName !== '运营看板') { // if (e.menuName !== '运营看板') {
// temp.push(e) // temp.push(e)
// } // }
// // temp.push(e) // // temp.push(e)
// } // }
// }); // });
return temp return temp;
}, },
systemMenu(state){ systemMenu(state) {
let temp = [] let temp = [];
state.menu.forEach(e => { state.menu.forEach((e) => {
if(e.dict_group_id=='09938937-3db9-47de-b967-7777ea4ebb2d'){//manager if (e.dict_group_id == "09938937-3db9-47de-b967-7777ea4ebb2d") {
temp.push(e) //manager
temp.push(e);
} }
}); });
return temp return temp;
} },
}) }),
}, },
watch: { watch: {
nameFlag(n,o){ nameFlag(n, o) {
this.getLogo() this.getLogo();
} },
// cartState() { // cartState() {
// this.getCartList(); // this.getCartList();
// }, // },
...@@ -138,26 +143,25 @@ export default { ...@@ -138,26 +143,25 @@ export default {
}, },
methods: { methods: {
openMsg() { openMsg() {
this.$emit('openMsg',true) this.$emit("openMsg", true);
}, },
...mapMutations(["setCartNum"]), ...mapMutations(["setCartNum"]),
navAction(path) { navAction(path) {
this.$router.push(path); this.$router.push(path);
}, },
gotoPage(){ gotoPage() {
window.open('/apaas/portal/ui/#/','_blank') window.open("/apaas/portal/ui/#/", "_blank");
}, },
changezz(item){ changezz(item) {
this.$trace.setOptionValue('appID',item.value) this.$trace.setOptionValue("appID", item.value);
}, },
getLogo(){ getLogo() {
// this.$axios.get(`/apaas/system/getPicAndSystemName`).then(res=>{ // this.$axios.get(`/apaas/system/getPicAndSystemName`).then(res=>{
// if(res.data.code==200){ // if(res.data.code==200){
// let data = res.data.data // let data = res.data.data
// this.name=data.systemName // this.name=data.systemName
// this.logo = data.picture // this.logo = data.picture
// document.title = this.name // document.title = this.name
// var link = document.querySelector("link[rel*='icon']")||document.createElement('link'); // var link = document.querySelector("link[rel*='icon']")||document.createElement('link');
// link.type = 'image/x-icon'; // link.type = 'image/x-icon';
// link.rel = 'shortcut icon'; // link.rel = 'shortcut icon';
...@@ -166,19 +170,19 @@ export default { ...@@ -166,19 +170,19 @@ export default {
// } // }
// }) // })
}, },
menuAction(n,parent) { menuAction(n, parent) {
if (n == "logout") { if (n == "logout") {
this.$axios.post(`/apaas/system/v5/user/logout`).then(res=>{ this.$axios.post(`/apaas/system/v5/user/logout`).then((res) => {
if(res.data.code=='200'){ if (res.data.code == "200") {
window.location.href = `/apaas/manage/ui/#/login`; window.location.href = `/apaas/manage/ui/#/login`;
this.$store.commit('setUserInfo',null) this.$store.commit("setUserInfo", null);
clearCookie('bgToken') clearCookie("bgToken");
this.$message.success('退出成功') this.$message.success("退出成功");
resetRouter() resetRouter();
}else{ } else {
this.$message.error('退出失败') this.$message.error("退出失败");
} }
}) });
} else if (n == "login") { } else if (n == "login") {
let path = this.$route.path; let path = this.$route.path;
window.location.href = `/apaas/manage/ui/#/login?redirect=${path}`; window.location.href = `/apaas/manage/ui/#/login?redirect=${path}`;
...@@ -186,38 +190,38 @@ export default { ...@@ -186,38 +190,38 @@ export default {
//是否有子路由,有则寻找子路由的第一个进行跳转,无则直接进行跳转 //是否有子路由,有则寻找子路由的第一个进行跳转,无则直接进行跳转
//使用childMenuAction是模拟template中,子路径点击跳转使用childMenuAction, //使用childMenuAction是模拟template中,子路径点击跳转使用childMenuAction,
//防止出现层级错误的问题 //防止出现层级错误的问题
if(parent.children&&parent.children.length&&parent.menuType!==1){ if (parent.children && parent.children.length && parent.menuType !== 1) {
this.childMenuAction(parent.children[0],parent) this.childMenuAction(parent.children[0], parent);
}else{ } else {
this.pathToUrl(n,parent) this.pathToUrl(n, parent);
} }
} }
}, },
childMenuAction(v,parent) { childMenuAction(v, parent) {
//最多只有2层目录,childMenuAction已经进入第一层,只需判断是否还有第二层即可 //最多只有2层目录,childMenuAction已经进入第一层,只需判断是否还有第二层即可
//有第二层则继续找第二层的第一个跳转 //有第二层则继续找第二层的第一个跳转
//无第二层则直接跳转 //无第二层则直接跳转
if(v.children&&v.children.length){ if (v.children && v.children.length) {
for (let index = 0; index < v.children.length; index++) { for (let index = 0; index < v.children.length; index++) {
const e = v.children[index]; const e = v.children[index];
if(e.menuType!==2){ if (e.menuType !== 2) {
this.pathToUrl(e,parent) this.pathToUrl(e, parent);
break break;
} }
} }
}else{ } else {
this.pathToUrl(v,parent) this.pathToUrl(v, parent);
} }
}, },
pathToUrl(item,parent){ pathToUrl(item, parent) {
//判断是否是外链,是则新开窗口跳转 //判断是否是外链,是则新开窗口跳转
if(item.path.includes('http')){ if (item.path.includes("http")) {
window.open(item.path,'_blank') window.open(item.path, "_blank");
}else{ } else {
//判断是否是新窗口打开 //判断是否是新窗口打开
if(item.new_window){ if (item.new_window) {
window.open(item.path,'_blank') window.open(item.path, "_blank");
}else{ } else {
this.$router.push(item.path); this.$router.push(item.path);
} }
} }
...@@ -231,18 +235,16 @@ export default { ...@@ -231,18 +235,16 @@ export default {
scrollAction() { scrollAction() {
this.documentScrollTop = document.documentElement.scrollTop || 0; this.documentScrollTop = document.documentElement.scrollTop || 0;
}, },
}, },
created() { created() {
this.getLogo() this.getLogo();
if (this.userInfo) { if (this.userInfo) {
// this.getUserDetail(this.userInfo.user_id) // this.getUserDetail(this.userInfo.user_id)
}else { } else {
// this.getUserInfo() // this.getUserInfo()
} }
}, },
mounted() { mounted() {
this.$nextTick(this.scrollAction); this.$nextTick(this.scrollAction);
window.addEventListener("scroll", this.scrollAction, true); window.addEventListener("scroll", this.scrollAction, true);
window.addEventListener("click", this.shopMenEventListener); window.addEventListener("click", this.shopMenEventListener);
...@@ -280,19 +282,18 @@ export default { ...@@ -280,19 +282,18 @@ export default {
} }
} }
> .menu-virtual{ > .menu-virtual {
width: 128px; width: 128px;
height: 10px; height: 10px;
position: absolute; position: absolute;
top: 49px; top: 49px;
right: 0; right: 0;
z-index: 9; z-index: 9;
background-color: rgba(0,0,0,0); background-color: rgba(0, 0, 0, 0);
} }
> .menu-list { > .menu-list {
box-shadow: 0px 4px 12px 0px box-shadow: 0px 4px 12px 0px rgba(18, 30, 63, 0.1);
rgba(18, 30, 63, 0.1);
background-color: #ffffff; background-color: #ffffff;
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
...@@ -362,15 +363,15 @@ export default { ...@@ -362,15 +363,15 @@ export default {
font-size: 24px; font-size: 24px;
font-weight: bolder; font-weight: bolder;
margin-left: 10px; margin-left: 10px;
background: linear-gradient(to bottom, #d6e0fc,#9cb0e5); background: linear-gradient(to bottom, #d6e0fc, #9cb0e5);
-webkit-background-clip:text; -webkit-background-clip: text;
color:transparent; color: transparent;
line-height: 40px; line-height: 40px;
} }
} }
//个人菜单 //个人菜单
.person-menu{ .person-menu {
height: 100%; height: 100%;
padding-left: 32px; padding-left: 32px;
position: inherit; position: inherit;
...@@ -378,14 +379,14 @@ export default { ...@@ -378,14 +379,14 @@ export default {
align-items: center; align-items: center;
column-gap: 35px; column-gap: 35px;
.message{ .message {
height: 16px; height: 16px;
line-height: 16px; line-height: 16px;
background-color: #d14731; background-color: #d14731;
border-radius: 8px; border-radius: 8px;
padding: 0 6px; padding: 0 6px;
font-size: 12px; font-size: 12px;
color: #ffffff; color: #ffffff;
position: absolute; position: absolute;
top: -8px; top: -8px;
left: 12px; left: 12px;
......
<template> <template>
<div class="login-by-account"> <div class="login-by-account">
<el-form <el-form ref="loginFormRef" label-position="top" :model="loginForm" :rules="steploginFormRules">
ref="loginForm" <el-form-item prop="userid">
label-position="top" <el-input v-model="loginForm.userid" placeholder="请输入账号" @keyup.enter.native="loginAction()" />
:model="loginForm"
:rules="steploginFormRules"
>
<el-form-item label="账号" prop="userid">
<el-input
v-model="loginForm.userid"
autofocus="autofocus"
placeholder="请输入账号"
@keyup.enter.native="loginAction()"
/>
</el-form-item> </el-form-item>
<el-form-item label="密码" prop="password"> <el-form-item prop="password">
<el-input <el-input
:type="hidePassword ? 'password' : 'text'" :type="hidePassword ? 'password' : 'text'"
v-model="loginForm.password" v-model="loginForm.password"
placeholder="请输入密码" placeholder="请输入密码"
@keyup.enter.native="loginAction()" @keyup.enter.native="loginAction()">
>
<span <span
slot="suffix" slot="suffix"
:title="hidePassword ? '显示密码' : '隐藏密码'" :title="hidePassword ? '显示密码' : '隐藏密码'"
:class="hidePassword ? 'hide-password' : 'show-password'" :class="hidePassword ? 'hide-password' : 'show-password'"
@click="hidePassword = !hidePassword" @click="hidePassword = !hidePassword"
style="cursor: pointer" style="cursor: pointer"></span>
></span>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="验证码" prop="yzm"> <el-form-item prop="yzm">
<div class="msg-code"> <div class="msg-code">
<el-input <el-input
v-model="loginForm.yzm" v-model="loginForm.yzm"
placeholder="请输入验证码" placeholder="请输入验证码"
@keyup.enter.native="loginAction()" @keyup.enter.native="loginAction()"
/> style="width: 240px" />
<img <div class="yzm_img">
class="yzm_img" <img title="看不清?换一张" :src="imgSrc" @click="getImg()" style="width: 100%" />
title="看不清?换一张" </div>
:src="imgSrc"
@click="getImg()"
/>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-checkbox v-model="rememberPassword">记住密码</el-checkbox> <el-button type="primary" @click="loginAction()" style="width: 100%"> 登录 </el-button>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loginAction()" style="width: 100%"> <el-button class="register_btn" @click.prevent="$emit('register')" style="width: 100%">
登 录 还没有账号?前往注册
<bg-icon class="icon-arrow-right" icon="#bg-ic-arrow-right"></bg-icon>
</el-button> </el-button>
</el-form-item> </el-form-item>
<div class="regist_bottom">
<el-checkbox v-model="rememberPassword">记住密码</el-checkbox>
<span class="fr forget_psd" @click.prevent="$emit('password')">忘记密码?</span>
</div>
</el-form> </el-form>
</div> </div>
</template> </template>
<script> <script setup>
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { getCookie, clearCookie, setCookie } from "@/services/cookie.js"; import { getCookie, clearCookie, setCookie } from "@/services/cookie.js";
import menu from "../router/function"; import menu from "../router/function";
import { generateRoutes } from "../router/index"; import { generateRoutes } from "../router/index";
import { reactive, toRefs, ref, onBeforeMount, nextTick } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { Encrypt } from "@/services/secret.js";
import { useStore } from "vuex";
export default { const state = reactive({
name: "LoginByAccount", // 账号密码登录 loginForm: {
data() { userid: "",
return { password: "",
loginForm: { yzm: "",
userid: "",
password: "",
yzm: "",
},
steploginFormRules: {
userid: [{ required: true, message: "请输入账号", trigger: "blur" }],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
yzm: [{ required: true, message: "请输入验证码", trigger: "blur" }],
},
imgId: "",
imgSrc: "",
identifyCode: "",
hidePassword: true,
rememberPassword: false,
};
}, },
methods: { steploginFormRules: {
loginAction() { userid: [{ required: true, message: "请输入账号", trigger: "blur" }],
if (this.rememberPassword) { password: [{ required: true, message: "请输入密码", trigger: "blur" }],
let userinfo = window.btoa( yzm: [{ required: true, message: "请输入验证码", trigger: "blur" }],
encodeURI(`${this.loginForm.userid},${this.loginForm.password}`) },
); imgId: "",
setCookie("userinfo", userinfo); imgSrc: "",
} else { identifyCode: "",
clearCookie("userinfo"); hidePassword: true,
} rememberPassword: false,
});
this.$refs.loginForm.validate((valid) => { const store = useStore();
if (valid) {
this.$axios
.get(
`/apaas/system/v5/user/verifyCaptcha?id=${this.imgId}&value=${this.loginForm.yzm}`
)
.then((res) => {
if (res.data.code == 200) {
this.login();
} else {
this.$message.error(res.data.data);
}
});
}
});
},
login() {
this.$axios
.post(`/apaas/system/v5/user/login`, {
system_account: this.loginForm.userid,
password: CryptoJS.AES.encrypt(
this.loginForm.password,
"swuE9cmCZQwrkYRV"
).toString(),
})
.then(({ data }) => {
if (data.code == 200) {
this.getUser();
} else {
this.getImg(true);
this.$message({
message: data.data,
type: "error",
});
}
})
.catch((error) => {
console.log(error);
});
},
getUserInfo() {
return this.$axios.get(`/apaas/system/v5/user/getUserInfo`);
},
getMenu(search) {
return this.$axios.get(`/apaas/system/v5/menu/user/tree?search=${search}`);
},
getUser() {
Promise.all([this.getUserInfo(), this.getMenu('dadb2d3f-e263-48d1-9389-42acb9ea49f8')]).then((res) => {
if (res[0].data.code == 200 && res[1].data.code == 200) {
let data = res[1].data.data&&res[1].data.data[0].children || [];
this.$store.commit("setUserInfo", res[0].data.data);
// if (res.data.data.userType == 1) {
//超管
this.$store.commit("setMenu", data);
menu.menuToRouter(data); const loginFormRef = ref(null);
this.$store.commit("setRoute", data); const loginAction = () => {
if (state.rememberPassword) {
let userinfo = window.btoa(encodeURI(`${state.loginForm.userid},${state.loginForm.password}`));
setCookie("userinfo", userinfo);
} else {
clearCookie("userinfo");
}
//存储菜单对象信息 loginFormRef.value.validate((valid) => {
let menuObj = {}; if (valid) {
this.getMenuObj(data, "", menuObj); axios.get(`/apaas/system/v5/user/verifyCaptcha?id=${state.imgId}&value=${state.loginForm.yzm}`).then((res) => {
this.$store.commit("setMenuObj", menuObj); if (res.data.code == 200) {
// } login();
generateRoutes(); } else {
// this.$router.push("/"); ElMessage.error(res.data.data);
//跳转到工作台页面
window.location.href = "/apaas/portal/ui/#/";
} }
}); });
}, }
getMenuObj(menu, parentRowPath, menuObj) { });
menu.forEach((e, idx) => { };
e.rowPath = parentRowPath + "." + idx; const login = () => {
menuObj[e.path] = e; axios
if (e.children && e.children.length) { .post(`/apaas/system/v5/user/login`, {
this.getMenuObj(e.children, e.rowPath, menuObj); system_account: state.loginForm.userid,
} password: Encrypt(state.loginForm.password),
}); })
}, .then(({ data }) => {
getImg(clearInput = false) { if (data.code == 200) {
this.$axios getUser();
.get(`/apaas/system/v5/user/getCaptcha??width=240&height=32`) } else {
.then((res) => { getImg(true);
if (res.data.code == 200) { ElMessage.error(data.data);
this.imgId = res.data.data.id;
this.imgSrc = res.data.data.captcha;
}
});
if (clearInput) {
this.loginForm.yzm = "";
} }
}, })
}, .catch((error) => {
created() { console.log(error);
this.getImg(); });
if (getCookie("userinfo")) { };
let userinfo = window.atob(decodeURI(getCookie("userinfo"))).split(","); const getUserInfo = () => {
return axios.get(`/apaas/system/v5/user/getUserInfo`);
};
const getMenu = (search) => {
return axios.get(`/apaas/system/v5/menu/user/tree?search=${search}`);
};
const getUser = () => {
Promise.all([getUserInfo(), getMenu("dadb2d3f-e263-48d1-9389-42acb9ea49f8")]).then((res) => {
if (res[0].data.code == 200 && res[1].data.code == 200) {
let data = (res[1].data.data && res[1].data.data[0].children) || [];
store.commit("setUserInfo", res[0].data.data);
// if (res.data.data.userType == 1) {
//超管
store.commit("setMenu", data);
menu.menuToRouter(data);
this.loginForm.userid = userinfo[0]; store.commit("setRoute", data);
this.loginForm.password = userinfo[1];
this.checked = true;
this.rememberPassword = true; //存储菜单对象信息
} else { let menuObj = {};
this.checked = false; getMenuObj(data, "", menuObj);
store.commit("setMenuObj", menuObj);
// }
generateRoutes();
// this.$router.push("/");
//跳转到工作台页面
window.location.href = "/apaas/portal/ui/#/";
} }
}, });
};
const getMenuObj = (menu, parentRowPath, menuObj) => {
menu.forEach((e, idx) => {
e.rowPath = parentRowPath + "." + idx;
menuObj[e.path] = e;
if (e.children && e.children.length) {
getMenuObj(e.children, e.rowPath, menuObj);
}
});
};
const getImg = (clearInput = false) => {
axios.get(`/apaas/system/v5/user/getCaptcha??width=138&height=36`).then((res) => {
if (res.data.code == 200) {
state.imgId = res.data.data.id;
state.imgSrc = res.data.data.captcha;
}
});
if (clearInput) {
state.loginForm.yzm = "";
}
}; };
onBeforeMount(() => {
getImg();
if (getCookie("userinfo")) {
let userinfo = window.atob(decodeURI(getCookie("userinfo"))).split(",");
state.loginForm.userid = userinfo[0];
state.loginForm.password = userinfo[1];
state.checked = true;
state.rememberPassword = true;
} else {
state.checked = false;
}
});
const { loginForm, steploginFormRules, imgId, imgSrc, identifyCode, hidePassword, rememberPassword } = toRefs(state);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.msg-code { .login-by-account {
display: flex; .msg-code {
justify-content: space-between; display: flex;
align-items: center; justify-content: space-between;
align-items: center;
.yzm_img {
margin: 4px 0 0 16px;
flex: 1;
}
> .bg-identify { > .bg-identify {
margin-left: 6px; margin-left: 6px;
flex-shrink: 0; flex-shrink: 0;
}
}
:deep() .el-input__wrapper {
background-color: #f7f8f9;
}
.regist_bottom {
line-height: 1;
display: flex;
align-items: center;
justify-content: space-between;
:deep(.el-checkbox) {
height: auto;
}
} }
} }
</style> </style>
<template> <template>
<div class="login-by-code"> <div class="login-by-code">
<el-form ref="loginForm" :model="loginForm" :rules="loginFormRules"> <el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules">
<el-form-item prop="mobile"> <el-form-item prop="mobile">
<template name="label"> <el-input
<div class="form-title"> v-model="loginForm.mobile"
<span> autofocus="autofocus"
手机号码 placeholder="请输入手机号码"
</span> @keyup.enter.native="loginAction()" />
</el-form-item>
<el-tooltip class="item" effect="dark" placement="top"> <el-form-item prop="code">
<template slot="content"> <div class="msg-code">
个人用户及企业(主账号)<br />可通过短信验证码登录
</template>
<img src="@/assets/imgs/ic_tips.png" />
</el-tooltip>
</div>
</template>
<el-input
v-model="loginForm.mobile"
autofocus="autofocus"
placeholder="请输入手机号码"
@keyup.enter.native="loginAction()"
/>
</el-form-item>
<el-form-item label="验证码" prop="code">
<el-input <el-input
v-model="loginForm.code" v-model="loginForm.code"
placeholder="请输入验证码" placeholder="请输入验证码"
@keyup.enter.native="loginAction()" @keyup.enter.native="loginAction()"
> style="width: 280px">
<template slot="append">
<a class="input-append disabled" v-if="countDown > 0">
{{ countDown }}秒后再次获取
</a>
<a class="input-append" @click="getMsgCode" v-else>
获取验证码
</a>
</template>
</el-input> </el-input>
</el-form-item> <div class="yzm_img">
<el-form-item style="margin-top: 54px;"> <el-button
<el-button type="primary" @click.prevent="loginAction()"> type="primary"
登 录 :disabled="countDown > 0"
</el-button> @click.prevent="getMsgCode()"
</el-form-item> style="width: 100%; height: 34px">
<el-form-item style="margin-top: 24px;"> {{ countDown > 0 ? countDown + "秒后再次获取" : "发送验证码" }}
<el-button @click.prevent="$emit('register')"> </el-button>
还没有账户?立即注册&emsp;<i class="el-icon-arrow-right"></i> <!-- <a class="input-append disabled" v-if="false && countDown > 0">
</el-button> {{ countDown }}秒后再次获取
</el-form-item> </a>
</el-form> <a class="input-append" @click="getMsgCode" v-else>
</div> 获取验证码
</template> </a> -->
</div>
<script> </div>
export default { </el-form-item>
name: "LoginByCode", // 短信验证码登录 <el-form-item>
data() { <el-button type="primary" @click.prevent="loginAction()" style="width: 100%"> 登 录 </el-button>
const validatePhone = (rule, value, callback) => { </el-form-item>
const reg = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/; <el-form-item>
<el-button class="register_btn" @click.prevent="$emit('register')" style="width: 100%">
setTimeout(() => { 还没有账号?前往注册
if (!reg.test(value)) { <bg-icon icon="#bg-ic-arrow-right"></bg-icon>
callback(new Error("请输入正确的手机号码")); </el-button>
} else { </el-form-item>
callback(); <div>
} <span class="fr forget_psd" @click.prevent="$emit('password')">忘记密码?</span>
}); </div>
}; </el-form>
</div>
return { </template>
loginForm: {
mobile: "", <script setup>
code: "", import { reactive, toRefs, ref, onBeforeMount, nextTick } from "vue";
}, import { ElMessage } from "element-plus";
loginFormRules: { import axios from "@/request/http.js";
mobile: [
{ required: true, message: "请输入手机号码", trigger: "change" }, const validatePhone = (rule, value, callback) => {
{ validator: validatePhone, trigger: "blur" }, const reg = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/;
],
code: [{ required: true, message: "请输入验证码", trigger: "blur" }], setTimeout(() => {
}, if (!reg.test(value)) {
countDown: 0, callback(new Error("请输入正确的手机号码"));
countDownTimer: null, } else {
}; callback();
}, }
methods: { });
getMsgCode() { };
this.$refs.loginForm.validateField("mobile", (errMsg) => {
if (!errMsg) { const state = reactive({
this.$api.general.getCode(this.loginForm.mobile).then(({ data }) => { loginForm: {
if (data.success == 1) { mobile: "",
this.countDownAction(); code: "",
} },
}); loginFormRules: {
} mobile: [
}); { required: true, message: "请输入手机号码", trigger: "blur" },
}, // 获取验证码 { validator: validatePhone, trigger: "blur" },
countDownAction() { ],
this.countDown = 60; code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
},
if (this.countDownTimer) { countDown: 0,
clearInterval(this.countDownTimer); countDownTimer: null,
});
const loginFormRef = ref(null);
const getMsgCode = () => {
loginFormRef.value.validateField("mobile", (valid) => {
if (valid) {
axios.post("/apaas/system/v5/sms/verifyCode", { phone: state.loginForm.mobile }).then(({ data }) => {
if (data.code == 200) {
countDownAction();
} else {
ElMessage.error(data.data);
} }
});
this.countDownTimer = setInterval(() => { }
if (this.countDown > 0) { });
this.countDown--; }; // 获取验证码
const countDownAction = () => {
state.countDown = 60;
if (state.countDownTimer) {
clearInterval(state.countDownTimer);
}
state.countDownTimer = setInterval(() => {
if (state.countDown > 0) {
state.countDown--;
} else {
clearInterval(state.countDownTimer);
}
}, 1000);
};
const loginAction = () => {
loginFormRef.value.validate((valid) => {
if (valid) {
axios
.post(`/apaas/system/v5/user/phone/login`, {
phone: state.loginForm.mobile,
code: state.loginForm.code,
})
.then(({ data }) => {
if (data.code == 200) {
getUser();
} else { } else {
clearInterval(this.countDownTimer); ElMessage.error(data.data);
}
}, 1000);
},
loginAction() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.$api.general
.loginByCode(this.loginForm)
.then(({ data }) => {
if (data.success == 1) {
let redirect = "/apaas/ui/#/index";
// GIS重定向使用
if (this.$route.query.ReturnUrl) {
redirect = this.$route.query.ReturnUrl;
}
// 前端重定向使用
else if (this.$route.query.redirect) {
redirect = `/apaas/ui/#${this.$route.query.redirect}`;
}
window.location.href = redirect;
} else {
this.$message({
message: data.errMsg || data.data || "登陆失败",
type: "error",
});
}
})
.catch((error) => {
console.log(error);
});
} }
})
.catch((error) => {
console.log(error);
}); });
}, // 短信验证码登录 }
}, });
}; }; // 短信验证码登录
</script>
const getUserInfo = () => {
<style lang="less" scoped> return axios.get(`/apaas/system/v5/user/getUserInfo`);
.login-by-code { };
.el-form { const getMenu = (search) => {
.form-title { return axios.get(`/apaas/system/v5/menu/user/tree?search=${search}`);
display: flex; };
justify-content: flex-start; const getUser = () => {
align-items: center; Promise.all([getUserInfo(), getMenu("dadb2d3f-e263-48d1-9389-42acb9ea49f8")]).then((res) => {
line-height: 20px; if (res[0].data.code == 200 && res[1].data.code == 200) {
margin-bottom: 5px; let data = (res[1].data.data && res[1].data.data[0].children) || [];
store.commit("setUserInfo", res[0].data.data);
> img { // if (res.data.data.userType == 1) {
margin-left: 5px; //超管
} store.commit("setMenu", data);
menu.menuToRouter(data);
store.commit("setRoute", data);
//存储菜单对象信息
let menuObj = {};
getMenuObj(data, "", menuObj);
store.commit("setMenuObj", menuObj);
// }
generateRoutes();
// this.$router.push("/");
//跳转到工作台页面
window.location.href = "/apaas/portal/ui/#/";
}
});
};
const { loginForm, loginFormRules, countDown, countDownTimer } = toRefs(state);
</script>
<style lang="scss" scoped>
.login-by-code {
.msg-code {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.yzm_img {
flex: 1;
margin-left: 20px;
}
}
.el-form {
.form-title {
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 20px;
margin-bottom: 5px;
> img {
margin-left: 5px;
} }
} }
} }
</style> }
</style>
\ No newline at end of file
import {createI18n} from 'vue-i18n' import {createI18n} from 'vue-i18n/index'
import lang from './index' import lang from './index'
const i18n = createI18n({ const i18n = createI18n({
......
import { createApp } from 'vue' import { createApp } from "vue";
import ElementPlus from 'element-plus' import ElementPlus from "element-plus";
import 'element-plus/dist/index.css' import "element-plus/dist/index.css";
import locale from 'element-plus/lib/locale/lang/zh-cn' import locale from "element-plus/lib/locale/lang/zh-cn";
import * as ElementPlusIconsVue from '@element-plus/icons-vue' import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import bgui from "@/bg-ui"; import bgui from "@/bg-ui";
import "@/bg-ui/index.scss"; import "@/bg-ui/index.scss";
import msgSdk from './msg-sdk/index.js'; import msgSdk from "./msg-sdk/index.js";
import App from './App.vue' import App from "./App.vue";
import router from './router' import router from "./router";
import {generateRoutes} from './router/index.js' import { generateRoutes } from "./router/index.js";
import "../src/assets/css/font.css";
import "../src/assets/css/index.css";
import "../src/assets/item.css";
import '../src/assets/css/font.css' import store from "@/store";
import '../src/assets/css/index.css'
import '../src/assets/item.css'
import store from '@/store'; import i18n from "./i18n/i18n.js";
import i18n from './i18n/i18n.js' import axios from "./request/http.js";
import axios from './request/http.js' const createVue = createApp(App);
// createVue.use(ElementPlus, { locale });
const createVue = createApp(App)
createVue.use(ElementPlus, { locale });
function getMsgAppid() { function getMsgAppid() {
axios.get(`/apaas/system/v5/message/account`).then(res => { axios.get(`/apaas/system/v5/message/account`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
createVue.use(msgSdk, { createVue.use(msgSdk, {
requestUrl: 'https://msg.wodcloud.com', // 请求地址 requestUrl: "https://msg.wodcloud.com", // 请求地址
appID: decodeURIComponent(escape(window.atob(res.data.data.app_id))), // 应用id appID: decodeURIComponent(escape(window.atob(res.data.data.app_id))), // 应用id
secretKey: decodeURIComponent(escape(window.atob(res.data.data.secret_key))), // 应用密钥 secretKey: decodeURIComponent(escape(window.atob(res.data.data.secret_key))), // 应用密钥
userId: '', userId: "",
userType: '', userType: "",
roleId: '', roleId: "",
organization: '', organization: "",
}) });
} }
}) });
} }
// getMsgAppid() // getMsgAppid()
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
createVue.component(key, component) createVue.component(key, component);
} }
createVue.config.globalProperties.$axios = axios createVue.config.globalProperties.$axios = axios;
import menu from './router/function.js' import menu from "./router/function.js";
//获取用户信息 //获取用户信息
function getUser() { function getUser() {
return axios.get(`/apaas/system/v5/user/getUserInfo`) return axios.get(`/apaas/system/v5/user/getUserInfo`);
} }
//获取用户菜单信息 //获取用户菜单信息
function getMenu(search) { function getMenu(search) {
return axios.get(`/apaas/system/v5/menu/user/tree?search=${search}`) return axios.get(`/apaas/system/v5/menu/user/tree?search=${search}`);
} }
//处理菜单成为对象 //处理菜单成为对象
function getMenuObj(menu,parentRowPath,menuObj){ function getMenuObj(menu, parentRowPath, menuObj) {
menu.forEach((e,idx) => { menu.forEach((e, idx) => {
e.rowPath = parentRowPath + '.' + idx e.rowPath = parentRowPath + "." + idx;
menuObj[e.path] = e menuObj[e.path] = e;
if(e.children&&e.children.length){ if (e.children && e.children.length) {
getMenuObj(e.children,e.rowPath,menuObj) getMenuObj(e.children, e.rowPath, menuObj);
} }
}); });
} }
store.commit("setWhiteList", ["/", "/login", "/register", "/password"]);
Promise.all([getUser(), getMenu("dadb2d3f-e263-48d1-9389-42acb9ea49f8")])
Promise.all([getUser(),getMenu('dadb2d3f-e263-48d1-9389-42acb9ea49f8')]).then(res => { .then((res) => {
if (res[0].data.code == 200&&res[1].data.code == 200) { if (res[0].data.code == 200 && res[1].data.code == 200) {
//已登录则记录菜单和用户信息 //已登录则记录菜单和用户信息
let data = res[1].data.data&&res[1].data.data[0].children||[] let data = (res[1].data.data && res[1].data.data[0].children) || [];
store.commit('setUserInfo', res[0].data.data) store.commit("setUserInfo", res[0].data.data);
// if (res[0].data.data.userType == 1) {//超管 // if (res[0].data.data.userType == 1) {//超管
store.commit('setMenu', data) store.commit("setMenu", data);
menu.menuToRouter(data) menu.menuToRouter(data);
store.commit('setRoute',data) store.commit("setRoute", data);
//存储菜单对象信息 //存储菜单对象信息
let menuObj = {} let menuObj = {};
getMenuObj(data,'',menuObj) getMenuObj(data, "", menuObj);
store.commit('setMenuObj',menuObj) store.commit("setMenuObj", menuObj);
// } // }
} }
generateRoutes() generateRoutes();
})
createVue.use(ElementPlus).use(store).use(router).use(i18n).use(bgui) .catch((e) => {
createVue.mount('#app') console.error(e);
}).catch(() => {
createVue.use(ElementPlus).use(store).use(router).use(i18n).use(bgui)
createVue.mount('#app')
}) })
.finally(() => {
createVue.use(ElementPlus, { locale }).use(store).use(router).use(i18n).use(bgui);
createVue.mount("#app");
});
//后期加入权限处理,参考msg/ui //后期加入权限处理,参考msg/ui
<template> <template>
<div class="login-container"> <div
<div class="bg-main"> class="login-container"
<div class="bg-logo"> :style="{
'background-image': `url(${
configOptions.backgroundUrl
? JSON.parse(configOptions.backgroundUrl)[0].url
: getImageUrl('bg.png')
})`,
}">
<el-alert
class="bg-warning"
title="系统有效期剩余345 天,请管理员及时更换license!"
type="warning" />
<div class="bg-main">
<!-- <div class="bg-logo">
<img class="logo" src="../../assets/imgs/login_img_logo.png" /> <img class="logo" src="../../assets/imgs/login_img_logo.png" />
<!-- <span>BD-aPaaS</span> --> </div> -->
</div>
<div class="bg-content">
<div class="bg-content"> <bg-tabs
<bg-tabs class="login-tab"
class="login-tab" v-model="loginTab"
v-model="loginTab" style="width: 480px"
style="min-height: 450px;" v-if="pageType === 'login'">
v-if="pageType === 'login'" <bg-tab label="账号密码登录" name="account">
> <LoginByAccount @register="switchPageType('account')" @password="password" />
<bg-tab label="账号密码登录" name="account"> </bg-tab>
<LoginByAccount @register="switchPageType('register')" /> <bg-tab label="验证码登录" name="register">
</bg-tab> <LoginByCode @register="switchPageType('register')" @password="password" />
</bg-tabs> </bg-tab>
</div> </bg-tabs>
</div> </div>
</div>
<p class="bg-msg" v-if="pageType !== 'register'"> <!-- v-if="pageType !== 'register'" -->
登录即代表您已同意 <span>《BD-aPaaS平台用户协议与隐私政策》</span> <div class="bg-msg">
<p v-if="configOptions && configOptions.patent">{{ configOptions.patent }}</p>
<p v-if="configOptions">
<span class="can_click_text" @click="open(configOptions.icpUrl)">
{{ configOptions.icpFiling }} |
</span>
<span class="can_click_text" @click="open(configOptions.publicSecurityUrl)">
{{ configOptions.publicSecurityFiling }}
</span>
</p>
<p>
<span class="can_click_text" @click="open(configOptions.legalStatementUrl)">法律声明</span>
|
<span class="can_click_text" @click="open(configOptions.privacyPolicyUrl)">隐私政策</span>
</p> </p>
</div> </div>
</template>
<el-dialog class="dialog_box" title="提示" v-model="dialogPasswordChange" width="400px">
<script> <div>密码已过期,请修改密码后再次登录</div>
import LoginByAccount from "@/components/login-by-account.vue"; <template v-slot:footer>
// import LoginByCode from "@/components/login-by-code.vue"; <div class="apaas_button">
// import RegisterPersonalUser from "@/components/register-personal-user.vue"; <el-button type="primary" @click="password">立即修改</el-button>
// import RegisterFrimUser from "@/components/register-firm-user.vue"; </div>
// import RegisterOrgUser from "@/components/register-org-user.vue"; </template>
// import RegisterSuccess from "@/components/register-success.vue"; </el-dialog>
</div>
export default { </template>
name: "Index",
components: { <script setup>
LoginByAccount, import LoginByAccount from "@/components/login-by-account.vue";
// LoginByCode, import LoginByCode from "@/components/login-by-code.vue";
// RegisterPersonalUser, import axios from "axios";
// RegisterFrimUser, import { ElMessage } from "element-plus";
// RegisterOrgUser, import { ref, onBeforeMount, onMounted } from "vue";
// RegisterSuccess, import { useRouter } from "vue-router";
}, import store from "../../store";
data() { import { getImageUrl } from "@/services/helper.js";
return { const router = useRouter();
pageType: "login", // login(登录) / register(注册) / success(认证)
loginTab: "account", // account(账号密码登录) / or register(短信验证码登录) const pageType = ref("login");
registerTab: "personal", // personal(个人用户) / firm(企业用户) / org(政府机构用户) const loginTab = ref("account");
};
}, const configOptions = ref({});
methods: { const dialogPasswordChange = ref(false);
switchPageType(type) {
this.pageType = type; const switchPageType = (type) => {
}, // pageType.value = type
}, router.push("/register");
}; };
</script> const password = () => {
router.push("/password");
<style lang="scss" scoped> };
.login-container { const getLoginPageConfig = () => {
width: 100vw; axios.get(`/apaas/system/v5/login/loginDetail`).then((res) => {
height: calc(100vh - 56px); if (res.data.code == 200) {
background-image: url("@/assets/imgs/login_ysgz.jpg"); configOptions.value = res.data.data || null;
background-size: cover; store.commit("setSystemLogo", configOptions.value.logoUrl);
background-position: center center; } else {
position: relative; ElMessage.error(res.data.data);
}
.bg-main { });
position: absolute; };
top: 50%;
right: 0; const open = (url) => {
margin-right: 16vw; if (url !== "") {
margin-bottom: 80px; window.open(url);
transform: translateY(calc(-50%)); } else {
width: 500px; return;
max-height: calc(100vh - 100px); }
overflow: hidden auto; };
onBeforeMount(() => {
&::-webkit-scrollbar { getLoginPageConfig();
width: 16px; });
height: 1px; </script>
}
<style lang="scss" scoped>
/* &::-webkit-scrollbar-track { .login-container {
width: 100vw;
height: calc(100vh - 56px);
background-image: url("@/assets/imgs/bg.png");
background-size: 100% 100%;
background-position: center center;
background-size: cover;
position: relative;
.bg-main {
position: absolute;
top: calc(50vh - 250px);
right: calc(28vw - 240px);
width: 500px;
max-height: calc(100vh - 100px);
overflow: hidden auto;
&::-webkit-scrollbar {
width: 16px;
height: 1px;
}
/* &::-webkit-scrollbar-track {
border-radius: 8px; border-radius: 8px;
box-shadow: 8px 0 0 #f4f4f4 inset; box-shadow: 8px 0 0 #f4f4f4 inset;
border: 4px solid rgba(0, 0, 0, 0); border: 4px solid rgba(0, 0, 0, 0);
} */ } */
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
border-radius: 8px; border-radius: 8px;
box-shadow: 8px 0 0 #a5adb7 inset; box-shadow: 8px 0 0 #a5adb7 inset;
border: 4px solid rgba(0, 0, 0, 0); border: 4px solid rgba(0, 0, 0, 0);
}
> .bg-logo {
display: flex;
justify-content: center;
align-items: center;
.logo {
width: 450px;
} }
> .bg-logo { > span {
display: flex; font-size: 36px;
justify-content: center; color: #ffffff;
align-items: center; margin-left: 25px;
.logo{
width: 450px;
}
> span {
font-size: 36px;
color: #ffffff;
margin-left: 25px;
}
} }
}
> .bg-content {
.bg-content {
:deep(.bg-tabs-content) {
padding: 32px 0;
} }
} }
:deep(.el-form) {
> .bg-msg { .el-form-item {
position: absolute; .el-input,
bottom: 70px; .el-button {
left: 0; height: 40px;
width: 100%; }
font-size: 14px;
line-height: 20px;
color: #bcc1d0;
text-align: center;
> span {
color: #fff;
cursor: pointer;
} }
} }
} }
</style> > .bg-warning {
text-align: center;
\ No newline at end of file background-color: #fdf4e2;
color: #e56600;
font-size: 14px;
height: 32px;
line-height: 32px;
display: flex;
justify-content: center;
}
> .bg-msg {
position: absolute;
bottom: 10px;
left: 0;
width: 100%;
font-size: 14px;
line-height: 20px;
color: #616f94;
text-align: center;
> p {
padding: 8px 0;
}
}
}
</style>
<!-- 角色管理 -->
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="form_content apaas_scroll_nor">
<el-form
ref="refForm"
label-position="left"
:model="formData"
:rules="rules"
label-width="82px">
<div class="top_content">
<el-form-item label="规则名称" prop="ruleName">
<el-input placeholder="请输入" maxlength="100" v-model="formData.ruleName"></el-input>
</el-form-item>
<el-form-item label="规则类型" prop="ruleType">
<el-select placeholder="请选择" style="width: 100%" v-model="formData.ruleType">
<el-option label="IP" :value="1"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="规则" prop="ruleDetail">
<el-input
placeholder="请输入"
rows="5"
maxlength="300"
show-word-limit
type="textarea"
v-model="formData.ruleDetail" />
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>输入IP段,不可重复,例如:192.168.0.0/24</span><br />
<span
>输入IP地址,例如192.168.0.1(支持ipv4地址,配置多个IP时使用回车符分隔)</span
>
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
<el-form-item class="switch-item" label="是否启用" prop="state" required>
<bg-switch
:labels="['否', '是']"
:values="[0, 1]"
v-model="formData.state"></bg-switch>
</el-form-item>
</div>
<el-form-item class="userScope" label="用户范围" prop="userScope">
<el-button type="primary" @click="userMaintain"> 用户维护 </el-button>
<div class="table_content clearfix">
<bg-table
ref="bgTable"
:headers="detailHeaders"
:rows="tableRows"
height="550"
:stripe="true">
<template v-slot:isAdmin="{ row }">
<span>{{ userTypeConfig[row.isAdmin] }}</span>
</template>
</bg-table>
<bg-pagination
:page="pageConfig.page"
:size="pageConfig.limit"
:total="pageConfig.total"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</el-form-item>
</el-form>
<el-dialog
class="dialog_box_maintain"
title="用户维护"
v-model="dialogMaintain"
width="1062px">
<div class="content_detail">
<div class="form_filter">
<div class="left">
<span class="sleceted_tip"
>已选择<span class="num">{{ selectedNum }}</span
></span
>
<span class="clean" @click="cleanSelected">清空</span>
</div>
<div class="right">
<el-select
placeholder="全部类型"
v-model="dialogFilterData.isAdmin"
style="width: 200px; margin-left: 16px">
<el-option
v-for="option in userTypeList"
:key="option.value"
:label="option.label"
:value="option.value">
</el-option>
</el-select>
<el-tree-select
style="width: 200px; margin-left: 16px"
placeholder="请选择所属组织"
v-model="dialogFilterData.organizationId"
:data="orgData"
:props="treeProps"
:render-after-expand="false"></el-tree-select>
<el-input
placeholder="请输入关键词"
v-model="dialogFilterData.search"
style="width: 200px; margin: 0 16px 0"
:prefix-icon="Search" />
<el-button type="primary" @click="dialogChangePage(1)">查询</el-button>
<el-button type="default" @click="resetFilter">重置</el-button>
</div>
</div>
<div class="table_content clearfix">
<bg-table
ref="dialogBgTable"
height="430"
select
rowKey="systemId"
:headers="detailHeaders"
:rows="dialogTableRows"
:stripe="true"
@selectAc="selectChange">
<template v-slot:isAdmin="{ row }">
<span>{{ userTypeConfig[row.isAdmin] }}</span>
</template>
</bg-table>
<bg-pagination
:page="dialogPageConfig.page"
:size="dialogPageConfig.limit"
:total="dialogPageConfig.total"
@change-page="dialogChangePage"
@change-size="dialogChangeSize">
</bg-pagination>
</div>
<div class="operate_btns" style="border-top: none">
<el-button @click="dialogMaintain = false"> 取消 </el-button>
<el-button type="primary" @click="save"> 保存 </el-button>
</div>
</div>
</el-dialog>
</div>
<div class="operate_btns">
<el-button type="primary" @click="submit"> 保存 </el-button>
</div>
</div>
</div>
</template>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { reactive, toRefs, computed, ref, onBeforeMount, nextTick } from "vue";
import { useRouter } from "vue-router";
import { useStore } from "vuex";
import axios from "../../../../../request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const router = useRouter();
const { getters } = useStore();
const userTypeConfig = computed(() => getters.getUserTypeConfig || {});
const userTypeList = computed(() =>
Object.keys(userTypeConfig.value).map((key) => ({
label: userTypeConfig.value[key],
value: +key,
}))
);
const dialogBgTable = ref(null);
const state = reactive({
//表单数据
formData: {
ruleName: "",
ruleType: "",
ruleDetail: "",
state: 0,
userScope: [],
},
//表单校验规则
rules: {
ruleName: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
ruleType: [
{
required: true,
message: "请选择",
trigger: "blur",
},
],
ruleDetail: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
userScope: [
{
required: true,
message: "请选择",
blur: "change",
},
],
},
dialogFilterData: {
isAdmin: "",
organizationId: "",
search: "",
},
pageConfig: {
page: 1,
limit: 10,
total: 0,
},
//弹框中表格分页配置项
dialogPageConfig: {
page: 1,
limit: 10,
total: 0,
},
//表格数据
tableRows: [],
//被选中的所有数据
selectedRows: {},
//弹框中表格数据
dialogTableRows: [],
//已选择数据条数
selectedNum: 0,
detailHeaders: [
{
label: "账号",
prop: "systemAccount",
// minWidth: 280,
},
{
label: "类型",
prop: "isAdmin",
// minWidth: 360,
},
{
label: "用户手机号",
prop: "phone",
// width: 200,
},
{
label: "所属组织",
prop: "name",
// width: 120,
},
],
orgData: [],
treeProps: {
label: "name",
children: "Child",
value: "organization_id",
},
//用户维护弹框
dialogMaintain: false,
});
const {
formData,
rules,
dialogFilterData,
pageConfig,
dialogPageConfig,
tableRows,
dialogTableRows,
selectedNum,
detailHeaders,
orgData,
treeProps,
dialogMaintain,
} = toRefs(state);
onBeforeMount(() => {
getOrgTree();
getTableList();
});
//用户维护
const userMaintain = () => {
state.dialogMaintain = true;
};
//获取所属组织级联数据
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
state.orgData = orgDataTemp;
} else {
ElMessage.error(res.data.data);
}
});
};
const changePage = (page) => {
state.pageConfig.page = page;
state.tableRows = state.selectedRows.slice(
(page - 1) * state.pageConfig.limit,
page * state.pageConfig.limit
);
};
const changeSize = (size) => {
state.pageConfig.limit = size;
changePage(1);
};
const dialogChangePage = (page) => {
state.dialogPageConfig.page = page;
getTableList();
};
const dialogChangeSize = (size) => {
state.dialogPageConfig.limit = size;
dialogChangePage(1);
};
//获取用户维护数据
const getTableList = () => {
const params = {
limit: state.dialogPageConfig.limit,
page: state.dialogPageConfig.page,
disp: 1,
...state.dialogFilterData,
};
axios.get("/apaas/system/v5/accessRule/listRuleUser", { params }).then((res) => {
if (res.data.code == 200) {
state.dialogTableRows = res.data.data || [];
state.dialogPageConfig.total = res.data.total || 0;
} else {
ElMessage.error(res.data.data);
}
});
};
//重置查询参数
const resetFilter = () => {
Object.keys(state.dialogFilterData).forEach((key) => {
state.dialogFilterData[key] = "";
});
dialogChangePage(1);
};
//用户维护弹框中清空
const cleanSelected = () => {
dialogBgTable.value.clearTable();
};
//用户维护选择项发生变化
const selectChange = (params) => {
state.selectedNum = params.allLength;
};
//保存
const save = () => {
state.dialogMaintain = false;
const res = dialogBgTable.value.dealSelectData();
state.selectedRows = Object.values(res);
state.formData.userScope = state.selectedRows.map((item) => ({
systemId: item.systemId,
}));
state.pageConfig.total = state.formData.userScope.length;
changePage(1);
};
//提交
const submit = () => {
axios.post("/apaas/system/v5/accessRule/addAccessRule", state.formData).then((res) => {
if (res.data.code == 200) {
ElMessage.success("添加成功");
router.push("/config/accessRule");
} else {
ElMessage.error(res.data.data);
}
});
};
</script>
<style lang="scss" scoped>
.page_container {
.main_container {
position: relative;
margin: 0 0 16px;
width: 100%;
height: calc(100% - 62px);
padding: 40px 0 70px;
overflow: auto;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
.form_content {
overflow: auto;
height: 100%;
padding-left: 40px;
.el-form {
::v-deep .el-form-item {
display: block;
margin-bottom: 24px;
width: 60%;
.el-form-item__label {
display: block;
margin-bottom: 6px;
height: 14px;
line-height: 14px;
}
&.switch-item {
display: flex;
align-items: center;
.el-form-item__label {
display: inline-flex;
margin-bottom: 0px;
}
.el-switch {
height: 24px;
}
}
&.userScope {
width: 100%;
margin-bottom: 16px;
.el-button {
width: 92px;
}
.el-form-item__label {
margin-bottom: 16px;
}
.el-form-item__content {
display: block;
}
.table_content {
padding-right: 40px;
margin-top: 16px;
}
}
}
}
}
::v-deep .dialog_box_maintain {
.el-dialog__body {
padding: 0 0 70px 0;
height: 630px;
}
.form_filter {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
height: 69px;
border-bottom: 1px solid #e6e9ef;
.left {
font-size: 0px;
.sleceted_tip {
margin: 0 24px 0;
vertical-align: middle;
font-size: 14px;
color: #404a62;
.num {
margin: 0 3px 0 3px;
font-weight: 600;
color: #202531;
}
}
.clean {
vertical-align: middle;
font-size: 14px;
color: #3759be;
cursor: pointer;
}
}
.right {
margin-right: 16px;
.el-button {
width: 64px;
&:last-child {
margin-left: 16px;
}
}
}
}
.table_content {
padding: 0 16px;
}
.operate_btns {
.el-button {
width: 64px;
&:first-child {
margin-right: 4px;
}
}
}
}
.operate_btns {
position: absolute;
bottom: 0;
width: 100%;
height: 70px;
text-align: right;
line-height: 68px;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
margin-right: 16px;
}
}
}
}
</style>
<!-- 角色管理 -->
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="form_content apaas_scroll_nor">
<el-form
ref="refForm"
label-position="left"
:model="formData"
:rules="rules"
label-width="82px">
<div class="top_content">
<el-form-item label="规则名称" prop="ruleName">
<el-input placeholder="请输入" maxlength="100" v-model="formData.ruleName"></el-input>
</el-form-item>
<el-form-item label="规则类型" prop="ruleType">
<el-select placeholder="请选择" style="width: 100%" v-model="formData.ruleType">
<el-option label="IP" :value="1"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="规则" prop="ruleDetail">
<el-input
placeholder="请输入"
rows="5"
maxlength="300"
show-word-limit
type="textarea"
v-model="formData.ruleDetail" />
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>输入IP段,不可重复,例如:192.168.0.0/24</span><br />
<span
>输入IP地址,例如192.168.0.1(支持ipv4地址,配置多个IP时使用回车符分隔)</span
>
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
<el-form-item class="switch-item" label="是否启用" prop="state" required>
<bg-switch
:labels="['否', '是']"
:values="[0, 1]"
v-model="formData.state"></bg-switch>
</el-form-item>
</div>
<el-form-item class="userScope" label="用户范围" prop="userScope">
<el-button type="primary" @click="userMaintain"> 用户维护 </el-button>
<div class="table_content clearfix">
<bg-table
ref="bgTable"
:headers="detailHeaders"
:rows="tableRows"
height="550"
:stripe="true">
<template v-slot:isAdmin="{ row }">
<span>{{ userTypeConfig[row.isAdmin] }}</span>
</template>
</bg-table>
<bg-pagination
:page="pageConfig.page"
:size="pageConfig.limit"
:total="pageConfig.total"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</el-form-item>
</el-form>
<el-dialog
class="dialog_box_maintain"
title="用户维护"
v-model="dialogMaintain"
width="1062px">
<div class="content_detail">
<div class="form_filter">
<div class="left">
<span class="sleceted_tip"
>已选择<span class="num">{{ selectedNum }}</span
></span
>
<span class="clean" @click="cleanSelected">清空</span>
</div>
<div class="right">
<el-select
placeholder="全部类型"
v-model="dialogFilterData.isAdmin"
style="width: 200px; margin-left: 16px">
<el-option
v-for="option in userTypeList"
:key="option.value"
:label="option.label"
:value="option.value">
</el-option>
</el-select>
<el-tree-select
style="width: 200px; margin-left: 16px"
placeholder="请选择所属组织"
v-model="dialogFilterData.organizationId"
:data="orgData"
:props="treeProps"
:render-after-expand="false"></el-tree-select>
<el-input
placeholder="请输入关键词"
v-model="dialogFilterData.search"
style="width: 200px; margin: 0 16px 0"
:prefix-icon="Search" />
<el-button type="primary" @click="dialogChangePage(1)">查询</el-button>
<el-button type="default" @click="resetFilter">重置</el-button>
</div>
</div>
<div class="table_content clearfix">
<bg-table
ref="dialogBgTable"
height="430"
select
rowKey="systemId"
:headers="detailHeaders"
:rows="dialogTableRows"
:originSelectedData="selectedRows"
:stripe="true"
@selectAc="selectChange">
<template v-slot:isAdmin="{ row }">
<span>{{ userTypeConfig[row.isAdmin] }}</span>
</template>
</bg-table>
<bg-pagination
:page="dialogPageConfig.page"
:size="dialogPageConfig.limit"
:total="dialogPageConfig.total"
@change-page="dialogChangePage"
@change-size="dialogChangeSize">
</bg-pagination>
</div>
<div class="operate_btns" style="border-top: none">
<el-button @click="dialogMaintain = false"> 取消 </el-button>
<el-button type="primary" @click="save"> 保存 </el-button>
</div>
</div>
</el-dialog>
</div>
<div class="operate_btns">
<el-button type="primary" @click="submit"> 保存 </el-button>
</div>
</div>
</div>
</template>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { reactive, toRefs, computed, ref, onBeforeMount, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useStore } from "vuex";
import axios from "../../../../../request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const router = useRouter();
const { getters } = useStore();
const userTypeConfig = computed(() => getters.getUserTypeConfig || {});
const userTypeList = computed(() =>
Object.keys(userTypeConfig.value).map((key) => ({
label: userTypeConfig.value[key],
value: +key,
}))
);
const dialogBgTable = ref(null);
const state = reactive({
//表单数据
formData: {
ruleName: "",
ruleType: "",
ruleDetail: "",
state: 0,
userScope: [],
},
//表单校验规则
rules: {
ruleName: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
ruleType: [
{
required: true,
message: "请选择",
trigger: "blur",
},
],
ruleDetail: [
{
required: true,
message: "请输入",
trigger: "blur",
},
],
userScope: [
{
required: true,
message: "请选择",
blur: "change",
},
],
},
dialogFilterData: {
isAdmin: "",
organizationId: "",
search: "",
},
pageConfig: {
page: 1,
limit: 10,
total: 0,
},
//弹框中表格分页配置项
dialogPageConfig: {
page: 1,
limit: 10,
total: 0,
},
//表格数据
tableRows: [],
//被选中的所有数据
selectedRows: {},
//弹框中表格数据
dialogTableRows: [],
//已选择数据条数
selectedNum: 0,
detailHeaders: [
{
label: "账号",
prop: "systemAccount",
// minWidth: 280,
},
{
label: "类型",
prop: "isAdmin",
// minWidth: 360,
},
{
label: "用户手机号",
prop: "phone",
// width: 200,
},
{
label: "所属组织",
prop: "name",
// width: 120,
},
],
orgData: [],
treeProps: {
label: "name",
children: "Child",
value: "organization_id",
},
//用户维护弹框
dialogMaintain: false,
});
const {
formData,
rules,
dialogFilterData,
pageConfig,
dialogPageConfig,
tableRows,
selectedRows,
dialogTableRows,
selectedNum,
detailHeaders,
orgData,
treeProps,
dialogMaintain,
} = toRefs(state);
onBeforeMount(() => {
echoFormData();
getOrgTree();
getTableList();
});
//回显编辑数据
const echoFormData = () => {
const query = route.query;
getUserScopeList();
state.formData.ruleName = query.ruleName;
state.formData.state = +query.state;
state.formData.ruleType = +query.ruleType;
state.formData.ruleDetail = query.ruleDetail;
};
//用户维护
const userMaintain = () => {
state.dialogMaintain = true;
};
//获取所属组织级联数据
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
state.orgData = orgDataTemp;
} else {
ElMessage.error(res.data.data);
}
});
};
const changePage = (page) => {
state.pageConfig.page = page;
state.tableRows = state.selectedRows.slice(
(page - 1) * state.pageConfig.limit,
page * state.pageConfig.limit
);
};
const changeSize = (size) => {
state.pageConfig.limit = size;
changePage(1);
};
const dialogChangePage = (page) => {
state.dialogPageConfig.page = page;
getTableList();
};
const dialogChangeSize = (size) => {
state.dialogPageConfig.limit = size;
dialogChangePage(1);
};
//编辑时回显用户范围数据
const getUserScopeList = () => {
const params = {
limit: 10000,
page: 1,
id: route.query.id,
disp: 0,
};
axios.get("/apaas/system/v5/accessRule/listRuleUser", { params }).then((res) => {
if (res.data.code == 200) {
state.selectedRows = res.data.data || [];
state.pageConfig.total = state.selectedRows.length;
state.selectedNum = state.selectedRows.length;
changePage(1);
} else {
ElMessage.error(res.data.data);
}
});
};
//获取用户维护数据
const getTableList = () => {
const params = {
limit: state.dialogPageConfig.limit,
page: state.dialogPageConfig.page,
disp: 1,
...state.dialogFilterData,
};
axios.get("/apaas/system/v5/accessRule/listRuleUser", { params }).then((res) => {
if (res.data.code == 200) {
state.dialogTableRows = res.data.data || [];
state.dialogPageConfig.total = res.data.total || 0;
} else {
ElMessage.error(res.data.data);
}
});
};
//重置查询参数
const resetFilter = () => {
Object.keys(state.dialogFilterData).forEach((key) => {
state.dialogFilterData[key] = "";
});
dialogChangePage(1);
};
//用户维护弹框中清空
const cleanSelected = () => {
dialogBgTable.value.clearTable();
};
//用户维护选择项发生变化
const selectChange = (params) => {
state.selectedNum = params.allLength;
};
//保存
const save = () => {
state.dialogMaintain = false;
const res = dialogBgTable.value.dealSelectData();
state.selectedRows = Object.values(res);
state.formData.userScope = state.selectedRows.map((item) => ({
systemId: item.systemId,
}));
state.pageConfig.total = state.formData.userScope.length;
changePage(1);
};
//提交
const submit = () => {
const params = {
ruleId: route.query.ruleId,
...state.formData,
};
axios.put("/apaas/system/v5/accessRule/updateAccessRule", params).then((res) => {
if (res.data.code == 200) {
ElMessage.success("更新成功");
router.push("/config/accessRule");
} else {
ElMessage.error(res.data.data);
}
});
};
</script>
<style lang="scss" scoped>
.page_container {
.main_container {
position: relative;
margin: 0 0 16px;
width: 100%;
height: calc(100% - 62px);
padding: 40px 0 70px;
overflow: auto;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
.form_content {
overflow: auto;
height: 100%;
padding-left: 40px;
.el-form {
::v-deep .el-form-item {
display: block;
margin-bottom: 24px;
width: 60%;
.el-form-item__label {
display: block;
margin-bottom: 6px;
height: 14px;
line-height: 14px;
}
&.switch-item {
display: flex;
align-items: center;
.el-form-item__label {
display: inline-flex;
margin-bottom: 0px;
}
.el-switch {
height: 24px;
}
}
&.userScope {
width: 100%;
margin-bottom: 16px;
.el-button {
width: 92px;
}
.el-form-item__label {
margin-bottom: 16px;
}
.el-form-item__content {
display: block;
}
.table_content {
padding-right: 40px;
margin-top: 16px;
}
}
}
}
}
::v-deep .dialog_box_maintain {
.el-dialog__body {
padding: 0 0 70px 0;
height: 630px;
}
.form_filter {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
height: 69px;
border-bottom: 1px solid #e6e9ef;
.left {
font-size: 0px;
.sleceted_tip {
margin: 0 24px 0;
vertical-align: middle;
font-size: 14px;
color: #404a62;
.num {
margin: 0 3px 0 3px;
font-weight: 600;
color: #202531;
}
}
.clean {
vertical-align: middle;
font-size: 14px;
color: #3759be;
cursor: pointer;
}
}
.right {
margin-right: 16px;
.el-button {
width: 64px;
&:last-child {
margin-left: 16px;
}
}
}
}
.table_content {
padding: 0 16px;
}
.operate_btns {
.el-button {
width: 64px;
&:first-child {
margin-right: 4px;
}
}
}
}
.operate_btns {
position: absolute;
bottom: 0;
width: 100%;
height: 70px;
text-align: right;
line-height: 68px;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
margin-right: 16px;
}
}
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-filter-group
@search="changeSearch"
v-model="filter.search"
placeholder="请输入规则名称或规则">
<template v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="addRule">
<bg-icon
style="font-size: 12px; color: #fff; margin-right: 8px"
icon="#bg-ic-add"></bg-icon>
新增
</el-button>
<el-button @click="openDeleteDialog(2)"> 批量删除 </el-button>
<span class="sleceted_tip"
>已选<span class="num">{{ selectedNum }}</span
></span
>
<span class="clean" @click="cleanSelected">清空</span>
</div>
</template>
<template v-slot:filter_group>
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">修改时间</span>
<el-date-picker
v-model="filter.time"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 300px" />
</div>
</div>
<div class="right-action apaas_button">
<el-button type="primary" @click="filterAction"> 查询 </el-button>
<el-button type="default" @click="filterClear"> 重置 </el-button>
</div>
</template>
</bg-filter-group>
<div class="table_container">
<bg-table
ref="rulesTable"
:headers="headers"
:rows="tableRows"
:stripe="true"
select
@selectAc="selectRows"
canEdit
canEditFlag="state">
<template v-slot:rule_type="{ row }">
<span>{{ ["", "IP"][row.rule_type] }}</span>
</template>
<template v-slot:num_user="{ row }">
<span class="can_click_text under_line" @click="openUserDialog(row)">{{
row.num_user
}}</span>
</template>
<template v-slot:state="{ row }">
<bg-switch
@click="stateChange(row)"
:labels="['否', '是']"
:values="[0, 1]"
v-model="row.state"></bg-switch>
</template>
<template v-slot:updated_time="{ row }">
<span>{{ dateStringTransform(row.updated_time) }}</span>
</template>
<template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :key="row.id">
<bg-table-btn @click="edit(row)">编辑</bg-table-btn>
<bg-table-btn :disabled="row.state == 1" @click="openDeleteDialog(1, row)"
>删除</bg-table-btn
>
</bg-table-btns2>
</template>
</bg-table>
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
<el-dialog class="dialog_box_detail" title="用户详情" v-model="dialogDetail" width="1062px">
<div class="content_detail">
<div class="form_filter">
<div class="left">
<el-select
v-model="userFilter.isAdmin"
placeholder="请选择"
style="width: 200px; margin-left: 16px">
<el-option
v-for="(item, index) in userTypeList"
:key="'pushOptions' + index"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
<el-cascader
v-model="userFilter.organizationId"
:options="orgList"
placeholder="请选择组织"
:props="{
expandTrigger: 'hover',
label: 'name',
value: 'organization_id',
emitPath: false,
checkStrictly: true,
children: 'Child',
}"
:clearable="true"
collapse-tags
style="width: 200px; margin-left: 16px">
<template #default="{ data }">
<span>{{ data.name }}</span>
</template>
</el-cascader>
<el-input
placeholder="请输入关键词"
v-model.trim="userFilter.search"
style="width: 200px; margin-left: 16px"
:prefix-icon="Search" />
</div>
<div class="right">
<el-button type="primary" @click="searchUsers">查询</el-button>
<el-button type="default" @click="clearAction">重置</el-button>
</div>
</div>
<div class="table_content">
<bg-table
ref="bgUserTable"
:headers="userHeaders"
:rows="userTableRows"
height="430"
:stripe="true">
<template v-slot:isAdmin="{ row }">
<span>{{ ["", "业务系统用户", "组织管理员", "平台用户"][row.isAdmin] }}</span>
</template>
</bg-table>
<bg-pagination
:page="userFilter.page"
:size="userFilter.limit"
:total="userTableTotal"
@change-page="changeUserPage"
@change-size="changeUserSize">
</bg-pagination>
</div>
</div>
</el-dialog>
<el-dialog
class="dialog_box"
:title="deleteDialogConfig.title"
v-model="dialogDelete"
width="400px">
<div style="text-align: center">
{{ deleteDialogConfig.tips }}
</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="dialogDelete = false">取 消</el-button>
<el-button type="primary" @click="confimDelete">确 定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { reactive, toRefs, computed, onBeforeMount, ref } from "vue";
import { Search } from "@element-plus/icons-vue";
import { useRouter } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import store from "@/store";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { dateStringTransform } from "@/services/helper.js";
const router = useRouter();
const rulesTable = ref(null);
const state = reactive({
filter: {
search: "",
page: 1,
limit: 10,
time: [],
},
headers: [
{
label: "规则名称",
prop: "rule_name",
},
{
label: "规则类型",
prop: "rule_type",
},
{
label: "用户数量",
prop: "num_user",
},
{
label: "规则",
prop: "rule_detail",
},
{
label: "是否启用",
prop: "state",
},
{
label: "修改时间",
prop: "updated_time",
width: 240,
},
{
label: "操作",
prop: "action",
width: 120,
fixed: "right",
},
],
tableRows: [],
tableTotal: 0,
selectedNum: 0,
actionRow: {},
dialogDetail: false,
userFilter: {
page: 1,
limit: 10,
search: "",
isAdmin: "",
organizationId: "",
disp: 0,
},
userTypeList: [
{
name: "全部类型",
value: "",
},
{
name: "业务系统用户",
value: 1,
},
{
name: "组织管理员",
value: 2,
},
{
name: "平台用户",
value: 3,
},
],
orgList: [],
userHeaders: [
{
label: "账号",
prop: "systemAccount",
},
{
label: "类型",
prop: "isAdmin",
},
{
label: "用户手机号",
prop: "phone",
},
{
label: "所属组织",
prop: "name",
},
],
userTableRows: [],
userTableTotal: 0,
selection: [],
dialogDelete: false,
deleteDialogConfig: {
title: "删除",
ruleId: [],
tips: "确定要删除当前行数据吗?",
},
});
const getOrgList = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
state.orgList = res.data.data || [];
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取组织
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 关键字
const changePage = (page) => {
state.filter.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
}; // 改变每页条数
const filterAction = () => {
changePage(1);
}; // 高级搜索中查询
const filterClear = () => {
state.filter = {
search: "",
page: 1,
limit: 10,
time: [],
};
changePage(1);
}; // 高级搜索中重置
const getTableRows = () => {
let params = { ...state.filter };
params.updatedTimeFrom = params.time ? params.time[0] || "" : "";
params.updatedTimeTo = params.time ? params.time[1] || "" : "";
delete params.time;
axios
.get(`/apaas/system/v5/accessRule/listAccessRule`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.tableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取表格数据
const selectRows = (data) => {
state.selectedNum = data.allLength;
state.selection = data.selection;
};
// 新增规则跳转
const addRule = () => {
router.push("/config/accessRule/add");
};
const cleanSelected = () => {
rulesTable.value.clearTable();
}; //清空
// 改变规则状态
const stateChange = (row) => {
axios
.put(`/apaas/system/v5/accessRule/updateState?id=${row.id}&state=${row.state}`)
.then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
changePage(1);
} else {
ElMessage.error(res.data.data);
row.state = row.state == 0 ? 1 : 0;
}
});
};
// 打开用户弹窗
const openUserDialog = (row) => {
state.dialogDetail = true;
state.actionRow = row;
clearAction();
};
const searchUsers = () => {
changeUserPage(1);
}; // 用户弹窗查询
// 用户弹窗重置
const clearAction = () => {
state.userFilter = {
page: 1,
limit: 10,
search: "",
isAdmin: "",
organizationId: "",
disp: 0,
};
changeUserPage(1);
};
// 用户详情改变分页
const changeUserPage = (page) => {
state.userFilter.page = page;
getUserTableRows();
};
const changeUserSize = (size) => {
state.userFilter.limit = size;
changeUserPage(1);
};
// 用户详情弹窗数据
const getUserTableRows = () => {
let params = {
...state.userFilter,
id: state.actionRow.id,
};
axios.get(`/apaas/system/v5/accessRule/listRuleUser`, { params }).then((res) => {
if (res.data.code == 200) {
state.userTableRows = res.data.data || [];
state.userTableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
const edit = (row) => {
router.push({
path: "/config/accessRule/edit",
query: {
id: row.id,
ruleId: row.rule_id,
ruleName: row.rule_name,
state: row.state,
ruleType: row.rule_type,
ruleDetail: row.rule_detail,
},
});
}; //编辑
//打开删除弹窗
const openDeleteDialog = (type, row) => {
if (type === 2) {
const res = rulesTable.value.dealSelectData();
const list = Object.values(res);
if (list.length === 0) return ElMessage.warning("请选择要删除的数据");
state.dialogDelete = true;
const ruleId = list.map((item) => item.rule_id);
state.deleteDialogConfig = { title: "批量删除", ruleId, tips: "确定要删除所选数据吗?" };
return;
}
state.dialogDelete = true;
state.deleteDialogConfig = {
title: "删除",
ruleId: [row.rule_id],
tips: "确定要删除当前行数据吗?",
};
};
//确定删除
const confimDelete = () => {
axios
.delete("/apaas/system/v5/accessRule/delAccessRule", {
data: {
ruleId: state.deleteDialogConfig.ruleId,
},
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success("删除成功");
changePage(1);
} else {
ElMessage.error(res.data.data);
}
})
.finally(() => {
state.dialogDelete = false;
});
};
const {
filter,
headers,
userHeaders,
tableRows,
tableTotal,
selectedNum,
dialogDetail,
userTableRows,
userTableTotal,
userFilter,
userTypeList,
orgList,
selection,
dialogDelete,
deleteDialogConfig,
} = toRefs(state);
onBeforeMount(() => {
getTableRows();
getOrgList();
});
</script>
<style lang="scss" scoped>
.page_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
width: 100%;
padding: 0 24px;
min-height: 100%;
.main_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
flex-grow: 1;
width: 100%;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
padding: 0 0 16px 0;
margin-bottom: 16px;
position: relative;
.sleceted_tip {
margin: 0 24px 0 40px;
vertical-align: middle;
font-size: 14px;
color: #404a62;
.num {
margin: 0 3px 0 3px;
font-weight: 600;
color: #202531;
}
}
.clean {
vertical-align: middle;
font-size: 14px;
color: #3759be;
cursor: pointer;
}
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
.filter_item {
display: flex;
align-items: center;
.filter_title {
width: 84px;
white-space: pre-wrap;
font-weight: normal;
}
}
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
padding: 0 16px;
.el-table {
flex: 1;
.under_line {
text-decoration: underline;
}
}
}
}
:deep() .dialog_box_detail {
.el-dialog__body {
padding: 0 0 18px 0;
height: 580px;
}
.form_filter {
display: flex;
justify-content: space-between;
align-items: center;
height: 69px;
border-bottom: 1px solid #e6e9ef;
.right {
margin-right: 16px;
.el-button {
width: 64px;
&:last-child {
margin-left: 16px;
}
}
}
}
.table_content {
padding: 0 16px;
}
}
}
</style>
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字"> <bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字">
<template v-slot:left_action v-if="nodeClassifyId != '263758a4-0349-4d49-a816-e8ff8d33a8bb'"> <template v-slot:left_action v-if="nodeClassifyId != '263758a4-0349-4d49-a816-e8ff8d33a8bb'">
<div class="apaas_button"> <div class="apaas_button">
<el-button class="register_btn" type="primary" @click="backDict" v-if="dictLevel != 1"> <el-button type="primary" @click="backDict" v-if="dictLevel != 1">
<!-- <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> --> <!-- <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> -->
返回上级 返回上级
</el-button> </el-button>
<el-button class="register_btn" type="primary" @click="register"> <el-button type="primary" @click="register">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增 新增
</el-button> </el-button>
......
<!-- 角色管理 -->
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="form_content apaas_scroll_nor">
<el-form ref="refForm" :model="formData" :rules="rules" label-width="96px" class="registerForm">
<el-form-item label="LOGO" prop="logoUrl">
<bg-upload-image
v-model="formData.logoUrl"
:showTips="true"
customTips="请选择图片上传:支持jpg、png等格式,图片需小于500KB"
:fileSize="500"
:fileSizeUnit="'KB'"
:limit="1"
listType="picture-card"
@change="changeLogo"
:accept="['.jpg', '.jpeg', '.png']"></bg-upload-image>
</el-form-item>
<el-form-item label="登录背景图" prop="backgroundUrl">
<bg-upload-image
v-model="formData.backgroundUrl"
:fileSize="2"
:showTips="true"
customTips="请选择图片上传:大小1920 * 1026像素支持jpg、png等格式,图片需小于2MB"
:limit="1"
listType="picture-card"
@change="changeBanner"
:accept="['.jpg', '.jpeg', '.png']"></bg-upload-image>
</el-form-item>
<bg-form-gap title="底部所有权内容"></bg-form-gap>
<el-form-item label="内容" prop="patent">
<el-input
v-model.trim="formData.patent"
placeholder="例如:Copyright © 某某大数据, All Rights Reserved."></el-input>
</el-form-item>
<bg-form-gap title="底部ICP备案"></bg-form-gap>
<el-form-item label="内容" prop="icpFiling">
<el-input placeholder="请输入" v-model.trim="formData.icpFiling"></el-input>
</el-form-item>
<el-form-item label="跳转连接" prop="icpUrl">
<el-input placeholder="例如:https://...或http://..." v-model.trim="formData.icpUrl"></el-input>
</el-form-item>
<bg-form-gap title="底部公安网备案"></bg-form-gap>
<el-form-item label="内容" prop="publicSecurityFiling">
<el-input placeholder="请输入" v-model.trim="formData.publicSecurityFiling"></el-input>
</el-form-item>
<el-form-item label="跳转连接" prop="publicSecurityUrl">
<el-input placeholder="例如:https://...或http://..." v-model.trim="formData.publicSecurityUrl"></el-input>
</el-form-item>
<bg-form-gap title="法律声明"></bg-form-gap>
<el-form-item label="跳转连接" prop="legalStatementUrl">
<el-input placeholder="例如:https://...或http://..." v-model.trim="formData.legalStatementUrl"></el-input>
</el-form-item>
<bg-form-gap title="隐私政策"></bg-form-gap>
<el-form-item label="跳转连接" prop="privacyPolicyUrl">
<el-input placeholder="例如:https://...或http://..." v-model.trim="formData.privacyPolicyUrl"></el-input>
</el-form-item>
</el-form>
</div>
<div class="operate_btns">
<el-button type="primary" @click="save"> 保存 </el-button>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, ref, onBeforeMount, nextTick } from "vue";
import axios from "../../../../request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import { validateLink } from "@/services/rules.js";
import store from "../../../../store";
const refForm = ref(null);
const state = reactive({
formData: {
logoUrl: [],
backgroundUrl: [],
patent: "",
icpFiling: "",
icpUrl: "",
publicSecurityFiling: "",
publicSecurityUrl: "",
legalStatementUrl: "",
privacyPolicyUrl: "",
}, //表单数据
rules: {
logoUrl: [{ required: true, message: "请上传Logo", trigger: "change" }],
backgroundUrl: [{ required: true, message: "请上传背景图", trigger: "change" }],
icpUrl: [{ validator: validateLink, trigger: "blur" }],
publicSecurityUrl: [{ validator: validateLink, trigger: "blur" }],
legalStatementUrl: [{ validator: validateLink, trigger: "blur" }],
privacyPolicyUrl: [{ validator: validateLink, trigger: "blur" }],
}, //表单校验规则
});
const changeLogo = (value) => {
if (value && value.length > 0) {
refForm.value.clearValidate("logoUrl");
}
};
const changeBanner = (value) => {
if (value && value.length > 0) {
refForm.value.clearValidate("backgroundUrl");
}
};
const save = () => {
refForm.value.validate((valid) => {
if (valid) {
let params = {
...state.formData,
};
params.logoUrl = JSON.stringify(params.logoUrl);
params.backgroundUrl = JSON.stringify(params.backgroundUrl);
axios.put(`/apaas/system/v5/login/updateLogin`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getLoginPageConfig();
} else {
ElMessage.error(res.data.data);
}
});
} else {
ElMessage.error("请先将表单填写完整");
}
});
};
const getLoginPageConfig = () => {
axios.get(`/apaas/system/v5/login/loginDetail`).then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
store.commit("setSystemLogo", data.logoUrl);
data.logoUrl = data.logoUrl ? JSON.parse(data.logoUrl) : [];
data.backgroundUrl = data.backgroundUrl ? JSON.parse(data.backgroundUrl) : [];
Object.assign(state.formData, data);
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getLoginPageConfig();
});
const { formData, rules } = toRefs(state);
</script>
<style lang="scss" scoped>
.page_container {
.main_container {
position: relative;
margin: 0 0 16px;
width: 100%;
height: calc(100% - 62px);
padding: 32px 0 70px;
overflow: auto;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
.form_content {
overflow: auto;
height: 100%;
padding-left: 24px;
.el-form {
width: 60%;
:deep() .el-form-item {
&:nth-of-type(1) {
.el-upload--picture-card {
width: 120px;
height: 120px;
}
}
&:nth-of-type(2) {
.el-upload--picture-card {
width: 367px;
height: 196px;
}
}
}
}
:deep() .gap-title {
font-size: 16px;
color: #202531;
}
}
.operate_btns {
position: absolute;
bottom: 0;
width: 100%;
height: 70px;
text-align: right;
line-height: 68px;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
margin-right: 16px;
}
}
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="parent_container">
<div class="left_container bgc_white">
<el-menu default-active="1" @select="switchMenu">
<el-menu-item index="1">
<span>授权信息</span>
</el-menu-item>
<el-menu-item index="2">
<span>安全相关</span>
</el-menu-item>
<el-menu-item index="3">
<span>登录注册配置</span>
</el-menu-item>
</el-menu>
</div>
<div class="right_container bgc_white">
<!-- 授权信息表单 -->
<el-form
v-if="activeIndex == 1"
ref="authorizeFormRef"
:model="authorizeFormData"
:rules="authorizeRules"
label-width="110px"
class="authorizeForm">
<el-form-item label="当前版本号" prop="system_version">
<el-input disabled v-model="authorizeFormData.system_version" />
</el-form-item>
<el-form-item label="User" prop="system_user">
<el-input placeholder="统一管理用户认证平台" v-model="authorizeFormData.system_user" maxlength="30" />
</el-form-item>
<el-form-item label="Key" prop="license">
<el-input
placeholder="请输入"
rows="5"
v-model="authorizeFormData.license"
type="textarea"
@blur="getLicenseInfo" />
</el-form-item>
<el-form-item label="有效期至" prop="license_dead_date">
<el-input disabled v-model="authorizeFormData.license_dead_date" />
</el-form-item>
<el-form-item label="剩余有效期提醒" prop="license_inform_day">
<el-input placeholder="请输入" v-model.trim.number="authorizeFormData.license_inform_day">
<template #append></template>
</el-input>
<el-tooltip placement="top-start" effect="light">
<template #content>
范围(0~90),单位:天, 当剩余有效期在配置区间内时,系统会在用户登录系统时发出提醒,0表示不提醒
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
</el-form>
<!-- 安全相关表单 -->
<el-form
v-if="activeIndex == 2"
ref="secureFormRef"
:model="secureFormData"
:rules="secureRules"
label-width="110px"
class="secureForm">
<div class="passwordItem">
<el-form-item label="最低密码强度" prop="min_pwd_level">
<el-select v-model="secureFormData.min_pwd_level" placeholder="请选择">
<el-option label="弱" :value="1" />
<el-option label="中" :value="2" />
<el-option label="强" :value="3" />
</el-select>
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>支持大写字母/小写字符/数字/特殊符号</span>
<br />
<span>密码长度应至少8位字符</span>
<br />
<span>弱:至少包含一种组合。</span>
<br />
<span>中:至少包含两种组合。</span>
<br />
<span>强:至少包含三种及以上组合。</span>
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
<el-form-item label="是否强制修改" prop="force_update_state">
<bg-switch
:labels="['否', '是']"
:values="[0, 1]"
v-model="secureFormData.force_update_state"></bg-switch>
</el-form-item>
</div>
<el-form-item label="密码有效期" prop="pwd_validity">
<el-input placeholder="请输入" v-model.trim.number="secureFormData.pwd_validity" maxlength="3">
<template #append></template>
</el-input>
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>单位,天</span>
<br />
<span>密码有效期是指强制修改密码的周期,例如60天表示用户需要每60天修改一次密码。</span>
<br />
<span>若配置为0,表示密码有效期为永久</span>
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
<el-form-item label="会话有效期" prop="session_validity">
<el-input placeholder="请输入" v-model.trim.number="secureFormData.session_validity">
<template #append>分钟</template>
</el-input>
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>范围(10~30)</span>
<br />
<span>单位,分钟</span>
<br />
<span>会话有效期是指您登录后,一定时间内无操作,系统将自动登出</span>
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
<el-form-item label="访问规则模式" prop="access_rule_state">
<el-select placeholder="请选择" v-model="secureFormData.access_rule_state">
<el-option label="关闭" :value="0"> </el-option>
<el-option label="打开" :value="1"> </el-option>
</el-select>
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>访问规则模式开启后,按照【访问规则管理】配置执行。</span>
<br />
<span>该模式针对超管无效</span>
</template>
<div class="tip-image"></div>
</el-tooltip>
</el-form-item>
</el-form>
<!-- 登录注册配置表单 -->
<el-form
v-if="activeIndex == 3"
ref="registerFormRef"
:model="registerFormData"
:rules="registerRules"
label-width="125px"
class="registerForm">
<bg-form-gap title="登录受限配置"></bg-form-gap>
<el-form-item label="登录受限是否启用" prop="login_config_state">
<bg-switch
:labels="['否', '是']"
:values="[0, 1]"
v-model="registerFormData.login_config_state"></bg-switch>
</el-form-item>
<div class="input_password_config" v-if="registerFormData.login_config_state == 1">
<span></span>
<el-form-item prop="login_limit_time" label-width="0">
<el-input
placeholder="请输入小时数"
v-model.trim.number="registerFormData.login_limit_time"
maxlength="3"></el-input>
</el-form-item>
<span>小时内</span>
<el-form-item prop="login_pwd_error" label-width="0">
<el-input
placeholder="请输入密码输错次数"
v-model.trim.number="registerFormData.login_pwd_error"
maxlength="3"></el-input>
</el-form-item>
<span>次输错密码,自动锁定</span>
<el-form-item prop="login_lock_time" label-width="0">
<el-input
placeholder="请输入分钟数"
v-model.trim.number="registerFormData.login_lock_time"
maxlength="3"></el-input>
</el-form-item>
<span>分钟</span>
<el-button type="primary" @click="restoreDialog = true">一键还原受限</el-button>
<el-tooltip placement="top-start" effect="light">
<template #content>
<span>必须为大于0的正整数且不能为空</span>
<br />
<span>一键还原按钮将所有锁定的账号解锁并将输错次数还原</span>
</template>
<div class="tip-image"></div>
</el-tooltip>
</div>
<bg-form-gap title="注册配置"></bg-form-gap>
<el-form-item label="允许注册" prop="register_config_state">
<el-radio-group v-model="registerFormData.register_config_state">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div class="operate_btns">
<el-button type="primary" @click="save"> 保存 </el-button>
</div>
</div>
</div>
<el-dialog class="dialog_box" title="提示" v-model="restoreDialog" width="420px">
<div>该操作将还原所有锁定账号和输错次数,是否继续?</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="restoreDialog = false">取 消</el-button>
<el-button type="primary" @click="confirm">确 定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { reactive, toRefs, onBeforeMount, ref } from "vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
const authorizeFormRef = ref(null);
const secureFormRef = ref(null);
const registerFormRef = ref(null);
const state = reactive({
//授权信息表单
authorizeFormData: {
id: "",
system_version: "",
system_user: "",
license: "",
license_dead_date: "",
license_inform_day: "",
},
//授权表单校验规则
authorizeRules: {
license_inform_day: [{ type: "number", min: 0, max: 90, message: "请输入0~90的整数", trigger: "blur" }],
},
//安全相关信息表单
secureFormData: {
id: "",
min_pwd_level: "",
force_update_state: 0,
pwd_validity: "",
session_validity: "",
access_rule_state: "",
},
//安全相关表单校验规则
secureRules: {
pwd_validity: [
{
type: "number",
message: "请输入大于或等于0的整数",
trigger: "blur",
},
],
session_validity: [
{
type: "number",
min: 10,
max: 30,
message: "请输入10~30的整数",
trigger: "blur",
},
],
},
//登录注册配置表单
registerFormData: {
id: "",
login_config_state: 0,
login_limit_time: "",
login_pwd_error: "",
login_lock_time: "",
register_config_state: 0,
},
//登录注册配置表单校验规则
registerRules: {
login_limit_time: [
{
type: "number",
min: 1,
message: "请输入正整数",
trigger: "blur",
},
],
login_pwd_error: [
{
type: "number",
min: 1,
message: "请输入正整数",
trigger: "blur",
},
],
login_lock_time: [
{
type: "number",
min: 1,
message: "请输入正整数",
trigger: "blur",
},
],
},
//选中项索引
activeIndex: 1,
restoreDialog: false,
});
const {
authorizeFormData,
authorizeRules,
secureFormData,
secureRules,
registerFormData,
registerRules,
activeIndex,
restoreDialog,
} = toRefs(state);
onBeforeMount(() => {
getPreferenceConfig();
});
//切换菜单选项
const switchMenu = (index) => {
state.activeIndex = index;
};
//获取首选项配置
const getPreferenceConfig = () => {
axios.get("/apaas/system/v5/sysOptions").then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
Object.keys(state.authorizeFormData).forEach((item) => {
state.authorizeFormData[item] = data[item];
});
Object.keys(state.secureFormData).forEach((item) => {
state.secureFormData[item] = data[item];
});
Object.keys(state.registerFormData).forEach((item) => {
state.registerFormData[item] = data[item];
});
} else {
ElMessage.error(res.data.data);
}
});
};
//根据license获取授权信息
const getLicenseInfo = () => {
if (!state.authorizeFormData.license) return;
axios
.post("/apaas/system/v5/sysOptions/getLicenseInfo", {
license: state.authorizeFormData.license,
})
.then((res) => {
if (res.data.code == 200) {
const data = res.data.data || {};
state.authorizeFormData.system_version = data.version;
state.authorizeFormData.license_dead_date = data.deadDate;
} else {
ElMessage.error(res.data.data);
}
});
};
//保存表单项
const save = () => {
let params = {};
if (state.activeIndex == 1) {
authorizeFormRef.value.validate((valid) => {
if (valid) {
params = {
...state.authorizeFormData,
};
postData("/apaas/system/v5/sysOptions/licenseOpts", params);
}
});
} else if (state.activeIndex == 2) {
secureFormRef.value.validate((valid) => {
if (valid) {
params = {
...state.secureFormData,
};
postData("/apaas/system/v5/sysOptions/safeOpts", params);
}
});
} else {
registerFormRef.value.validate((valid) => {
if (valid) {
params = {
...state.registerFormData,
};
if (params.login_config_state == 0) {
params.login_limit_time = 0;
params.login_pwd_error = 0;
params.login_lock_time = 0;
}
postData("/apaas/system/v5/sysOptions/loginOpts", params);
}
});
}
};
// 请求接口发送消息
const postData = (url, params) => {
axios.post(url, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
});
};
const confirm = () => {
axios.post(`/apaas/system/v5/sysOptions/reStartConfig`).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
state.restoreDialog = false;
} else {
ElMessage.error(res.data.data);
}
});
};
</script>
<style lang="scss" scoped>
.parent_container {
display: flex;
justify-content: space-between;
height: calc(100% - 46px - 20px);
.left_container {
width: 240px;
height: 100%;
padding: 24px 16px 0;
.el-menu {
border: none;
.el-menu-item {
justify-content: center;
height: 36px;
color: #404a62 !important;
&.is-active,
&:hover {
background-color: #f2f3f7;
border-radius: 4px;
}
}
}
}
.right_container {
position: relative;
width: calc(100% - 256px);
height: 100%;
padding: 32px 0 68px 24px;
.authorizeForm,
.secureForm,
.registerForm {
:deep() .el-form-item {
margin-bottom: 24px;
width: 750px;
font-size: 14px;
.el-form-item__label,
.el-radio__label {
color: var(--el-text-color-primary);
}
.el-select {
width: 100%;
}
.el-input-group__append {
width: 60px;
color: #404a62;
border-radius: 0 6px 6px 0;
background: #f7f7f9;
}
}
}
.secureForm {
.passwordItem {
display: flex;
align-items: center;
.el-form-item:nth-of-type(1) {
flex-shrink: 0;
margin-right: 56px;
}
}
}
.registerForm {
.input_password_config {
position: relative;
display: flex;
align-items: center;
width: 798px;
margin-bottom: 24px;
font-size: 14px;
color: var(--el-text-color-primary);
.el-form-item {
margin: 0px 8px;
&:nth-of-type(1),
&:nth-of-type(3) {
width: 120px;
}
&:nth-of-type(2) {
width: 150px;
}
}
.el-button {
margin-left: 18px;
}
}
.el-radio {
margin-right: 54px;
}
}
.operate_btns {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 68px;
padding-right: 16px;
line-height: 68px;
text-align: right;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
}
}
}
}
</style>
...@@ -51,22 +51,6 @@ const checkPhone = (rule, value, callback) => { ...@@ -51,22 +51,6 @@ const checkPhone = (rule, value, callback) => {
}); });
}; };
// const checkPhoneRepet = (rule, value, callback) => {
// let params = null;
// if (props.id){
// params = {id: parseInt(props.id),contact_phone: value,}
// }else {
// params = {id: 0,contact_phone: value}
// }
// $axios.post(`/apaas/system/v5/org/check`,params)
// .then((res) => {
// if (res.data.code == 200) {
// callback()
// }else {
// callback(new Error(res.data.data))
// }
// })
// }
const checkName = (rule, value, callback) => { const checkName = (rule, value, callback) => {
var reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/; var reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/;
...@@ -86,7 +70,6 @@ const contactFormRules = reactive({ ...@@ -86,7 +70,6 @@ const contactFormRules = reactive({
contact_phone: [ contact_phone: [
{ required: true, message: "请输入联系人手机号", trigger: "blur" }, { required: true, message: "请输入联系人手机号", trigger: "blur" },
{ validator: checkPhone, trigger: "blur" }, { validator: checkPhone, trigger: "blur" },
// { validator: checkPhoneRepet, trigger: 'blur' }
], ],
contact_email: [ contact_email: [
{ type: "email", message: "请输入正确的邮箱", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱", trigger: "blur" },
......
...@@ -114,6 +114,7 @@ const formData = reactive({ ...@@ -114,6 +114,7 @@ const formData = reactive({
logo: "", logo: "",
system_role_id: "", system_role_id: "",
system_account: "", system_account: "",
system_phone: "",
password: "", password: "",
confirm_password: "", confirm_password: "",
access_address: "", access_address: "",
...@@ -213,6 +214,7 @@ const getDetail = () => { ...@@ -213,6 +214,7 @@ const getDetail = () => {
business_name: form.business_name, business_name: form.business_name,
business_desc: form.business_desc, business_desc: form.business_desc,
system_account: form.system_account, system_account: form.system_account,
system_phone: form.system_phone,
access_address: form.access_address, access_address: form.access_address,
develop_id: form.develop_id, develop_id: form.develop_id,
state: form.state, state: form.state,
......
...@@ -22,13 +22,28 @@ ...@@ -22,13 +22,28 @@
<el-input v-model="systemForm.business_name" /> <el-input v-model="systemForm.business_name" />
</el-form-item> </el-form-item>
<el-form-item label="AppId" prop="appid" v-if="formType"> <el-form-item label="AppId" prop="appid" v-if="formType">
<el-input v-model="systemForm.appid" :disabled="formType" style="width: 80%" /> <el-input v-model="systemForm.appid" :disabled="formType">
<span class="pl-1"><el-button type="primary" @click="copyText(systemForm.appid)">复制</el-button></span> <template #suffix>
<bg-icon
icon="#bg-ic-copy"
style="cursor: pointer"
@click="copyText(systemForm.appid)"></bg-icon>
</template>
</el-input>
<!-- <span class="pl-1"><el-button type="primary" @click="copyText(systemForm.appid)">复制</el-button></span> -->
</el-form-item> </el-form-item>
<el-form-item label="AppSecret" prop="appsecret" v-if="formType"> <el-form-item label="AppSecret" prop="appsecret" v-if="formType">
<el-input v-model="systemForm.appsecret" :disabled="formType" style="width: 80%" /> <div style="display: flex; width: 100%">
<span class="pl-1"><el-button type="primary" @click="copyText(systemForm.appsecret)">复制</el-button></span> <el-input v-model="systemForm.appsecret" :disabled="formType">
<span class="pl-1"><el-button type="primary" @click="resetSecret">重置</el-button></span> <template #suffix>
<bg-icon
icon="#bg-ic-copy"
style="cursor: pointer"
@click="copyText(systemForm.appsecret)"></bg-icon>
</template>
</el-input>
<span class="pl-1"><el-button type="primary" @click="resetSecret">重置</el-button></span>
</div>
</el-form-item> </el-form-item>
<el-form-item label="系统LOGO" prop="logo"> <el-form-item label="系统LOGO" prop="logo">
<bg-upload-image <bg-upload-image
...@@ -42,20 +57,39 @@ ...@@ -42,20 +57,39 @@
customTips="请选择图片上传:大小120 * 120像素支持jpg、png等格式,图片需小于500KB"></bg-upload-image> customTips="请选择图片上传:大小120 * 120像素支持jpg、png等格式,图片需小于500KB"></bg-upload-image>
</el-form-item> </el-form-item>
<el-form-item label="业务系统概述" prop="business_desc"> <el-form-item label="业务系统概述" prop="business_desc">
<el-input type="textarea" :rows="3" v-model="systemForm.business_desc" show-word-limit maxlength="300" /> <el-input
type="textarea"
:rows="3"
v-model="systemForm.business_desc"
show-word-limit
maxlength="300" />
</el-form-item> </el-form-item>
<el-form-item label="角色" prop="system_role_id" v-if="!formType"> <el-form-item label="角色" prop="system_role_id" v-if="!formType">
<el-select v-model="systemForm.system_role_id" placeholder="请选择角色" :disabled="true" style="width: 100%"> <el-select
<el-option v-for="item in roleList" :key="item.role_id" :label="item.role_name" :value="item.role_id" /> v-model="systemForm.system_role_id"
placeholder="请选择角色"
:disabled="true"
style="width: 100%">
<el-option
v-for="item in roleList"
:key="item.role_id"
:label="item.role_name"
:value="item.role_id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="账号" prop="system_account"> <el-form-item label="账号" prop="system_account">
<el-input v-model="systemForm.system_account" /> <el-input v-model="systemForm.system_account" />
</el-form-item> </el-form-item>
<el-form-item label="手机号" prop="system_phone">
<el-input v-model="systemForm.system_phone" />
</el-form-item>
<el-form-item label="密码" prop="password" v-if="!formType"> <el-form-item label="密码" prop="password" v-if="!formType">
<el-input :type="password_eye ? 'text' : 'password'" v-model="systemForm.password"> <el-input :type="password_eye ? 'text' : 'password'" v-model="systemForm.password">
<template #suffix> <template #suffix>
<bg-icon @click="password_eye = !password_eye" class="icon_eye" icon="#bg-ic-eye"></bg-icon> <bg-icon
@click="password_eye = !password_eye"
class="icon_eye"
icon="#bg-ic-eye"></bg-icon>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
...@@ -71,7 +105,11 @@ ...@@ -71,7 +105,11 @@
</el-form-item> </el-form-item>
<el-form-item label="开发厂商名称" prop="develop_id"> <el-form-item label="开发厂商名称" prop="develop_id">
<el-select v-model="systemForm.develop_id" placeholder="请选择开发厂商" style="width: 100%"> <el-select v-model="systemForm.develop_id" placeholder="请选择开发厂商" style="width: 100%">
<el-option v-for="item in firmList" :key="item.dict_id" :label="item.dict_name" :value="item.dict_id" /> <el-option
v-for="item in firmList"
:key="item.dict_id"
:label="item.dict_name"
:value="item.dict_id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="是否启用" prop="state"> <el-form-item label="是否启用" prop="state">
...@@ -84,6 +122,7 @@ ...@@ -84,6 +122,7 @@
import { reactive, ref, onBeforeMount, onMounted, computed } from "vue"; import { reactive, ref, onBeforeMount, onMounted, computed } from "vue";
import axios from "@/request/http.js"; import axios from "@/request/http.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { validatePhone } from "@/services/rules.js";
const props = defineProps({ const props = defineProps({
formType: { formType: {
type: Boolean, type: Boolean,
...@@ -102,6 +141,7 @@ const systemForm = reactive({ ...@@ -102,6 +141,7 @@ const systemForm = reactive({
logo: [], logo: [],
system_role_id: "", system_role_id: "",
system_account: "", system_account: "",
system_phone: "",
password: "", password: "",
confirm_password: "", confirm_password: "",
access_address: "", access_address: "",
...@@ -127,7 +167,11 @@ const validateBusinessName = (rule, value, callback) => { ...@@ -127,7 +167,11 @@ const validateBusinessName = (rule, value, callback) => {
} else { } else {
let params = null; let params = null;
if (props.id) { if (props.id) {
params = { id: parseInt(props.id), business_name: value, organization_id: systemForm.organization_id }; params = {
id: parseInt(props.id),
business_name: value,
organization_id: systemForm.organization_id,
};
} else { } else {
params = { business_name: value, organization_id: systemForm.organization_id }; params = { business_name: value, organization_id: systemForm.organization_id };
} }
...@@ -164,6 +208,22 @@ const validateSystemAccount = (rule, value, callback) => { ...@@ -164,6 +208,22 @@ const validateSystemAccount = (rule, value, callback) => {
} }
}; };
const checkPhoneRepet = (rule, value, callback) => {
let params = null;
if (props.id) {
params = { id: parseInt(props.id), contact_phone: value };
} else {
params = { id: 0, contact_phone: value };
}
axios.post(`/apaas/system/v5/org/check`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
};
const formRules = reactive({ const formRules = reactive({
organization_id: [{ required: true, message: "请选择组织机构", trigger: "change" }], organization_id: [{ required: true, message: "请选择组织机构", trigger: "change" }],
business_name: [ business_name: [
...@@ -178,6 +238,11 @@ const formRules = reactive({ ...@@ -178,6 +238,11 @@ const formRules = reactive({
{ max: 20, message: "帐号最大长度为20个字符", trigger: "blur" }, { max: 20, message: "帐号最大长度为20个字符", trigger: "blur" },
{ validator: validateSystemAccount, trigger: "blur" }, { validator: validateSystemAccount, trigger: "blur" },
], ],
system_phone: [
{ required: true, message: "请输入账号", trigger: "blur" },
{ validator: validatePhone, trigger: "blur" },
{ validator: checkPhoneRepet, trigger: "blur" },
],
password: [ password: [
{ required: true, message: "请输入密码", trigger: "blur" }, { required: true, message: "请输入密码", trigger: "blur" },
{ min: 8, message: "密码长度不得低于8位", trigger: "blur" }, { min: 8, message: "密码长度不得低于8位", trigger: "blur" },
......
...@@ -32,12 +32,12 @@ ...@@ -32,12 +32,12 @@
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字"> <bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字">
<template v-slot:left_action> <template v-slot:left_action>
<div class="apaas_button"> <div class="apaas_button">
<el-button class="register_btn" type="primary" @click="addAccount"> <el-button type="primary" @click="addAccount">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增 新增
</el-button> </el-button>
<el-button class="register_btn" @click="deleteBatch"> 批量删除 </el-button> <el-button @click="deleteBatch"> 批量删除 </el-button>
<el-button class="register_btn" @click="resetPsd"> 重置密码 </el-button> <el-button @click="resetPsd"> 重置密码 </el-button>
<span class="header_info" <span class="header_info"
>已选择<span style="color: #202531; font-weight: bold">{{ selected.length }}</span >已选择<span style="color: #202531; font-weight: bold">{{ selected.length }}</span
></span ></span
......
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content">
<bg-form-gap title="注册信息"></bg-form-gap>
<bg-detail-table2 class="register_info" :list="instanceData.approveBasicInfo">
<!-- <template v-slot:approvalStatus="{ data }">
<p class="detail-module">
<span>{{ data.label }}</span>
<span>{{ data.value }}</span>
</p>
</template> -->
</bg-detail-table2>
<bg-form-gap title="审批"></bg-form-gap>
<div class="approve">
<div class="header">
<div class="left">
<span class="approve_person">平台运营者审批</span>
<span class="approve_status">待审批</span>
</div>
<div class="right">
<span class="label">申请时间:</span>
<span class="value">{{ instanceData.approveBasicInfo[5].value }}</span>
</div>
</div>
<el-form
ref="approveFormRef"
:model="instanceData.formData"
:rules="instanceData.rules"
label-width="80px"
class="approveForm">
<el-form-item label="审批单位">
<el-input disabled v-model="userInfo.organization_name" maxlength="20" />
</el-form-item>
<el-form-item label="审批人">
<el-input disabled v-model="userInfo.contact_name" maxlength="20" />
</el-form-item>
<el-form-item label="审批结果" prop="status">
<el-radio-group v-model="instanceData.formData.status">
<el-radio :label="1"> 通过 </el-radio>
<el-radio :label="0"> 驳回 </el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="审批意见" prop="comments">
<el-input
placeholder="请输入"
rows="5"
maxlength="200"
v-model="instanceData.formData.comments"
show-word-limit
type="textarea" />
</el-form-item>
</el-form>
</div>
<div class="operate_btns">
<el-button type="default" @click="cancel"> 取消 </el-button>
<el-button type="primary" @click="save"> 保存 </el-button>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, onBeforeMount, computed, ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
// import { dateStringTransform } from "@/services/helper";
import store from "@/store";
const route = useRoute();
const router = useRouter();
const approveFormRef = ref(null);
const instanceData = reactive({
approveBasicInfo: [
{
key: "organization_name",
label: "所属机构",
value: "",
// slot: "approvalStatus",
},
{
key: "business_name",
label: "业务系统名称",
value: "",
},
{
key: "system_account",
label: "账号",
value: "",
},
{
key: "phone",
label: "手机号",
value: "",
},
{
key: "develop_name",
label: "开发厂商名称",
value: "",
},
{
key: "created_time",
label: "提交时间",
value: "",
},
{
key: "contact_name",
label: "联系人",
value: "",
},
{
key: "contact_phone",
label: "联系人手机号",
value: "",
},
{
key: "business_desc",
label: "业务系统描述",
value: "",
},
],
formData: {
status: "",
comments: "",
},
rules: {
status: [
{
required: true,
message: "请选择",
},
],
},
});
const userInfo = computed(() => {
return store.state.userInfo;
});
onBeforeMount(() => {
getApproveInfo();
});
const getApproveInfo = () => {
axios
.get(`/apaas/system/v5/user/approval/detail/${route.query.id}`)
.then((res) => {
if (res.data.code == 200) {
const result = res.data.data || {};
instanceData.approveBasicInfo.forEach((item) => {
// if (item.key === "created_time") {
// item.value = dateStringTransform(result[item.key]);
// return;
// }
item.value = result[item.key];
});
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
ElMessage.error(err);
});
};
//取消
const cancel = () => {};
//保存
const save = () => {
approveFormRef.value.validate((val) => {
if (val) {
const params = {
...instanceData.formData,
id: +route.query.id,
};
axios.post(`/apaas/system/v5/user/approval`, params).then((res) => {
if (res.data.code == "200") {
ElMessage.success("操作成功");
router.push("/develop/systemApproval");
} else {
ElMessage.error(res.data.data);
}
});
}
});
};
</script>
<style lang="scss" scoped>
.page_content {
position: relative;
padding: 24px 0 68px 24px;
.register_info {
margin-bottom: 24px;
width: 960px;
}
.approve {
overflow: hidden;
width: 1127px;
height: 378px;
background-color: #ffffff;
border-radius: 4px;
border: solid 1px #e3e4ef;
.header {
display: flex;
justify-content: space-between;
height: 38px;
padding: 0 16px;
border-bottom: 1px solid #e3e4ef;
background-color: #f9fafc;
.left {
display: flex;
justify-content: space-between;
align-items: center;
width: 150px;
height: 100%;
.approve_person {
display: inline-block;
width: 98px;
font-size: 14px;
font-weight: 600;
color: #242c43;
}
.approve_status {
display: inline-block;
width: 46px;
height: 18px;
font-size: 12px;
text-align: center;
color: #e56600;
background-color: #fcf0e6;
border-radius: 3px;
border: solid 1px #f2b380;
}
}
.right {
display: flex;
justify-content: space-between;
align-items: center;
width: 210px;
height: 100%;
font-size: 14px;
color: #7784a6;
.value {
color: #242c43;
}
}
}
.approveForm {
padding: 24px 24px 0 24px;
:deep() .el-form-item {
margin-bottom: 24px;
}
:deep() .el-form-item__label,
:deep() .el-radio__label {
color: var(--el-text-color-primary);
}
}
}
.operate_btns {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 64px;
padding-right: 16px;
line-height: 64px;
text-align: right;
border-top: solid 1px #e6e9ef;
.el-button {
width: 92px;
& + .el-button {
margin-left: 16px;
}
}
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content">
<bg-form-gap title="注册信息"></bg-form-gap>
<bg-detail-table2 class="register_info" :list="instanceData.approveBasicInfo"> </bg-detail-table2>
<bg-form-gap title="审批信息"></bg-form-gap>
<bg-detail-table2 class="approve_info" :list="instanceData.approveInfo"> </bg-detail-table2>
</div>
</div>
</template>
<script setup>
import { reactive, onBeforeMount } from "vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import { useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const route = useRoute();
const instanceData = reactive({
approveBasicInfo: [
{
key: "organization_name",
label: "所属机构",
value: "",
// slot: "approvalStatus",
},
{
key: "business_name",
label: "业务系统名称",
value: "",
},
{
key: "system_account",
label: "账号",
value: "",
},
{
key: "phone",
label: "手机号",
value: "",
},
{
key: "develop_name",
label: "开发厂商名称",
value: "",
},
{
key: "created_time",
label: "提交时间",
value: "",
},
{
key: "contact_name",
label: "联系人",
value: "",
},
{
key: "contact_phone",
label: "联系人手机号",
value: "",
},
{
key: "business_desc",
label: "业务系统描述",
value: "",
},
],
approveInfo: [
{
key: "status",
label: "审核状态",
value: "",
},
{
key: "approval_by",
label: "审核人",
value: "",
},
{
key: "approval_time",
label: "审批时间",
value: "",
},
{
key: "comments",
label: "审批意见",
value: "",
},
],
});
onBeforeMount(() => {
getApproveInfo();
});
const getApproveInfo = () => {
axios
.get(`/apaas/system/v5/user/approval/detail/${route.query.id}`)
.then((res) => {
if (res.data.code == 200) {
const result = res.data.data || {};
instanceData.approveBasicInfo.forEach((item) => {
// if (item.key === "created_time") {
// item.value = dateStringTransform(result[item.key]);
// return;
// }
item.value = result[item.key];
});
instanceData.approveInfo.forEach((item) => {
if (item.key === "status") {
item.value = result[item.key] === 1 ? "通过" : "驳回";
}
item.value = result[item.key];
});
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
ElMessage.error(err);
});
};
</script>
<style lang="scss" scoped>
.page_content {
position: relative;
padding: 24px 0 68px 24px;
.register_info,
.approve_info {
margin-bottom: 24px;
width: 960px;
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入业务系统名称、账号或所属机构">
<template v-slot:filter_group>
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">审批状态</span>
<el-select v-model="filter.status" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in stateOptions"
:key="'pushOptions' + index"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">提交时间</span>
<el-date-picker
v-model="filter.time"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 300px" />
</div>
</div>
<div class="right-action apaas_button">
<el-button type="primary" @click="filterAction"> 查询 </el-button>
<el-button type="default" @click="filterClear"> 重置 </el-button>
</div>
</template>
</bg-filter-group>
<div class="table_container">
<bg-table ref="bgTable" :headers="headers" :rows="tableRows" :isIndex="true" :stripe="true">
<template v-slot:ability_name="{ row }">
<span @click="goDetail(row)" class="can_click_text">
{{ row.ability_name }}
<span v-if="row.include_mock_service" class="mock_tip"> mock </span>
</span>
</template>
<template v-slot:ability_state="{ row }">
<span class="circle" :class="'bgc_' + row.ability_state"></span>
{{ ["待上架", "已上架", "已下架", "上架中", "下架中"][row.ability_state] }}
</template>
<template v-slot:action="{ row }">
<bg-table-btns2>
<bg-table-btn v-if="row.status === 0" @click="approve(row)">审批</bg-table-btn>
<bg-table-btn v-else @click="approveDetail(row)">审批详情</bg-table-btn>
</bg-table-btns2>
</template>
</bg-table>
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
<el-dialog class="dialog_box" title="删除" v-model="dialogDelete" width="400px">
<div style="text-align: left">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;确定要删除数据吗?数据删除后不能恢复,请谨慎操作
</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="dialogDelete = false">取 消</el-button>
<el-button type="primary" @click="deleteData">确 定</el-button>
</div>
</template>
</el-dialog>
<el-dialog class="dialog_box" title="提示" v-model="cacheDialog" width="400px">
<div style="font-size: 16px; color: #404a62">你有未提交的服务,是否继续编辑该服务?</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="cancelCache">取 消</el-button>
<el-button type="primary" @click="confirmCache">确 定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { reactive, toRefs, computed, onBeforeMount } from "vue";
import { useRouter } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const router = useRouter();
const state = reactive({
filter: {
search: "",
status: "",
time: [],
page: 1,
limit: 10,
},
stateOptions: [
{
name: "全部",
value: "",
},
{
name: "待审批",
value: 0,
},
{
name: "通过",
value: 1,
},
{
name: "驳回",
value: 2,
},
],
headers: [
{
label: "业务系统名称",
prop: "business_name",
minWidth: 120,
},
{
label: "账号",
prop: "system_account",
minWidth: 120,
},
{
label: "所属机构",
prop: "organization_name",
width: 200,
},
{
label: "审批状态",
prop: "status",
width: 120,
},
{
label: "提交时间",
prop: "created_time",
minWidth: 180,
},
{
label: "操作",
prop: "action",
width: 180,
fixed: "right",
},
],
tableRows: [],
tableTotal: 0,
actionRow: {},
dialogDelete: false,
cacheDialog: false,
});
const { filter, stateOptions, headers, tableRows, tableTotal, dialogDelete, cacheDialog } = toRefs(state);
const cancelCache = () => {
axios
.get(`/apaas/service/v5/ability/clear/cach?abilityType=0`)
.then((res) => {
if (res.data.code == 200) {
state.cacheDialog = false;
router.push("/ability-register/add");
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
router.push("/ability-register/add");
});
}; // 取消按钮,清空缓存跳转注册页
const confirmCache = () => {
state.cacheDialog = false;
router.push("/ability-register/add");
}; // 确定按钮,直接跳转注册页
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
};
const changePage = (page) => {
state.filter.page = page;
getTableRows();
};
const getTableRows = () => {
let params = { ...state.filter };
params.start_at = params.time ? params.time[0] || "" : "";
params.end_at = params.time ? params.time[1] || "" : "";
delete params.time;
if (!params.status.toString()) delete params.status;
axios
.get(`/apaas/system/v5/user/approval/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.tableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
const filterAction = () => {
changePage(1);
};
const changeSize = (limit) => {
state.filter.limit = limit;
changePage(1);
};
const filterClear = () => {
state.filter = {
search: "",
status: 0,
time: [],
page: 1,
limit: 10,
};
changePage(1);
};
const approve = (row) => {
router.push({
path: "/develop/systemApproval/approval",
query: {
id: row.id,
},
});
};
const approveDetail = (row) => {
router.push({
path: "/develop/systemApproval/detail",
query: {
id: row.id,
},
});
};
const deleteData = () => {
axios.delete(`/apaas/service/v5/ability/${state.actionRow.id}`).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
state.dialogDelete = false;
changePage(1);
} else {
ElMessage.error(res.data.data);
}
});
};
const goDetail = (row) => {
router.push({
path: "/ability-manage/real-list/detail",
query: {
id: row.id,
},
});
};
onBeforeMount(() => {
getTableRows();
});
</script>
<style lang="scss" scoped>
.page_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
width: 100%;
padding: 0 24px;
min-height: 100%;
.main_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
flex-grow: 1;
width: 100%;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
padding: 0 0 16px 0;
margin-bottom: 16px;
position: relative;
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
.filter_item {
display: flex;
align-items: center;
.filter_title {
width: 84px;
white-space: pre-wrap;
font-weight: normal;
}
}
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
padding: 0 16px;
.el-table {
flex: 1;
.circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 3px;
margin-right: 8px;
transform: translateY(-2px);
}
.bgc_1 {
background-color: #48ad97;
}
.bgc_2 {
background-color: #d75138;
}
.bgc_3 {
background-color: #3759be;
}
.bgc_4 {
background-color: #ea7d19;
}
.bgc_0 {
background-color: #9e9e9e;
}
.mock_tip {
display: inline-block;
margin-left: 4px;
width: 43px;
height: 20px;
font-size: 12px;
color: #2b4695;
text-align: center;
background-color: #eff2fa;
border-radius: 3px;
border: solid 1px #b0bee8;
}
}
}
}
}
</style>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<bg-filter-group :showSearch="false"> <bg-filter-group :showSearch="false">
<template v-slot:left_action> <template v-slot:left_action>
<div class="apaas_button"> <div class="apaas_button">
<el-button class="register_btn" type="primary" @click="addBanner"> <el-button type="primary" @click="addBanner">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增 新增
</el-button> </el-button>
......
...@@ -642,12 +642,12 @@ const { ...@@ -642,12 +642,12 @@ const {
</style> </style>
<style> <style>
.select_dialog { .select_dialog {
margin-top: 80px; margin-top: 8vh;
} }
.el-dialog .el-dialog__body { .select_dialog .el-dialog__body {
padding: 0; padding: 0;
} }
.el-dialog .el-dialog__footer { .select_dialog .el-dialog__footer {
padding: 16px; padding: 16px;
} }
</style> </style>
<!-- banner管理 --> <!-- 推荐管理 -->
<template> <template>
<div class="detail_container"> <div class="detail_container">
<bg-breadcrumb></bg-breadcrumb> <bg-breadcrumb></bg-breadcrumb>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<bg-filter-group :showSearch="false"> <bg-filter-group :showSearch="false">
<template v-slot:left_action> <template v-slot:left_action>
<div class="apaas_button"> <div class="apaas_button">
<el-button class="register_btn" type="primary" @click="addBanner"> <el-button type="primary" @click="addBanner">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增 新增
</el-button> </el-button>
......
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="flex_row">
<div class="flex_left">
<div class="box">
<el-date-picker
style="width: 100%"
type="date"
value-format="YYYY-MM-DD"
v-model="date"
placeholder="请选择日期" />
<div class="type_station bg-scroll">
<div
class="type-box"
:class="{ 'current-type': selectedNodeContainer == item.value }"
@click="nodeClick(item)"
v-for="(item, index) in containerList"
:key="index"
:title="item.name">
{{ item.name }}
</div>
</div>
</div>
</div>
<div class="flex_right">
<div class="form-filter">
<el-form :model="filterForm" inline>
<el-form-item label="级别">
<el-select placeholder="全部" style="width: 160px" v-model="filterForm.level">
<el-option label="info" value="1"> </el-option>
<el-option label="warning" value="2"> </el-option>
<el-option label="error" value="3"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="关键字">
<el-input
placeholder="请输入"
maxlength="100"
style="width: 240px"
v-model="filterForm.search"></el-input>
</el-form-item>
</el-form>
<div class="operate_btns">
<el-button type="primary" @click="search"> 查询 </el-button>
<el-button type="default" @click="reset"> 重置 </el-button>
</div>
</div>
<div class="search-result">
<div class="item-container apaas_scroll">
<p v-for="(item, index) in logList" :key="index">{{ item }}</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, watch, onBeforeMount, toRefs } from "vue";
import { ElMessage } from "element-plus";
import axios from "../../../../request/http.js";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const state = reactive({
date: "",
containerList: [], // 容器数据
selectedNodeContainer: "",
filterForm: {
level: "",
search: "",
},
logList: [],
});
watch(
() => state.date,
(val) => {
state.selectedNodeContainer = "";
getContainerList();
}
);
const nodeClick = (item) => {
state.selectedNodeContainer = item.value;
reset();
};
// 获取容器列表
const getContainerList = () => {
let params = {
date: state.date,
};
axios
.get("/apaas/system/v5/log/system/tree", { params })
.then((res) => {
if (res.data.code == 200) {
state.containerList = res.data.data || [];
state.selectedNodeContainer = state.containerList.length
? state.containerList[0].value
: "";
state.selectedNodeContainer ? reset() : (state.logList = []);
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
console.error(err);
});
};
//查询
const search = () => {
let params = {
index: state.selectedNodeContainer,
...state.filterForm,
};
axios
.get("/apaas/system/v5/log/system/log", { params })
.then((res) => {
if (res.data.code == 200) {
state.logList = (res.data.data || []).map((item) => JSON.stringify(item));
state.logList = state.logList.concat(state.logList);
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
console.error(err);
});
};
//重置
const reset = () => {
state.filterForm = {
level: "",
search: "",
};
search();
};
onBeforeMount(() => {
getContainerList();
});
const { date, containerList, selectedNodeContainer, filterForm, logList } = toRefs(state);
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px;
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
.flex_row {
// flex-grow: 1;
width: 100%;
display: flex;
margin-bottom: 16px;
position: relative;
height: calc(100% - 62px);
.flex_left {
width: 240px;
background-color: #fff;
margin-right: 16px;
border-radius: 6px;
padding: 16px;
height: 100%;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
overflow: hidden;
.box {
width: 208px;
height: 100%;
overflow: hidden;
.type_station {
width: 100%;
margin-top: 16px;
height: calc(100% - 50px);
.type-box {
overflow: hidden;
text-overflow: ellipsis;
height: 32px;
white-space: nowrap;
line-height: 32px;
text-align: center;
font-size: 14px;
color: #404a62;
cursor: pointer;
&:hover {
background-color: #f2f3f7;
}
}
.current-type {
background-color: #f2f3f7;
border-radius: 4px;
}
}
}
}
.flex_right {
flex: 1;
height: 100%;
.form-filter {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
height: 68px;
width: 100%;
padding: 16px 16px 16px 24px;
background-color: #ffffff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
.el-form {
width: calc(100% - 144px);
}
.el-form-item {
margin-bottom: 0px;
}
.operate_btns {
width: 144px;
}
}
.search-result {
width: 100%;
height: calc(100% - 84px);
padding: 15px 0;
color: #fff;
background-color: #1a1a1a;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.1);
border-radius: 6px;
.item-container {
overflow: auto;
padding: 0 15px;
height: 100%;
}
p {
word-wrap: break-word;
word-break: break-all;
}
}
}
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-filter-group
@search="changeSearch"
v-model="filter.search"
placeholder="请输入账号、手机号和所属机构">
<template v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="exportFile">
<bg-icon
style="font-size: 12px; color: #fff; margin-right: 8px"
icon="#bg-ic-file-send"></bg-icon>
导出
</el-button>
<el-popconfirm
class="force-modify-btn"
width="220"
icon-color="#ff9900"
title="确认修改密码吗?"
@confirm="forceModifyPwd">
<template #reference>
<el-button slot="reference" type="primary">
<span>强制修改密码</span>
</el-button>
</template>
</el-popconfirm>
<span class="sleceted_tip"
>已选<span class="num">{{ selectedNum }}</span
></span
>
<span class="clean" @click="cleanSelected">清空</span>
</div>
</template>
<template v-slot:filter_group>
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">用户类型</span>
<el-select v-model="filter.is_admin" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in userTypeList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">上次访问时间</span>
<el-date-picker
v-model="filter.time"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 300px" />
</div>
<div class="filter_item">
<span class="filter_title">活跃度</span>
<el-select v-model="filter.active" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in activeOptions"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">密码强度</span>
<el-select v-model="filter.pwd_level" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in pwdLevelList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</div>
<div class="right-action apaas_button">
<el-button type="primary" @click="filterAction"> 查询 </el-button>
<el-button type="default" @click="filterClear"> 重置 </el-button>
</div>
</template>
</bg-filter-group>
<div class="table_container">
<bg-table
ref="accountTable"
:headers="headers"
:rows="tableRows"
:stripe="true"
select
@selectAc="selectChange">
</bg-table>
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="filter.total"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, ref, computed, onBeforeMount } from "vue";
import { useStore } from "vuex";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { downloadBlob } from "@/services/helper.js";
const { getters } = useStore();
const userTypeList = computed(() => {
const temp = getters.getUserTypeConfig || {};
return Object.keys(temp).map((key) => ({
label: temp[key],
value: +key,
}));
});
const accountTable = ref(null);
const state = reactive({
filter: {
search: "",
is_admin: "",
time: [],
active: 0,
pwd_level: "",
page: 1,
limit: 10,
total: 0,
},
activeOptions: [
{ label: "全部", value: "" },
{ label: "", value: 1 },
{ label: "", value: 2 },
{ label: "", value: 3 },
],
pwdLevelList: [
{ label: "全部", value: "" },
{ label: "", value: 1 },
{ label: "", value: 2 },
{ label: "", value: 3 },
],
headers: [
{
label: "账号",
prop: "system_account",
// minWidth: 280,
},
{
label: "手机号",
prop: "contact_phone",
// minWidth: 360,
},
{
label: "用户类型",
prop: "is_admin",
// width: 200,
},
{
label: "所属机构",
prop: "name",
// width: 120,
},
{
label: "活跃度",
prop: "active",
// width: 120,
},
{
label: "密码强度",
prop: "pwd_level",
width: 240,
},
{
label: "密码使用时长(天)",
prop: "pwd_is_used",
width: 240,
},
{
label: "创建时间",
prop: "created_time",
width: 240,
},
],
tableRows: [],
//选中数量
selectedNum: 0,
actionRow: {},
dialogDetail: false,
cacheDialog: false,
});
const { filter, activeOptions, pwdLevelList, headers, tableRows, selectedNum } = toRefs(state);
//选择项发生变化
const selectChange = (params) => {
state.selectedNum = params.allLength;
};
//导出
const exportFile = () => {
let params = { ...state.filter };
params.start_at = params.time ? params.time[0] || "" : "";
params.end_at = params.time ? params.time[1] || "" : "";
delete params.time;
axios
.get(`/apaas/system/v5/log/userAccountAudit/list/export`, {
params,
responseType: "blob",
})
.then((res) => {
if (res.status === 200) {
const type =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
downloadBlob(res.data, type);
} else {
ElMessage.error(res.statusText);
}
});
};
//强制修改密码
const forceModifyPwd = () => {
const selectedObj = accountTable.value.dealSelectData();
const selectedRows = Object.values(selectedObj);
if (!selectedRows.length) return ElMessage.warning("请先选择修改项");
const ids = selectedRows.map((item) => item.id);
axios.post("/apaas/system/v5/user/resetpwd", { ids }).then((res) => {
if (res.data.code === 200) {
ElMessage.success(res.data.msg);
cleanSelected();
getTableRows();
} else {
ElMessage.error(res.data.data);
}
});
};
//清空
const cleanSelected = () => {
accountTable.value.clearTable();
};
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
};
const changePage = (page) => {
state.filter.page = page;
getTableRows();
};
const getTableRows = () => {
let params = { ...state.filter };
params.start_at = params.time ? params.time[0] || "" : "";
params.end_at = params.time ? params.time[1] || "" : "";
delete params.time;
axios
.get(`/apaas/system/v5/log/userAccountAudit/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.filter.total = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
const filterAction = () => {
changePage(1);
};
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
};
const filterClear = () => {
state.filter = {
search: "",
is_admin: "",
time: [],
active: 0,
pwd_level: "",
page: 1,
limit: 10,
total: 0,
};
changePage(1);
};
onBeforeMount(() => {
getTableRows();
});
</script>
<style lang="scss" scoped>
.page_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
width: 100%;
padding: 0 24px;
min-height: 100%;
.main_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
flex-grow: 1;
width: 100%;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
padding: 0 0 16px 0;
margin-bottom: 16px;
position: relative;
.sleceted_tip {
margin: 0 24px 0 40px;
vertical-align: middle;
font-size: 14px;
color: #404a62;
.num {
margin: 0 3px 0 3px;
font-weight: 600;
color: #202531;
}
}
.clean {
vertical-align: middle;
font-size: 14px;
color: #3759be;
cursor: pointer;
}
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
.filter_item {
display: flex;
align-items: center;
.filter_title {
width: 84px;
white-space: pre-wrap;
font-weight: normal;
}
}
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
padding: 0 16px;
.el-table {
flex: 1;
.circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 3px;
margin-right: 8px;
transform: translateY(-2px);
}
.bgc_1 {
background-color: #48ad97;
}
.bgc_2 {
background-color: #d75138;
}
.bgc_3 {
background-color: #3759be;
}
.bgc_4 {
background-color: #ea7d19;
}
.bgc_0 {
background-color: #9e9e9e;
}
.mock_tip {
display: inline-block;
margin-left: 4px;
width: 43px;
height: 20px;
font-size: 12px;
color: #2b4695;
text-align: center;
background-color: #eff2fa;
border-radius: 3px;
border: solid 1px #b0bee8;
}
:deep() td {
padding: 9px 0 !important;
}
:deep() .el-switch {
height: 20px;
width: 44px;
.el-switch__core {
height: 20px;
min-width: 44px;
}
}
}
}
}
:deep() .dialog_box_detail {
.el-dialog__body {
padding: 0 0 18px 0;
height: 580px;
}
.form_filter {
display: flex;
justify-content: space-between;
align-items: center;
height: 69px;
border-bottom: 1px solid #e6e9ef;
.right {
margin-right: 16px;
.el-button {
width: 64px;
&:last-child {
margin-left: 16px;
}
}
}
}
.table_content {
padding: 0 16px;
}
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content">
<bg-form-gap title="详情"></bg-form-gap>
<bg-detail-table2 class="detail_info" :list="instanceData.detailInfo"> </bg-detail-table2>
</div>
</div>
</template>
<script setup>
import { reactive, onBeforeMount } from "vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import { useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const route = useRoute();
const instanceData = reactive({
detailInfo: [
{
key: "system_account",
label: "账号",
value: "",
// slot: "approvalStatus",
},
{
key: "phone",
label: "手机号",
value: "",
},
{
key: "user_type",
label: "用户类型",
value: "",
},
{
key: "org_name",
label: "所属机构",
value: "",
},
{
key: "system_module",
label: "系统模块",
value: "",
},
{
key: "created_time",
label: "操作时间",
value: "",
},
{
key: "operate_type",
label: "操作类型",
value: "",
},
{
key: "req_method_str",
label: "请求方式",
value: "",
},
{
key: "operate_status_str",
label: "操作状态",
value: "",
},
{
key: "operate_ip",
label: "操作地址",
value: "",
},
{
key: "operate_addr",
label: "操作地点",
value: "",
width: "100%",
},
{
key: "req_url",
label: "请求地址",
value: "",
width: "100%",
},
{
key: "req_param",
label: "请求参数",
value: "",
},
{
key: "operate_method",
label: "操作方法",
value: "",
},
{
key: "res_fields",
label: "返回参数",
value: "",
},
],
});
onBeforeMount(() => {
getDetailInfo();
});
const getDetailInfo = () => {
axios
.get(`/apaas/system/v5/log/userBehavior/detail/${route.query.id}`)
.then((res) => {
if (res.data.code == 200) {
const result = res.data.data || {};
instanceData.detailInfo.forEach((item) => {
item.value = result[item.key];
});
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
ElMessage.error(err);
});
};
</script>
<style lang="scss" scoped>
.page_content {
position: relative;
padding: 24px 0 68px 24px;
.detail_info,
.approve_info {
margin-bottom: 24px;
width: 960px;
}
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-filter-group
@search="changeSearch"
v-model="filter.search"
placeholder="请输入账号、手机号和所属机构">
<template v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="exportFile">
<bg-icon
style="font-size: 12px; color: #fff; margin-right: 8px"
icon="#bg-ic-file-send"></bg-icon>
导出
</el-button>
<el-button @click="deleteBatch"> 批量删除 </el-button>
<span class="sleceted_tip"
>已选<span class="num">{{ selectedNum }}</span
></span
>
<span class="clean" @click="cleanSelected">清空</span>
</div>
</template>
<template v-slot:filter_group>
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">用户类型</span>
<el-select v-model="filter.is_admin" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in userTypeList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">操作时间</span>
<el-date-picker
v-model="filter.time"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 300px" />
</div>
<div class="filter_item">
<span class="filter_title">操作类型</span>
<el-select v-model="filter.operate_type" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in operateTypeList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">请求方式</span>
<el-select v-model="filter.req_method" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in reqMethodList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">操作状态</span>
<el-select v-model="filter.operate_status" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in operateStatusList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</div>
<div class="right-action apaas_button">
<el-button type="primary" @click="filterAction"> 查询 </el-button>
<el-button type="default" @click="filterClear"> 重置 </el-button>
</div>
</template>
</bg-filter-group>
<div class="table_container">
<bg-table
ref="userTable"
:headers="headers"
:rows="tableRows"
:stripe="true"
select
@selectAc="selectChange">
<template v-slot:is_admin="{ row }">
<span>{{ userTypeConfig[row.is_admin] }}</span>
</template>
<template v-slot:req_method="{ row }"
><span>{{ filterReqMethod(row.req_method) }}</span></template
>
<template v-slot:operate_status="{ row }">{{
filterOperateStatus(row.req_method)
}}</template>
<template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :key="row.id">
<bg-table-btn @click="goDetail(row)">详情</bg-table-btn>
<bg-table-btn @click="deleteCurrent(row)">删除</bg-table-btn>
</bg-table-btns2>
</template>
</bg-table>
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="filter.total"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
<el-dialog class="dialog_box" title="提示" v-model="deleteDialog" width="400px">
<div style="font-size: 16px; color: #404a62">{{ deleteTips }}</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="deleteDialog = false">取 消</el-button>
<el-button type="primary" @click="confirmDelete">确 定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { reactive, ref, toRefs, computed, onBeforeMount } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { operateTypeList, reqMethodList } from "@/services/enumList.js";
import { downloadBlob } from "@/services/helper.js";
const { getters } = useStore();
const router = useRouter();
const userTable = ref(null);
const userTypeConfig = computed(() => getters.getUserTypeConfig || {});
const userTypeList = computed(() => {
const temp = getters.getUserTypeConfig || {};
return Object.keys(temp).map((key) => ({
label: temp[key],
value: +key,
}));
});
const state = reactive({
filter: {
search: "",
is_admin: "",
time: [],
operate_type: "",
req_method: "",
operate_status: "",
page: 1,
limit: 10,
total: 0,
},
operateStatusList: [
{ label: "全部", value: "" },
{ label: "成功", value: 1 },
{ label: "失败", value: 2 },
],
headers: [
{
label: "账号",
prop: "system_account",
// minWidth: 280,
},
{
label: "用户类型",
prop: "is_admin",
// minWidth: 360,
},
{
label: "系统模块",
prop: "system_module",
// width: 200,
},
{
label: "操作类型",
prop: "operate_type",
// width: 120,
},
{
label: "请求方式",
prop: "req_method",
// width: 120,
},
{
label: "操作状态",
prop: "operate_status",
// width: 240,
},
{
label: "操作地点",
prop: "operate_addr",
// width: 240,
},
{
label: "操作时间",
prop: "created_time",
// width: 240,
},
{
label: "操作",
prop: "action",
width: 120,
},
],
//选中数量
selectedNum: 0,
detailHeaders: [
{
label: "账号",
prop: "ability_name",
// minWidth: 280,
},
{
label: "类型",
prop: "synopsis",
// minWidth: 360,
},
{
label: "用户手机号",
prop: "created_time",
// width: 200,
},
{
label: "所属组织",
prop: "ability_state",
// width: 120,
},
],
tableRows: [],
tableTotal: 0,
//选中项
selectedRows: [],
actionRow: {},
dialogDetail: false,
deleteDialog: false,
deleteTips: "",
});
const { filter, operateStatusList, headers, selectedNum, tableRows, deleteDialog, deleteTips } =
toRefs(state);
//导出
const exportFile = () => {
let params = { ...state.filter };
params.start_at = params.time ? params.time[0] || "" : "";
params.end_at = params.time ? params.time[1] || "" : "";
delete params.time;
delete params.total;
axios
.get(`/apaas/system/v5/log/userBehavior/list/export`, {
params,
responseType: "blob",
})
.then((res) => {
if (res.status === 200) {
const type =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
downloadBlob(res.data, type);
} else {
ElMessage.error(res.statusText);
}
});
};
//请求方式过滤器
const filterReqMethod = (value) => {
const findItem = reqMethodList.find((item) => item.value === value);
return (findItem || {}).label;
};
//操作状态过滤器
const filterOperateStatus = (value) => {
const findItem = operateTypeList.find((item) => item.value === value);
return (findItem || {}).label;
};
//选择项发生变化
const selectChange = (params) => {
state.selectedNum = params.allLength;
};
//批量删除
const deleteBatch = () => {
state.selectedRows = [];
const selectedObj = userTable.value.dealSelectData();
state.selectedRows = Object.values(selectedObj);
if (!state.selectedRows.length) return ElMessage.warning("请先选择删除项");
state.deleteTips = "确定要删除选中项吗?";
state.deleteDialog = true;
};
//删除当前行
const deleteCurrent = (row) => {
state.selectedRows = [row];
state.deleteTips = "确定要删除当前行吗?";
state.deleteDialog = true;
};
//确定删除
const confirmDelete = () => {
const ids = state.selectedRows.map((item) => item.id);
axios
.delete(`/apaas/system/v5/log/userBehavior/delete?ids=${ids.join(",")}`)
.then((res) => {
if (res.data.code === 200) {
ElMessage.success(res.data.data);
cleanSelected();
getTableRows();
} else {
ElMessage.error(res.data.data);
}
})
.finally(() => {
state.deleteDialog = false;
});
};
//清空
const cleanSelected = () => {
userTable.value.clearTable();
};
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
};
const changePage = (page) => {
state.filter.page = page;
getTableRows();
};
const getTableRows = () => {
let params = { ...state.filter };
params.start_at = params.time ? params.time[0] || "" : "";
params.end_at = params.time ? params.time[1] || "" : "";
delete params.time;
axios
.get(`/apaas/system/v5/log/userBehavior/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.filter.total = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
const filterAction = () => {
changePage(1);
};
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
};
const filterClear = () => {
state.filter = {
search: "",
is_admin: "",
time: [],
operate_type: "",
req_method: "",
operate_status: "",
page: 1,
limit: 10,
total: 0,
};
changePage(1);
};
const goDetail = (row) => {
router.push({
path: "/log/userBehavior/detail",
query: {
id: row.id,
},
});
};
onBeforeMount(() => {
getTableRows();
});
</script>
<style lang="scss" scoped>
.page_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
width: 100%;
padding: 0 24px;
min-height: 100%;
.main_container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
flex-grow: 1;
width: 100%;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
padding: 0 0 16px 0;
margin-bottom: 16px;
position: relative;
.sleceted_tip {
margin: 0 24px 0 40px;
vertical-align: middle;
font-size: 14px;
color: #404a62;
.num {
margin: 0 3px 0 3px;
font-weight: 600;
color: #202531;
}
}
.clean {
vertical-align: middle;
font-size: 14px;
color: #3759be;
cursor: pointer;
}
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
.filter_item {
display: flex;
align-items: center;
.filter_title {
width: 84px;
white-space: pre-wrap;
font-weight: normal;
}
}
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
padding: 0 16px;
.el-table {
flex: 1;
.circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 3px;
margin-right: 8px;
transform: translateY(-2px);
}
.bgc_1 {
background-color: #48ad97;
}
.bgc_2 {
background-color: #d75138;
}
.bgc_3 {
background-color: #3759be;
}
.bgc_4 {
background-color: #ea7d19;
}
.bgc_0 {
background-color: #9e9e9e;
}
.mock_tip {
display: inline-block;
margin-left: 4px;
width: 43px;
height: 20px;
font-size: 12px;
color: #2b4695;
text-align: center;
background-color: #eff2fa;
border-radius: 3px;
border: solid 1px #b0bee8;
}
:deep() td {
padding: 9px 0 !important;
}
:deep() .el-switch {
height: 20px;
width: 44px;
.el-switch__core {
height: 20px;
min-width: 44px;
}
}
}
}
}
:deep() .dialog_box_detail {
.el-dialog__body {
padding: 0 0 18px 0;
height: 580px;
}
.form_filter {
display: flex;
justify-content: space-between;
align-items: center;
height: 69px;
border-bottom: 1px solid #e6e9ef;
.right {
margin-right: 16px;
.el-button {
width: 64px;
&:last-child {
margin-left: 16px;
}
}
}
}
.table_content {
padding: 0 16px;
}
}
}
</style>
...@@ -34,12 +34,12 @@ ...@@ -34,12 +34,12 @@
<bg-filter-group @search="changeSearch" v-model="filter.key_word" placeholder="请输入关键字"> <bg-filter-group @search="changeSearch" v-model="filter.key_word" placeholder="请输入关键字">
<template v-slot:left_action> <template v-slot:left_action>
<div class="apaas_button"> <div class="apaas_button">
<el-button class="register_btn" type="primary" @click="addAccount"> <el-button type="primary" @click="addAccount">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
{{ selectTreeDataType === 1 ? "新增组织管理员" : "新增平台用户" }} {{ selectTreeDataType === 1 ? "新增组织管理员" : "新增平台用户" }}
</el-button> </el-button>
<el-button class="register_btn" @click="deleteBatch"> 批量删除 </el-button> <el-button @click="deleteBatch"> 批量删除 </el-button>
<el-button class="register_btn" @click="resetPsd"> 重置密码 </el-button> <el-button @click="resetPsd"> 重置密码 </el-button>
<span class="header_info" <span class="header_info"
>已选择<span style="color: #202531; font-weight: bold">{{ selected.length }}</span >已选择<span style="color: #202531; font-weight: bold">{{ selected.length }}</span
></span ></span
......
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入角色名称"> <bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入角色名称">
<template v-slot:left_action> <template v-slot:left_action>
<div class="apaas_button"> <div class="apaas_button">
<el-button class="register_btn" type="primary" @click="register"> <el-button type="primary" @click="register">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon> <bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增 新增
</el-button> </el-button>
<el-button class="register_btn" type="primary" @click="deleteRows"> 批量删除 </el-button> <el-button type="primary" @click="deleteRows"> 批量删除 </el-button>
<div class="select_text"> <div class="select_text">
<span>已选择</span> <span>已选择</span>
<span class="num">{{ selection.length }}</span> <span class="num">{{ selection.length }}</span>
......
<template>
<el-form
:label-position="'right'"
label-width="120px"
:model="accountForm"
:rules="formRules"
ref="accountRef"
style="max-width: 90%">
<el-form-item label="手机号" prop="phone">
<el-input v-model="accountForm.phone" @input="phoneChange" />
</el-form-item>
<el-form-item label="账号" prop="account">
<el-input v-model="accountForm.account" disabled />
</el-form-item>
<el-form-item label="验证码" prop="code">
<div class="msg-code">
<el-input v-model="accountForm.code" placeholder="请输入" style="860px"> </el-input>
<div class="yzm_img">
<el-button type="primary" :disabled="countDown > 0" @click.prevent="getMsgCode()" style="width: 100%; height: 34px">
{{ countDown > 0 ? countDown + "秒后再次获取" : "发送验证码" }}
</el-button>
</div>
</div>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onBeforeMount, onMounted, computed } from "vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { validatePhone } from "@/services/rules.js";
const props = defineProps({});
const accountForm = reactive({
phone: "",
account: "",
code: "",
});
const formRules = reactive({
phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{ validator: validatePhone, trigger: "blur" },
],
account: [{ required: true, message: "请输入账号", trigger: "blur" }],
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
});
const countDown = ref(0);
const countDownTimer = ref(null);
const accountRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!accountRef) return;
await accountRef.value.validate((valid, fields) => {
if (valid) {
emit("action", accountForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!accountRef) return;
accountRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(accountForm, data);
};
const getMsgCode = () => {
if (accountForm.account) {
axios.post("/apaas/system/v5/sms/verifyCode", { phone: accountForm.phone }).then(({ data }) => {
if (data.code == 200) {
countDownAction();
} else {
ElMessage.error(data.data);
}
});
} else {
ElMessage.error("该手机号未注册,请核对手机号!");
}
}; // 获取验证码
const countDownAction = () => {
countDown.value = 60;
if (countDownTimer.value) {
clearInterval(countDownTimer.value);
}
countDownTimer.value = setInterval(() => {
if (countDown.value > 0) {
countDown.value--;
} else {
clearInterval(countDownTimer.value);
}
}, 1000);
};
const phoneChange = () => {
if (accountForm.phone.length > 10) {
accountRef.value.validateField("phone").then((valid) => {
if (valid) {
axios.get(`/apaas/system/v5/user/phoneToAccount?phone=${accountForm.phone}`).then((res) => {
if (res.data.code == 200) {
accountForm.account = res.data.data || "";
} else {
ElMessage.error(res.data.data);
}
});
}
});
}
};
onBeforeMount(() => {});
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<style lang="scss" scoped>
.msg-code {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.yzm_img {
flex: 1;
margin-left: 20px;
}
}
</style>
<template>
<div class="password_container">
<div class="bg-breadcrumb">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/login' }"> 登录 </el-breadcrumb-item>
<el-breadcrumb-item> 忘记密码 </el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="page_content flex_cloumn">
<div class="content_top apaas_scroll">
<div class="content_process">
<div>
<el-steps :active="step">
<el-step title="" :class="{ process_complete: step > 1 }">
<template #icon>
<span class="process_desc">
<span class="icon_box" v-if="step > 0"
><bg-icon class="step_icon" icon="#bg-ic-file-editing"></bg-icon
></span>
<span class="circle" v-else></span>
验证账号
</span>
</template>
</el-step>
<el-step title="" :class="{ process_complete: step > 2 }">
<template #icon>
<span class="process_desc">
<span class="icon_box" v-if="step > 1"
><bg-icon class="step_icon" icon="#bg-ic-file-lock"></bg-icon
></span>
<span class="circle" v-else></span>
确认密码
</span>
</template>
</el-step>
<el-step title="">
<template #icon>
<span class="process_desc">
<span class="icon_box" v-if="step > 2"
><bg-icon class="step_icon" icon="#bg-ic-file-success"></bg-icon
></span>
<span class="circle" v-else></span>
完成
</span>
</template>
</el-step>
</el-steps>
</div>
</div>
<div class="content_main">
<accountFrom
v-show="step === 1"
ref="accountFromRef"
:form-type="route.query.id ? true : false"
@action="getAccountFromData"></accountFrom>
<passwordForm
v-show="step === 2"
ref="passwordFormRef"
@action="getPasswordFormData"></passwordForm>
<div class="process_end" v-show="step === 3">
<div>
<div>
<img v-if="successFlag" src="@/assets/imgs/img_data-complete.png" alt="" />
<img v-else src="@/assets/imgs/img_data-fail.png" alt="" />
</div>
<div class="font_bold">
{{ successFlag ? "密码修改成功" : "密码修改失败" }}
</div>
<el-button type="primary" @click="cancel">返回登录页</el-button>
<el-button type="primary" @click="continueEdit">重新修改</el-button>
</div>
</div>
</div>
</div>
<div class="content_bottom" v-if="step !== 3">
<div v-show="step === 1">
<el-button @click="cancel">返回登录页</el-button>
<el-button type="primary" @click="nextStep">下一步</el-button>
</div>
<div v-show="step === 2">
<el-button @click="cancel">返回登录页</el-button>
<el-button type="primary" @click="previousStep">上一步</el-button>
<el-button type="primary" @click="submit">提交</el-button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { useRoute, useRouter } from "vue-router";
import accountFrom from "./account-form.vue";
import passwordForm from "./password-form.vue";
import { reactive, ref, onBeforeMount, toRefs, computed, onBeforeUnmount, onMounted } from "vue";
import CryptoJS from "crypto-js";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { Encrypt } from "@/services/secret.js";
const route = useRoute();
const router = useRouter();
const step = ref(1);
const accountFromRef = ref(null);
const passwordFormRef = ref(null);
const formData = reactive({
phone: "",
account: "",
code: "",
new_password: "",
});
const successFlag = ref(false);
// 下一步
const nextStep = () => {
accountFromRef.value.submitForm();
};
//验证账号表单检验触发事件 data为null 校验失败
const getAccountFromData = (data) => {
if (data) {
Object.assign(formData, data);
step.value = 2;
//校验手机号验证码 未出接口
} else {
}
};
//密码表单检验触发事件 data为null 校验失败
const getPasswordFormData = (data) => {
if (data) {
Object.assign(formData, data);
let params = {
phone: formData.phone,
password: Encrypt(formData.new_password),
};
axios.post(`/apaas/system/v5/user/update/pwd`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
} else {
ElMessage.error(res.data.data);
}
step.value = 3;
});
}
};
//上一步
const previousStep = () => {
step.value--;
};
//提交表单
const submit = () => {
passwordFormRef.value.submitForm();
};
//继续创建 清空表单
const continueEdit = () => {
accountFromRef.value.clearForm();
passwordFormRef.value.clearForm();
step.value = 1;
successFlag.value = false;
};
//取消
const cancel = () => {
router.go(-1);
};
onBeforeUnmount(() => {});
onMounted(() => {});
</script>
<style scoped>
.password_container {
margin: 0 auto;
width: 1200px;
height: 70%;
}
.flex_cloumn {
display: flex;
flex-direction: column;
}
.content_top {
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
}
/* .content_top::-webkit-scrollbar {
width: 5px;
height: 0px;
}
.content_top::-webkit-scrollbar-thumb {
background: #dedede;
border-radius: 10px;
height: 0px;
}
.content_top::-webkit-scrollbar-track {
background: transparent;
border-radius: 2px;
} */
.content_bottom {
height: 68px;
line-height: 68px;
text-align: right;
padding: 0 20px;
border-top: 1px solid #e6e9ef;
}
.content_process {
border-bottom: 1px solid #e6e9ef;
padding: 38px 16%;
}
.content_main {
flex: 1;
padding: 30px;
box-sizing: border-box;
}
.process_desc {
background-color: #fff;
display: inline-block;
position: absolute;
padding: 0 5px;
font-size: 18px;
color: #202531;
font-weight: bold;
}
.process_desc img {
height: 25px;
width: 25px;
vertical-align: middle;
}
.process_end {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.process_end div {
text-align: center;
}
.step_icon {
color: #fff;
font-weight: 600;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.icon_box {
display: inline-block;
background-color: #2b4695;
width: 48px;
height: 48px;
border-radius: 99px;
position: relative;
border: 3px solid #b0bee8;
vertical-align: middle;
}
.circle {
display: inline-block;
background-color: #a9b1c7;
width: 24px;
height: 24px;
border-radius: 99px;
position: relative;
border: 4px solid #e6e9ef;
vertical-align: middle;
}
.content_process :deep() .el-step.is-horizontal .el-step__line {
height: 4px;
}
.content_process :deep() .el-step__head.is-finish .el-step__line {
background: linear-gradient(to right, #2b4695 50%, #e6e9ef 50%);
}
.process_complete :deep() .el-step__head.is-finish .el-step__line {
background: linear-gradient(to right, #2b4695 100%, #e6e9ef 0%);
}
</style>
<template>
<el-form
:label-position="'right'"
label-width="120px"
:model="passwordForm"
:rules="passwordFormRules"
ref="passwordRef"
style="max-width: 90%">
<el-form-item label="新密码" prop="new_password">
<el-input type="password" v-model="passwordForm.new_password" />
</el-form-item>
<el-form-item label="确认密码" prop="confirm_password">
<el-input type="password" v-model="passwordForm.confirm_password" />
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
const passwordForm = reactive({
new_password: "",
confirm_password: "",
});
const props = defineProps({});
const validatePass = (rule, value, callback) => {
if (value !== passwordForm.new_password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const passwordFormRules = reactive({
new_password: [
{ required: true, message: "请输入新密码", trigger: "blur" },
{ min: 8, message: "密码长度不得低于8位", trigger: "blur" },
],
confirm_password: [
{ required: true, message: "请确认密码", trigger: "blur" },
{ validator: validatePass, trigger: "blur" },
],
});
const passwordRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!passwordRef) return;
await passwordRef.value.validate((valid, fields) => {
if (valid) {
emit("action", passwordForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!passwordRef) return;
passwordRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(passwordForm, data);
};
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<div class="registe-container">
<div class="bg-breadcrumb">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/login' }"> 登录 </el-breadcrumb-item>
<el-breadcrumb-item> 注册 </el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="registe-content">
<div class="registe-header">
<div>业务系统注册</div>
<div class="registe-heade-sub">注册信息提示审批后即可登录</div>
</div>
<div class="registe-form">
<el-form ref="infoFormRef" :model="infoForm" label-width="120px" :rules="infoFormRules" style="width: 90%">
<div class="registe-info">
<div class="title">
<div><span class="icon_box"></span> 基础信息</div>
<div class="dashed_line"></div>
</div>
<div class="info-form">
<el-form-item prop="organization_id" label="所属机构">
<el-tree-select
v-model="infoForm.organization_id"
:data="orgData"
:props="treeProps"
:render-after-expand="false"
filterable
style="width: 100%" />
</el-form-item>
<el-form-item prop="business_name" label="业务系统名称">
<el-input v-model="infoForm.business_name" placeholder="请输入" maxlength="20" show-word-limit />
</el-form-item>
<el-form-item prop="develop_id" label="开发厂商名称">
<el-select v-model="infoForm.develop_id" placeholder="请选择,如需新增,请输入任意字符" filterable style="width: 100%">
<el-option
v-for="item in developList"
:key="'develop_' + item.dict_id"
:label="item.dict_name"
:value="item.dict_id" />
<template #empty>
<div class="select-empty">
<div>无匹配数据</div>
<el-button style="height: 32px; margin-top: 10px" @click="addDevelop"> 新增</el-button>
</div>
</template>
</el-select>
</el-form-item>
<el-form-item prop="system_account" label="账号">
<el-input v-model="infoForm.system_account" placeholder="请输入" />
</el-form-item>
<el-form-item prop="password" label="密码">
<el-input type="password" v-model="infoForm.password" placeholder="请输入" />
</el-form-item>
<el-form-item prop="confirm_password" label="确认密码">
<el-input type="password" v-model="infoForm.confirm_password" placeholder="请输入" />
</el-form-item>
<el-form-item prop="phone" label="手机号">
<el-input v-model="infoForm.phone" placeholder="请输入" />
</el-form-item>
<el-form-item prop="code" label="验证码">
<div class="msg-code">
<el-input v-model="infoForm.code" placeholder="请输入" style="860px"> </el-input>
<div class="yzm_img">
<el-button
type="primary"
style="width: 100%; height: 34px"
@click="sendSms"
:disabled="countDown > 0">
{{ countDown > 0 ? countDown + "秒后再次获取" : "发送验证码" }}
</el-button>
</div>
</div>
</el-form-item>
<el-form-item prop="business_desc" label="业务系统概述">
<el-input
type="textarea"
:rows="4"
v-model="infoForm.business_desc"
placeholder="请输入"
maxlength="200"
show-word-limit />
</el-form-item>
</div>
</div>
<div class="registe-info">
<div class="title">
<div><span class="icon_box"></span> 联系人信息</div>
<div class="dashed_line"></div>
</div>
<div class="info-form">
<el-form-item prop="contact_name" label="联系人">
<el-input v-model="infoForm.contact_name" placeholder="请输入" />
</el-form-item>
<el-form-item prop="contact_phone" label="联系电话">
<el-input v-model="infoForm.contact_phone" placeholder="请输入" />
</el-form-item>
</div>
</div>
</el-form>
</div>
<div class="registe-footer">
<el-button @click="router.go(-1)">返回登录页</el-button>
<el-button type="primary" @click="submit">注册</el-button>
</div>
</div>
<el-dialog v-model="dialogVisit" title="新增" width="520px" :before-close="handleCloseDialog" destroy-on-close>
<div class="dialog_form">
<el-form
ref="developFormRef"
:model="developForm"
label-width="120px"
:rules="developFormRules"
style="width: 90%">
<el-form-item prop="develop" label="开发厂商名称">
<el-input v-model="developForm.develop" placeholder="请输入" />
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDialog">取消</el-button>
<el-button type="primary" @click="confirmAdd">确认</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, onMounted, reactive, toRefs } from "vue";
import { useRouter } from "vue-router";
import axios from "@/request/http.js";
import { Encrypt } from "@/services/secret.js";
import { ElMessage } from "element-plus";
import { validatePhone } from "@/services/rules.js";
const validateBusinessName = (rule, value, callback) => {
let reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母、数字和汉字"));
} else {
let params = { business_name: value };
axios.post(`/apaas/system/v5/user/checkBusiness`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
}
};
const validateSystemAccount = (rule, value, callback) => {
let reg = /^[a-zA-Z0-9]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母和数字"));
} else {
let params = { system_account: value };
axios.post(`/apaas/system/v5/user/checkAccount`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
}
};
const checkPhoneRepet = (rule, value, callback) => {
let params = { phone: value };
axios.post(`/apaas/system/v5/user/checkPhone`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
};
const validatePass = (rule, value, callback) => {
if (value !== state.infoForm.password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const router = useRouter();
const state = reactive({
infoForm: {
organization_id: "",
business_name: "",
develop_id: "",
system_account: "",
password: "",
confirm_password: "",
phone: "",
code: "",
business_desc: "",
contact_name: "",
contact_phone: "",
},
infoFormRules: {
organization_id: [{ required: true, message: "请选择开发厂商", trigger: "blur" }],
business_name: [
{ required: true, message: "请输入业务系统名称", trigger: "blur" },
{ validator: validateBusinessName, trigger: "blur" },
],
develop_id: [{ required: true, message: "请选择开发厂商", trigger: "blur" }],
system_account: [
{ required: true, message: "请输入账号", trigger: "blur" },
{ min: 4, message: "帐号长度不得低于4个字符", trigger: "blur" },
{ max: 20, message: "帐号最大长度为20个字符", trigger: "blur" },
{ validator: validateSystemAccount, trigger: "blur" },
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 8, message: "密码长度不得低于8位", trigger: "blur" },
],
confirm_password: [
{ required: true, message: "请确认密码", trigger: "blur" },
{ validator: validatePass, trigger: "blur" },
],
phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{ validator: validatePhone, trigger: "blur" },
{ validator: checkPhoneRepet, trigger: "blur" },
],
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
contact_name: [{ required: true, message: "请输入联系人", trigger: "blur" }],
contact_phone: [
{ required: true, message: "请输入联系电话", trigger: "blur" },
{ validator: validatePhone, trigger: "blur" },
],
},
developForm: {
develop: "",
},
developFormRules: {
develop: [{ required: true, message: "请输入开发厂商名称", trigger: "blur" }],
},
dialogVisit: false,
countDown: 0,
countDownTimer: null,
orgData: [],
developList: [],
});
const treeProps = {
label: "name",
children: "Child",
value: "organization_id",
};
// const loading = ref(false)
const list = ref([]);
const infoFormRef = ref(null);
const developFormRef = ref(null);
// const remoteMethod = (query) => {
// if (query) {
// loading.value = true
// setTimeout(() => {
// loading.value = false
// state.devOptions = state.developList.filter((item) => {
// return item.dict_name.includes(query)
// })
// }, 200)
// } else {
// state.devOptions = []
// }
// }
const submit = () => {
infoFormRef.value.validate((valid) => {
if (valid) {
const params = {
organization_id: state.infoForm.organization_id,
business_name: state.infoForm.business_name,
business_desc: state.infoForm.business_desc,
system_account: state.infoForm.system_account,
password: Encrypt(state.infoForm.password),
develop_id: state.infoForm.develop_id.toString(),
contact_name: state.infoForm.contact_name,
contact_phone: state.infoForm.contact_phone,
phone: state.infoForm.phone,
code: state.infoForm.code,
};
axios.post("/apaas/system/v5/user/register", params).then(({ data }) => {
if (data.code == 200) {
ElMessage.success("注册信息已提交!");
router.go(-1);
} else {
ElMessage.error(data.data);
}
});
}
});
};
const sendSms = () => {
infoFormRef.value.validateField("phone", (valid) => {
if (valid) {
axios.post("/apaas/system/v5/sms/verifyCode", { phone: state.infoForm.phone }).then(({ data }) => {
if (data.code == 200) {
countDownAction();
}
});
}
});
};
const countDownAction = () => {
state.countDown = 60;
if (state.countDownTimer) {
clearInterval(state.countDownTimer);
}
state.countDownTimer = setInterval(() => {
if (state.countDown > 0) {
state.countDown--;
} else {
clearInterval(state.countDownTimer);
}
}, 1000);
};
const addDevelop = () => {
state.dialogVisit = true;
};
const handleCloseDialog = () => {
state.dialogVisit = false;
};
const confirmAdd = () => {
developFormRef.value.validate((valid) => {
if (valid) {
axios
.post("/apaas/system/v5/user/dict/develop/add", { dict_name: state.developForm.develop })
.then(({ data }) => {
if (data.code == 200) {
state.infoForm.develop_id = data.data;
getDevelopList();
} else {
ElMessage.error(data.data);
}
handleCloseDialog();
});
}
});
};
const getOrgData = () => {
axios.get("/apaas/system/v5/user/org/tree").then(({ data }) => {
if (data.code == 200) {
state.orgData = data.data || [];
}
});
};
const getDevelopList = () => {
axios.get("/apaas/system/v5/user/dict/develop").then(({ data }) => {
if (data.code == 200) {
state.developList = data.data || [];
}
});
};
onMounted(() => {
getOrgData();
getDevelopList();
});
const {
infoForm,
infoFormRules,
dialogVisit,
developForm,
developFormRules,
countDown,
countDownTimer,
orgData,
developList,
} = toRefs(state);
</script>
<style lang="scss" scoped>
.registe-container {
margin: 0 auto;
width: 1200px;
height: 100%;
.registe-content {
background-color: #ffffff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
// height: calc(100% - 100px);
.registe-header {
padding: 20px 0;
text-align: center;
font-size: 22px;
color: #1a1a1a;
font-weight: bold;
.registe-heade-sub {
font-size: 14px;
font-weight: 400;
color: #404a62;
padding: 10px 0;
}
}
.registe-form {
padding: 0 24px;
.title {
font-size: 18px;
color: #1a1a1a;
font-weight: 600;
margin-bottom: 10px;
display: flex;
align-items: center;
.icon_box {
display: inline-block;
width: 4px;
height: 14px;
background-color: #3759be;
border-radius: 2px;
margin-right: 5px;
}
.dashed_line {
flex: 1;
height: 1px;
margin: 0 10px;
border-bottom: dashed 1px #dadee7;
}
}
.msg-code {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.yzm_img {
flex: 1;
margin-left: 20px;
}
}
}
.registe-footer {
border-top: solid 1px #e6e9ef;
text-align: right;
padding: 24px;
}
}
.dialog_form {
margin: 20px 0;
}
}
</style>
...@@ -2,111 +2,130 @@ ...@@ -2,111 +2,130 @@
* axios封装 * axios封装
* 请求拦截、响应拦截、错误统一处理 * 请求拦截、响应拦截、错误统一处理
*/ */
import axios from 'axios'; import axios from "axios";
import router from '../router/index'; import router from "../router/index";
import store from '../store/index'; import store from "../store/index";
function getCookie(name) { function getCookie(name) {
var strCookie = document.cookie; var strCookie = document.cookie;
var arrCookie = strCookie.split("; "); var arrCookie = strCookie.split("; ");
for (var i = 0; i < arrCookie.length; i++) { for (var i = 0; i < arrCookie.length; i++) {
var arr = arrCookie[i].split("="); var arr = arrCookie[i].split("=");
if (arr[0] == name) return arr[1]; if (arr[0] == name) return arr[1];
} }
return ""; return "";
} }
const tip = msg => { const tip = (msg) => {
console.log(msg) console.log(msg);
} };
/** /**
* 跳转登录页 * 跳转登录页
* 携带当前页面路由,以期在登录页面完成登录后返回当前页面 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
*/ */
const toLogin = () => { const toLogin = () => {
router.replace({ let path = router.currentRoute.value.path;
path: '/login', //白名单中的401不做跳转
query: { if (!store.state.whiteList.includes(path)) {
redirect: router.currentRoute.fullPath window.location.href = `/apaas/manage/ui/#/login`;
} }
}); // router.replace({
} // path: '/login',
// query: {
// redirect: router.currentRoute.fullPath
// }
// });
};
/** /**
* 请求失败后的错误统一处理 * 请求失败后的错误统一处理
* @param {Number} status 请求失败的状态码 * @param {Number} status 请求失败的状态码
*/ */
const errorHandle = (status, other) => { const errorHandle = (status, other) => {
// 状态码判断 // 状态码判断
switch (status) { switch (status) {
case 400: tip('请求错误(400)'); break; case 400:
// 401: 未登录状态,跳转登录页 tip("请求错误(400)");
case 401: break;
toLogin(); // 401: 未登录状态,跳转登录页
break; case 401:
// 403 token过期 toLogin();
// 清除token并跳转登录页 break;
case 403: // 403 token过期
tip('登录过期,请重新登录'); // 清除token并跳转登录页
localStorage.removeItem('token'); case 403:
store.commit('loginSuccess', null); tip("登录过期,请重新登录");
setTimeout(() => { localStorage.removeItem("token");
// toLogin(); store.commit("loginSuccess", null);
}, 1000); setTimeout(() => {
break; // toLogin();
case 404: tip('请求的资源不存在'); break; }, 1000);
case 408: tip('请求超时(408)'); break;
case 500: tip('服务器错误(500)'); case 404:
case 501: tip('服务未实现(501)'); tip("请求的资源不存在");
case 502: tip('网络错误(502)'); break;
case 503: tip('服务不可用(503)'); case 408:
case 504: tip('网络超时(504)'); tip("请求超时(408)");
case 505: tip('HTTP版本不受支持(505)'); case 500:
default: tip(`连接出错,${other}`); tip("服务器错误(500)");
} case 501:
} tip("服务未实现(501)");
case 502:
tip("网络错误(502)");
case 503:
tip("服务不可用(503)");
case 504:
tip("网络超时(504)");
case 505:
tip("HTTP版本不受支持(505)");
default:
tip(`连接出错,${other}`);
}
};
// 创建axios实例 // 创建axios实例
var instance = axios.create({ timeout: 1000 * 12 }); var instance = axios.create({ timeout: 1000 * 12 });
// 设置post请求头 // 设置post请求头
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; instance.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
/** /**
* 请求拦截器 * 请求拦截器
* 每次请求前,如果存在token则在请求头中携带token * 每次请求前,如果存在token则在请求头中携带token
*/ */
instance.interceptors.request.use( instance.interceptors.request.use(
config => { (config) => {
// const token = store.state.token; // const token = store.state.token;
// var token = 'Basic cm9vdA%3D%3D' // var token = 'Basic cm9vdA%3D%3D'
// token && (config.headers.Authorization = token); // token && (config.headers.Authorization = token);
// const token = store.state.token; // const token = store.state.token;
// var token = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXh0IjoibGltaW5nZSIsInR5cGUiOiJ1c2VyIn0.YUPQ-3nttgfRGOUV4T06JZ6osH46nZ0UUolYdEBhvSQ' // var token = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXh0IjoibGltaW5nZSIsInR5cGUiOiJ1c2VyIn0.YUPQ-3nttgfRGOUV4T06JZ6osH46nZ0UUolYdEBhvSQ'
// token && (config.headers.Authorization = token); // token && (config.headers.Authorization = token);
// if(config.headers.Authorization!="headers"){ // if(config.headers.Authorization!="headers"){
// const token = process.env.DRONE_TOKEN ? process.env.DRONE_TOKEN : Conf.token; // const token = process.env.DRONE_TOKEN ? process.env.DRONE_TOKEN : Conf.token;
// var Authorization = `Bearer ${token}` // var Authorization = `Bearer ${token}`
// token && (config.headers.Authorization = Authorization); // token && (config.headers.Authorization = Authorization);
// }else{ // }else{
// config.headers.Authorization = ''; // config.headers.Authorization = '';
// } // }
return config; return config;
}, },
error => Promise.error(error)) (error) => Promise.error(error)
);
// 响应拦截器 // 响应拦截器
instance.interceptors.response.use( instance.interceptors.response.use(
// 请求成功 // 请求成功
res => res.status === 200|| res.status === 201? Promise.resolve(res) : Promise.reject(res), (res) => (res.status === 200 || res.status === 201 ? Promise.resolve(res) : Promise.reject(res)),
// 请求失败 // 请求失败
error => { (error) => {
const { response } = error; const { response } = error;
if (response) { if (response) {
// 请求已发出,但是不在2xx的范围 // 请求已发出,但是不在2xx的范围
errorHandle(response.status, response.data.errmessage); errorHandle(response.status, response.data.errmessage);
return Promise.reject(response); return Promise.reject(response);
} }
}); }
);
export default instance; export default instance;
...@@ -100,7 +100,7 @@ var adminMenu = [ ...@@ -100,7 +100,7 @@ var adminMenu = [
dict_group_id: "64c156e0-bfff-4bfc-a63a-56effe130a25", dict_group_id: "64c156e0-bfff-4bfc-a63a-56effe130a25",
menuType: 2, menuType: 2,
}, },
] ],
}, },
], ],
dict_group_id: "64c156e0-bfff-4bfc-a63a-56effe130a25", dict_group_id: "64c156e0-bfff-4bfc-a63a-56effe130a25",
...@@ -169,7 +169,7 @@ var adminMenu = [ ...@@ -169,7 +169,7 @@ var adminMenu = [
dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d", dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d",
menuType: 1, //system:64c156e0-bfff-4bfc-a63a-56effe130a25:apaas后管,能力注册页等 font:2cb4f767-fad7-44f2-afa3-f055e15dd2b6:apaas前台页 manager:09938937-3db9-47de-b967-7777ea4ebb2d:apaas管理中心 知识中心:26d3903a-863e-4efc-b53e-0fb8772ddaa4 menuType: 1, //system:64c156e0-bfff-4bfc-a63a-56effe130a25:apaas后管,能力注册页等 font:2cb4f767-fad7-44f2-afa3-f055e15dd2b6:apaas前台页 manager:09938937-3db9-47de-b967-7777ea4ebb2d:apaas管理中心 知识中心:26d3903a-863e-4efc-b53e-0fb8772ddaa4
path: "/system/organization", path: "/system/organization",
children:[ children: [
{ {
menuName: "新增平台用户", menuName: "新增平台用户",
dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d", dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d",
...@@ -198,27 +198,27 @@ var adminMenu = [ ...@@ -198,27 +198,27 @@ var adminMenu = [
show: false, show: false,
path: "/system/organization/org-detail", path: "/system/organization/org-detail",
}, },
] ],
}, },
{ {
menuName: "角色管理", menuName: "角色管理",
dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d", dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d",
menuType: 1, //system:64c156e0-bfff-4bfc-a63a-56effe130a25:apaas后管,能力注册页等 font:2cb4f767-fad7-44f2-afa3-f055e15dd2b6:apaas前台页 manager:09938937-3db9-47de-b967-7777ea4ebb2d:apaas管理中心 知识中心:26d3903a-863e-4efc-b53e-0fb8772ddaa4 menuType: 1, //system:64c156e0-bfff-4bfc-a63a-56effe130a25:apaas后管,能力注册页等 font:2cb4f767-fad7-44f2-afa3-f055e15dd2b6:apaas前台页 manager:09938937-3db9-47de-b967-7777ea4ebb2d:apaas管理中心 知识中心:26d3903a-863e-4efc-b53e-0fb8772ddaa4
path: "/system/role", path: "/system/role",
children:[ children: [
{ {
menuName:'新增角色', menuName: "新增角色",
menuType:2, menuType: 2,
dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d", dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d",
path: "/system/role/add", path: "/system/role/add",
}, },
{ {
menuName:'编辑角色', menuName: "编辑角色",
menuType:2, menuType: 2,
dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d", dict_group_id: "09938937-3db9-47de-b967-7777ea4ebb2d",
path: "/system/role/edit", path: "/system/role/edit",
}, },
] ],
}, },
], ],
}, },
...@@ -241,13 +241,13 @@ var adminMenu = [ ...@@ -241,13 +241,13 @@ var adminMenu = [
}, },
]; ];
function getName(str){ function getName(str) {
if(str=='/'){ if (str == "/") {
return 'index' return "index";
} }
let temp = str.slice(1) let temp = str.slice(1);
temp = temp.replaceAll('/','-') temp = temp.replaceAll("/", "-");
return temp return temp;
} }
function getViews(path) { function getViews(path) {
...@@ -277,7 +277,7 @@ function getViews(path) { ...@@ -277,7 +277,7 @@ function getViews(path) {
//处理路由方法 //处理路由方法
var menuToRouter = (menu) => { var menuToRouter = (menu) => {
menu.forEach((e) => { menu.forEach((e) => {
e.name = getName(e.path) e.name = getName(e.path);
if (e.children && e.menuType == 0) { if (e.children && e.menuType == 0) {
// 其他层级作为文件夹,只提供父级 // 其他层级作为文件夹,只提供父级
e.component = () => import("../page/parent/parent.vue"); e.component = () => import("../page/parent/parent.vue");
...@@ -285,9 +285,9 @@ var menuToRouter = (menu) => { ...@@ -285,9 +285,9 @@ var menuToRouter = (menu) => {
} else if (e.children && e.menuType !== 0) { } else if (e.children && e.menuType !== 0) {
//叶子层级需要加载到对应文件 //叶子层级需要加载到对应文件
//对首页做兼容 //对首页做兼容
if(e.source){ if (e.source) {
e.component = getViews(e.source); e.component = getViews(e.source);
}else{ } else {
e.component = getViews(e.path); e.component = getViews(e.path);
} }
menuToRouter(e.children); menuToRouter(e.children);
...@@ -295,15 +295,15 @@ var menuToRouter = (menu) => { ...@@ -295,15 +295,15 @@ var menuToRouter = (menu) => {
//叶子层级需要加载到对应文件 //叶子层级需要加载到对应文件
//对首页做兼容 //对首页做兼容
if (e.path == "/") { if (e.path == "/") {
if(e.source){ if (e.source) {
e.component = () => import(`../page/main/${e.source}/index.vue`); e.component = () => import(`../page/main/${e.source}/index.vue`);
}else{ } else {
e.component = () => import("../page/main/index/index.vue"); e.component = () => import("../page/main/index/index.vue");
} }
} else { } else {
if(e.source){ if (e.source) {
e.component = getViews(e.source); e.component = getViews(e.source);
}else{ } else {
e.component = getViews(e.path); e.component = getViews(e.path);
} }
} }
......
//路由前端原则可以不写,但是需要在recorder中记录,防止以后忘记 //路由前端原则可以不写,但是需要在recorder中记录,防止以后忘记
//不用新增父路由的文件,父路由全部由parent/parent.vue来支撑 //不用新增父路由的文件,父路由全部由parent/parent.vue来支撑
import {createRouter, createWebHashHistory} from "vue-router"; import { createRouter, createWebHashHistory } from "vue-router";
import store from '../store' import store from "../store";
//写入初始必须有的路由 //写入初始必须有的路由
//或者隐藏式路由,不会表现在菜单上,但是需要存在的路由 //或者隐藏式路由,不会表现在菜单上,但是需要存在的路由
const routes = [ const routes = [
{ {
path: '/login', path: "/login",
name: 'login', name: "login",
show:true, show: true,
component: () => import('../page/login/index.vue') component: () => import("../page/login/index.vue"),
},
{
path: "/register",
name: "register",
show: true,
component: () => import("../page/register/index.vue"),
}, },
{ {
path: '/', path: "/password",
name: 'index', name: "password",
component: () => import('../page/welcom.vue'), show: true,
component: () => import("../page/password/index.vue"),
}, },
{ {
path: '/404', path: "/",
show:true, name: "index",
component: () => import('../page/404.vue') component: () => import("../page/welcom.vue"),
}, },
] {
path: "/404",
show: true,
component: () => import("../page/404.vue"),
},
];
//重新创建router //重新创建router
function newRouterFunc(){ function newRouterFunc() {
return createRouter({ return createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes routes,
}); });
} }
const router = newRouterFunc() const router = newRouterFunc();
function inWhiteList(toPath) { function inWhiteList(toPath) {
//配置白名单 //配置白名单
const whiteList = ['/login'] const whiteList = store.state.whiteList;
const path = whiteList.find((value) => { const path = whiteList.find((value) => {
// 使用正则匹配 // 使用正则匹配
const reg = new RegExp('^' + value) const reg = new RegExp("^" + value);
return reg.test(toPath) return reg.test(toPath);
}) });
return !!path return !!path;
} }
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const userInfo = store.state.userInfo;
const userInfo = store.state.userInfo
//已登录不可跳转登陆页 //已登录不可跳转登陆页
if(userInfo&&(to.path=='/login'||to.path=='/')){ if (userInfo && (to.path == "/login" || to.path == "/")) {
next({path:'/develop/account'}) next({
path: "/develop/account",
});
} }
// 检查to.path是否存在于免登陆白名单 // 检查to.path是否存在于免登陆白名单
if (inWhiteList(to.path)) { if (inWhiteList(to.path)) {
next() return next();
} else { } else {
// 判断是否已经登录,未登录则重定向到首页或其他页面(通过query传参记录原来的路径) // 判断是否已经登录,未登录则重定向到首页或其他页面(通过query传参记录原来的路径)
// 根据配置判断是否跳转第三方登录,跳转第三方登录则不跳login // 根据配置判断是否跳转第三方登录,跳转第三方登录则不跳login
// axios封装中也需要对是否登录过期进行判断,如果登录过期,则跳转登录页,具体跳转地址根据配置来· // axios封装中也需要对是否登录过期进行判断,如果登录过期,则跳转登录页,具体跳转地址根据配置来·
if (!userInfo) { if (!userInfo) {
next({ next({
path: '/login', path: "/login",
}) });
} else { } else {
} }
} }
//判读是否匹配,否则跳转404 //判读是否匹配,否则跳转404
if (to.matched.length !== 0) { if (to.matched.length !== 0) {
next() next();
} else { } else {
return next({ path: '/404' }) return next({
path: "/404",
});
} }
}) });
// 在路由完成初始导航时调用,如果有异步操作放置到这里 // 在路由完成初始导航时调用,如果有异步操作放置到这里
// 请求相应的角色和菜单 // 请求相应的角色和菜单
// router.onReady(() => { // router.onReady(() => {
// generateRoutes() // generateRoutes()
// }) // })
function addRoute(router,routers){ function addRoute(router, routers) {
routers.forEach(e => { routers.forEach((e) => {
if(e.path[0]=='/'){ if (e.path[0] == "/") {
router.addRoute(e) router.addRoute(e);
if(e.children&&e.children.length){ if (e.children && e.children.length) {
addRoute(router,e.children) addRoute(router, e.children);
} }
} }
}); });
} }
export function generateRoutes() { export function generateRoutes() {
const _asyncRoutes = store.state.route const _asyncRoutes = store.state.route;
if (_asyncRoutes) { if (_asyncRoutes) {
//动态添加路由 //动态添加路由
addRoute(router,_asyncRoutes) addRoute(router, _asyncRoutes);
} }
router.addRoute( router.addRoute({
{ path: "/:pathMatch(.*)",
path: '/:pathMatch(.*)', redirect: "/404",
redirect: '/404' });
}
)
} }
//新创建一个router替代之前的router,并把matcher方法替换成新的router的matcher //新创建一个router替代之前的router,并把matcher方法替换成新的router的matcher
export function resetRouter() { export function resetRouter() {
const newRouter = newRouterFunc() const newRouter = newRouterFunc();
router.matcher = newRouter.matcher router.matcher = newRouter.matcher;
} }
export default router;
export default router
//操作类型
export const operateTypeList = [
{ label: "全部", value: "" },
{
label: "新建",
value: "新建",
},
{
label: "编辑",
value: "编辑",
},
{
label: "上移",
value: "上移",
},
{
label: "下移",
value: "下移",
},
{
label: "导入",
value: "导入",
},
{
label: "导出",
value: "导出",
},
{
label: "删除",
value: "删除",
},
{
label: "批量启用",
value: "批量启用",
},
{
label: "批量禁用",
value: "批量禁用",
},
{
label: "批量删除",
value: "批量删除",
},
{
label: "分配角色",
value: "分配角色",
},
{
label: "默认角色管理",
value: "默认角色管理",
},
{
label: "分配用户",
value: "分配用户",
},
{
label: "置顶/取消置顶",
value: "置顶/取消置顶",
},
{
label: "预览",
value: "预览",
},
{
label: "发布",
value: "发布",
},
{
label: "重置",
value: "重置",
},
{
label: "对接记录",
value: "对接记录",
},
{
label: "置顶",
value: "置顶",
},
{
label: "强制修改密码",
value: "强制修改密码",
},
{
label: "清空",
value: "清空",
},
{
label: "详情",
value: "详情",
},
{
label: "移出",
value: "移出",
},
{
label: "查看",
value: "查看",
},
];
export const reqMethodList = [
{ label: "全部", value: "" },
{
label: "HEAD",
value: 88,
},
{
label: "PUT",
value: 89,
},
{
label: "DELETE",
value: 90,
},
{
label: "CONNECT",
value: 91,
},
{
label: "OPTIONS",
value: 92,
},
{
label: "TRACE",
value: 93,
},
{
label: "POST",
value: 87,
},
{
label: "GET",
value: 86,
},
];
import router from '@/router' import router from "@/router";
var GetProperty = function (obj, prop) { var GetProperty = function (obj, prop) {
if (!obj) return null; if (!obj) return null;
let res = obj; let res = obj;
if (prop) { if (prop) {
let props = prop.split('.'); let props = prop.split(".");
for (let i = 0; i < props.length; i++) { for (let i = 0; i < props.length; i++) {
res = res[props[i]]; res = res[props[i]];
if (typeof res == "undefined" || res == null) { if (typeof res == "undefined" || res == null) {
...@@ -14,7 +13,7 @@ var GetProperty = function (obj, prop) { ...@@ -14,7 +13,7 @@ var GetProperty = function (obj, prop) {
} }
} }
return res; return res;
} };
var dateFormat = function (fmt, timestamp) { var dateFormat = function (fmt, timestamp) {
let date = new Date(timestamp); let date = new Date(timestamp);
...@@ -25,17 +24,17 @@ var dateFormat = function (fmt, timestamp) { ...@@ -25,17 +24,17 @@ var dateFormat = function (fmt, timestamp) {
"d+": date.getDate().toString(), // 日 "d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时 "H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分 "M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒 "S+": date.getSeconds().toString(), // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串 // 有其他格式化字符需求可以继续添加,必须转化成字符串
}; };
for (let k in opt) { for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt); ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) { if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0"));
}; }
}; }
return fmt; return fmt;
} };
var dateStringTransform = function (date) { var dateStringTransform = function (date) {
/* /*
...@@ -45,8 +44,8 @@ var dateStringTransform = function (date) { ...@@ -45,8 +44,8 @@ var dateStringTransform = function (date) {
if (String(date).indexOf("T") != -1) { if (String(date).indexOf("T") != -1) {
let arr = date.split("T"); let arr = date.split("T");
let t = arr[1]; let t = arr[1];
let tarr = t.split('.000'); let tarr = t.split(".000");
let marr = tarr[0].split(':'); let marr = tarr[0].split(":");
let h = parseInt(marr[0]) >= 10 ? parseInt(marr[0]) : "0" + parseInt(marr[0]); let h = parseInt(marr[0]) >= 10 ? parseInt(marr[0]) : "0" + parseInt(marr[0]);
let m = parseInt(marr[1]) >= 10 ? parseInt(marr[1]) : "0" + parseInt(marr[1]); let m = parseInt(marr[1]) >= 10 ? parseInt(marr[1]) : "0" + parseInt(marr[1]);
let s = parseInt(marr[2]) >= 10 ? parseInt(marr[2]) : "0" + parseInt(marr[2]); let s = parseInt(marr[2]) >= 10 ? parseInt(marr[2]) : "0" + parseInt(marr[2]);
...@@ -55,7 +54,7 @@ var dateStringTransform = function (date) { ...@@ -55,7 +54,7 @@ var dateStringTransform = function (date) {
} else { } else {
return date; return date;
} }
} };
var dateStringTransformChat = function (date) { var dateStringTransformChat = function (date) {
/* /*
...@@ -65,27 +64,27 @@ var dateStringTransformChat = function (date) { ...@@ -65,27 +64,27 @@ var dateStringTransformChat = function (date) {
if (String(date).indexOf("T") != -1) { if (String(date).indexOf("T") != -1) {
let arr = date.split("T"); let arr = date.split("T");
let t = arr[1]; let t = arr[1];
let arr1 = arr[0].split("-") let arr1 = arr[0].split("-");
let tarr = t.split('.000'); let tarr = t.split(".000");
let marr = tarr[0].split(':'); let marr = tarr[0].split(":");
let h = parseInt(marr[0]) >= 10 ? parseInt(marr[0]) : "0" + parseInt(marr[0]); let h = parseInt(marr[0]) >= 10 ? parseInt(marr[0]) : "0" + parseInt(marr[0]);
let m = parseInt(marr[1]) >= 10 ? parseInt(marr[1]) : "0" + parseInt(marr[1]); let m = parseInt(marr[1]) >= 10 ? parseInt(marr[1]) : "0" + parseInt(marr[1]);
let s = parseInt(marr[2]) >= 10 ? parseInt(marr[2]) : "0" + parseInt(marr[2]); let s = parseInt(marr[2]) >= 10 ? parseInt(marr[2]) : "0" + parseInt(marr[2]);
let dd = arr1[1]+"-"+arr1[2] + " " + h + ":" + m; let dd = arr1[1] + "-" + arr1[2] + " " + h + ":" + m;
return dd; return dd;
} else if(date){ } else if (date) {
let arr = date.split(" "); let arr = date.split(" ");
let t = arr[1]; let t = arr[1];
let arr1 = arr[0].split("-") let arr1 = arr[0].split("-");
let tarr = t.split('.000'); let tarr = t.split(".000");
let marr = tarr[0].split(':'); let marr = tarr[0].split(":");
let h = parseInt(marr[0]) >= 10 ? parseInt(marr[0]) : "0" + parseInt(marr[0]); let h = parseInt(marr[0]) >= 10 ? parseInt(marr[0]) : "0" + parseInt(marr[0]);
let m = parseInt(marr[1]) >= 10 ? parseInt(marr[1]) : "0" + parseInt(marr[1]); let m = parseInt(marr[1]) >= 10 ? parseInt(marr[1]) : "0" + parseInt(marr[1]);
let s = parseInt(marr[2]) >= 10 ? parseInt(marr[2]) : "0" + parseInt(marr[2]); let s = parseInt(marr[2]) >= 10 ? parseInt(marr[2]) : "0" + parseInt(marr[2]);
let dd = arr1[1]+"-"+arr1[2] + " " + h + ":" + m; let dd = arr1[1] + "-" + arr1[2] + " " + h + ":" + m;
return dd; return dd;
} }
} };
var downloadFileFormat = function (fileUrl) { var downloadFileFormat = function (fileUrl) {
/* /*
...@@ -97,7 +96,7 @@ var downloadFileFormat = function (fileUrl) { ...@@ -97,7 +96,7 @@ var downloadFileFormat = function (fileUrl) {
} else { } else {
return ""; return "";
} }
} };
var downloadFileFormatNew = function (fileUrl) { var downloadFileFormatNew = function (fileUrl) {
/* /*
...@@ -105,18 +104,18 @@ var downloadFileFormatNew = function (fileUrl) { ...@@ -105,18 +104,18 @@ var downloadFileFormatNew = function (fileUrl) {
output: 1234.png output: 1234.png
*/ */
if (fileUrl != "") { if (fileUrl != "") {
var temp = fileUrl.split('/')[fileUrl.split('/').length-1] var temp = fileUrl.split("/")[fileUrl.split("/").length - 1];
var name = temp.split('_')[0] var name = temp.split("_")[0];
var type = temp.split('_')[temp.split('_').length-1].split('.')[1] var type = temp.split("_")[temp.split("_").length - 1].split(".")[1];
if(temp.indexOf('_')==-1){ if (temp.indexOf("_") == -1) {
return name return name;
}else{ } else {
return name+'.'+type return name + "." + type;
} }
} else { } else {
return ""; return "";
} }
} };
var numberFormat = function (num, decimals) { var numberFormat = function (num, decimals) {
/* /*
...@@ -133,7 +132,7 @@ var numberFormat = function (num, decimals) { ...@@ -133,7 +132,7 @@ var numberFormat = function (num, decimals) {
arr[1] = arr[1].toString() + "0"; arr[1] = arr[1].toString() + "0";
str += arr[1]; str += arr[1];
} else { } else {
str += arr[1].substr(0, 2) str += arr[1].substr(0, 2);
} }
} else { } else {
return mathNum; return mathNum;
...@@ -142,34 +141,34 @@ var numberFormat = function (num, decimals) { ...@@ -142,34 +141,34 @@ var numberFormat = function (num, decimals) {
} else { } else {
return num; return num;
} }
} };
var CreationDateDesc = function (timestamp) { var CreationDateDesc = function (timestamp) {
let date = new Date(timestamp); let date = new Date(timestamp);
return date.toLocaleDateString("zh-CN", { return date.toLocaleDateString("zh-CN", {
timeZone: "Asia/Shanghai" timeZone: "Asia/Shanghai",
}); });
} };
var join_str = function (arr,str,sp) { var join_str = function (arr, str, sp) {
let temp = '' let temp = "";
if(arr){ if (arr) {
if(arr.length){ if (arr.length) {
arr.forEach((e,idx) => { arr.forEach((e, idx) => {
if(idx==arr.length-1){ if (idx == arr.length - 1) {
temp = temp + e[str] temp = temp + e[str];
}else{ } else {
temp = temp + e[str] + sp temp = temp + e[str] + sp;
} }
}); });
return temp return temp;
}else{ } else {
return '' return "";
} }
}else{ } else {
return arr return arr;
} }
} };
var getQueryString = function (name, url) { var getQueryString = function (name, url) {
let search = url.substr(url.indexOf("?")); let search = url.substr(url.indexOf("?"));
...@@ -182,87 +181,108 @@ var getQueryString = function (name, url) { ...@@ -182,87 +181,108 @@ var getQueryString = function (name, url) {
} }
} }
return theRequest[name]; return theRequest[name];
} };
var timeForMatReduce = function(count) { var timeForMatReduce = function (count) {
// 拼接时间 // 拼接时间
let time1 = new Date() let time1 = new Date();
time1.setTime(time1.getTime() - (24 * 60 * 60 * 1000)) time1.setTime(time1.getTime() - 24 * 60 * 60 * 1000);
let Y1 = time1.getFullYear() let Y1 = time1.getFullYear();
let M1 = ((time1.getMonth() + 1) >= 10 ? (time1.getMonth() + 1) : '0' + (time1.getMonth() + 1)) let M1 = time1.getMonth() + 1 >= 10 ? time1.getMonth() + 1 : "0" + (time1.getMonth() + 1);
let D1 = (time1.getDate() >= 10 ? time1.getDate() : '0' + time1.getDate()) let D1 = time1.getDate() >= 10 ? time1.getDate() : "0" + time1.getDate();
let timer1 = Y1 + '-' + M1 + '-' + D1 // 当前时间 let timer1 = Y1 + "-" + M1 + "-" + D1; // 当前时间
let time2 = new Date() let time2 = new Date();
time2.setTime(time2.getTime() - (24 * 60 * 60 * 1000 * count)) time2.setTime(time2.getTime() - 24 * 60 * 60 * 1000 * count);
let Y2 = time2.getFullYear() let Y2 = time2.getFullYear();
let M2 = ((time2.getMonth() + 1) >= 10 ? (time2.getMonth() + 1) : '0' + (time2.getMonth() + 1)) let M2 = time2.getMonth() + 1 >= 10 ? time2.getMonth() + 1 : "0" + (time2.getMonth() + 1);
let D2 = (time2.getDate() >= 10 ? time2.getDate() : '0' + time2.getDate()) let D2 = time2.getDate() >= 10 ? time2.getDate() : "0" + time2.getDate();
let timer2 = Y2 + '-' + M2 + '-' + D2 // 之前的7天或者30天 let timer2 = Y2 + "-" + M2 + "-" + D2; // 之前的7天或者30天
return { return {
t1: timer1, t1: timer1,
t2: timer2 t2: timer2,
} };
} };
var timeForMatAdd = function(count) { var timeForMatAdd = function (count) {
// 拼接时间 // 拼接时间
let time1 = new Date() let time1 = new Date();
time1.setTime(time1.getTime() - (24 * 60 * 60 * 1000)) time1.setTime(time1.getTime() - 24 * 60 * 60 * 1000);
let Y1 = time1.getFullYear() let Y1 = time1.getFullYear();
let M1 = ((time1.getMonth() + 1) >= 10 ? (time1.getMonth() + 1) : '0' + (time1.getMonth() + 1)) let M1 = time1.getMonth() + 1 >= 10 ? time1.getMonth() + 1 : "0" + (time1.getMonth() + 1);
let D1 = (time1.getDate() >= 10 ? time1.getDate() : '0' + time1.getDate()) let D1 = time1.getDate() >= 10 ? time1.getDate() : "0" + time1.getDate();
let timer1 = Y1 + '-' + M1 + '-' + D1 // 当前时间 let timer1 = Y1 + "-" + M1 + "-" + D1; // 当前时间
let time2 = new Date() let time2 = new Date();
time2.setTime(time2.getTime() + (24 * 60 * 60 * 1000 * count)) time2.setTime(time2.getTime() + 24 * 60 * 60 * 1000 * count);
let Y2 = time2.getFullYear() let Y2 = time2.getFullYear();
let M2 = ((time2.getMonth() + 1) >= 10 ? (time2.getMonth() + 1) : '0' + (time2.getMonth() + 1)) let M2 = time2.getMonth() + 1 >= 10 ? time2.getMonth() + 1 : "0" + (time2.getMonth() + 1);
let D2 = (time2.getDate() >= 10 ? time2.getDate() : '0' + time2.getDate()) let D2 = time2.getDate() >= 10 ? time2.getDate() : "0" + time2.getDate();
let timer2 = Y2 + '-' + M2 + '-' + D2 // 之前的7天或者30天 let timer2 = Y2 + "-" + M2 + "-" + D2; // 之前的7天或者30天
return { return {
t1: timer1, t1: timer1,
t2: timer2 t2: timer2,
} };
} };
var useConsole = function(){ var useConsole = function () {
//改写console.log,防止打印数据泄露 //改写console.log,防止打印数据泄露
window.isDebug = false; // 控制是否屏蔽全局console.log 日志;isDebug设为false即可屏蔽 window.isDebug = false; // 控制是否屏蔽全局console.log 日志;isDebug设为false即可屏蔽
//前面做一道筛选,满足则正常打印 //前面做一道筛选,满足则正常打印
//不满足则改写console.log,可以通过window.isDebug改变打印状态 //不满足则改写console.log,可以通过window.isDebug改变打印状态
//方便线上环境进行查看 //方便线上环境进行查看
if (window.isDebug||process.env.NODE_ENV === 'development') { if (window.isDebug || process.env.NODE_ENV === "development") {
return return;
} }
console.log = (function (oldLogFunc) { console.log = (function (oldLogFunc) {
return function () { return function () {
if (window.isDebug||process.env.NODE_ENV === 'development') { if (window.isDebug || process.env.NODE_ENV === "development") {
oldLogFunc.apply(this, arguments); oldLogFunc.apply(this, arguments);
} }
} };
})(console.log); })(console.log);
} };
var getFirstChild = function(menuObj,path){ var getFirstChild = function (menuObj, path) {
let parentPath = menuObj[path].parentPath let parentPath = menuObj[path].parentPath;
if(parentPath){ if (parentPath) {
let temp = menuObj[parentPath].children||[] let temp = menuObj[parentPath].children || [];
for (let index = 0; index < temp.length; index++) { for (let index = 0; index < temp.length; index++) {
const e = temp[index]; const e = temp[index];
if(e.show){ if (e.show) {
pathToUrl(e.path) pathToUrl(e.path);
break break;
} }
} }
} }
} };
var getImageUrl = function (name) {
return new URL(`../assets/imgs/${name}`, import.meta.url).href;
};
var pathToUrl = (path)=>{ var pathToUrl = (path) => {
if(path.includes('http')){ if (path.includes("http")) {
window.open(path,'_blank') window.open(path, "_blank");
}else{ } else {
router.push(path); router.push(path);
} }
} };
const downloadBlob = (blobData, type, fileName) => {
const blob = new Blob([blobData], {
type,
});
const url = window.URL.createObjectURL(blob);
const aLink = document.createElement("a");
aLink.style.display = "none";
aLink.href = url;
//指定文件名,不指定就默认
if (fileName) aLink.setAttribute("download", fileName);
document.body.appendChild(aLink);
aLink.click();
/** 下载完成移除元素 */
document.body.removeChild(aLink);
/** 释放掉blob对象 */
window.URL.revokeObjectURL(url);
};
export { export {
GetProperty, GetProperty,
...@@ -279,4 +299,6 @@ export { ...@@ -279,4 +299,6 @@ export {
timeForMatAdd, timeForMatAdd,
useConsole, useConsole,
getFirstChild, getFirstChild,
} getImageUrl,
downloadBlob,
};
...@@ -55,3 +55,15 @@ export function validateIdNumber(rule, value, callback) { ...@@ -55,3 +55,15 @@ export function validateIdNumber(rule, value, callback) {
} }
}, 100); }, 100);
} // 验证身份证号码 } // 验证身份证号码
export function validateLink(rule,value,callback) {
const reg = /^(http(s)?:\/\/)\w+[^\s]+(\.[^\s]+){1,}$/
setTimeout(() => {
if (reg.test(value) || value == "") {
callback()
}else {
callback(new Error("地址格式不正确,请重新输入"))
}
})
}
const CryptoJS = require('crypto-js'); // const CryptoJS = require('crypto-js');
import * as CryptoJS from 'crypto-js'
const key = "swuE9cmCZQwrkYRV"; const key = "swuE9cmCZQwrkYRV";
function Decrypt(word) { function Decrypt(word) {
let decrypt = CryptoJS.AES.decrypt(word, key); let decrypt = CryptoJS.AES.decrypt(word, key);
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8); let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString(); return decryptedStr.toString();
} }
function Encrypt(word) { function Encrypt(word) {
let encrypted = CryptoJS.AES.encrypt(word, key); let encrypted = CryptoJS.AES.encrypt(word, key);
return encrypted.toString(); return encrypted.toString();
} }
export {Decrypt , Encrypt} export {
\ No newline at end of file Decrypt,
Encrypt
}
import {createStore} from 'vuex' import { createStore } from "vuex";
const store = createStore({ const store = createStore({
state: { state: {
userInfo:null, userInfo: null,
menu:null, menu: null,
route:null, route: null,
nameFlag:false, nameFlag: false,
msgBoxFlag:false, msgBoxFlag: false,
nowzz:null, nowzz: null,
menuObj:{}, menuObj: {},
treeFlag:false, treeFlag: false,
registerValid:false, registerValid: false,
msgUnreadNum: 0 msgUnreadNum: 0,
systemLogo: "",
whiteList: [],
userTypeConfig: {
1: "业务系统账号",
2: "组织管理员账号",
3: "平台用户账号",
4: "超级管理员",
},
}, },
getters: { getters: {
count(state) { count(state) {
return state.userInfo return state.userInfo;
} },
getUserTypeConfig(state) {
return state.userTypeConfig;
},
}, },
mutations: { mutations: {
setUserInfo(state, info) { setUserInfo(state, info) {
state.userInfo = info state.userInfo = info;
}, },
setMenu(state,menu){ setMenu(state, menu) {
state.menu = menu state.menu = menu;
}, },
setMenuObj(state,menuObj){ setMenuObj(state, menuObj) {
state.menuObj = menuObj state.menuObj = menuObj;
}, },
setRoute(state,route){ setRoute(state, route) {
state.route = route state.route = route;
}, },
setNameFlag(state,nameFlag){ setNameFlag(state, nameFlag) {
state.nameFlag = nameFlag state.nameFlag = nameFlag;
}, },
setMsgBoxFlag(state,msgBoxFlag){ setMsgBoxFlag(state, msgBoxFlag) {
state.msgBoxFlag = msgBoxFlag state.msgBoxFlag = msgBoxFlag;
}, },
setNowzz(state,nowzz){ setNowzz(state, nowzz) {
state.nowzz = nowzz state.nowzz = nowzz;
}, },
setTreeFlag(state,treeFlag){ setTreeFlag(state, treeFlag) {
state.treeFlag = treeFlag state.treeFlag = treeFlag;
}, },
setRegisterValid(state,registerValid){ setRegisterValid(state, registerValid) {
state.registerValid = registerValid state.registerValid = registerValid;
}, },
setUnreadNum(state, num) { setUnreadNum(state, num) {
state.msgUnreadNum = num state.msgUnreadNum = num;
},
setSystemLogo(state, logo) {
state.systemLogo = logo;
},
setWhiteList(state, arr) {
state.whiteList = arr;
}, },
}, },
actions: {} actions: {},
}); });
export default store; export default store;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment