Commit 6c696f85 authored by 张耀's avatar 张耀

Merge branch 'dev' into zy

parents c11a241c a91640a0
<template>
<el-form
:label-position="'right'"
label-width="120px"
:model="directoryForm"
:rules="directoryFormRules"
ref="directoryRef"
style="max-width: 80%">
<el-form-item label="上级目录" prop="p_organization_id" v-if="formType === 'create'">
<el-tree-select
v-model="directoryForm.p_organization_id"
:data="orgData"
:props="treeProps"
:render-after-expand="false"
:check-strictly="true"
:disabled="directoryForm.level"
style="width: 80%" />
<el-form-item label="" style="padding-left: 16px">
<el-checkbox v-model="directoryForm.level" @change="isTop" label="顶级" />
</el-form-item>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="directoryForm.name" />
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted, onBeforeMount, nextTick } from "vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const props = defineProps({
formType: {
type: String,
default: "create", //false 新增 true 编辑
},
});
const directoryForm = reactive({
p_organization_id: "",
name: "",
level: false,
});
const directoryFormRules = reactive({
p_organization_id: [{ required: true, message: "请输入上级目录", trigger: "blur" }],
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
});
const directoryRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!directoryRef) return;
await directoryRef.value.validate((valid, fields) => {
if (valid) {
emit("action", directoryForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!directoryRef) return;
directoryRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(directoryForm, data);
};
const orgData = ref([]);
const treeProps = {
label: "name",
children: "Child",
value: "organization_id",
disabled: "disabled",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
orgDataTemp.shift();
orgData.value = filterOrg(orgDataTemp);
} else {
ElMessage.error(res.data.data);
}
});
};
const filterOrg = (data) => {
if (data.length > 0) {
data.forEach((item) => {
item.disabled = item.data_type === 0 ? false : true;
if (item.Child) {
filterOrg(item.Child);
} else {
return;
}
});
}
return data;
};
const isTop = (data) => {
directoryForm.p_organization_id = data ? " " : ""; //空格绕过表单非空校验
};
onBeforeMount(() => {
getOrgTree();
});
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<div>组织管理</div>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="flex_row">
<div class="flex_left bgc_white">
<div class="tree_header">政务组织</div>
<div class="tree_content">
<div class="search">
<el-input v-model="search" placeholder="请输入组织名称搜索" :prefix-icon="Search" @input="searchChange" />
</div>
<div class="tree">
<tree ref="orgTree" @action="treeAction" @select="treeSelect"></tree>
</div>
</div>
</div>
<div class="flex_right">
<div class="info_container bgc_white">
<div class="title">
<span class="icon_box">
<span class="step_icon">
<bg-icon icon="#bg-ic-file"></bg-icon>
</span>
<span> 基本信息 </span>
</span>
<span class="can_click_text detail_btn" v-if="selectTreeDataType === 1" @click="toOrgDetail">
查看详情
<bg-icon style="font-size: 8px; color: #95a3ca; vertical-align: middle" icon="#bg-ic-arrow-right" />
</span>
</div>
<bg-info class="info_box" v-if="selectTreeDataType === 1" :data="baseInfo"></bg-info>
<bg-info class="info_box" v-if="selectTreeDataType === 2" :data="baseInfo2"></bg-info>
</div>
<div class="main_container bgc_white">
<bg-filter-group @search="changeSearch" v-model="filter.key_word" placeholder="请输入关键字">
<template v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="addAccount">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
{{ selectTreeDataType === 1 ? "新增组织管理员" : "新增平台用户" }}
</el-button>
<el-button @click="deleteBatch"> 批量删除 </el-button>
<el-button @click="resetPsd"> 重置密码 </el-button>
<span class="header_info"
>已选择<span style="color: #202531; font-weight: bold">{{ selected.length }}</span
></span
>
<span class="header_info can_click_text" @click="clearSelected">清空</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.state" 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>
<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 apaas_scroll">
<bg-table
ref="dataTable"
:headers="headers"
:rows="tableRows"
:isIndex="true"
canEdit
canEditFlag="canSelect"
:stripe="true"
:select="true"
@selectAc="selectRows">
<template v-slot:system_account="{ row }">
<span @click="goDetail(row)" class="can_click_text">
{{ row.system_account }}
</span>
</template>
<template v-slot:state="{ row }">
<bg-switch
@click="stateChange(row)"
:labels="['否', '是']"
:values="[0, 1]"
v-model="row.state"
:disabled="row.is_admin == 4"></bg-switch>
</template>
<template v-slot:action="{ row }">
<bg-table-btn :disabled="row.is_admin == 4" @click="editAccount(row)" class="can_click_text">
编辑
</bg-table-btn>
<bg-table-btn
:disabled="row.is_admin == 4 && userInfo.is_admin !== 4"
@click="editPsdAccount(row)"
class="can_click_text">
修改密码
</bg-table-btn>
<bg-table-btn :disabled="row.is_admin == 4" @click="deleteAccount(row)" class="can_click_text">
删除
</bg-table-btn>
</template>
</bg-table>
<div class="pagination_box">
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</div>
</div>
<el-dialog
v-model="dialogDirectory"
:title="action === 'create' ? '新增目录' : '编辑目录'"
width="758px"
:before-close="handleCloseDirectory"
destroy-on-close>
<div class="dialog_form">
<directoryForm
ref="directoryFormRef"
:form-type="directoryFormType"
@action="getDirectoryFromData"></directoryForm>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDirectory">取消</el-button>
<el-button type="primary" @click="saveDirectory">保存</el-button>
</span>
</template>
</el-dialog>
<el-dialog
v-model="dialogOrg"
:title="action === 'create' ? '新增组织' : '编辑组织'"
width="758px"
:before-close="handleCloseOrg"
destroy-on-close>
<div class="dialog_form">
<orgForm ref="orgFormRef" :form-type="orgFormType" @action="getOrgFormData"></orgForm>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseOrg">取消</el-button>
<el-button type="primary" @click="saveOrg">保存</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="dialogDelNode" title="删除" width="520px" :before-close="handleCloseDelNode">
<div class="dialog_form">确认删除吗?</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDelNode">取消</el-button>
<el-button type="primary" @click="confirmDelNode">确认</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="deleteRowFlag" title="删除" width="520px" :before-close="handleCloseRowDelete">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedRow.system_account }}</span
>做删除操作。
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseRowDelete">取消</el-button>
<el-button type="primary" @click="deleteRowConfirm">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="editFlag" title="修改密码" width="520px" :before-close="handleCloseEdit">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedRow.system_account }}</span
>做修改密码操作,修改后旧密码将无法登录。
</div>
<div>
<el-form
:label-position="'right'"
label-width="120px"
:model="passwordForm"
:rules="passwordFormRules"
ref="passwordRef"
style="max-width: 80%">
<el-form-item label="新密码" prop="password">
<el-input
v-model="passwordForm.password"
:type="password_eye ? 'text' : 'password'"
placeholder="请输入密码">
<template #suffix>
<bg-icon @click="password_eye = !password_eye" class="icon_eye" icon="#bg-ic-eye"></bg-icon>
</template>
</el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="confirm_password">
<el-input
v-model="passwordForm.confirm_password"
:type="confirm_eye ? 'text' : 'password'"
placeholder="请确认新密码">
<template #suffix>
<bg-icon @click="confirm_eye = !confirm_eye" class="icon_eye" icon="#bg-ic-eye"></bg-icon>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseEdit">取消</el-button>
<el-button type="primary" @click="editConfirm">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="deleteFlag" title="删除" width="520px" :before-close="handleCloseDelete">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; mdeleteconfirmargin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedName.join("、") }}</span
>做删除操作。
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDelete">取消</el-button>
<el-button type="primary" @click="deleteConfirm">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="resetFlag" title="重置密码" width="520px" :before-close="handleCloseReset">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedName.join("、") }}</span
>做重置密码操作。
</div>
<div>重置密码为123456,是否继续?</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseReset">取消</el-button>
<el-button type="primary" @click="resetConfirm">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup></script>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { computed, onBeforeMount, nextTick, reactive, ref, toRefs } from "@vue/runtime-core";
import { useRouter } from "vue-router";
import tree from "./tree.vue";
import directoryForm from "./directory-form.vue";
import orgForm from "./org-form.vue";
import CryptoJS from "crypto-js";
import { downloadFileFormatNew } from "@/services/helper";
import store from "@/store";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
<style lang="scss" scoped></style>
const dataTable = ref(null);
const toOrgDetail = () => {
router.push({
path: "/authority/organization/org-detail",
query: {
id: selectOrgNode.value.organization_id,
},
});
};
const baseInfo = reactive([
{
name: "组织类型",
value: "",
nameWidth: 130,
},
{
name: "组织代码",
value: "",
nameWidth: 130,
},
{
name: "组织名称",
value: "",
callback: toOrgDetail,
nameWidth: 130,
},
{
name: "创建时间",
value: "",
nameWidth: 130,
},
{
name: "组织管理员数量",
value: "",
nameWidth: 130,
},
{
name: "业务系统数量",
value: "",
nameWidth: 130,
},
]);
const baseInfo2 = reactive([
{
name: "组织名称",
value: "",
nameWidth: 130,
},
{
name: "组织代码",
value: "",
nameWidth: 130,
},
{
name: "用户数",
value: "",
nameWidth: 130,
full: true,
},
]);
const headers = reactive([
{
label: "账号",
prop: "system_account",
minWidth: 150,
},
{
label: "手机号",
prop: "contact_phone",
minWidth: 150,
},
{
label: "角色",
prop: "system_role",
minWidth: 150,
},
{
label: "创建时间",
prop: "created_time",
minWidth: 200,
},
{
label: "是否启用",
prop: "state",
width: 80,
},
{
label: "操作",
prop: "action",
width: 220,
fixed: "right",
},
]);
const stateOptions = ref([
{
name: "全部",
value: "",
},
{
name: "启用",
value: "1",
},
{
name: "禁用",
value: "0",
},
]);
const tableRows = ref([]);
const tableTotal = ref(0);
const orgTree = ref(null);
const selectTreeData = ref(null);
const actionTreeData = ref(null);
const selectTreeDataType = ref(2);
const selectOrgNode = ref(null);
const dialogDelNode = ref(false);
const router = useRouter();
const filter = reactive({
state: "",
key_word: "",
page: 1,
limit: 10,
});
const deleteFlag = ref(false);
const deleteRowFlag = ref(false);
const resetFlag = ref(false);
const selectedRow = ref({});
const selected = ref([]);
const selectedName = ref([]);
const editFlag = ref(false);
const password_eye = ref(false);
const confirm_eye = ref(false);
const passwordRef = ref(null);
const passwordForm = reactive({
password: "",
confirm_password: "",
});
const search = ref("");
const userInfo = computed(() => {
return store.state.userInfo;
});
const validatePass = (rule, value, callback) => {
if (value !== passwordForm.password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const passwordFormRules = reactive({
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 8, message: "密码长度不得低于8位", trigger: "blur" },
],
confirm_password: [
{ required: true, message: "请确认密码", trigger: "blur" },
{ validator: validatePass, trigger: "blur" },
],
});
const addAccount = () => {
if (selectTreeDataType.value === 1) {
router.push({
path: "/authority/organization/org-user",
query: {
orgId: selectOrgNode.value.organization_id,
},
});
} else {
router.push({
path: "/authority/organization/platform-user",
});
}
};
const changeSize = (size) => {
filter.limit = size;
changePage(1);
};
const changePage = (page) => {
filter.page = page;
getTableRows();
};
const changeSearch = (val) => {
filter.key_word = val;
changePage(1);
}; // 表格关键字筛选
const filterAction = () => {
changePage(1);
}; // 查询按钮
const filterClear = () => {
filter.state = "";
filter.key_word = "";
filter.limit = 10;
filter.page = 1;
changePage(1);
}; // 重置筛选项
const dialogDirectory = ref(false);
const directoryFormType = ref("create");
const orgFormType = ref("create");
const handleCloseDirectory = () => {
dialogDirectory.value = false;
};
const directoryFormRef = ref(null);
const saveDirectory = () => {
directoryFormRef.value.submitForm();
};
//新增/编剧目录
const getDirectoryFromData = (data) => {
if (directoryFormType.value === "create") {
const params = {
p_organization_id: data.level ? "" : data.p_organization_id,
name: data.name,
data_type: 0,
};
axios.post(`/apaas/system/v5/org/add`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
orgTree.value.getOrgTree(res.data.data.id);
} else {
ElMessage.error(res.data.data);
}
handleCloseDirectory();
});
} else if (directoryFormType.value === "edit") {
const params = {
name: data.name,
data_type: 0,
};
axios.put(`/apaas/system/v5/org/${actionTreeData.value.id}`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
orgTree.value.getOrgTree(actionTreeData.value.id);
} else {
ElMessage.error(res.data.data);
}
handleCloseDirectory();
});
}
};
const dialogOrg = ref(false);
const handleCloseOrg = () => {
dialogOrg.value = false;
};
const orgFormRef = ref(null);
const saveOrg = () => {
orgFormRef.value.submitForm();
};
//新增/编辑组织
const getOrgFormData = (data) => {
if (orgFormType.value === "create") {
const params = {
p_organization_id: data.level ? "" : data.p_organization_id,
name: data.name,
organization_code: data.organization_code,
description: data.description,
attachment:
data.attachment && data.attachment.length > 0 ? data.attachment.map((item) => item.url).join(",") : "",
data_type: 1,
};
axios.post(`/apaas/system/v5/org/add`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
orgTree.value.getOrgTree(res.data.data.id);
} else {
ElMessage.error(res.data.data);
}
handleCloseOrg();
});
} else if (orgFormType.value === "edit") {
const params = {
// p_organization_id: data.level ? "" : data.p_organization_id,
name: data.name,
organization_code: data.organization_code,
description: data.description,
attachment:
data.attachment && data.attachment.length > 0 ? data.attachment.map((item) => item.url).join(",") : "",
data_type: 1,
};
axios.put(`/apaas/system/v5/org/${actionTreeData.value.id}`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
orgTree.value.getOrgTree(actionTreeData.value.id);
} else {
ElMessage.error(res.data.data);
}
handleCloseOrg();
});
}
};
const handleCloseDelNode = () => {
dialogDelNode.value = false;
};
//删除目录/组织
const confirmDelNode = () => {
axios.delete(`/apaas/system/v5/org/${actionTreeData.value.id}`).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
orgTree.value.getOrgTree(actionTreeData.value.id === selectTreeData.value.id ? null : selectTreeData.value.id);
} else {
ElMessage.error(res.data.data);
}
handleCloseDelNode();
});
};
const moveOrg = (params) => {
axios.put(`/apaas/system/v5/org/sort`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
orgTree.value.getOrgTree(selectTreeData.value.id);
} else {
ElMessage.error(res.data.data);
}
});
};
const action = ref("create");
const treeAction = (data) => {
action.value = data.action;
if (data.action === "create" || data.action === "edit") {
if (data.type === "org") {
orgFormType.value = data.action;
dialogOrg.value = true;
nextTick(() => {
if (data.data) {
if (data.action === "edit") {
orgFormRef.value.setForm({
name: data.data.value.name,
p_organization_id: data.data.value.p_organization_id,
level: data.data.value.p_organization_id ? false : true,
organization_code: data.data.value.organization_code,
description: data.data.value.description,
attachment: data.data.value.attachment.split(",").map((i) => {
return { name: downloadFileFormatNew(i), url: i };
}),
});
} else if (data.action === "create") {
orgFormRef.value.setForm({ p_organization_id: data.data.value.organization_id });
}
}
});
} else {
directoryFormType.value = data.action;
dialogDirectory.value = true;
nextTick(() => {
if (data.data) {
if (data.action === "edit") {
directoryFormRef.value.setForm({ name: data.data.value.name });
} else if (data.action === "create") {
directoryFormRef.value.setForm({ p_organization_id: data.data.value.organization_id });
}
}
});
}
} else if (data.action === "delete") {
dialogDelNode.value = true;
} else if (data.action === "mvup" || data.action === "mvdown") {
moveOrg(data.data);
}
};
const treeSelect = (data) => {
if (data.type === "action") {
actionTreeData.value = data.data.value;
} else {
selectTreeData.value = data.data.value;
}
if (data.type === "click" && (data.data.value.data_type === 1 || data.data.value.data_type === 2)) {
selectTreeDataType.value = data.data.value.data_type;
selectOrgNode.value = data.data.value;
getTableRows();
}
};
const getTableRows = () => {
let params = {
...filter,
organization_id: selectTreeData.value.organization_id,
data_type: selectTreeData.value.data_type,
};
axios
.get(`/apaas/system/v5/org/detail`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
tableRows.value = (res.data.data.org_users.data || []).map((item) => {
item.system_role = item.system_role ? item.system_role.join("") : "-";
return item;
});
tableRows.value.forEach((e) => {
if (e.is_admin == 4 && userInfo.value.is_admin != 4) {
e.canSelect = 1;
} else {
e.canSelect = 0;
}
});
tableTotal.value = res.data.data.org_users.total;
if (params.data_type === 1) {
baseInfo[0].value = res.data.data.org_info.organization_type;
baseInfo[1].value = res.data.data.org_info.organization_code;
baseInfo[2].value = res.data.data.org_info.name;
baseInfo[3].value = res.data.data.org_info.created_time;
baseInfo[4].value = res.data.data.org_info.org_admin_number;
baseInfo[5].value = res.data.data.org_info.business_system_number;
} else {
baseInfo2[0].value = res.data.data.org_info.name;
baseInfo2[1].value = res.data.data.org_info.organization_code;
baseInfo2[2].value = res.data.data.org_info.platform_users_number;
}
console.log(baseInfo);
} else {
ElMessage.error(res.data.data);
}
});
};
const searchChange = (val) => {
orgTree.value.filterTree(val);
};
const goDetail = (params) => {
router.push({
path: "/authority/organization/user-detail",
query: {
id: params.id,
},
});
};
const stateChange = (row) => {
if (row.is_admin == 4) {
return;
}
const state = row.state.toString();
axios.post(`/apaas/system/v5/user/state/${row.id}/${state}`).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
row.state = row.state == 0 ? 1 : 0;
}
});
};
const editPsdAccount = (data) => {
selectedRow.value = data;
editFlag.value = true;
};
const handleCloseEdit = () => {
if (!passwordRef) return;
passwordRef.value.resetFields();
editFlag.value = false;
};
const editConfirm = () => {
if (!passwordRef) return;
passwordRef.value.validate((valid, fields) => {
if (valid) {
axios
.post(`/apaas/system/v5/user/editpwd`, {
id: selectedRow.value.id,
password: CryptoJS.AES.encrypt(passwordForm.password, "swuE9cmCZQwrkYRV").toString(),
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
handleCloseEdit();
});
}
});
};
const deleteAccount = (data) => {
if (data.state === 0) {
selectedRow.value = data;
deleteRowFlag.value = true;
} else {
ElMessage.error("当前状态已启用,不可删除!");
}
};
const handleCloseRowDelete = () => {
deleteRowFlag.value = false;
};
const deleteRowConfirm = () => {
axios.delete(`/apaas/system/v5/user/delete`, { data: { ids: [selectedRow.value.id] } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
}
handleCloseRowDelete();
});
};
const editAccount = (data) => {
if (selectTreeDataType.value === 1) {
router.push({
path: "/authority/organization/org-user/edit",
query: {
id: data.id,
orgId: selectOrgNode.value.organization_id,
},
});
} else {
router.push({
path: "/authority/organization/platform-user/edit",
query: {
id: data.id,
},
});
}
};
const handleCloseDelete = () => {
deleteFlag.value = false;
};
const deleteConfirm = () => {
const ids = selected.value.map((item) => item.id);
axios.delete(`/apaas/system/v5/user/delete`, { data: { ids: ids } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
}
handleCloseDelete();
});
};
const deleteBatch = () => {
if (selectedName.value.length > 0) {
deleteFlag.value = true;
} else {
ElMessage.error("请先选择需要操作的数据!");
}
};
const handleCloseReset = () => {
resetFlag.value = false;
};
const resetPsd = () => {
if (selectedName.value.length > 0) {
resetFlag.value = true;
} else {
ElMessage.error("请先选择需要操作的数据!");
}
};
const resetConfirm = () => {
const ids = selected.value.map((item) => item.id);
axios.post(`/apaas/system/v5/user/resetpwd`, { ids: ids }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
}
handleCloseReset();
});
};
const selectRows = (data) => {
selected.value = data.selection;
selectedName.value = data.selection.map((item) => item.system_account);
};
const clearSelected = () => {
dataTable.value.clearTable();
};
onBeforeMount(() => {});
</script>
<style scoped>
.tree_header {
height: 40px;
line-height: 40px;
background-color: #f7f7f9;
border-radius: 6px 6px 0px 0px;
font-size: 16px;
letter-spacing: 0px;
color: #202531;
padding-left: 16px;
}
.tree_content {
overflow: hidden;
height: calc(100% - 45px);
}
.search {
padding: 16px;
}
.tree {
overflow: hidden auto;
height: calc(100% - 65px);
/* padding: 5px; */
}
.tree :deep() .el-tree-node > .el-tree-node__children {
overflow: unset;
}
.flex_right {
display: flex;
flex-direction: column;
}
.info_container {
padding: 15px;
margin-bottom: 10px;
}
.title {
font-size: 18px;
color: #202531;
font-weight: bold;
margin-bottom: 10px;
max-width: 960px;
display: flex;
justify-content: space-between;
align-items: center;
}
.detail_btn {
font-size: 14px;
font-weight: normal;
}
.icon_box {
display: flex;
align-items: center;
}
.step_icon {
display: inline-block;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
background-color: #2a4aa7;
color: #fff;
border-radius: 4px;
font-size: 14px;
margin-right: 8px;
}
.info_box {
max-width: 960px;
}
.main_container {
flex: 1;
overflow: hidden;
}
.filter-group .left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
}
.filter-group .right-action {
width: 144px;
padding-bottom: 16px;
}
.filter-group .right-action .el-button {
width: 64px;
}
.table_container {
height: calc(100% - 20px);
overflow: auto;
padding: 0 16px;
}
.bg-pagination {
bottom: unset;
}
.dialog_form {
padding: 24px 8px 6px;
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content apaas_scroll">
<div class="info_row">
<div class="title">
<div><span class="icon_box"></span> 基础信息</div>
<div class="dashed_line"></div>
</div>
<div class="info_content">
<div class="info_box">
<bg-info :data="baseInfo"></bg-info>
</div>
<div class="org_file info_box">
<div class="pl-1">组织附件</div>
<div>
<div class="file_item pl-1" v-for="(item, index) in fileList" :key="'file_' + index">
<span><bg-icon style="font-size: 24px" :icon="'#bg-ic-' + formatFile(item)"></bg-icon></span>
<span class="file_name">{{ downloadFileFormatNew(item) }}</span>
<span class="fr download_btn">
<el-button type="primary" @click="downloadFile(item)"
><bg-icon icon="#bg-ic-to-bottom"></bg-icon>下载</el-button
>
</span>
</div>
</div>
</div>
</div>
</div>
<div>
<div class="title">
<div><span class="icon_box"></span> 业务系统信息</div>
<div class="dashed_line"></div>
</div>
<div class="info_content info_box">
<bg-table ref="bgTable" :headers="headers" :rows="tableRows" :isIndex="true" :stripe="true"> </bg-table>
<div class="pagination_box">
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, ref, computed, onBeforeMount } from "vue";
import { useRoute } from "vue-router";
import { downloadFileFormatNew } from "@/services/helper";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const baseInfo = reactive([
{
name: "组织名称",
value: "",
nameWidth: 130,
},
{
name: "组织代码",
value: "",
nameWidth: 130,
},
{
name: "组织管理员数量",
value: "",
nameWidth: 130,
},
{
name: "业务系统数量",
value: "",
nameWidth: 130,
},
{
name: "组织描述",
value: "",
nameWidth: 130,
},
]);
const headers = reactive([
{
label: "业务系统名称",
prop: "business_name",
},
{
label: "是否启用",
prop: "state",
},
{
label: "业务系统账号",
prop: "system_account",
},
]);
const tableRows = ref([]);
const fileList = ref([]);
const filter = reactive({
page: 1,
limit: 10,
});
const tableTotal = ref(0);
const changeSize = (size) => {
filter.limit = size;
changePage(1);
};
const changePage = (page) => {
filter.page = page;
getSystemInfo();
};
const downloadFile = (data) => {
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", data); // href链接
a.click(); // 自执行点击事件
};
const formatFile = (url) => {
const file = url.split(".")[1];
let icon = "";
if ("docx".indexOf(file) !== -1) {
icon = "c-file-doc";
} else if ("xlsx".indexOf(file) !== -1) {
icon = "c-file-xlsx";
} else if ("pdf".indexOf(file) !== -1) {
icon = "c-file-pdf";
} else if ("txt".indexOf(file) !== -1) {
icon = "c-file-txt";
} else if ("zip".indexOf(file) !== -1) {
icon = "c-file-zip";
} else if ("jpg,png".indexOf(file) !== -1) {
icon = "c-file-image";
} else {
icon = "txt";
}
return icon;
};
const getDetail = () => {
axios
.get(`/apaas/system/v5/org/detail?organization_id=${route.query.id}&key_word=&state=&limit=&page=&data_type=1`)
.then((res) => {
if (res.data.code == 200) {
const detail = res.data.data.org_info;
baseInfo[0].value = detail.name;
baseInfo[1].value = detail.organization_code;
baseInfo[2].value = detail.org_admin_number;
baseInfo[3].value = detail.business_system_number;
baseInfo[4].value = detail.description;
fileList.value = detail.attachment ? detail.attachment.split(",") : [];
} else {
ElMessage.error(res.data.data);
}
});
};
const getSystemInfo = () => {
const params = { ...filter, organization_id: route.query.id };
axios.get(`/apaas/system/v5/org/business/msg`, { params }).then((res) => {
if (res.data.code == 200) {
tableRows.value = res.data.data || [];
tableTotal.value = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
if (route.query.id) {
getDetail();
getSystemInfo();
}
});
</script>
<style scoped>
.page_content {
padding: 15px;
overflow: auto;
font-size: 14px;
color: #202531;
}
.info_content {
/* display: flex; */
}
.org_file {
margin-top: 15px;
}
.file_item {
height: 48px;
line-height: 48px;
background-color: #fafafa;
border-radius: 4px;
font-size: 14px;
margin-bottom: 8px;
}
.file_name {
padding-left: 10px;
color: #202531;
}
.download_btn {
padding-right: 4px;
}
.info_row {
margin-bottom: 40px;
}
.img_box {
width: 120px\;;
}
.info_box {
width: 60%;
}
.title {
font-size: 18px;
color: #1a1a1a;
font-weight: bold;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.dashed_line {
flex: 1;
height: 1px;
margin: 0 10px;
border-bottom: dashed 1px #dadee7;
}
.icon_box {
display: inline-block;
width: 4px;
height: 14px;
background-color: #3759be;
border-radius: 2px;
margin-right: 5px;
}
.pagination_box {
position: sticky;
position: -webkit-sticky;
margin-top: 16px;
bottom: -15px;
background-color: #fff;
z-index: 1024;
height: 40px;
line-height: 40px;
padding-top: 5px;
}
.bg-pagination {
margin-top: 0px;
}
.info_content :deep() .bg-table .empty_container {
height: 160px;
padding-top: 25px;
}
</style>
<template>
<el-form :label-position="'right'" label-width="120px" :model="orgForm" :rules="formRules" ref="orgRef">
<el-form-item label="上级目录" prop="p_organization_id" v-if="formType === 'create'">
<el-tree-select
v-model="orgForm.p_organization_id"
:data="orgData"
:props="treeProps"
:render-after-expand="false"
:check-strictly="true"
:disabled="orgForm.level"
style="width: 80%" />
<el-form-item label="" style="padding-left: 16px">
<el-checkbox v-model="orgForm.level" @change="isTop" label="顶级" />
</el-form-item>
</el-form-item>
<el-form-item label="政务组织名称" prop="name">
<el-input v-model="orgForm.name" />
</el-form-item>
<el-form-item label="组织代码" prop="organization_code">
<el-input v-model="orgForm.organization_code" />
</el-form-item>
<el-form-item label="组织介绍" prop="description">
<el-input type="textarea" :rows="3" v-model="orgForm.description" maxlength="300" show-word-limit />
</el-form-item>
<el-form-item label="组织附件" prop="logo">
<bg-upload
v-model="orgForm.attachment"
customTips
:limit="3"
:fileTypes="['zip', 'rar', 'doc', 'docx', 'xlsx', 'xls', 'png', 'jpg']"
:otherInfo="'最多可上传三个附件,可上传zip,rar,doc,docx,xlsx,xls,png,jpg,可上传营业执照和相关协议文件等'">
<span>将文件拖到此处,或 点击上传</span>
</bg-upload>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted, onBeforeMount } from "vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const props = defineProps({
formType: {
type: String,
default: "create", //false 新增 true 编辑
},
});
const orgForm = reactive({
p_organization_id: "",
level: false,
name: "",
organization_code: "",
description: "",
attachment: [],
});
const checkCode = (rule, value, callback) => {
var reg = /^[a-zA-Z0-9]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母和数字"));
} else {
callback();
}
};
const checkName = (rule, value, callback) => {
var reg = /^[a-zA-Z\u4e00-\u9fa5]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母和汉字"));
} else {
callback();
}
};
const formRules = reactive({
p_organization_id: [{ required: true, message: "输入上级目录", trigger: "blur" }],
name: [
{ required: true, message: "请输入组织名称", trigger: "blur" },
{ max: 50, message: "组织名称最大长度为50位", trigger: "blur" },
{ validator: checkName, trigger: "blur" },
],
organization_code: [
{ required: true, message: "请输入组织代码", trigger: "blur" },
{ max: 18, message: "组织代码最大长度为18位", trigger: "blur" },
{ validator: checkCode, trigger: "blur" },
],
});
const orgRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!orgRef) return;
await orgRef.value.validate((valid, fields) => {
if (valid) {
emit("action", orgForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!orgRef) return;
orgRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(orgForm, data);
};
const orgData = ref([]);
const treeProps = {
label: "name",
children: "Child",
value: "organization_id",
disabled: "disabled",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
orgDataTemp.shift();
orgData.value = filterOrg(orgDataTemp);
} else {
ElMessage.error(res.data.data);
}
});
};
const filterOrg = (data) => {
if (data.length > 0) {
data.forEach((item) => {
item.disabled = item.data_type === 0 ? false : true;
if (item.Child) {
filterOrg(item.Child);
} else {
return;
}
});
}
return data;
};
const isTop = (data) => {
orgForm.p_organization_id = data ? " " : ""; //空格绕过表单非空校验
};
onBeforeMount(() => {
getOrgTree();
});
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<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"></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-staff"></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">
<orgAccountForm
v-show="step === 1"
:form-type="route.query.id ? true : false"
:id="route.query.id"
ref="orgAccountRef"
@action="getOrgAccountFormData"></orgAccountForm>
<orgPersonForm v-show="step === 2" ref="orgPersonRef" @action="getOrgPersonFormData"></orgPersonForm>
<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">
{{
route.query.id
? successFlag
? "组织用户编辑成功"
: "组织用户编辑失败"
: successFlag
? "组织用户新增成功"
: "组织用户新增失败"
}}
</div>
<el-button @click="cancel">返回列表</el-button>
<el-button v-if="!route.query.id" type="primary" @click="continueCreate">继续创建</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 orgAccountForm from "./org-account-form.vue";
import orgPersonForm from "./org-person-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 bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const router = useRouter();
const step = ref(1);
const orgAccountRef = ref(null);
const orgPersonRef = ref(null);
const formData = reactive({
organization_id: "",
select_role: "",
logo: [],
system_account: "",
contact_phone: "",
password: "",
confirm_password: "",
state: 1,
contact_name: "",
document_type: "",
document_number: "",
contact_email: "",
remark: "",
}); //账号信息表单+个人信息表单
const successFlag = ref(false);
const orgId = ref("");
// 下一步
const nextStep = () => {
orgAccountRef.value.submitForm();
};
//账号信息表单检验触发事件 data为null 校验失败
const getOrgAccountFormData = (data) => {
if (data) {
Object.assign(formData, data);
step.value = 2;
} else {
}
};
//个人信息表单检验触发事件 data为null 校验失败
const getOrgPersonFormData = (data) => {
if (data) {
if (data) {
Object.assign(formData, data);
if (route.query.id) {
let params = {
...formData,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
};
params.document_type = params.document_type == "" ? 0 : params.document_type;
axios.put(`/apaas/system/v5/org/update/user/${route.query.id}`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
} else {
const params = {
...formData,
// organization_id: orgId.value,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
is_admin: 2,
password: CryptoJS.AES.encrypt(formData.password, "swuE9cmCZQwrkYRV").toString(),
};
params.document_type = params.document_type == "" ? 0 : params.document_type;
axios.post(`/apaas/system/v5/org/add/user`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
}
}
}
};
//上一步
const previousStep = () => {
step.value--;
};
//提交表单
const submit = () => {
orgPersonRef.value.submitForm();
};
//继续创建 清空表单
const continueCreate = () => {
orgAccountRef.value.clearForm();
orgPersonRef.value.clearForm();
step.value = 1;
successFlag.value = false;
};
//取消
const cancel = () => {
router.push({
path: "/system/organization",
query: {
id: route.query.orgId,
},
});
};
const getDetail = () => {
axios.get(`/apaas/system/v5/org/user/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const form = res.data.data;
orgAccountRef.value.setForm({
organization_id: form.organization_id,
select_role: form.select_role,
logo: form.logo ? [{ url: form.logo }] : [],
system_account: form.system_account,
contact_phone: form.contact_phone,
state: form.state,
});
orgPersonRef.value.setForm({
contact_name: form.contact_name,
document_type: form.document_type ? form.document_type : "",
document_number: form.document_number,
contact_email: form.contact_email,
remark: form.remark,
});
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
if (route.query.id) {
getDetail();
}
});
onMounted(() => {});
</script>
<style scoped>
.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="orgAccountForm"
:rules="orgAccountFormRules"
ref="orgformAccountRef"
style="max-width: 66%">
<el-form-item label="所属组织" prop="organization_id">
<el-tree-select
v-model="orgAccountForm.organization_id"
:data="orgData"
:props="treeProps"
:render-after-expand="false"
:disabled="true"
style="width: 100%" />
<!-- <el-input v-model="orgAccountForm.organization_id" /> -->
</el-form-item>
<el-form-item label="角色" prop="select_role" v-if="!formType">
<el-select
v-model="orgAccountForm.select_role"
multiple
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-form-item>
<el-form-item label="头像" prop="logo">
<bg-upload-image
v-model="orgAccountForm.logo"
:showTips="true"
:limit="1"
:fileSize="500"
:fileSizeUnit="'KB'"
listType="picture-card"
:accept="['.jpg', '.jpeg', '.png']"
customTips="请选择图片上传:大小120 * 120像素支持jpg、png等格式,图片需小于500KB"></bg-upload-image>
</el-form-item>
<el-form-item label="账号" prop="system_account">
<el-input v-model="orgAccountForm.system_account" />
</el-form-item>
<el-form-item label="手机号" prop="contact_phone">
<el-input v-model="orgAccountForm.contact_phone" />
</el-form-item>
<el-form-item label="密码" prop="password" v-if="!formType">
<el-input type="password" v-model="orgAccountForm.password" />
</el-form-item>
<el-form-item label="确认密码" prop="confirm_password" v-if="!formType">
<el-input type="password" v-model="orgAccountForm.confirm_password" />
</el-form-item>
<el-form-item label="是否启用" prop="state">
<bg-switch :labels="['否', '是']" :values="[0, 1]" v-model="orgAccountForm.state"></bg-switch>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted, onBeforeMount } from "vue";
import { useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const route = useRoute();
const props = defineProps({
formType: {
type: Boolean,
default: false, //false 新增 true 编辑
},
id: {
type: String,
default: "",
},
});
const orgAccountForm = reactive({
organization_id: "",
select_role: "",
logo: [],
system_account: "",
contact_phone: "",
password: "",
confirm_password: "",
state: 1,
});
const validatePass = (rule, value, callback) => {
if (value !== orgAccountForm.password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const validateSystemAccount = (rule, value, callback) => {
let reg = /^[a-zA-Z0-9]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母和数字"));
} else {
let params = null;
if (props.id) {
params = { id: parseInt(props.id), system_account: value };
} else {
params = { system_account: value };
}
axios.post(`/apaas/system/v5/user/check/account`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
}
};
const checkPhone = (rule, value, callback) => {
var phone_ruler = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/;
setTimeout(() => {
if (!phone_ruler.test(value) && value.length !== 0) {
callback(new Error("请输入正确的手机号码"));
} else {
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 orgAccountFormRules = reactive({
organization_id: [{ required: true, message: "请选择组织", trigger: "blur" }],
select_role: [{ 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" },
],
contact_phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{ validator: checkPhone, trigger: "blur" },
{ validator: checkPhoneRepet, 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" },
],
});
const orgformAccountRef = ref(null);
const emit = defineEmits(["action"]);
const roleList = ref([]);
const submitForm = async () => {
if (!orgformAccountRef) return;
await orgformAccountRef.value.validate((valid, fields) => {
if (valid) {
emit("action", orgAccountForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!orgformAccountRef) return;
orgformAccountRef.value.resetFields();
orgAccountForm.select_role = [roleList.value[0].role_id];
};
const setForm = (data) => {
Object.assign(orgAccountForm, data);
};
const orgData = ref([]);
const treeProps = {
label: "name",
children: "Child",
value: "organization_id",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
orgData.value = res.data.data || [];
} else {
ElMessage.error(res.data.data);
}
});
};
const getRoleList = () => {
axios.get(`/apaas/system/v5/org/select/role?is_admin=2`).then((res) => {
if (res.data.code == 200) {
roleList.value = res.data.data;
orgAccountForm.select_role = [roleList.value[0].role_id];
} else {
}
});
};
onBeforeMount(() => {
getOrgTree();
getRoleList();
orgAccountForm.organization_id = route.query.orgId;
});
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<el-form
:label-position="'right'"
label-width="120px"
:model="orgPersonForm"
:rules="orgPersonFormRules"
ref="orgPersonFormRef"
style="max-width: 66%">
<el-form-item label="联系人姓名" prop="contact_name">
<el-input v-model="orgPersonForm.contact_name" />
</el-form-item>
<el-form-item label="证件类型" prop="document_type">
<el-select v-model="orgPersonForm.document_type" placeholder="请选择证件类型" style="width: 100%">
<el-option v-for="item in documentTypeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="证件号" prop="document_number">
<el-input v-model="orgPersonForm.document_number" />
</el-form-item>
<el-form-item label="联系人邮箱" prop="contact_email">
<el-input v-model="orgPersonForm.contact_email" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="orgPersonForm.remark" />
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
const orgPersonForm = reactive({
contact_name: "",
document_type: "",
document_number: "",
contact_email: "",
remark: "",
});
const documentTypeList = ref([
{
label: "身份证",
value: 1,
},
]);
const orgPersonFormRules = reactive({
contact_email: [
// { required: true, message: '请输入手机号', trigger: 'blur' },
{ type: "email", message: "请输入正确的邮箱", trigger: "blur" },
],
document_number: [
{
pattern:
/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}[0-9Xx]$)/,
message: "请输入正确的身份证号",
trigger: "blur",
},
],
});
const orgPersonFormRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!orgPersonFormRef) return;
await orgPersonFormRef.value.validate((valid, fields) => {
if (valid) {
emit("action", orgPersonForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!orgPersonFormRef) return;
orgPersonFormRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(orgPersonForm, data);
};
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content flex_cloumn">
<div class="content_top apaas_scroll">
<div class="content_process" v-if="!route.query.id">
<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"></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-staff"></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">
<platformAccountForm
v-show="step === 1"
:form-type="route.query.id ? true : false"
:id="route.query.id"
ref="platformAccountFormRef"
@action="getPlatformAccountFormData"></platformAccountForm>
<platformPersonForm
v-show="step === 2"
ref="plplatformPersonFormRef"
@action="getPlatformPersonFormData"></platformPersonForm>
<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">
{{
route.query.id
? successFlag
? "平台用户编辑成功"
: "平台用户编辑失败"
: successFlag
? "平台用户新增成功"
: "平台用户新增失败"
}}
</div>
<el-button @click="cancel">返回列表</el-button>
<el-button v-if="!route.query.id" type="primary" @click="continueCreate">继续创建</el-button>
</div>
</div>
</div>
</div>
<div class="content_bottom" v-if="step !== 3">
<div v-show="!route.query.id && 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 v-show="route.query.id">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="nextStep">保存</el-button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { useRoute, useRouter } from "vue-router";
import platformAccountForm from "./platform-account-form.vue";
import platformPersonForm from "./platform-person-form.vue";
import CryptoJS from "crypto-js";
import { reactive, ref, onBeforeMount, toRefs, computed, onMounted } from "vue";
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 step = ref(1);
const platformAccountFormRef = ref(null);
const plplatformPersonFormRef = ref(null);
const formData = reactive({
logo: "",
system_account: "",
contact_phone: "",
password: "",
confirm_password: "",
select_role: "",
state: "",
contact_name: "",
contact_email: "",
remark: "",
}); //账号信息表单+个人信息表单
const orgId = ref(null);
const successFlag = ref(false);
// 下一步
const nextStep = () => {
platformAccountFormRef.value.submitForm();
};
//账号信息表单检验触发事件 data为null 校验失败
const getPlatformAccountFormData = (data) => {
if (data) {
if (route.query.id) {
Object.assign(formData, data);
let params = {
...formData,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
};
axios.put(`/apaas/system/v5/org/update/user/${route.query.id}`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
} else {
Object.assign(formData, data);
step.value = 2;
}
} else {
}
};
//个人信息表单检验触发事件 data为null 校验失败
const getPlatformPersonFormData = (data) => {
if (data) {
Object.assign(formData, data);
if (route.query.id) {
console.log(formData);
// let params = {
// }
// axios.post(`/apaas/system/v5/org/update/user/${route.query.id}`,params)
// .then((res) => {
// if (res.data.code == 200) {
// successFlag.value = true;
// step.value = 3;
// }else {
// ElMessage.error(res.data.msg)
// }
// })
} else {
const params = {
...formData,
organization_id: orgId.value,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
is_admin: 3,
password: CryptoJS.AES.encrypt(formData.password, "swuE9cmCZQwrkYRV").toString(),
};
axios.post(`/apaas/system/v5/org/add/user`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
}
}
};
//上一步
const previousStep = () => {
step.value--;
};
//提交表单
const submit = () => {
plplatformPersonFormRef.value.submitForm();
};
//继续创建 清空表单
const continueCreate = () => {
platformAccountFormRef.value.clearForm();
plplatformPersonFormRef.value.clearForm();
step.value = 1;
successFlag.value = false;
};
//取消
const cancel = () => {
router.go(-1);
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
orgId.value = res.data.data[0].organization_id;
} else {
ElMessage.error(res.data.data);
}
});
};
const getDetail = () => {
axios.get(`/apaas/system/v5/org/user/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const form = res.data.data;
console.log(form);
platformAccountFormRef.value.setForm({
logo: form.logo ? [{ url: form.logo }] : [],
system_account: form.system_account,
contact_phone: form.contact_phone,
state: form.state,
contact_name: form.contact_name,
contact_email: form.contact_email,
remark: form.remark,
select_role: form.select_role,
});
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getOrgTree();
if (route.query.id) {
getDetail();
}
});
onMounted(() => {});
</script>
<style scoped>
.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="platformAccountForm"
:rules="platformAccountFormRules"
ref="platformAccountRef"
style="max-width: 66%">
<el-form-item label="头像" prop="logo">
<bg-upload-image
v-model="platformAccountForm.logo"
:showTips="true"
:limit="1"
:fileSize="500"
:fileSizeUnit="'KB'"
listType="picture-card"
:accept="['.jpg', '.jpeg', '.png']"
customTips="请选择图片上传:大小120 * 120像素支持jpg、png等格式,图片需小于500KB"></bg-upload-image>
</el-form-item>
<el-form-item label="账号" prop="system_account">
<el-input v-model="platformAccountForm.system_account" />
</el-form-item>
<el-form-item label="手机号" prop="contact_phone">
<el-input v-model="platformAccountForm.contact_phone" />
</el-form-item>
<el-form-item v-if="!formType" label="密码" prop="password">
<el-input type="password" v-model="platformAccountForm.password" />
</el-form-item>
<el-form-item v-if="!formType" label="确认密码" prop="confirm_password">
<el-input type="password" v-model="platformAccountForm.confirm_password" />
</el-form-item>
<el-form-item label="角色授权" prop="select_role">
<el-select v-model="platformAccountForm.select_role" multiple placeholder="请选择角色" 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-form-item>
<el-form-item v-if="formType" label="姓名" prop="contact_name">
<el-input v-model="platformAccountForm.contact_name" />
</el-form-item>
<el-form-item v-if="formType" label="邮箱" prop="contact_email">
<el-input v-model="platformAccountForm.contact_email" />
</el-form-item>
<el-form-item v-if="formType" label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="platformAccountForm.remark" />
</el-form-item>
<el-form-item label="是否启用" prop="state">
<bg-switch :labels="['否', '是']" :values="[0, 1]" v-model="platformAccountForm.state"></bg-switch>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted, onBeforeMount } from "vue";
import axios from "@/request/http.js";
const props = defineProps({
formType: {
type: Boolean,
default: false, //false 新增 true 编辑
},
id: {
type: String,
default: "",
},
});
const platformAccountForm = reactive({
logo: [],
system_account: "",
contact_phone: "",
password: "",
confirm_password: "",
select_role: "",
state: 1,
contact_name: "",
contact_email: "",
remark: "",
});
const validatePass = (rule, value, callback) => {
if (value !== platformAccountForm.password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const checkPhone = (rule, value, callback) => {
var phone_ruler = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/;
setTimeout(() => {
if (!phone_ruler.test(value) && value.length !== 0) {
callback(new Error("请输入正确的手机号码"));
} else {
callback();
}
});
};
const validateSystemAccount = (rule, value, callback) => {
let reg = /^[a-zA-Z0-9]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母和数字"));
} else {
let params = null;
if (props.id) {
params = { id: parseInt(props.id), system_account: value };
} else {
params = { system_account: value };
}
axios.post(`/apaas/system/v5/user/check/account`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
}
};
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 platformAccountFormRules = reactive({
system_account: [
{ required: true, message: "请输入账号", trigger: "blur" },
{ min: 4, message: "帐号长度不得低于4个字符", trigger: "blur" },
{ max: 20, message: "帐号最大长度为20个字符", trigger: "blur" },
{ validator: validateSystemAccount, trigger: "blur" },
],
contact_phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{ validator: checkPhone, trigger: "blur" },
{ validator: checkPhoneRepet, trigger: "blur" },
],
select_role: [{ required: true, message: "请选择角色", 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" },
],
contact_email: [{ type: "email", message: "请输入正确的邮箱", trigger: "blur" }],
});
const roleList = ref([]);
const platformAccountRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!platformAccountRef) return;
await platformAccountRef.value.validate((valid, fields) => {
if (valid) {
emit("action", platformAccountForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!platformAccountRef) return;
platformAccountRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(platformAccountForm, data);
};
const getRoleList = () => {
axios.get(`/apaas/system/v5/org/select/role?is_admin=3`).then((res) => {
if (res.data.code == 200) {
roleList.value = res.data.data;
} else {
}
});
};
onBeforeMount(() => {
getRoleList();
});
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<el-form
:label-position="'right'"
label-width="120px"
:model="platformPersonForm"
:rules="platformPersonFormRules"
ref="platformPersonFormRef"
style="max-width: 66%">
<el-form-item label="姓名" prop="contact_name">
<el-input v-model="platformPersonForm.contact_name" />
</el-form-item>
<el-form-item label="邮箱" prop="contact_email">
<el-input v-model="platformPersonForm.contact_email" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="platformPersonForm.remark" />
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
const platformPersonForm = reactive({
contact_name: "",
contact_email: "",
remark: "",
});
const platformPersonFormRules = reactive({
contact_email: [{ type: "email", message: "请输入正确的邮箱", trigger: "blur" }],
});
const platformPersonFormRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!platformPersonFormRef) return;
await platformPersonFormRef.value.validate((valid, fields) => {
if (valid) {
emit("action", platformPersonForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!platformPersonFormRef) return;
platformPersonFormRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(platformPersonForm, data);
};
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<el-tree
ref="treeRef"
class="file-tree"
:data="orgData"
:props="defaultProps"
@node-click="handleNodeClick"
node-key="id"
:highlight-current="true"
:filter-node-method="filterNode"
:expand-on-click-node="false"
:default-expand-all="true">
<template #default="{ node, data }">
<div class="custom_tree_node">
<span class="label-text" :title="data.name">{{ data.name }} </span>
<span
v-if="data.data_type === 2"
class="tree-action-box first_node"
:class="{ first_node_focus: (selectData && selectData.id === data.id) || !selectData }"
@click.stop="showAction($event, data, node)">
<bg-icon class="tree-more" icon="#bg-ic-s-more"></bg-icon>
</span>
<span
v-else
class="tree-action-box"
@click.stop="showAction($event, data, node)">
<bg-icon class="tree-more" icon="#bg-ic-s-more"></bg-icon>
</span>
</div>
</template>
</el-tree>
<Teleport to="body">
<div
ref="treeActionRef"
class="tree-action"
v-show="actionFlag"
:style="{ top: acTop, left: acLeft, bottom: acBottom }">
<!-- 平台用户组织 -->
<div
v-if="selectData && selectData.data_type === 2"
class="action"
@click="treeAction({ type: 'directory', action: 'create', target: null })">
新增目录
</div>
<div
v-if="selectData && selectData.data_type === 2"
class="action"
@click="treeAction({ type: 'org', action: 'create', target: null })">
新增组织
</div>
<!-- 目录 -->
<div
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'directory', action: 'create', target: 'local' })">
新增本级目录
</div>
<div
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'directory', action: 'create', target: 'child' })">
新增下级目录
</div>
<div
v-if="selectData && selectData.data_type === 0 && selectData.level !== 1"
class="action"
@click="treeAction({ type: 'org', action: 'create', target: 'local' })">
新增本级组织
</div>
<div
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'org', action: 'create', target: 'child' })">
新增下级组织
</div>
<div
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'directory', action: 'edit', target: 'local' })">
编辑目录
</div>
<div
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'directory', action: 'delete', target: 'local' })">
删除
</div>
<div
:class="{
disable:
mvDataParent.indexOf(selectData) === 0 ||
(mvDataParent.indexOf(selectData) === 1 && mvDataParent[0].data_type == 2),
}"
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'directory', action: 'mvup', target: 'local' })">
上移
</div>
<div
:class="{ disable: mvDataParent.indexOf(selectData) === mvDataParent.length - 1 }"
v-if="selectData && selectData.data_type === 0"
class="action"
@click="treeAction({ type: 'directory', action: 'mvdown', target: 'local' })">
下移
</div>
<!-- 组织 -->
<div
v-if="selectData && selectData.data_type === 1"
class="action"
@click="treeAction({ type: 'org', action: 'create', target: 'local' })">
新增本级组织
</div>
<div
v-if="selectData && selectData.data_type === 1"
class="action"
@click="treeAction({ type: 'org', action: 'edit', target: 'local' })">
编辑组织
</div>
<div
v-if="selectData && selectData.data_type === 1"
class="action"
@click="treeAction({ type: 'org', action: 'delete', target: 'local' })">
删除
</div>
<div
:class="{ disable: mvDataParent.indexOf(selectData) === 0 }"
v-if="selectData && selectData.data_type === 1"
class="action"
@click="treeAction({ type: 'org', action: 'mvup', target: 'local' })">
上移
</div>
<div
:class="{ disable: mvDataParent.indexOf(selectData) === mvDataParent.length - 1 }"
v-if="selectData && selectData.data_type === 1"
class="action"
@click="treeAction({ type: 'org', action: 'mvdown', target: 'local' })">
下移
</div>
</div>
</Teleport>
</template>
<script setup>
import { reactive, toRefs, ref, computed, onBeforeMount, onBeforeUnmount, watch, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const route = useRoute();
const acTop = ref("");
const acLeft = ref("");
const acBottom = ref("");
const actionFlag = ref(false);
const selectData = ref(null);
const selectDataParent = ref(null);
const mvDataParent = ref([]);
const treeRef = ref(null);
const treeActionRef = ref(null);
const bottomGap = ref(30); //弹窗吸底高度
const orgData = ref([]);
const selectNodeObj = ref(null);
const customNodeClass = (data, node) => {
if (data.data_type == 0) {
return "noFocus";
} else {
return "";
}
};
const defaultProps = {
label: "name",
children: "Child",
value: "organization_id",
class: customNodeClass,
};
const getOrgTree = (data) => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
orgData.value = res.data.data || [];
console.log(route.query.id);
if (route.query.id) {
searchItem(orgData.value, route.query.id);
data = selectNodeObj.value;
}
if (data) {
nextTick(() => {
setCurrentNode(data);
});
} else {
nextTick(() => {
setCurrentNode(orgData.value[0].id);
});
}
} else {
ElMessage.error(res.data.data);
}
});
};
const searchItem = (data, id) => {
data.forEach((e) => {
if (e.organization_id == id) {
selectNodeObj.value = e;
} else {
if (e.Child) {
searchItem(e.Child, id);
}
}
});
};
const filterTree = (val) => {
treeRef.value.filter(val);
};
const setCurrentNode = (data) => {
if (data) {
treeRef.value.setCurrentKey(data, true);
const curNode = treeRef.value.getCurrentNode();
selectData.value = curNode;
emit("select", { data: ref(curNode), type: "click" });
} else {
treeRef.value.setCurrentKey(orgData.value[0].id, true);
const curNode = treeRef.value.getCurrentNode();
selectData.value = curNode;
emit("select", { data: ref(curNode), type: "click" });
}
};
const filterNode = (value, data) => {
if (!value) return true;
return data.name.includes(value);
};
const showAction = (e, data, node) => {
acTop.value = "";
acLeft.value = "";
acBottom.value = "";
var allHeight = document.body.scrollHeight;
actionFlag.value = true;
selectData.value = data;
selectDataParent.value = node.parent.data.name ? node.parent.data : null;
mvDataParent.value = node.parent.data.Child ? node.parent.data.Child : node.parent.data;
const rect = e.target.getBoundingClientRect(); //获取点击的dom的位置
nextTick().then(() => {
setTimeout(() => {
var height = window.getComputedStyle(treeActionRef.value).height;
height = parseInt(height);
//判断弹窗位置是否超过屏幕,超过则吸底展示
if (height + rect.y - 17 > allHeight - bottomGap.value) {
acBottom.value = bottomGap.value + "px";
acLeft.value = rect.x + 35 + "px";
} else {
acTop.value = rect.y - 17 + "px";
acLeft.value = rect.x + 35 + "px";
}
});
});
// acTop.value = rect.y - 17 + "px";
// acLeft.value = rect.x + 35 + "px";
};
const isSticky = (data) => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
context.font = "14px MicrosoftYaHei";
const { width } = context.measureText(data);
return width > 255 ? true : false;
};
const closeAction = () => {
actionFlag.value = false;
};
const emit = defineEmits(["action", "select"]);
const handleNodeClick = (node, nodeAttr, treeNode, event) => {
if (node.data_type !== 0) {
selectData.value = node;
emit("select", { data: selectData, type: "click" });
} else {
nextTick(() => {
treeRef.value.setCurrentKey(null);
});
}
//只读则无操作事件
closeAction();
};
const treeAction = (params) => {
emit("select", { data: selectData, type: "action" });
let data = null;
if (params.action === "create") {
if (params.target === "local") {
data = selectDataParent;
} else if (params.target === "child") {
data = selectData;
} else {
}
} else if (params.action === "mvup") {
// 已经是第一个元素 或者上一个元素是平台组织 则不可上移 平台组织始终在第一个
if (
mvDataParent.value.indexOf(selectData.value) === 0 ||
(mvDataParent.value.indexOf(selectData.value) === 1 && mvDataParent.value[0].data_type == 2)
) {
// ElMessage.error('已经是第一个元素,不可上移')
return 0;
} else {
let brother = mvDataParent.value[mvDataParent.value.indexOf(selectData.value) - 1];
data = [
{ id: selectData.value.id, sort: brother.sort },
{ id: brother.id, sort: selectData.value.sort },
];
}
} else if (params.action === "mvdown") {
if (mvDataParent.value.indexOf(selectData.value) === mvDataParent.value.length - 1) {
// ElMessage.error('已经是最后一个元素,不可下移')
return 0;
} else {
let brother = mvDataParent.value[mvDataParent.value.indexOf(selectData.value) + 1];
data = [
{ id: selectData.value.id, sort: brother.sort },
{ id: brother.id, sort: selectData.value.sort },
];
}
} else {
data = selectData;
}
emit("action", { type: params.type, action: params.action, data: data });
};
onBeforeMount(() => {
//只读则无操作事件
window.addEventListener("click", closeAction);
window.addEventListener("scroll", closeAction, true);
getOrgTree();
});
onBeforeUnmount(() => {
//只读则无操作事件
window.removeEventListener("click", closeAction);
window.removeEventListener("scroll", closeAction);
});
defineExpose({ getOrgTree, filterTree, setCurrentNode });
</script>
<style scoped>
.tree-action-box {
display: none;
position: absolute;
right: -5px;
top: 0px;
width: 44px;
height: 36px;
line-height: 36px;
text-align: center;
background-color: #f2f3f7;
box-shadow: -3px 0px 8px -3px rgba(0, 7, 101, 0.15);
}
.position_sticky {
position: sticky;
position: -webkit-sticky;
}
.tree-more {
font-size: 12px;
color: #3759be;
}
.file-tree :deep() .el-tree-node__content:hover .tree-action-box {
display: inline-block;
}
.file-tree :deep() .el-tree-node__content:hover + .label-text {
width: calc(100% - 48px);
}
.file-tree :deep() .el-tree-node__content .first_node {
display: inline-block;
background-color: #fff;
box-shadow: none;
}
.file-tree :deep() .el-tree-node__content .first_node_focus {
background-color: #f2f3f7;
box-shadow: -3px 0px 8px -3px rgba(0, 7, 101, 0.15);
}
.file-tree :deep() .el-tree-node__content:hover .first_node {
background-color: #f2f3f7;
box-shadow: -3px 0px 8px -3px rgba(0, 7, 101, 0.15);
}
.file-tree :deep() .el-tree-node > .el-tree-node__children {
overflow: visible;
}
.file-tree :deep() .el-tree-node__content {
position: relative;
}
.action-box:hover .tree-action {
display: block;
}
.label-text {
font-size: 14px;
color: #404a62;
display: inline-block;
width: calc(100% - 24px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tree-action-box:hover + .label-text {
padding: 8px 0;
background-color: var(--el-tree-node-hover-bg-color);
}
.label-text:hover {
padding: 8px 0;
/* background-color: var(--el-tree-node-hover-bg-color); */
width: calc(100% - 48px);
}
.is_active {
padding: 8px 0;
background-color: var(--el-color-primary-light-9);
}
.custom_tree_node {
width: 100%;
font-size: 14px;
color: #202531;
padding-right: 16px;
}
.text_clip {
width: 100%;
display: inline-block;
}
.tree-action .action {
width: 100%;
height: 34px;
line-height: 34px;
padding-left: 16px;
font-size: 14px;
color: #202531;
cursor: pointer;
}
.tree-action :deep().el-upload {
width: 100%;
}
.tree-action .action:hover {
background-color: #eff2fa;
color: #3759be;
}
.tree-action .disable {
cursor: not-allowed;
color: #616f94;
}
.tree-action .disable:hover {
background-color: #fff;
color: #616f94;
}
.tree-action {
/* display: none; */
width: 144px;
background-color: #ffffff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
padding: 4px 0;
border-radius: 4px;
position: fixed;
z-index: 9;
}
.file-tree :deep().el-tree-node__content {
height: 36px !important;
}
.tree-action .disable {
cursor: not-allowed;
color: #616f94;
}
.tree-action .disable:hover {
background-color: #fff;
color: #616f94;
}
.file-tree :deep().noFocus:focus > .el-tree-node__content {
background-color: #fff;
}
</style>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content apaas_scroll">
<div class="info_row">
<div class="title">
<div><span class="icon_box"></span> 账号信息</div>
<div class="dashed_line"></div>
</div>
<div class="info_content">
<div class="img_box">
<img v-if="logo" :src="logo" style="height: 96px; width: 96px; border-radius: 99px" alt="" />
<img
v-else
src="/src/assets/imgs/home_ic_user.png"
style="height: 96px; width: 96px; border-radius: 99px"
alt="" />
</div>
<div class="info_box">
<bg-info :data="accountInfo"></bg-info>
</div>
</div>
</div>
<div>
<div class="title">
<div><span class="icon_box"></span> 个人信息</div>
<div class="dashed_line"></div>
</div>
<div class="info_content">
<div class="img_box"></div>
<div class="info_box">
<bg-info v-if="accountType === 2" :data="personInfo"></bg-info>
<bg-info v-if="accountType === 3" :data="personInfo2"></bg-info>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, ref, computed, onBeforeMount } from "vue";
import { useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const accountInfo = reactive([
{
name: "手机号",
value: "",
nameWidth: 130,
},
{
name: "账号",
value: "",
nameWidth: 130,
},
{
name: "角色",
value: "",
nameWidth: 130,
},
{
name: "所属组织",
value: "",
nameWidth: 130,
},
{
name: "创建人",
value: "",
nameWidth: 130,
},
{
name: "创建账号",
value: "",
nameWidth: 130,
},
{
name: "最后编辑时间",
value: "",
nameWidth: 130,
},
{
name: "创建时间",
value: "",
nameWidth: 130,
},
]);
const personInfo = reactive([
{
name: "姓名",
value: "",
nameWidth: 130,
},
{
name: "邮箱",
value: "",
nameWidth: 130,
},
{
name: "证据类型",
value: "",
nameWidth: 130,
},
{
name: "身份证号",
value: "",
idCard: true,
nameWidth: 130,
},
{
name: "备注",
value: "",
full: true,
nameWidth: 130,
},
]);
const personInfo2 = reactive([
{
name: "姓名",
value: "",
nameWidth: 130,
},
{
name: "邮箱",
value: "",
nameWidth: 130,
},
{
name: "备注",
value: "",
full: true,
nameWidth: 130,
},
]);
const logo = ref("");
const accountType = ref(2); //1.业务系统账号 2.组织管理员账号 3.平台用户账号
const getDetail = () => {
axios.get(`/apaas/system/v5/org/user/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const detail = res.data.data;
accountInfo[0].value = detail.contact_phone;
accountInfo[1].value = detail.system_account;
accountInfo[2].value = detail.system_role && detail.system_role.length > 0 ? detail.system_role.join("") : "";
accountInfo[3].value = detail.organization;
accountInfo[4].value = detail.created_by;
accountInfo[5].value = detail.created_by_account;
accountInfo[6].value = detail.updated_time;
accountInfo[7].value = detail.created_time;
personInfo[0].value = detail.contact_name;
personInfo[1].value = detail.contact_email;
personInfo[2].value = detail.document_type === 1 ? "身份证" : "";
personInfo[3].value = detail.document_number;
personInfo[4].value = detail.remark;
personInfo2[0].value = detail.contact_name;
personInfo2[1].value = detail.contact_email;
personInfo2[2].value = detail.remark;
logo.value = detail.logo;
accountType.value = detail.is_admin;
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
if (route.query.id) {
getDetail();
}
});
</script>
<style scoped>
.page_content {
padding: 15px;
overflow: auto;
}
.info_content {
display: flex;
}
.info_row {
margin-bottom: 40px;
}
.img_box {
width: 120px;
}
.info_box {
width: 60%;
}
.title {
font-size: 18px;
color: #1a1a1a;
font-weight: bold;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.dashed_line {
flex: 1;
height: 1px;
margin: 0 10px;
border-bottom: dashed 1px #dadee7;
}
.icon_box {
display: inline-block;
width: 4px;
height: 14px;
background-color: #3759be;
border-radius: 2px;
margin-right: 5px;
}
</style>
<!-- 角色管理新增 -->
<template>
<role-form></role-form>
</template>
<script setup>
import roleForm from "./role_form.vue";
</script>
<!-- 角色管理 -->
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="top_form bg-scroll">
<el-form ref="form" :rules="rules" :model="formData" class="role_form">
<el-form-item prop="role_name" label="角色名称">
<el-input v-model.trim="formData.role_name" maxlength="50" show-word-limit :disabled="rowType != 0" />
</el-form-item>
<el-form-item prop="role_desc" label="描述">
<el-input
class="decs_box"
type="textarea"
v-model="formData.role_desc"
maxlength="300"
show-word-limit
:autosize="{ minRows: 5 }"
:disabled="rowType != 0"></el-input>
</el-form-item>
<el-form-item label="数据权限" prop="data_purview">
<el-radio-group v-model="formData.data_purview" :disabled="rowType != 0">
<el-radio :label="3">全平台所有</el-radio>
<el-radio :label="2">本组织所有</el-radio>
<el-radio :label="1">仅自己</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单功能权限" prop="permission_arr">
<bg-permission
:values="formData.permission_arr"
:options="permissionData"
:props="defaultProps"
@changeMenu="changeMenu" />
</el-form-item>
<el-form-item label="是否启用" prop="state" class="state_item">
<el-switch
class="bg-switch-ele"
v-model="formData.state"
:active-value="1"
:inactive-value="0"
inline-prompt
active-text="是"
inactive-text="否"
:disabled="rowType != 0" />
</el-form-item>
</el-form>
</div>
<div class="bottom_action">
<el-button @click="goList"> 取消 </el-button>
<el-button type="primary" @click="saveRole"> 保存 </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 { useRouter, useRoute } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const router = useRouter();
const route = useRoute();
const form = ref(null);
const checkMenuLength = (rule, value, callback) => {
if (value.length === 0) {
callback(new Error("请选择所需菜单"));
} else {
callback();
}
};
const roleState = reactive({
form,
formData: {
role_name: "",
role_desc: "",
data_purview: 3,
state: 1,
permission_arr: [],
}, // 表单项
rules: {
role_name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
data_purview: [{ required: true, message: "请选择数据权限", trigger: "change" }],
state: [{ required: true, message: "请选择是否启用", trigger: "change" }],
permission_arr: [{ required: true, type: "array", validator: checkMenuLength, trigger: "change" }],
}, // 表单校验规则
defaultProps: {
name: "menu_name",
value: "id",
children: "Child",
remark: "remark",
}, // 菜单框默认配置
permissionData: [], // 菜单数据
rowType: 0,
});
const getMenuTree = () => {
axios.get(`/apaas/system/v5/menu/tree`).then((res) => {
if (res.data.code == 200) {
roleState.permissionData = res.data.data || [];
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取菜单数据
const changeMenu = (val) => {
roleState.formData.permission_arr = val;
}; // 修改选中的菜单
const getRoleDetail = () => {
axios.get(`/apaas/system/v5/role/detail/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
let { role_name, role_desc, data_purview, state, menus } = res.data.data;
roleState.rowType = res.data.data.role_type;
let permission_arr = [];
if (menus && menus.length > 0) {
menus.forEach((e) => {
permission_arr.push(e.id);
});
}
roleState.formData = {
role_name,
role_desc,
data_purview,
state,
permission_arr: [...permission_arr],
};
console.log(roleState.formData.permission_arr);
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取角色详情
const saveRole = () => {
roleState.form.validate((valid) => {
if (valid) {
let params = {
role_name: roleState.formData.role_name,
role_desc: roleState.formData.role_desc,
state: roleState.formData.state,
data_purview: roleState.formData.data_purview,
menu_ids: [...roleState.formData.permission_arr],
};
if (!route.query.id) {
// 新增
axios.put(`/apaas/system/v5/role/create`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
router.push("/system/role");
} else {
ElMessage.error(res.data.data);
}
});
} else {
// 编辑
params.id = +route.query.id;
axios.post(`/apaas/system/v5/role/update`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
router.push("/system/role");
} else {
ElMessage.error(res.data.data);
}
});
}
}
});
}; // 新增或编辑角色的保存
const goList = () => {
router.push("/system/role");
};
onBeforeMount(() => {
getMenuTree();
if (route.query.id) {
// 有id表示是编辑,请求详情,回显
getRoleDetail();
}
});
const { formData, rules, defaultProps, permissionData, rowType } = toRefs(roleState);
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
padding: 0 24px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
.main_container {
flex-grow: 1;
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
margin: 0 0 16px;
position: relative;
height: calc(100% - 62px);
.top_form {
height: calc(100% - 68px);
padding: 30px 0 0 40px;
.role_form {
width: 1048px;
:deep().el-form-item {
display: block;
margin-bottom: 24px;
.el-form-item__label {
display: block;
}
.el-input__count {
bottom: -20px;
right: 4px;
color: #a9b1c7;
}
}
.state_item {
display: flex;
}
}
}
.bottom_action {
height: 68px;
border-top: 1px solid #e6e9ef;
padding: 16px;
text-align: right;
.el-button {
width: 92px;
}
}
}
}
</style>
<!-- 角色管理编辑 -->
<template>
<role-form></role-form>
</template>
<script setup>
import roleForm from "../add/role_form.vue";
</script>
<!-- 角色管理 -->
<template>
<div>角色管理</div>
<div class="detail_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="register">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增
</el-button>
<el-button type="primary" @click="deleteRows"> 批量删除 </el-button>
<div class="select_text">
<span>已选择</span>
<span class="num">{{ selection.length }}</span>
<span></span>
<span class="can_click_text" @click="clearRoleSelection">清空</span>
</div>
</div>
</template>
</bg-filter-group>
<div class="table_container">
<div class="table bg-scroll">
<bg-table
ref="Bgtable"
:headers="headers"
:rows="tableRows"
:select="true"
:stripe="true"
canEdit
canEditFlag="state"
@selectAc="selectRows">
<template v-slot:state="{ row }">
<bg-switch
@click="changeUseRow(row)"
:labels="['否', '是']"
:values="[0, 1]"
v-model="row.state"
:disabled="row.role_type == 1 || row.role_type == 2" />
</template>
<template v-slot:created_time="{ row }">
{{ row.created_time.split("+")[0].replace("T", " ").replace("Z", " ") }}
</template>
<template v-slot:action="{ row }">
<bg-table-btn
class="can_click_text"
:click="
() => {
edit_row(row);
}
">
编辑
</bg-table-btn>
<bg-table-btn
class="can_click_text"
:click="
() => {
distribute_user(row);
}
"
:disabled="row.cant_allot == 1">
分配用户
</bg-table-btn>
<bg-table-btn
class="can_click_text"
:click="
() => {
delete_row(row);
}
"
:disabled="row.state == 1 || row.role_type == 1">
删除
</bg-table-btn>
</template>
</bg-table>
</div>
<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="delDialog" width="400px">
<div>确定要删除选中的数据吗?</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="delDialog = false">取 消</el-button>
<el-button type="primary" @click="deleteData">确 定</el-button>
</div>
</template>
</el-dialog>
<!-- 分配用户 -->
<el-dialog class="distribute_dialog" title="分配用户" v-model="distributeDialog" width="1062px">
<div class="distribute_box">
<div class="topFilter">
<div class="left">
<span>已选择</span>
<span class="num">{{ userSelection.length }}</span>
<span></span>
<span class="can_click_text" @click="clearUserSelection">清空</span>
</div>
<div class="right">
<el-select v-model="userFilter.is_admin" placeholder="请选择" style="width: 200px">
<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.organization_id"
:options="orgList"
placeholder="请选择组织"
:props="{
expandTrigger: 'hover',
label: 'name',
value: 'id',
emitPath: false,
checkStrictly: true,
children: 'Child',
}"
:clearable="true"
collapse-tags
style="width: 200px">
<template #default="{ data }">
<span>{{ data.name }}</span>
</template>
</el-cascader>
<el-input
v-model.trim="userFilter.search"
placeholder="请输入内容"
style="width: 200px"
:prefix-icon="Search" />
<el-button type="primary" @click="searchAction">查询</el-button>
<el-button type="default" @click="clearAction">重置</el-button>
</div>
</div>
<div class="table_box">
<div class="user_table bg-scroll">
<bg-table
ref="userTable"
:headers="userHeaders"
:rows="userRows"
:select="true"
:stripe="true"
@selectAc="selectUserRows">
<template v-slot:is_admin="{ row }">
{{ ["", "业务系统账号", "组织管理员账号", "平台用户账号"][row.is_admin] }}
</template>
</bg-table>
</div>
<bg-pagination
:page="userFilter.page"
:size="userFilter.limit"
:total="total"
@change-page="changeUserPage"
@change-size="changeUserSize">
</bg-pagination>
</div>
</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="distributeDialog = false">取 消</el-button>
<el-button type="primary" @click="distribute">确 定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup></script>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { reactive, toRefs, ref, onBeforeMount, nextTick } from "vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { useRouter } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const router = useRouter();
const Bgtable = ref(null);
const userTable = ref(null);
const state = reactive({
filter: {
page: 1,
limit: 10,
search: "",
},
headers: [
{
label: "角色名",
prop: "role_name",
width: 220,
},
{
label: "创建人",
prop: "created_by",
width: 220,
},
{
label: "创建时间",
prop: "created_time",
width: 276,
},
{
label: "账号数",
prop: "user_count",
},
{
label: "描述",
prop: "role_desc",
minWidth: 346,
},
{
label: "是否启用",
prop: "state",
width: 95,
},
{
label: "操作",
prop: "action",
width: 220,
fixed: "right",
},
],
tableRows: [],
tableTotal: 0,
actionRow: {},
selection: [],
delDialog: false,
delType: 1, // 删除类型 1-单条删除 2-批量删除
});
const userState = reactive({
userFilter: {
is_admin: "",
organization_id: "",
search: "",
limit: 10,
page: 1,
},
userTypeList: [
{
name: "全部类型",
value: "",
},
{
name: "组织管理员账号",
value: 2,
},
{
name: "平台用户账号",
value: 3,
},
],
orgList: [],
userHeaders: [
{
label: "帐号",
prop: "system_account",
},
{
label: "类型",
prop: "is_admin",
},
{
label: "用户手机号",
prop: "contact_phone",
},
{
label: "所属组织",
prop: "organization_name",
},
],
userRows: [],
total: 0,
userSelection: [],
distributeDialog: false, // 分配用户弹窗
});
const getRoleRows = () => {
let params = { ...state.filter };
console.log(params);
axios.get(`/apaas/system/v5/role/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);
}
});
}; // 获取角色列表
<style lang="scss" scoped></style>
const getOrgList = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
console.log(res.data.data);
userState.orgList = res.data.data || [];
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取组织列表
const changePage = (val) => {
state.filter.page = val;
getRoleRows();
}; // 改变页码
const changeSize = (val) => {
state.filter.limit = val;
changePage(1);
}; // 改变每页条数
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const changeUseRow = (row) => {
if (row.role_type == 1 || row.role_type == 2) {
return;
}
axios.post(`/apaas/system/v5/role/state/${row.id}/${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 selectRows = (data) => {
state.selection = data.selection;
}; // 表格多选
const clearRoleSelection = () => {
Bgtable.value.clearTable();
};
const register = () => {
router.push("/authority/role/add");
}; // 新增角色
const edit_row = (row) => {
router.push({
path: "/authority/role/edit",
query: {
id: row.id,
},
});
}; // 编辑角色
const distribute_user = (row) => {
clearAction(1);
userState.distributeDialog = true;
state.actionRow = row;
getUserList();
}; // 分配角色按钮
const getUserList = () => {
nextTick(() => {
clearUserSelection();
});
let params = {
limit: userState.userFilter.limit,
page: userState.userFilter.page,
search: userState.userFilter.search,
organization_id: userState.userFilter.organization_id,
is_admin: userState.userFilter.is_admin,
role_id: state.actionRow.id,
};
axios.get(`/apaas/system/v5/role/allotment/list`, { params }).then((res) => {
if (res.data.code == 200) {
console.log(res.data.data);
userState.userRows = res.data.data || [];
userState.total = res.data.total;
nextTick(() => {
userState.userRows.forEach((e) => {
if (e.is_bind == 1) {
console.log(userTable);
userTable.value.toggleRowSelection(e, true);
}
});
});
} else {
ElMessage.error(res.data.data);
}
});
};
const changeUserPage = (val) => {
userState.userFilter.page = val;
getUserList();
};
const changeUserSize = (val) => {
userState.userFilter.limit = val;
changeUserPage(1);
};
const searchAction = () => {
console.log(userState.userFilter);
changeUserPage(1);
};
const clearAction = (type) => {
userState.userFilter = {
is_admin: "",
organization_id: "",
search: "",
limit: 10,
page: 1,
};
if (type != 1) {
changeUserPage(1);
}
};
const clearUserSelection = () => {
console.log(userTable.value);
userTable.value.clearTable();
};
const selectUserRows = (data) => {
userState.userSelection = data.selection;
};
const distribute = () => {
let user_ids = [];
userState.userSelection.forEach((e) => {
user_ids.push(e.id);
});
let params = {
id: state.actionRow.id,
user_ids: user_ids,
};
axios.post(`/apaas/system/v5/role/allotment/user`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
userState.distributeDialog = false;
changePage(1);
} else {
ElMessage.error(res.data.data);
}
});
};
const delete_row = (row) => {
state.actionRow = row;
state.delType = 1;
state.delDialog = true;
}; // 删除角色
const deleteRows = () => {
if (state.selection.length == 0) {
ElMessage.error("请先选择要删除的数据");
} else {
state.delType = 2;
state.delDialog = true;
}
}; // 批量删除按钮
const deleteData = () => {
let ids = [];
if (state.delType == 1) {
ids.push(state.actionRow.id);
} else {
state.selection.forEach((e) => {
ids.push(e.id);
});
}
let params = {
ids: [...ids],
};
axios.delete(`/apaas/system/v5/role/delete`, { data: { ids: [...ids] } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
state.delDialog = false;
changePage(1);
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getRoleRows();
getOrgList();
});
const { filter, headers, tableRows, tableTotal, delDialog, selection } = toRefs(state);
const { userFilter, userTypeList, orgList, userHeaders, userRows, total, userSelection, distributeDialog } =
toRefs(userState);
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
padding: 0 24px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
.main_container {
flex-grow: 1;
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
background-color: #fff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
margin: 0 0 16px;
position: relative;
height: calc(100% - 62px);
.table_container {
height: calc(100% - 70px);
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
.select_text {
display: inline-block;
margin-left: 40px;
font-size: 14px;
color: #404a62;
.num {
color: #202531;
font-weight: 700;
margin: 0 3px;
}
.can_click_text {
margin-left: 24px;
}
}
}
.distribute_dialog {
.distribute_box {
width: 100%;
height: 626px;
.topFilter {
height: 68px;
padding: 16px;
border-bottom: 1px solid #e6e9ef;
display: flex;
text-align: left;
font-size: 14px;
align-items: center;
.left {
width: 240px;
padding-left: 15px;
color: #404a62;
.num {
color: #202531;
font-weight: 700;
margin: 0 3px;
}
.can_click_text {
margin-left: 24px;
}
}
.right {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.el-button {
margin: 0;
width: 64px;
}
}
}
.table_box {
padding: 10px 16px;
height: calc(100% - 68px);
.user_table {
max-height: calc(100% - 48px);
:deep().bg-table {
.el-scrollbar {
--el-scrollbar-bg-color: #fff;
}
.el-table__empty-block {
.empty_container {
height: calc(100% - 45px);
}
}
}
}
}
}
}
}
</style>
<style>
.distribute_dialog .el-dialog__footer {
padding: 16px !important;
}
.distribute_dialog .el-dialog__body {
padding: 0px !important;
}
.distribute_dialog {
margin-top: 130px !important;
}
</style>
<template>
<el-form
:label-position="'right'"
label-width="120px"
:model="contactForm"
:rules="contactFormRules"
ref="contactRef"
style="max-width: 66%">
<el-form-item label="联系人姓名" prop="contact_name">
<el-input v-model="contactForm.contact_name" />
</el-form-item>
<el-form-item label="联系人手机号" prop="contact_phone">
<el-input v-model="contactForm.contact_phone" />
</el-form-item>
<el-form-item label="联系人邮箱" prop="contact_email">
<el-input v-model="contactForm.contact_email" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="contactForm.remark" show-word-limit maxlength="300" />
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
const contactForm = reactive({
contact_name: "",
contact_phone: "",
contact_email: "",
remark: "",
});
const props = defineProps({
formType: {
type: Boolean,
default: false, //false 新增 true 编辑
},
id: {
type: String,
default: "",
},
});
const checkPhone = (rule, value, callback) => {
var phone_ruler = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/;
setTimeout(() => {
if (!phone_ruler.test(value) && value.length !== 0) {
callback(new Error("请输入正确的手机号码"));
} else {
callback();
}
});
};
const checkName = (rule, value, callback) => {
var reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母、数字和汉字"));
} else {
callback();
}
};
const contactFormRules = reactive({
contact_name: [
{ required: true, message: "请输入联系人姓名", trigger: "blur" },
{ max: 50, message: "联系人姓名最大长度为50个字符", trigger: "blur" },
{ validator: checkName, trigger: "blur" },
],
contact_phone: [
{ required: true, message: "请输入联系人手机号", trigger: "blur" },
{ validator: checkPhone, trigger: "blur" },
],
contact_email: [
{ type: "email", message: "请输入正确的邮箱", trigger: "blur" },
{ max: 100, message: "邮箱最大长度为100个字符", trigger: "blur" },
],
});
const contactRef = ref(null);
const emit = defineEmits(["action"]);
const submitForm = async () => {
if (!contactRef) return;
await contactRef.value.validate((valid, fields) => {
if (valid) {
emit("action", contactForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!contactRef) return;
contactRef.value.resetFields();
};
const setForm = (data) => {
Object.assign(contactForm, data);
};
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<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"></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-staff"></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">
<systemForm
v-show="step === 1"
ref="systemFormRef"
:form-type="route.query.id ? true : false"
:id="route.query.id"
@action="getSystemFormData"></systemForm>
<contactForm
v-show="step === 2"
ref="contactFormRef"
:id="route.query.id"
@action="getContactFormData"></contactForm>
<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">
{{
route.query.id
? successFlag
? "业务系统编辑成功"
: "业务系统编辑失败"
: successFlag
? "业务系统新增成功"
: "业务系统新增失败"
}}
</div>
<el-button @click="cancel">返回列表</el-button>
<el-button v-if="!route.query.id" type="primary" @click="continueCreate">继续创建</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 systemForm from "./system-form.vue";
import contactForm from "./contact-form.vue";
import { reactive, ref, onBeforeUnmount, onMounted } from "vue";
import CryptoJS from "crypto-js";
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 step = ref(1);
const systemFormRef = ref(null);
const contactFormRef = ref(null);
const formData = reactive({
organization_id: "",
business_code: "",
business_name: "",
business_desc: "",
logo: "",
system_role_id: "",
system_account: "",
system_phone: "",
password: "",
confirm_password: "",
access_address: "",
develop_id: "",
state: 1,
contact_name: "",
contact_phone: "",
contact_email: "",
remark: "",
}); //业务系统表单+联系人表单
const successFlag = ref(false);
// 下一步
const nextStep = () => {
systemFormRef.value.submitForm();
};
//业务系统表单检验触发事件 data为null 校验失败
const getSystemFormData = (data) => {
if (data) {
Object.assign(formData, data);
step.value = 2;
} else {
}
};
//联系人表单检验触发事件 data为null 校验失败
const getContactFormData = (data) => {
if (data) {
Object.assign(formData, data);
if (route.query.id) {
console.log(formData);
let params = {
...formData,
id: parseInt(route.query.id),
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
};
axios.post(`/apaas/system/v5/user/update`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
} else {
let params = {
...formData,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
password: CryptoJS.AES.encrypt(formData.password, "swuE9cmCZQwrkYRV").toString(),
};
axios.put(`/apaas/system/v5/user/create`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
}
}
};
//上一步
const previousStep = () => {
step.value--;
};
//提交表单
const submit = () => {
contactFormRef.value.submitForm();
};
//继续创建 清空表单
const continueCreate = () => {
systemFormRef.value.clearForm();
contactFormRef.value.clearForm();
step.value = 1;
successFlag.value = false;
};
//取消
const cancel = () => {
// router.go(-1);
router.push({
path: "/develop/account",
query: {
id: formData.organization_id,
},
});
};
const getDetail = () => {
axios.get(`/apaas/system/v5/user/detail/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const form = res.data.data;
systemFormRef.value.setForm({
organization_id: form.organization_id,
system_role_id: form.system_role_id,
logo: form.logo ? [{ url: form.logo }] : [],
business_code: form.business_code,
business_name: form.business_name,
business_desc: form.business_desc,
system_account: form.system_account,
system_phone: form.system_phone,
access_address: form.access_address,
develop_id: form.develop_id,
state: form.state,
appid: form.app_id,
appsecret: form.app_secret,
});
contactFormRef.value.setForm({
contact_name: form.contact_name,
contact_phone: form.contact_phone,
contact_email: form.contact_email,
remark: form.remark,
});
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeUnmount(() => {});
onMounted(() => {
if (route.query.id) {
getDetail();
}
});
</script>
<style scoped>
.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="systemForm"
:rules="formRules"
ref="systemRef"
style="max-width: 66%">
<el-form-item label="所属组织" prop="organization_id">
<el-tree-select
v-model="systemForm.organization_id"
:data="orgData"
:props="treeProps"
:render-after-expand="false"
:disabled="formType"
style="width: 100%" />
</el-form-item>
<el-form-item label="业务系统编码" prop="business_code" v-if="formType">
<el-input v-model="systemForm.business_code" :disabled="formType" />
</el-form-item>
<el-form-item label="业务系统名称" prop="business_name">
<el-input v-model="systemForm.business_name" />
</el-form-item>
<el-form-item label="AppId" prop="appid" v-if="formType">
<el-input v-model="systemForm.appid" :disabled="formType">
<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 label="AppSecret" prop="appsecret" v-if="formType">
<div style="display: flex; width: 100%">
<el-input v-model="systemForm.appsecret" :disabled="formType">
<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 label="系统LOGO" prop="logo">
<bg-upload-image
v-model="systemForm.logo"
:showTips="true"
:limit="1"
:fileSize="500"
:fileSizeUnit="'KB'"
listType="picture-card"
:accept="['.jpg', '.jpeg', '.png']"
customTips="请选择图片上传:大小120 * 120像素支持jpg、png等格式,图片需小于500KB"></bg-upload-image>
</el-form-item>
<el-form-item label="业务系统概述" prop="business_desc">
<el-input
type="textarea"
:rows="3"
v-model="systemForm.business_desc"
show-word-limit
maxlength="300" />
</el-form-item>
<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-option
v-for="item in roleList"
:key="item.role_id"
:label="item.role_name"
:value="item.role_id" />
</el-select>
</el-form-item>
<el-form-item label="账号" prop="system_account">
<el-input v-model="systemForm.system_account" />
</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-input :type="password_eye ? 'text' : 'password'" v-model="systemForm.password">
<template #suffix>
<bg-icon
@click="password_eye = !password_eye"
class="icon_eye"
icon="#bg-ic-eye"></bg-icon>
</template>
</el-input>
</el-form-item>
<el-form-item label="确认密码" prop="confirm_password" v-if="!formType">
<el-input :type="confirm_eye ? 'text' : 'password'" v-model="systemForm.confirm_password">
<template #suffix>
<bg-icon @click="confirm_eye = !confirm_eye" class="icon_eye" icon="#bg-ic-eye"></bg-icon>
</template>
</el-input>
</el-form-item>
<el-form-item label="访问地址" prop="access_address">
<el-input v-model="systemForm.access_address" />
</el-form-item>
<el-form-item label="开发厂商名称" prop="develop_id">
<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-select>
</el-form-item>
<el-form-item label="是否启用" prop="state">
<bg-switch :labels="['否', '是']" :values="[0, 1]" v-model="systemForm.state"></bg-switch>
</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({
formType: {
type: Boolean,
default: false, //false 新增 true 编辑
},
id: {
type: String,
default: "",
},
});
const systemForm = reactive({
organization_id: "",
business_code: "",
business_name: "",
business_desc: "",
logo: [],
system_role_id: "",
system_account: "",
system_phone: "",
password: "",
confirm_password: "",
access_address: "",
develop_id: "",
state: 1,
appid: "",
appsecret: "",
});
const password_eye = ref(false);
const confirm_eye = ref(false);
const validatePass = (rule, value, callback) => {
if (value !== systemForm.password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const validateBusinessName = (rule, value, callback) => {
let reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/;
if (!reg.test(value)) {
callback(new Error("只能输入字母、数字和汉字"));
} else {
let params = null;
if (props.id) {
params = {
id: parseInt(props.id),
business_name: value,
organization_id: systemForm.organization_id,
};
} else {
params = { business_name: value, organization_id: systemForm.organization_id };
}
axios.post(`/apaas/system/v5/user/check/business`, 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 = null;
if (props.id) {
params = { id: parseInt(props.id), system_account: value };
} else {
params = { system_account: value };
}
axios.post(`/apaas/system/v5/user/check/account`, params).then((res) => {
if (res.data.code == 200) {
callback();
} else {
callback(new Error(res.data.data));
}
});
}
};
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({
organization_id: [{ required: true, message: "请选择组织", trigger: "change" }],
business_name: [
{ required: true, message: "请输入业务系统名称", trigger: "blur" },
{ max: 50, message: "业务系统名称最大长度为50个字符", trigger: "blur" },
{ validator: validateBusinessName, trigger: "blur" },
],
system_role_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" },
],
system_phone: [
{ required: true, message: "请输入账号", trigger: "blur" },
{ validator: validatePhone, trigger: "blur" },
{ validator: checkPhoneRepet, 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" },
],
access_address: [{ max: 500, message: "访问地址最大长度为500个字符", trigger: "blur" }],
develop_id: [{ required: true, message: "请选择开发厂商", trigger: "change" }],
});
const systemRef = ref(null);
const emit = defineEmits(["action"]);
const roleList = ref([]);
const firmList = ref([]);
const submitForm = async () => {
if (!systemRef) return;
await systemRef.value.validate((valid, fields) => {
if (valid) {
emit("action", systemForm);
} else {
emit("action", null);
}
});
};
const clearForm = () => {
if (!systemRef) return;
systemRef.value.resetFields();
systemForm.system_role_id = roleList.value[0].role_id;
};
const setForm = (data) => {
Object.assign(systemForm, data);
};
const orgData = ref([]);
const treeProps = {
label: "name",
children: "Child",
value: "organization_id",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
orgDataTemp.shift();
orgData.value = orgDataTemp;
} else {
ElMessage.error(res.data.data);
}
});
};
const copyText = (data) => {
navigator.clipboard.writeText(data).then(
function () {
ElMessage.success("复制成功");
},
function () {}
);
};
const resetSecret = () => {
axios.get(`/apaas/system/v5/user/reset/secret/${props.id}`).then((res) => {
if (res.data.code == 200) {
systemForm.appsecret = res.data.data;
ElMessage.success("重置成功!");
} else {
ElMessage.error(res.data.data);
}
});
};
const getRoleList = () => {
axios.get(`/apaas/system/v5/org/select/role?is_admin=1`).then((res) => {
if (res.data.code == 200) {
roleList.value = res.data.data;
systemForm.system_role_id = roleList.value[0].role_id;
} else {
}
});
};
const getFirmList = () => {
axios.get(`/apaas/system/v5/dictionary/developer/list`).then((res) => {
if (res.data.code == 200) {
firmList.value = res.data.data || [];
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getOrgTree();
getRoleList();
getFirmList();
});
onMounted(() => {});
defineExpose({ submitForm, clearForm, setForm });
</script>
<template>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="page_content apaas_scroll">
<div class="info_row">
<div class="title">
<div><span class="icon_box"></span> 基础信息</div>
<div class="dashed_line"></div>
</div>
<div class="info_content">
<div class="img_box">
<img v-if="logo" :src="logo" style="height: 96px; width: 96px; border-radius: 99px" alt="" />
<img
v-else
src="/src/assets/imgs/home_ic_user.png"
style="height: 96px; width: 96px; border-radius: 99px"
alt="" />
</div>
<div class="info_box">
<bg-info :data="baseInfo"></bg-info>
</div>
</div>
</div>
<div>
<div class="title">
<div><span class="icon_box"></span> 联系人信息</div>
<div class="dashed_line"></div>
</div>
<div class="info_content">
<div class="img_box"></div>
<div class="info_box">
<bg-info :data="contactInfo"></bg-info>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, ref, onBeforeMount } from "vue";
import { useRoute, useRouter } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute();
const baseInfo = reactive([
{
name: "所属组织",
value: "",
nameWidth: 130,
},
{
name: "业务系统编码",
value: "",
nameWidth: 130,
},
{
name: "业务系统名称",
value: "",
nameWidth: 130,
},
{
name: "账号",
value: "",
nameWidth: 130,
},
{
name: "AppID",
value: "",
nameWidth: 130,
},
{
name: "AppSecret",
value: "",
copy_icon: true,
secret: true,
nameWidth: 130,
},
{
name: "创建人",
value: "",
nameWidth: 130,
},
{
name: "创建时间",
value: "",
nameWidth: 130,
},
{
name: "是否启用",
value: "",
state: "",
nameWidth: 130,
},
{
name: "开发厂商名称",
value: "",
nameWidth: 130,
},
{
name: "访问地址",
value: "",
full: true,
nameWidth: 130,
},
{
name: "业务系统描述",
value: "",
full: true,
nameWidth: 130,
},
]);
const contactInfo = reactive([
{
name: "联系人姓名",
value: "",
nameWidth: 130,
},
{
name: "联系人手机号",
value: "",
nameWidth: 130,
},
{
name: "联系人邮箱",
value: "",
full: true,
nameWidth: 130,
},
{
name: "备注",
value: "",
full: true,
nameWidth: 130,
},
]);
const logo = ref("");
const getDetail = () => {
axios.get(`/apaas/system/v5/user/detail/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const detail = res.data.data;
baseInfo[0].value = detail.organization_name;
baseInfo[1].value = detail.business_code;
baseInfo[2].value = detail.business_name;
baseInfo[3].value = detail.system_account;
baseInfo[4].value = detail.app_id;
baseInfo[5].value = detail.app_secret;
baseInfo[6].value =
detail.created_by + "(" + (detail.created_user_role ? detail.created_user_role.join("") : "") + ")";
baseInfo[7].value = detail.created_time;
baseInfo[8].value = detail.state === 1 ? "" : "";
baseInfo[8].state = detail.state === 1 ? "success" : "default";
baseInfo[9].value = detail.develop_name;
baseInfo[10].value = detail.access_address;
baseInfo[11].value = detail.business_desc;
contactInfo[0].value = detail.contact_name;
contactInfo[1].value = detail.contact_phone;
contactInfo[2].value = detail.contact_email;
contactInfo[3].value = detail.remark;
logo.value = detail.logo;
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getDetail();
});
</script>
<style scoped>
.page_content {
padding: 15px;
overflow: auto;
}
.info_content {
display: flex;
}
.info_row {
margin-bottom: 40px;
}
.img_box {
width: 120px;
}
.info_box {
width: 60%;
}
.title {
font-size: 18px;
color: #1a1a1a;
font-weight: bold;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.dashed_line {
flex: 1;
height: 1px;
margin: 0 10px;
border-bottom: dashed 1px #dadee7;
}
.icon_box {
display: inline-block;
width: 4px;
height: 14px;
background-color: #3759be;
border-radius: 2px;
margin-right: 5px;
}
</style>
<template>
<div>用户管理</div>
<div class="page_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="flex_row">
<div class="flex_left bgc_white">
<div class="tree_header">政务组织</div>
<div class="tree_content">
<div class="search">
<el-input v-model="filterTree" placeholder="请输入组织名称搜索" :prefix-icon="Search" />
</div>
<div class="tree">
<el-tree
ref="treeRef"
:data="orgData"
:props="defaultProps"
@node-click="handleNodeClick"
node-key="id"
:highlight-current="true"
:filter-node-method="filterNode"
:default-expand-all="true">
<template #default="{ node, data }">
<div class="custom_tree_node">
<span class="label-text" :title="node.label">{{ node.label }} </span>
</div>
</template>
</el-tree>
</div>
</div>
</div>
<div class="flex_right bgc_white">
<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="addAccount">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增
</el-button>
<el-button @click="deleteBatch"> 批量删除 </el-button>
<el-button @click="resetPsd"> 重置密码 </el-button>
<span class="header_info"
>已选择<span style="color: #202531; font-weight: bold">{{ selected.length }}</span
></span
>
<span class="header_info can_click_text" @click="clearSelected">清空</span>
</div>
</template>
</bg-filter-group>
<div class="table_container apaas_scroll">
<bg-table
ref="dataTable"
:headers="headers"
:rows="tableRows"
:isIndex="true"
:stripe="true"
:select="true"
@selectAc="selectRows">
<template v-slot:business_name="{ row }">
<span @click="goDetail(row)" class="can_click_text">
{{ row.business_name }}
</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:action="{ row }">
<bg-table-btn @click="editAccount(row.id)"> 编辑 </bg-table-btn>
<bg-table-btn @click="editPsdAccount(row)"> 修改密码 </bg-table-btn>
<bg-table-btn @click="deleteAccount(row)"> 删除 </bg-table-btn>
</template>
</bg-table>
<div class="pagination_box">
<bg-pagination
:page="filter.page"
:size="filter.limit"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</div>
</div>
<el-dialog v-model="deleteFlag" title="删除" width="520px" :before-close="handleCloseDelete">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedName.join("、") }}</span
>做删除操作。
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseDelete">取消</el-button>
<el-button type="primary" @click="deleteConfirm">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="deleteRowFlag" title="删除" width="520px" :before-close="handleCloseRowDelete">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedRow.business_name }}</span
>做删除操作。
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseRowDelete">取消</el-button>
<el-button type="primary" @click="deleteRowConfirm">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="resetFlag" title="重置密码" width="520px" :before-close="handleCloseReset">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedName.join("、") }}</span
>做重置密码操作。
</div>
<div>重置密码为123456,是否继续?</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseReset">取消</el-button>
<el-button type="primary" @click="resetConfirm">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="editFlag" title="修改密码" width="520px" :before-close="handleCloseEdit">
<div class="warning_info">
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: baseline"
icon="#bg-ic-circle-tips"></bg-icon>
您正在对 <span class="danger_info">{{ selectedRow.business_name }}</span
>做修改密码操作,修改后旧密码将无法登录。
</div>
<div>
<el-form
:label-position="'right'"
label-width="120px"
:model="passwordForm"
:rules="passwordFormRules"
ref="passwordRef"
style="max-width: 80%">
<el-form-item label="新密码" prop="password">
<el-input
v-model="passwordForm.password"
:type="password_eye ? 'text' : 'password'"
placeholder="请输入密码">
<template #suffix>
<bg-icon @click="password_eye = !password_eye" class="icon_eye" icon="#bg-ic-eye"></bg-icon>
</template>
</el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="confirm_password">
<el-input
v-model="passwordForm.confirm_password"
:type="confirm_eye ? 'text' : 'password'"
placeholder="请确认新密码">
<template #suffix>
<bg-icon @click="confirm_eye = !confirm_eye" class="icon_eye" icon="#bg-ic-eye"></bg-icon>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseEdit">取消</el-button>
<el-button type="primary" @click="editConfirm">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup></script>
<script setup>
import { Search } from "@element-plus/icons-vue";
import { watch, nextTick, reactive, ref, computed, onBeforeMount } from "vue";
import { useRoute, useRouter } from "vue-router";
import CryptoJS from "crypto-js";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
<style lang="scss" scoped></style>
const dataTable = ref(null);
const headers = ref([
{
label: "业务系统编码",
prop: "business_code",
minWidth: 160,
},
{
label: "业务系统名称",
prop: "business_name",
minWidth: 160,
},
{
label: "账号",
prop: "system_account",
},
{
label: "所属组织",
prop: "organization_name",
minWidth: 180,
},
{
label: "创建时间",
prop: "created_time",
width: 160,
},
{
label: "是否启用",
prop: "state",
},
{
label: "操作",
prop: "action",
width: 220,
fixed: "right",
},
]);
const tableRows = ref([]);
const search = ref("");
const filter = reactive({
search: "",
page: 1,
limit: 10,
});
const tableTotal = ref(0);
const deleteFlag = ref(false);
const deleteRowFlag = ref(false);
const resetFlag = ref(false);
const selectedRow = ref({});
const selected = ref([]);
const selectedName = ref([]);
const editFlag = ref(false);
const password_eye = ref(false);
const confirm_eye = ref(false);
const passwordRef = ref(null);
const passwordForm = reactive({
password: "",
confirm_password: "",
});
const selectNode = ref(null);
const selectNodeObj = ref(null);
const filterTree = ref("");
const treeRef = ref(null);
const validatePass = (rule, value, callback) => {
if (value !== passwordForm.password) {
callback(new Error("密码输入不一致"));
} else {
callback();
}
};
const passwordFormRules = reactive({
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 8, message: "密码长度不得低于8位", trigger: "blur" },
],
confirm_password: [
{ required: true, message: "请确认密码", trigger: "blur" },
{ validator: validatePass, trigger: "blur" },
],
});
const router = useRouter();
const route = useRoute();
const getTableRows = () => {
let params = { ...filter, organization_id: selectNode.value };
axios
.get(`/apaas/system/v5/user/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
tableRows.value = res.data.data || [];
tableTotal.value = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
const addAccount = (params) => {
router.push({
path: "/authority/user/add",
});
};
const handleNodeClick = (data) => {
if (data.data_type == 1) {
selectNode.value = data.id;
changePage(1);
} else {
nextTick(() => {
treeRef.value.setCurrentKey(null);
});
}
};
const orgData = ref([]);
const customNodeClass = (data, node) => {
if (data.data_type == 0) {
return "noFocus";
} else {
return "";
}
};
const defaultProps = {
label: "name",
children: "Child",
value: "organization_id",
class: customNodeClass,
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
if (res.data.code == 200) {
orgData.value = res.data.data || [];
orgData.value.shift();
const orgList = searchOrg(orgData.value);
if (route.query.id) {
searchItem(orgData.value, route.query.id);
} else {
selectNode.value = orgList.length > 0 ? orgList[0].id : "";
}
nextTick(() => {
if (route.query.id) {
treeRef.value.setCurrentNode(selectNodeObj.value);
} else {
if (orgList.length > 0) {
treeRef.value.setCurrentNode(orgList[0]);
}
}
});
getTableRows();
} else {
ElMessage.error(res.data.data);
}
});
};
const searchItem = (data, id) => {
data.forEach((e) => {
if (e.organization_id == id) {
selectNodeObj.value = e;
selectNode.value = e.id;
} else {
if (e.Child) {
searchItem(e.Child, id);
}
}
});
};
const searchOrg = (data) => {
const arr = [];
data.forEach((item) => {
if (item.data_type === 1) {
arr.push(item);
return;
} else {
if (item.Child) {
searchOrg(item.Child);
} else {
return;
}
}
});
return arr;
};
watch(filterTree, (val) => {
treeRef.value.filter(val);
});
const filterNode = (value, data) => {
if (!value) return true;
return data.name.includes(value);
};
const stateChange = (row) => {
const state = row.state.toString();
axios.post(`/apaas/system/v5/user/state/${row.id}/${state}`).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
row.state = row.state == 0 ? 1 : 0;
}
});
};
const changeSize = (size) => {
filter.limit = size;
filter.page = 1;
changePage(1);
};
const changePage = (page) => {
filter.page = page;
getTableRows();
};
const changeSearch = (val) => {
filter.search = val;
changePage(1);
}; // 表格关键字筛选
const goDetail = (params) => {
router.push({
path: "/authority/user/detail",
query: {
id: params.id,
},
});
};
const editAccount = (id) => {
router.push({
path: "/authority/user/edit",
query: {
id: id,
},
});
};
const deleteAccount = (data) => {
if (data.state === 0) {
selectedRow.value = data;
deleteRowFlag.value = true;
} else {
ElMessage.error("当前状态已启用,不可删除!");
}
};
const handleCloseDelete = () => {
deleteFlag.value = false;
};
const handleCloseRowDelete = () => {
deleteRowFlag.value = false;
};
const deleteConfirm = () => {
const ids = selected.value.map((item) => item.id);
axios.delete(`/apaas/system/v5/user/delete`, { data: { ids: ids } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
}
handleCloseDelete();
});
};
const deleteRowConfirm = () => {
axios.delete(`/apaas/system/v5/user/delete`, { data: { ids: [selectedRow.value.id] } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
}
handleCloseRowDelete();
});
};
const deleteBatch = () => {
if (selectedName.value.length > 0) {
deleteFlag.value = true;
} else {
ElMessage.error("请先选择需要操作的数据!");
}
};
const handleCloseReset = () => {
resetFlag.value = false;
};
const resetPsd = () => {
if (selectedName.value.length > 0) {
resetFlag.value = true;
} else {
ElMessage.error("请先选择需要操作的数据!");
}
};
const resetConfirm = () => {
const ids = selected.value.map((item) => item.id);
axios.post(`/apaas/system/v5/user/resetpwd`, { ids: ids }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
} else {
ElMessage.error(res.data.data);
}
handleCloseReset();
});
};
const editPsdAccount = (data) => {
selectedRow.value = data;
editFlag.value = true;
};
const handleCloseEdit = () => {
if (!passwordRef) return;
passwordRef.value.resetFields();
editFlag.value = false;
password_eye.value = false;
confirm_eye.value = false;
};
const editConfirm = () => {
if (!passwordRef) return;
passwordRef.value.validate((valid, fields) => {
if (valid) {
axios
.post(`/apaas/system/v5/user/editpwd`, {
id: selectedRow.value.id,
password: CryptoJS.AES.encrypt(passwordForm.password, "swuE9cmCZQwrkYRV").toString(),
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
} else {
ElMessage.error(res.data.data);
}
handleCloseEdit();
});
}
});
};
const selectRows = (data) => {
selected.value = data.selection;
selectedName.value = data.selection.map((item) => item.business_name);
};
const clearSelected = () => {
dataTable.value.clearTable();
};
onBeforeMount(() => {
getOrgTree();
//getTableRows()
});
</script>
<style scoped>
.tree_header {
height: 40px;
line-height: 40px;
background-color: #f7f7f9;
border-radius: 6px 6px 0px 0px;
font-size: 16px;
letter-spacing: 0px;
color: #202531;
padding-left: 16px;
}
.tree_content {
overflow: hidden;
height: calc(100% - 45px);
}
.search {
padding: 16px;
}
.tree {
overflow: auto;
height: calc(100% - 65px);
}
.tree :deep() .el-tree-node > .el-tree-node__children {
overflow: unset;
}
.tree :deep().noFocus:focus > .el-tree-node__content {
background-color: #fff;
}
.custom_tree_node {
width: 100%;
font-size: 14px;
color: #202531;
padding-right: 16px;
}
.label-text:hover {
padding: 3px 0;
background-color: var(--el-tree-node-hover-bg-color);
}
.main_container {
height: 100%;
}
.table_container {
height: calc(100% - 30px);
overflow: auto;
padding: 0 16px;
}
.pagination_box {
position: sticky;
position: -webkit-sticky;
margin-top: 16px;
bottom: 25px;
background-color: #fff;
z-index: 1024;
height: 40px;
line-height: 40px;
padding-top: 5px;
}
.bg-pagination {
bottom: unset;
margin-top: 0px;
}
</style>
<template>
<div>主机管理</div>
<div class="detail_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="register">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-add"></bg-icon>
新增
</el-button>
<el-button type="default" @click="deleteAllTips"> 批量删除 </el-button>
<span class="header_info"
>已选择 <span style="color: #202531; font-weight: bold"> {{ state.selected.length }} </span>
</span>
<span class="header_info can_click_text" @click="clearSelected">清空</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"
value-format="yyyy-MM-DD"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期" />
</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">
<div class="table bg-scroll">
<bg-table
ref="dataTable"
:headers="headers"
:rows="tableRows"
@selectAc="selectRows"
:isIndex="true"
:select="true"
:stripe="true">
<template v-slot:name="{ row }">
<span class="can_click_text" @click="getChildren(row)">
{{ row.name }}
</span>
</template>
<template v-slot:ipNumber="{ row }">
<span> {{ row.name }}/{{ row.name }} </span>
</template>
<template v-slot:updated_time="{ row }">
{{ row.updated_time.split("+")[0].replace("T", " ").replace("Z", " ") }}
</template>
<template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :tableData="tableRows">
<bg-table-btn @click="editRow(row)">编辑</bg-table-btn>
<bg-table-btn @click="checkRow(row)">状态检测</bg-table-btn>
<bg-table-btn @click="exportRow(row, 1)">导出异常</bg-table-btn>
<bg-table-btn @click="deleteRow(row, 2)">删除</bg-table-btn>
</bg-table-btns2>
</template>
</bg-table>
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
<!-- 新增/编辑弹窗 -->
<!-- <el-dialog
class="dialog_box"
:title="addType == 1 ? '新增' : '编辑'"
v-model="addDialog"
width="758px">
<el-form ref="bgForm" :model="formData" :rules="rules" label-width="80px" class="bg_form">
<el-form-item label="名称" prop="name">
<el-input
v-model.trim="formData.name"
show-word-limit
:maxlength="
nodeClassifyId == 'eb9c7d70-c123-42b7-8e61-dde1b022b669'
? 6
: nodeClassifyId == 'efd9ec3b-7f18-49e2-9d88-bcca022243bb'
? 4
: nodeClassifyId == '949a1138-4995-464e-97a9-424d097eb271'
? 2
: 20
"
placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="描述" prop="describe">
<el-input
v-model="formData.describe"
type="textarea"
:autosize="{ minRows: 5 }"
show-word-limit
maxlength="200"
resize="vertical"
placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="是否启用" prop="state" style="margin-bottom: 0px">
<el-switch
class="bg-switch-ele"
v-model="formData.state"
:active-value="1"
:inactive-value="0"
inline-prompt
active-text="是"
inactive-text="否" />
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="addDialog = false">取 消</el-button>
<el-button type="primary" @click="addConfirm">保 存</el-button>
</div>
</template>
</el-dialog> -->
<!-- 删除弹窗 -->
<!-- <el-dialog
class="dialog_box"
title="提示"
v-model="dialogDelete"
width="400px"
:before-close="
() => {
dialogDelete = false;
}
">
<div>确定要删除此字典值吗?</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> -->
</div>
</template>
<script setup></script>
<script setup>
import { reactive, ref, onBeforeMount, toRefs, computed, watch, nextTick, watchEffect } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { Search } from "@element-plus/icons-vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const bgForm = ref(null);
const dataTable = ref(null);
const headers = [
{
label: "主机分组名称",
prop: "name",
},
{
label: "IP数量(异常/全部)",
prop: "ipNumber",
},
{
label: "任务数量",
prop: "workTimes",
},
{
label: "创建人",
prop: "person",
},
{
label: "创建时间",
prop: "updated_time",
width: 220,
},
{
label: "操作",
prop: "action",
width: 200,
fixed: "right",
},
];
<style lang="scss" scoped></style>
const state = reactive({
bgForm,
typeList: [], // 分类数据
typeKeyword: "", // 分类删选关键词
nodeClassifyId: null, // 当前选中分类的uuid 用于新增字典
nodeId: null, // 当前选中分类的id 用于请求列表
timer: null, // 定时器
tableRows: [], // 表格数据
selected: [], //选择数据
tableTotal: 0, // 表格数据条数
filter: {
time: "",
search: "",
page: 1,
limit: 10,
}, // 表格筛选项
stateOptions: [
{
name: "全部",
value: "",
},
{
name: "启用",
value: "1",
},
{
name: "禁用",
value: "0",
},
], // 启用禁用
actionRow: null, // 当前操作的数据
dialogDelete: false, // 删除弹窗
addType: 0, //
addDialog: false,
formData: {
name: "",
describe: "",
state: 1,
p_dict_id: "",
},
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
describe: [
{ required: true, message: "请输入描述", trigger: "blur" },
{ max: 200, message: "描述最大为200字", trigger: "blur" },
],
state: [{ required: true, message: "请选择是否启用", trigger: "change" }],
},
fatherRow: null,
});
const selectRows = (data) => {
state.selected = data.selection;
};
const clearSelected = () => {
dataTable.value.clearTable();
};
const deleteAllTips = () => {};
const dictLevel = ref(1);
const getChildren = (row) => {
dictLevel.value = 2;
state.tableRows = row.children || [];
state.tableTotal = row.total_children;
state.fatherRow = row;
};
const getTypeList = () => {
let params = {
name: state.typeKeyword,
};
axios
.get(`/apaas/system/v5/dictionary/classify/list`, { params })
.then((res) => {
if (res.data.code == 200) {
state.typeList = res.data.data || [];
state.nodeClassifyId = state.typeList[0].classify_id || null;
state.nodeId = state.typeList[0].id || null;
if (state.nodeId) {
getTableRows();
}
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
console.log(err);
});
}; // 获取字典分类
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const filterAction = () => {
changePage(1);
}; // 查询按钮
const filterClear = () => {
state.filter = {
time: "",
search: "",
limit: 10,
page: 1,
};
changePage(1);
}; // 重置筛选项
const getTableRows = () => {
let params = { ...state.filter };
params.id = state.nodeId;
axios
.get(`/apaas/system/v5/dictionary/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
let data = res.data.data || [];
if (dictLevel.value == 1) {
state.tableRows = data;
state.tableTotal = res.data.total;
} else {
let row = data.filter((e) => {
return e.dict_id == state.fatherRow.dict_id;
});
state.tableRows = row[0].children;
state.tableTotal = row[0].total_children;
}
if (state.tableRows.length > 0) {
state.tableRows.forEach((e) => {
e.canMoveUp = true;
e.canMoveDown = true;
});
state.tableRows[0].canMoveUp = false;
state.tableRows[state.tableRows.length - 1].canMoveDown = false;
}
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取表格数据
const changePage = (page) => {
state.filter.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
}; // 改变每页条数
const register = () => {
state.formData = {
name: "",
describe: "",
state: 1,
p_dict_id: state.fatherRow ? state.fatherRow.dict_id : "",
};
if (state.bgForm) {
nextTick().then(() => {
state.bgForm.validate((valid) => {
if (!valid) {
state.bgForm.clearValidate();
}
});
});
}
state.addType = 1;
state.addDialog = true;
}; // 新增字典按钮
onBeforeMount(() => {
getTypeList();
});
const { tableRows, tableTotal, filter } = 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;
.main_container {
height: 100%;
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
}
.bg_form {
width: 100%;
box-sizing: border-box;
.el-form-item {
margin-bottom: 24px;
:deep().el-form-item__label {
line-height: 36px;
height: 36px;
}
.el-form-item__content {
width: 100%;
.el-textarea {
:deep().el-input__count {
bottom: -16px;
right: 4px;
font-family: Roboto-Regular;
color: #a9b1c7;
}
}
.bg-switch-ele {
width: 52px;
height: 24px;
:deep().el-switch__core {
width: 100%;
height: 24px;
.el-switch__inner,
.el-switch__action {
top: 3px;
}
}
}
}
}
}
}
</style>
<template>
<div>任务历史</div>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字"> </bg-filter-group>
<div class="table_container">
<div class="table bg-scroll">
<bg-table ref="dataTable" :headers="headers" :rows="tableRows" :stripe="true">
<template v-slot:name="{ row }">
<span class="can_click_text" @click="getChildren(row)">
{{ row.name }}
</span>
</template>
<template v-slot:state="{ row }">
<span> 执行中 </span>
</template>
</bg-table>
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</template>
<script setup></script>
<script setup>
import { reactive, ref, onBeforeMount, toRefs, computed, watch, nextTick, watchEffect } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { useRouter, useRoute } from "vue-router";
import { Search } from "@element-plus/icons-vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
<style lang="scss" scoped></style>
const router = useRouter();
const route = useRoute();
const bgForm = ref(null);
const dataTable = ref(null);
const headers = [
{
label: "状态",
prop: "state",
},
{
label: "任务名称",
prop: "name",
},
{
label: "执行耗时",
prop: "workTime",
},
{
label: "操作人",
prop: "person",
},
];
const state = reactive({
bgForm,
typeList: [], // 分类数据
typeKeyword: "", // 分类删选关键词
nodeClassifyId: null, // 当前选中分类的uuid 用于新增字典
nodeId: null, // 当前选中分类的id 用于请求列表
timer: null, // 定时器
tableRows: [], // 表格数据
selected: [], //选择数据
tableTotal: 0, // 表格数据条数
filter: {
time: "",
search: "",
page: 1,
limit: 10,
}, // 表格筛选项
actionRow: null, // 当前操作的数据
dialogDelete: false, // 删除弹窗
addType: 0, //
addDialog: false,
formData: {
name: "",
describe: "",
state: 1,
p_dict_id: "",
},
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
describe: [
{ required: true, message: "请输入描述", trigger: "blur" },
{ max: 200, message: "描述最大为200字", trigger: "blur" },
],
state: [{ required: true, message: "请选择是否启用", trigger: "change" }],
},
fatherRow: null,
});
const selectRows = (data) => {
state.selected = data.selection;
};
const clearSelected = () => {
dataTable.value.clearTable();
};
const deleteAllTips = () => {};
const getChildren = (row) => {
router.push(`/auto-maintenance/task-history/list`);
};
const getTypeList = () => {
let params = {
name: state.typeKeyword,
};
axios
.get(`/apaas/system/v5/dictionary/classify/list`, { params })
.then((res) => {
if (res.data.code == 200) {
state.typeList = res.data.data || [];
state.nodeClassifyId = state.typeList[0].classify_id || null;
state.nodeId = state.typeList[0].id || null;
if (state.nodeId) {
getTableRows();
}
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
console.log(err);
});
}; // 获取字典分类
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const filterAction = () => {
changePage(1);
}; // 查询按钮
const filterClear = () => {
state.filter = {
time: "",
search: "",
limit: 10,
page: 1,
};
changePage(1);
}; // 重置筛选项
const getTableRows = () => {
let params = { ...state.filter };
params.id = state.nodeId;
axios
.get(`/apaas/system/v5/dictionary/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
let data = res.data.data || [];
state.tableRows = data;
state.tableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取表格数据
const changePage = (page) => {
state.filter.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
}; // 改变每页条数
const register = () => {
state.formData = {
name: "",
describe: "",
state: 1,
p_dict_id: state.fatherRow ? state.fatherRow.dict_id : "",
};
if (state.bgForm) {
nextTick().then(() => {
state.bgForm.validate((valid) => {
if (!valid) {
state.bgForm.clearValidate();
}
});
});
}
state.addType = 1;
state.addDialog = true;
}; // 新增字典按钮
onBeforeMount(() => {
getTypeList();
});
const { tableRows, tableTotal, filter } = 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;
.main_container {
height: 100%;
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
}
.bg_form {
width: 100%;
box-sizing: border-box;
.el-form-item {
margin-bottom: 24px;
:deep().el-form-item__label {
line-height: 36px;
height: 36px;
}
.el-form-item__content {
width: 100%;
.el-textarea {
:deep().el-input__count {
bottom: -16px;
right: 4px;
font-family: Roboto-Regular;
color: #a9b1c7;
}
}
.bg-switch-ele {
width: 52px;
height: 24px;
:deep().el-switch__core {
width: 100%;
height: 24px;
.el-switch__inner,
.el-switch__action {
top: 3px;
}
}
}
}
}
}
}
</style>
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-filter-group
@search="changeSearch"
class="page-filter-group"
v-model="filter.search"
placeholder="请输入关键字">
<template v-slot:left_action>
<div class="apaas_button">
<el-button type="default" @click="deleteAllTips"> 返回 </el-button>
</div>
<span class="filter-group-item">执行ping命令</span>
</template>
</bg-filter-group>
<div class="table_container">
<div class="table bg-scroll">
<bg-table ref="dataTable" :headers="headers" :rows="tableRows" :stripe="true">
<template v-slot:desc="{ row }">
<span class="can_click_text" @click="getChildren(row)">
{{ row.name }}
</span>
</template>
<template v-slot:state="{ row }">
<span> 执行中 </span>
</template>
</bg-table>
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, ref, onBeforeMount, toRefs, computed, watch, nextTick, watchEffect } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { Search } from "@element-plus/icons-vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const bgForm = ref(null);
const dataTable = ref(null);
const headers = [
{
label: "状态",
prop: "state",
},
{
label: "执行说明",
prop: "desc",
},
{
label: "执行开始时间",
prop: "begin",
},
{
label: "执行耗时",
prop: "workTime",
},
{
label: "操作人",
prop: "person",
},
];
const state = reactive({
bgForm,
typeList: [], // 分类数据
typeKeyword: "", // 分类删选关键词
nodeClassifyId: null, // 当前选中分类的uuid 用于新增字典
nodeId: null, // 当前选中分类的id 用于请求列表
timer: null, // 定时器
tableRows: [], // 表格数据
selected: [], //选择数据
tableTotal: 0, // 表格数据条数
filter: {
time: "",
search: "",
page: 1,
limit: 10,
}, // 表格筛选项
actionRow: null, // 当前操作的数据
dialogDelete: false, // 删除弹窗
addType: 0, //
addDialog: false,
formData: {
name: "",
describe: "",
state: 1,
p_dict_id: "",
},
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
describe: [
{ required: true, message: "请输入描述", trigger: "blur" },
{ max: 200, message: "描述最大为200字", trigger: "blur" },
],
state: [{ required: true, message: "请选择是否启用", trigger: "change" }],
},
fatherRow: null,
});
const selectRows = (data) => {
state.selected = data.selection;
};
const clearSelected = () => {
dataTable.value.clearTable();
};
const deleteAllTips = () => {};
const getChildren = (row) => {
state.tableRows = row.children || [];
state.tableTotal = row.total_children;
state.fatherRow = row;
};
const getTypeList = () => {
let params = {
name: state.typeKeyword,
};
axios
.get(`/apaas/system/v5/dictionary/classify/list`, { params })
.then((res) => {
if (res.data.code == 200) {
state.typeList = res.data.data || [];
state.nodeClassifyId = state.typeList[0].classify_id || null;
state.nodeId = state.typeList[0].id || null;
if (state.nodeId) {
getTableRows();
}
} else {
ElMessage.error(res.data.data);
}
})
.catch((err) => {
console.log(err);
});
}; // 获取字典分类
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const filterAction = () => {
changePage(1);
}; // 查询按钮
const filterClear = () => {
state.filter = {
time: "",
search: "",
limit: 10,
page: 1,
};
changePage(1);
}; // 重置筛选项
const getTableRows = () => {
let params = { ...state.filter };
params.id = state.nodeId;
axios
.get(`/apaas/system/v5/dictionary/list`, {
params,
})
.then((res) => {
if (res.data.code == 200) {
let data = res.data.data || [];
state.tableRows = data;
state.tableTotal = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
}; // 获取表格数据
const changePage = (page) => {
state.filter.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
}; // 改变每页条数
const register = () => {
state.formData = {
name: "",
describe: "",
state: 1,
p_dict_id: state.fatherRow ? state.fatherRow.dict_id : "",
};
if (state.bgForm) {
nextTick().then(() => {
state.bgForm.validate((valid) => {
if (!valid) {
state.bgForm.clearValidate();
}
});
});
}
state.addType = 1;
state.addDialog = true;
}; // 新增字典按钮
onBeforeMount(() => {
getTypeList();
});
const { tableRows, tableTotal, filter } = 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;
.main_container {
height: 100%;
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
}
.bg_form {
width: 100%;
box-sizing: border-box;
.el-form-item {
margin-bottom: 24px;
:deep().el-form-item__label {
line-height: 36px;
height: 36px;
}
.el-form-item__content {
width: 100%;
.el-textarea {
:deep().el-input__count {
bottom: -16px;
right: 4px;
font-family: Roboto-Regular;
color: #a9b1c7;
}
}
.bg-switch-ele {
width: 52px;
height: 24px;
:deep().el-switch__core {
width: 100%;
height: 24px;
.el-switch__inner,
.el-switch__action {
top: 3px;
}
}
}
}
}
}
}
.page-filter-group {
position: relative;
.filter-group-item {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 14px;
color: #202531;
}
}
</style>
<template>
<div>预警列表</div>
<div class="detail_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="batchPush">
<bg-icon style="font-size: 12px; color: #fff; margin-right: 8px" icon="#bg-ic-edit"></bg-icon>
批量推送
</el-button>
<el-button type="default" @click="batchDelete"> 批量删除 </el-button>
<span class="header_info"
>已选择 <span style="color: #202531; font-weight: bold"> {{ state.selected.length }} </span>
</span>
<span class="header_info can_click_text" @click="clearSelected">清空</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.warning_type" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in warningTypes"
:key="'warningType' + index"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">预警指标</span>
<el-select v-model="filter.warning_target" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in warningTargets"
:key="'warningTargets' + index"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">风险等级</span>
<el-select v-model="filter.risk_level" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in riskLevels"
:key="'riskLevels' + index"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">状态</span>
<el-select v-model="filter.state" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in stateOptions"
:key="'stateOptions' + index"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="filter_item">
<span class="filter_title">预警时间</span>
<el-date-picker
style="width: 300px"
v-model="filter.time"
type="daterange"
value-format="yyyy-MM-DD"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期" />
</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">
<div class="table bg-scroll">
<bg-table
ref="dataTable"
:headers="headers"
:rows="tableRows"
@selectAc="selectRows"
:isIndex="true"
:select="true"
:stripe="true">
<template v-slot:warning_point="{ row }">
<span class="can_click_text" @click="goDetail(row)">
{{ row.warning_point }}
</span>
</template>
<template v-slot:warning_time="{ row }">
{{ row.warning_time ? row.warning_time.split("+")[0].replace("T", " ").replace("Z", " ") : "-" }}
</template>
<template v-slot:last_push_time="{ row }">
{{ row.last_push_time ? row.last_push_time.split("+")[0].replace("T", " ").replace("Z", " ") : "-" }}
</template>
<template #state="{ row }">
<span :class="`circle bgc_${row.state}`"></span>
{{ ["未恢复", "已恢复", "已关闭"][row.state] }}
</template>
<template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :tableData="tableRows">
<bg-table-btn :disabled="row.state != 0" @click="pushWarning(row)">推送提醒</bg-table-btn>
<bg-table-btn :disabled="row.state != 0" @click="closeWarning(row)">关闭预警</bg-table-btn>
</bg-table-btns2>
</template>
</bg-table>
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
<!-- todo: 推送提醒 -->
<!-- <el-dialog
class="dialog_box"
:title="addType == 1 ? '新增' : '编辑'"
v-model="addDialog"
width="758px">
<el-form ref="bgForm" :model="formData" :rules="rules" label-width="80px" class="bg_form">
<el-form-item label="名称" prop="name">
<el-input
v-model.trim="formData.name"
show-word-limit
:maxlength="
nodeClassifyId == 'eb9c7d70-c123-42b7-8e61-dde1b022b669'
? 6
: nodeClassifyId == 'efd9ec3b-7f18-49e2-9d88-bcca022243bb'
? 4
: nodeClassifyId == '949a1138-4995-464e-97a9-424d097eb271'
? 2
: 20
"
placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="描述" prop="describe">
<el-input
v-model="formData.describe"
type="textarea"
:autosize="{ minRows: 5 }"
show-word-limit
maxlength="200"
resize="vertical"
placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="是否启用" prop="state" style="margin-bottom: 0px">
<el-switch
class="bg-switch-ele"
v-model="formData.state"
:active-value="1"
:inactive-value="0"
inline-prompt
active-text="是"
inactive-text="否" />
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="addDialog = false">取 消</el-button>
<el-button type="primary" @click="addConfirm">保 存</el-button>
</div>
</template>
</el-dialog> -->
<!-- todo:关闭提醒 -->
<!-- <el-dialog
class="dialog_box"
title="提示"
v-model="dialogDelete"
width="400px"
:before-close="
() => {
dialogDelete = false;
}
">
<div>确定要删除此字典值吗?</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> -->
</div>
</template>
<script setup></script>
<script setup>
import { reactive, ref, onBeforeMount, toRefs, computed, watch, nextTick, watchEffect } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { Search } from "@element-plus/icons-vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const bgForm = ref(null);
const dataTable = ref(null);
const state = reactive({
bgForm,
warningTypes: [
{
name: "全部",
value: "",
},
{
name: "分类1",
value: 1,
},
{
name: "分类2",
value: 2,
},
], // 预警分类数据
warningTargets: [
{
name: "全部",
value: "",
},
{
name: "指标1",
value: 1,
},
{
name: "指标2",
value: 2,
},
], // 预警指标数据
riskLevels: [
{
name: "全部",
value: "",
},
{
name: "等级1",
value: 1,
},
{
name: "等级2",
value: 2,
},
], // 风险等级
stateOptions: [
{
name: "全部",
value: "",
},
{
name: "已恢复",
value: "1",
},
{
name: "未恢复",
value: "0",
},
{
name: "已关闭",
value: "2",
},
], // 状态
headers: [
{
label: "预警点",
prop: "warning_point",
width: 180,
},
{
label: "预警时间",
prop: "warning_time",
width: 160,
},
{
label: "预警分类",
prop: "warning_type_name",
},
{
label: "预警指标",
prop: "warning_target_name",
},
{
label: "风险等级",
prop: "risk_level_name",
},
{
label: "当前报警值",
prop: "now_warn_data",
},
{
label: "预警阈值",
prop: "warn_threshold",
},
{
label: "通知人数",
prop: "notice_people_num",
width: 80,
},
{
label: "推送次数",
prop: "push_times",
width: 80,
},
{
label: "最后推送时间",
prop: "last_push_time",
width: 160,
},
{
label: "状态",
prop: "state",
width: 90,
},
{
label: "操作",
prop: "action",
width: 180,
fixed: "right",
},
],
tableRows: [], // 表格数据
selected: [], //选择数据
tableTotal: 0, // 表格数据条数
filter: {
warning_type: "", // 预警类型
warning_target: "", // 预警指标
risk_level: "", // 风险等级
state: "", // 状态
time: [],
search: "",
page: 1,
limit: 10,
}, // 表格筛选项
actionRow: null, // 当前操作的数据
dialogDelete: false, // 删除弹窗
addType: 0, //
addDialog: false,
formData: {
name: "",
describe: "",
state: 1,
p_dict_id: "",
},
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
describe: [
{ required: true, message: "请输入描述", trigger: "blur" },
{ max: 200, message: "描述最大为200字", trigger: "blur" },
],
state: [{ required: true, message: "请选择是否启用", trigger: "change" }],
},
});
const selectRows = (data) => {
state.selected = data.selection;
};
const clearSelected = () => {
dataTable.value.clearTable();
}; // 清空
const batchDelete = () => {
console.log("批量删除");
}; // 批量删除
const goDetail = (row) => {
console.log("去详情");
}; // 查看详情
const changeSearch = (val) => {
state.filter.search = val;
changePage(1);
}; // 表格关键字筛选
const filterAction = () => {
changePage(1);
}; // 查询按钮
const filterClear = () => {
state.filter = {
warning_type: "", // 预警类型
warning_target: "", // 预警指标
risk_level: "", // 风险等级
state: "", // 状态
time: "",
search: "",
page: 1,
limit: 10,
};
changePage(1);
}; // 重置筛选项
const getTableRows = () => {
let params = { ...state.filter };
// axios
// .get(`/apaas/system/v5/dictionary/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);
// }
// });
state.tableTotal = 23;
state.tableRows = [
{
id: 1,
warning_point: "容器云/tyyh",
warning_time: "2020-01-01 00:00:00",
warning_type_name: "容器组",
warning_target_name: "服务中断",
risk_level_name: "重大风险",
now_warn_data: "",
warn_threshold: "",
notice_people_num: 2,
push_times: 2,
last_push_time: "2020-01-01 00:00:00",
state: 1,
},
{
id: 2,
warning_point: "容器云/kube-apiserver",
warning_time: "2020-01-01 00:00:00",
warning_type_name: "容器集群",
warning_target_name: "内存使用率",
risk_level_name: "较大风险",
now_warn_data: "66%",
warn_threshold: "60%-70%",
notice_people_num: 3,
push_times: 1,
last_push_time: "2020-01-01 00:00:00",
state: 0,
},
{
id: 3,
warning_point: "容器云/kube-apiserver",
warning_time: "2020-01-01 00:00:00",
warning_type_name: "容器集群",
warning_target_name: "内存使用率",
risk_level_name: "较大风险",
now_warn_data: "66%",
warn_threshold: "60%-70%",
notice_people_num: 3,
push_times: 1,
last_push_time: "2020-01-01 00:00:00",
state: 2,
},
];
}; // 获取表格数据
const changePage = (page) => {
state.filter.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
changePage(1);
}; // 改变每页条数
const batchPush = () => {
console.log("批量推送");
}; // 批量推送
const pushWarning = (row) => {
state.actionRow = row;
console.log("推送提醒");
}; // 推送提醒
const closeWarning = (row) => {
state.actionRow = row;
console.log("关闭预警");
}; // 关闭预警
onBeforeMount(() => {
getTableRows();
});
const { headers, tableRows, tableTotal, filter, warningTypes, warningTargets, riskLevels, stateOptions } =
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;
.main_container {
height: 100%;
.filter-group {
.left-filter {
flex: 1;
display: flex;
justify-content: start;
flex-wrap: wrap;
}
.right-action {
width: 144px;
padding-bottom: 16px;
.el-button {
width: 64px;
}
}
}
.table_container {
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
.circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 3px;
margin-right: 8px;
transform: translateY(-2px);
}
.bgc_0 {
background-color: #d75138;
}
.bgc_1 {
background-color: #48ad97;
}
.bgc_2 {
background-color: #9e9e9e;
}
}
}
}
<style lang="scss" scoped></style>
.bg_form {
width: 100%;
box-sizing: border-box;
.el-form-item {
margin-bottom: 24px;
:deep().el-form-item__label {
line-height: 36px;
height: 36px;
}
.el-form-item__content {
width: 100%;
.el-textarea {
:deep().el-input__count {
bottom: -16px;
right: 4px;
font-family: Roboto-Regular;
color: #a9b1c7;
}
}
.bg-switch-ele {
width: 52px;
height: 24px;
:deep().el-switch__core {
width: 100%;
height: 24px;
.el-switch__inner,
.el-switch__action {
top: 3px;
}
}
}
}
}
}
}
</style>
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