Commit 5715b4e7 authored by 张耀's avatar 张耀

Merge branch 'dev' into zy

parents c1620424 1cd8c8bf
......@@ -31,7 +31,9 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
image: registry.cn-qingdao.aliyuncs.com/wod/devops-node:16.16.0-slim
# 将宿主机中文件夹挂载到容器中,宿主机文件夹中的文件会被容器访问并修改,起到使用缓存的作用,避免每次运行都要重现下载依赖,提高运行速度
commands:
- yarn
# - npm install -g cnpm --registry=https://registry.npm.taobao.org
# - cnpm install
# - yarn
- export NODE_ENV=production
- yarn build
......@@ -153,7 +155,6 @@ trigger:
branch:
- master
kind: pipeline
name: master
steps:
......
......@@ -13,5 +13,6 @@
"editor.formatOnSave": true,
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
},
"vue.codeActions.enabled": false
}
......@@ -143,9 +143,9 @@ const { content } = toRefs(states);
right: 0 !important;
}
/* 光标颜色 */
.vue-ace-editor :deep() .ace_cursor {
/* .vue-ace-editor :deep() .ace_cursor {
color: #fff;
}
} */
.vue-ace-editor-disable :deep() .ace_scrollbar-v {
width: 6px !important;
right: 2px;
......
......@@ -12,7 +12,7 @@
</template>
<script setup>
import { reactive, ref, onBeforeMount, toRefs, watch } from "vue";
import { reactive, ref, onBeforeMount, watch } from "vue";
const props = defineProps({
modelValue: {
type: [String, Number],
......
......@@ -178,4 +178,9 @@ const getRowInfo = (row, key) => {
$_prop_path: propPath,
};
};
defineExpose({
clearSelection,
getRowInfo,
});
</script>
<template>
<el-table
:height="height"
ref="table"
class="bg-table"
:data="rows"
......@@ -14,7 +13,7 @@
<template v-slot:empty>
<div class="empty_container">
<img src="../assets/imgs/img-no-data.png" alt="" />
<div class="text">暂无数据</div>
<div class="text">{{ emptyText }}</div>
</div>
</template>
<el-table-column v-if="paddingLeft > 10 && !border" :width="paddingLeft - 10"></el-table-column>
......@@ -57,10 +56,6 @@ const { nowSelectData, allSelectData, initAllSelectData, selectData, initSelectT
selectTableMixin();
const props = defineProps({
height: {
type: [Number, String],
default: "auto",
},
headers: {
type: Array,
require: true,
......@@ -81,6 +76,10 @@ const props = defineProps({
type: String,
default: "序号",
},
emptyText: {
type: String,
default: "暂无数据",
},
stripe: {
type: Boolean,
default: false,
......
......@@ -6,6 +6,8 @@
directory: 'file',
uniqueCode: false,
}"
:limit="limit"
:http-request="httpRequest"
:before-upload="handleBeforeUpload"
:on-exceed="handleExceed"
:on-success="handleSuccess"
......@@ -95,6 +97,9 @@ const props = defineProps({
type: String,
default: "",
},
httpRequest: {
type: Function,
},
limit: {
type: Number,
default: 9999,
......@@ -123,10 +128,6 @@ watch(
}
);
const handleBeforeUpload = (file) => {
if (state.fileList && state.fileList.length >= props.limit) {
ElMessage.error(`只允许上传${props.limit}个文件`);
return false;
}
let temp = file.name.split(".");
let type = temp[temp.length - 1].toLocaleLowerCase();
let fileTypesOk = props.fileTypes.indexOf(type) > -1 || props.fileTypes.length == 0;
......@@ -143,7 +144,7 @@ const handleBeforeUpload = (file) => {
return fileTypesOk && fileMaxSizeOk;
};
const handleExceed = (file, fileList) => {
console.log(file, fileList);
ElMessage.error(`只允许上传${props.limit}个文件`);
};
const handlePreview = (val) => {
let a = document.createElement("a"); // 生成一个a元素
......
<template>
<div>
<el-table
:data="tableData"
style="width: 100%">
<el-table :data="tableData" style="width: 100%">
<el-table-column
v-for="(item,index) in header"
:key="'header'+index"
v-for="(item, index) in header"
:key="'header' + index"
prop="date"
:label="item.name"
:width="item.width">
<template v-slot:default="scope">
<span class="table-span" v-for="(it,idx) in item.value" :key="'it'+idx">
<span class="table-span" v-for="(it, idx) in item.value" :key="'it' + idx">
<el-input
v-if="it.type == 'input'"
v-show="it.show==undefined?true:typeof(it.show)=='function'?it.show(scope):it.show"
@change="changeData({...scope,type:it.value,check:it.check||null})"
v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
@change="changeData({ ...scope, type: it.value, check: it.check || null })"
v-model="scope.row[it.value]"
:style="{width:it.width}"
:style="{ width: it.width }"
:placeholder="it.placeholder"
:disabled="it.disabled"
></el-input>
:disabled="it.disabled"></el-input>
<el-select
v-if="it.type == 'select'"
v-show="it.show==undefined?true:typeof(it.show)=='function'?it.show(scope):it.show"
@change="changeData({...scope,type:it.value,check:it.check||null})"
v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
@change="changeData({ ...scope, type: it.value, check: it.check || null })"
:multiple="it.multiple || false"
v-model="scope.row[it.value]"
:style="{width:it.width}"
:style="{ width: it.width }"
:disabled="it.disabled"
:placeholder="it.placeholder"
>
:placeholder="it.placeholder">
<el-option
v-for="(itx, idxm) in it.arr"
:key="idxm + 600"
:label="itx.label"
:value="itx.value"
:disabled="itx.disabled"
></el-option>
:disabled="itx.disabled"></el-option>
</el-select>
<span v-if="it.type == 'text'" v-show="it.show==undefined?true:typeof(it.show)=='function'?it.show(scope):it.show">{{it.value}}</span>
<span v-if="it.type == 'value'" v-show="it.show==undefined?true:typeof(it.show)=='function'?it.show(scope):it.show">{{scope.row[it.value]}}</span>
<span class="button" v-if="it.type == 'button'" v-show="it.show==undefined?true:typeof(it.show)=='function'?it.show(scope):it.show" @click="it.callback(scope)">{{it.value}}</span>
<span
v-if="it.type == 'text'"
v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
>{{ it.value }}</span
>
<span
v-if="it.type == 'value'"
v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
>{{ scope.row[it.value] }}</span
>
<span
class="button"
v-if="it.type == 'button'"
v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
@click="it.callback(scope)"
>{{ it.value }}</span
>
</span>
</template>
</el-table-column>
......@@ -51,50 +60,38 @@
<script>
export default {
props: {
header:{
type:Array,
default:()=>[]
header: {
type: Array,
default: () => [],
},
tableData:{
type:Array,
default:()=>[]
}
tableData: {
type: Array,
default: () => [],
},
components: {
},
components: {},
data() {
return {
};
},
watch: {
},
computed: {
},
created() {
},
mounted() {
return {};
},
watch: {},
computed: {},
created() {},
mounted() {},
methods: {
changeData(val){
this.$emit('change',val)
}
changeData(val) {
this.$emit("change", val);
},
},
};
</script>
<style scoped>
.table-span{
.table-span {
float: left;
margin-right: 10px;
line-height: 40px;
}
.button{
.button {
cursor: pointer;
color: #2b4695;
}
......
......@@ -120,9 +120,7 @@ const login = () => {
ElMessage.error(data.data);
}
})
.catch((error) => {
console.log(error);
});
.catch((error) => {});
};
const getUserInfo = () => {
return axios.get(`/v1/api/user/getUserInfo`);
......
......@@ -30,7 +30,7 @@ import store from "@/store";
import i18n from "./i18n/i18n.js";
import axios from "./request/http.js";
import api from "./request/api.js";
import config from "../package.json";
import { menuData } from "@/components/menu.js";
......@@ -61,6 +61,7 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
}
createVue.config.globalProperties.$axios = axios;
createVue.config.globalProperties.$api = api;
import menu from "./router/function.js";
......
......@@ -77,7 +77,7 @@ const treeProps = {
disabled: "disabled",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
orgDataTemp.shift();
......
......@@ -149,7 +149,7 @@ const formatFile = (url) => {
const getDetail = () => {
axios
.get(`/apaas/system/v5/org/detail?organization_id=${route.query.id}&key_word=&state=&limit=&page=&data_type=1`)
.get(`/v1/api/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;
......
......@@ -22,16 +22,6 @@
<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>
......@@ -51,7 +41,6 @@ const orgForm = reactive({
name: "",
organization_code: "",
description: "",
attachment: [],
});
const checkCode = (rule, value, callback) => {
......@@ -115,7 +104,7 @@ const treeProps = {
disabled: "disabled",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) {
const orgDataTemp = res.data.data || [];
orgDataTemp.shift();
......
......@@ -198,7 +198,7 @@ const treeProps = {
value: "organization_id",
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) {
orgData.value = res.data.data || [];
} else {
......
......@@ -211,7 +211,7 @@ const cancel = () => {
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) {
orgId.value = res.data.data[0].organization_id;
} else {
......
......@@ -20,10 +20,7 @@
@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)">
<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>
......@@ -141,8 +138,8 @@
</template>
<script setup>
import { reactive, toRefs, ref, computed, onBeforeMount, onBeforeUnmount, watch, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ref, onBeforeMount, onBeforeUnmount, nextTick } from "vue";
import { useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const route = useRoute();
......@@ -174,10 +171,9 @@ const defaultProps = {
};
const getOrgTree = (data) => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/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;
......
......@@ -18,14 +18,6 @@
: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"
......@@ -76,14 +68,11 @@ const roleState = reactive({
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" }],
}, // 表单校验规则
......@@ -97,7 +86,7 @@ const roleState = reactive({
rowType: 0,
});
const getMenuTree = () => {
axios.get(`/apaas/system/v5/menu/tree`).then((res) => {
axios.get(`/v1/api/menu/tree`).then((res) => {
if (res.data.code == 200) {
roleState.permissionData = res.data.data || [];
} else {
......@@ -111,9 +100,9 @@ const changeMenu = (val) => {
}; // 修改选中的菜单
const getRoleDetail = () => {
axios.get(`/apaas/system/v5/role/detail/${route.query.id}`).then((res) => {
axios.get(`/v1/api/role/detail/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
let { role_name, role_desc, data_purview, state, menus } = res.data.data;
let { role_name, role_desc, state, menus } = res.data.data;
roleState.rowType = res.data.data.role_type;
let permission_arr = [];
if (menus && menus.length > 0) {
......@@ -124,11 +113,9 @@ const getRoleDetail = () => {
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);
}
......@@ -142,15 +129,14 @@ const saveRole = () => {
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) => {
axios.put(`/v1/api/role/create`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
router.push("/system/role");
router.push("/authority/role");
} else {
ElMessage.error(res.data.data);
}
......@@ -158,10 +144,10 @@ const saveRole = () => {
} else {
// 编辑
params.id = +route.query.id;
axios.post(`/apaas/system/v5/role/update`, params).then((res) => {
axios.post(`/v1/api/role/update`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
router.push("/system/role");
router.push("/authority/role");
} else {
ElMessage.error(res.data.data);
}
......@@ -171,7 +157,7 @@ const saveRole = () => {
});
}; // 新增或编辑角色的保存
const goList = () => {
router.push("/system/role");
router.push("/authority/role");
};
onBeforeMount(() => {
......
......@@ -69,7 +69,7 @@
delete_row(row);
}
"
:disabled="row.state == 1 || row.role_type == 1">
:disabled="row.state == 1 || row.role_type == 1 || row.role_type == 2 || row.user_count > 0">
删除
</bg-table-btn>
</template>
......@@ -105,14 +105,6 @@
<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"
......@@ -127,7 +119,7 @@
}"
:clearable="true"
collapse-tags
style="width: 200px">
style="width: 200px; margin-right: 30px">
<template #default="{ data }">
<span>{{ data.name }}</span>
</template>
......@@ -135,9 +127,9 @@
<el-input
v-model.trim="userFilter.search"
placeholder="请输入内容"
style="width: 200px"
style="width: 200px; margin-right: 30px"
:prefix-icon="Search" />
<el-button type="primary" @click="searchAction">查询</el-button>
<el-button style="margin-right: 15px" type="primary" @click="searchAction">查询</el-button>
<el-button type="default" @click="clearAction">重置</el-button>
</div>
</div>
......@@ -236,26 +228,11 @@ const state = reactive({
});
const userState = reactive({
userFilter: {
is_admin: "",
organization_id: "",
search: "",
limit: 10,
page: 1,
},
userTypeList: [
{
name: "全部类型",
value: "",
},
{
name: "组织管理员账号",
value: 2,
},
{
name: "平台用户账号",
value: 3,
},
],
orgList: [],
userHeaders: [
{
......@@ -280,10 +257,10 @@ const userState = reactive({
userSelection: [],
distributeDialog: false, // 分配用户弹窗
});
// 获取角色列表
const getRoleRows = () => {
let params = { ...state.filter };
console.log(params);
axios.get(`/apaas/system/v5/role/list`, { params }).then((res) => {
axios.get(`/v1/api/role/list`, { params }).then((res) => {
if (res.data.code == 200) {
state.tableRows = res.data.data || [];
state.tableTotal = res.data.total;
......@@ -291,12 +268,11 @@ const getRoleRows = () => {
ElMessage.error(res.data.data);
}
});
}; // 获取角色列表
};
//获取组织树
const getOrgList = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/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);
......@@ -319,10 +295,11 @@ const changeSearch = (val) => {
}; // 表格关键字筛选
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) => {
axios.post(`/v1/api/role/state/${row.id}/${row.state}`).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
changePage(1);
......@@ -370,10 +347,9 @@ const getUserList = () => {
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) => {
axios.get(`/v1/api/role/allotment/list`, { params }).then((res) => {
if (res.data.code == 200) {
console.log(res.data.data);
userState.userRows = res.data.data || [];
......@@ -381,7 +357,6 @@ const getUserList = () => {
nextTick(() => {
userState.userRows.forEach((e) => {
if (e.is_bind == 1) {
console.log(userTable);
userTable.value.toggleRowSelection(e, true);
}
});
......@@ -402,13 +377,11 @@ const changeUserSize = (val) => {
};
const searchAction = () => {
console.log(userState.userFilter);
changeUserPage(1);
};
const clearAction = (type) => {
userState.userFilter = {
is_admin: "",
organization_id: "",
search: "",
limit: 10,
......@@ -420,7 +393,6 @@ const clearAction = (type) => {
};
const clearUserSelection = () => {
console.log(userTable.value);
userTable.value.clearTable();
};
......@@ -437,7 +409,7 @@ const distribute = () => {
id: state.actionRow.id,
user_ids: user_ids,
};
axios.post(`/apaas/system/v5/role/allotment/user`, params).then((res) => {
axios.post(`/v1/api/role/allotment/user`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
userState.distributeDialog = false;
......@@ -475,7 +447,7 @@ const deleteData = () => {
let params = {
ids: [...ids],
};
axios.delete(`/apaas/system/v5/role/delete`, { data: { ids: [...ids] } }).then((res) => {
axios.delete(`/v1/api/role/delete`, { data: { ids: [...ids] } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
state.delDialog = false;
......@@ -492,8 +464,7 @@ onBeforeMount(() => {
const { filter, headers, tableRows, tableTotal, delDialog, selection } = toRefs(state);
const { userFilter, userTypeList, orgList, userHeaders, userRows, total, userSelection, distributeDialog } =
toRefs(userState);
const { userFilter, orgList, userHeaders, userRows, total, userSelection, distributeDialog } = toRefs(userState);
</script>
<style lang="scss" scoped>
......@@ -569,7 +540,7 @@ const { userFilter, userTypeList, orgList, userHeaders, userRows, total, userSel
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
justify-content: flex-end;
.el-button {
margin: 0;
width: 64px;
......
<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>
......@@ -3,88 +3,17 @@
<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">
<div class="content_bottom">
<div>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="previousStep">上一步</el-button>
<el-button type="primary" @click="submit">保存</el-button>
</div>
</div>
......@@ -95,17 +24,14 @@
<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: "",
......@@ -120,41 +46,26 @@ const formData = reactive({
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);
//提交表单
const submit = () => {
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) => {
axios.put(`/v1/api/user/${route.query.id}`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
ElMessage.success(res.data.msg);
cancel();
} else {
ElMessage.error(res.data.data);
}
......@@ -165,37 +76,21 @@ const getContactFormData = (data) => {
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) => {
axios.put(`/v1/api/user/add`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
ElMessage.success(res.data.msg);
cancel();
} 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",
path: "/authority/user",
query: {
id: formData.organization_id,
},
......@@ -203,7 +98,7 @@ const cancel = () => {
};
const getDetail = () => {
axios.get(`/apaas/system/v5/user/detail/${route.query.id}`).then((res) => {
axios.get(`/v1/api/user/${route.query.id}`).then((res) => {
if (res.data.code == 200) {
const form = res.data.data;
systemFormRef.value.setForm({
......@@ -221,13 +116,6 @@ const getDetail = () => {
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);
}
......
......@@ -14,7 +14,7 @@
:data="orgData"
:props="defaultProps"
@node-click="handleNodeClick"
node-key="id"
node-key="organization_id"
:highlight-current="true"
:filter-node-method="filterNode"
:default-expand-all="true">
......@@ -276,7 +276,7 @@ const route = useRoute();
const getTableRows = () => {
let params = { ...filter, organization_id: selectNode.value };
axios
.get(`/apaas/system/v5/user/list`, {
.get(`/v1/api/org/detail`, {
params,
})
.then((res) => {
......@@ -297,7 +297,7 @@ const addAccount = (params) => {
const handleNodeClick = (data) => {
if (data.data_type == 1) {
selectNode.value = data.id;
selectNode.value = data.organization_id;
changePage(1);
} else {
nextTick(() => {
......@@ -321,18 +321,19 @@ const defaultProps = {
class: customNodeClass,
};
const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => {
axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) {
orgData.value = res.data.data || [];
orgData.value.shift();
// orgData.value.shift();
const orgList = searchOrg(orgData.value);
if (route.query.id) {
searchItem(orgData.value, route.query.id);
console.log("orgList", orgList);
if (route.query.organization_id) {
searchItem(orgData.value, route.query.organization_id);
} else {
selectNode.value = orgList.length > 0 ? orgList[0].id : "";
selectNode.value = orgList.length > 0 ? orgList[0].organization_id : "";
}
nextTick(() => {
if (route.query.id) {
if (route.query.organization_id) {
treeRef.value.setCurrentNode(selectNodeObj.value);
} else {
if (orgList.length > 0) {
......@@ -346,14 +347,14 @@ const getOrgTree = () => {
}
});
};
const searchItem = (data, id) => {
const searchItem = (data, organization_id) => {
data.forEach((e) => {
if (e.organization_id == id) {
if (e.organization_id == organization_id) {
selectNodeObj.value = e;
selectNode.value = e.id;
selectNode.value = e.organization_id;
} else {
if (e.Child) {
searchItem(e.Child, id);
searchItem(e.Child, organization_id);
}
}
});
......@@ -361,7 +362,7 @@ const searchItem = (data, id) => {
const searchOrg = (data) => {
const arr = [];
data.forEach((item) => {
if (item.data_type === 1) {
if (item.data_type > 0) {
arr.push(item);
return;
} else {
......@@ -385,8 +386,11 @@ const filterNode = (value, data) => {
};
const stateChange = (row) => {
const state = row.state.toString();
axios.post(`/apaas/system/v5/user/state/${row.id}/${state}`).then((res) => {
const params = {
id: row.id,
state: row.state == 1 ? 0 : 1,
};
axios.post(`/v1/api/user/updateState`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
......@@ -449,7 +453,7 @@ const handleCloseRowDelete = () => {
const deleteConfirm = () => {
const ids = selected.value.map((item) => item.id);
axios.delete(`/apaas/system/v5/user/delete`, { data: { ids: ids } }).then((res) => {
axios.delete(`/v1/api/user/del`, { data: { ids: ids } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
......@@ -461,7 +465,7 @@ const deleteConfirm = () => {
};
const deleteRowConfirm = () => {
axios.delete(`/apaas/system/v5/user/delete`, { data: { ids: [selectedRow.value.id] } }).then((res) => {
axios.delete(`/v1/api/user/del`, { data: { ids: [selectedRow.value.id] } }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
......@@ -494,7 +498,7 @@ const resetPsd = () => {
const resetConfirm = () => {
const ids = selected.value.map((item) => item.id);
axios.post(`/apaas/system/v5/user/resetpwd`, { ids: ids }).then((res) => {
axios.post(`/v1/api/user/resetPwd`, { ids: ids }).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
getTableRows();
......@@ -522,7 +526,7 @@ const editConfirm = () => {
passwordRef.value.validate((valid, fields) => {
if (valid) {
axios
.post(`/apaas/system/v5/user/editpwd`, {
.post(`/v1/api/user/updatePwd`, {
id: selectedRow.value.id,
password: CryptoJS.AES.encrypt(passwordForm.password, "swuE9cmCZQwrkYRV").toString(),
})
......
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="content_main bg-scroll">
<el-form
label-position="top"
label-width="100px"
ref="ruleFormRef"
:model="formData"
:rules="formRules"
style="max-width: 70%">
<el-form-item label="主机分组名称" prop="host_name">
<el-input
:disabled="route.query.id"
clearable
v-model="formData.host_name"
maxlength="20"
placeholder="请输入主机分组名称"
show-word-limit />
</el-form-item>
</el-form>
<bg-inner-tabs v-model="currentTab" :data="tabOptions"></bg-inner-tabs>
<listTable v-show="currentTab == 0" ref="listTableRef" :initTableData="initTableData"></listTable>
<div class="upload_container" v-show="currentTab == 1">
<div class="upload_top">
<div class="required-item">上传文件</div>
<div>
模版下载:<span class="file" @click="downloadFile(`/主机IP模板.xlsx`)"
>IP主机模板<bg-icon icon="#bg-ic-to-bottom"></bg-icon
></span>
</div>
</div>
<bg-upload
:httpRequest="httpRequest"
style="width: 360px"
v-model="attachment"
customTips
:limit="1"
:fileTypes="['xlsx', 'xls']">
<span>将文件拖到此处,或 点击上传</span><br />
<span>支持上传一个后缀为.xlsx或.xls的文件,文件大小不超过20M,最多解析1000个IP</span>
</bg-upload>
</div>
</div>
<div class="content_foot apaas_button">
<el-button type="default" @click="back"> 取消 </el-button>
<el-button type="primary" @click="save"> 保存 </el-button>
</div>
</div>
<checkStatusDialog v-model="checkStatusVisible" :enter="1" :checkStatusData="checkStatusData"></checkStatusDialog>
</div>
</template>
<script setup>
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import listTable from "../components/list-table.vue";
import checkStatusDialog from "../components/check-status-dialog.vue";
import { downloadFileFormat } from "@/services/helper.js";
const { proxy } = getCurrentInstance();
const { $api } = proxy;
const router = useRouter();
const route = useRoute();
const formData = reactive({
host_name: "",
});
const formRules = reactive({
host_name: [{ required: true, message: "主机分组名称不能为空", trigger: "blur" }],
});
const attachment = ref([]);
const downloadFile = (data) => {
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", data); // href链接
a.click(); // 自执行点击事件
};
const currentTab = ref(0);
const tabOptions = ref(["列表维护", "文件上传"]);
const ruleFormRef = ref();
const listTableRef = ref();
const checkStatusVisible = ref(false);
const checkStatusData = ref({});
const save = () => {
ruleFormRef.value.validate((valid) => {
if (currentTab.value == 0) {
let { flag, list } = listTableRef.value.getData();
if (flag && valid) {
checkStatusData.value = {
detection_type: 2,
host_manage_list: list,
host_name: formData.host_name,
};
checkStatusVisible.value = true;
}
} else {
if (attachment.value.length == 0) {
return ElMessage.error("请上传文件");
}
checkStatusData.value = {
detection_type: 3,
file_name: attachment.value[0].url.split("/").at(-1),
host_file_url: attachment.value[0].url,
host_name: formData.host_name,
};
if (valid) {
checkStatusVisible.value = true;
}
}
});
};
const back = () => {
router.back();
};
const initTableData = ref([]);
const getHostManageDetail = () => {
$api.autoMaintenance.getHostManageDetail(route.query.id).then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
formData.host_name = data.host_name;
initTableData.value = data.host_list || [];
if (data.host_file_url) {
currentTab.value = 1;
attachment.value = [
{
name: downloadFileFormat(data.host_file_url),
url: data.host_file_url,
},
];
}
} else {
ElMessage.error(res.data.data);
}
});
};
const httpRequest = (file) => {
let formData = new FormData();
formData.append("upload_file", file.file);
$api.autoMaintenance.uploadHostManageFile(formData).then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
file.onSuccess({
data,
});
} else {
ElMessage.error(res.data.data);
}
});
};
onMounted(() => {
if (route.query.id) {
getHostManageDetail();
}
});
</script>
<style lang="scss" scoped>
.main_container {
.content_main {
padding: 30px;
height: 0;
flex: auto;
overflow: auto;
}
.content_foot {
border-top: 1px solid #e6e9ef;
padding: 16px 16px 0 16px;
display: flex;
justify-content: flex-end;
}
.upload_container {
width: 360px;
.upload_top {
margin: 16px 0 10px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: #404a62;
.file {
color: #3759be;
cursor: pointer;
}
}
}
.required-item::before {
content: "*";
color: #d75138;
margin-right: 4px;
}
}
</style>
<template>
<el-dialog
class="dialog_box check_status_dialog"
title="连接状态检测"
v-model="dialogVisible"
width="1024px"
@closed="resetDialog">
<div class="main">
<div class="title" v-if="props.enter == 0">主机分组名称:{{ props.checkStatusData.host_name }}</div>
<div class="loading-container">
<span class="icon_box" :class="{ ic_animation: stateValue == 0 }"
><bg-icon :class="getClassName(stateValue)" :icon="getIcon(stateValue)"
/></span>
<span>{{ getText(stateValue) }}</span>
</div>
<div class="table-container">
<div class="table-top">
<span>异常状态列表</span>
<el-button type="primary" @click="exportFile" :disabled="stateValue == 0 || tableTotal == 0">
导出
</el-button>
</div>
<div class="status-lists">
<div class="table">
<bg-table
:empty-text="'无异常数据'"
:height="300"
ref="taskTable"
:headers="taskHeaders"
:rows="taskRows"
:isIndex="true"
:stripe="true">
<template v-slot:voucher_type="{ row }">
{{ row.voucher_type == 0 ? "密码验证" : "密钥验证" }}
</template>
</bg-table>
</div>
<bg-pagination
v-if="taskRows.length > 0"
:page="filter.page"
:size="filter.size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination>
</div>
</div>
</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="dialogVisible = false">{{ props.enter == 0 ? "关闭" : "取消" }}</el-button>
<el-button :disabled="stateValue != 1" v-if="props.enter != 0" type="primary" @click="save"
>剔除异常数据并保存</el-button
>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, ref, onBeforeMount, getCurrentInstance, computed, watch, nextTick, watchEffect } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const { $api } = proxy;
const router = useRouter();
const route = useRoute();
const props = defineProps({
modelValue: {
type: Boolean,
},
checkStatusData: {
type: Object,
},
// 0:列表页 1:详情页
enter: {
type: Number,
},
});
const emit = defineEmits(["update:modelValue"]);
const dialogVisible = computed({
get() {
if (props.modelValue) {
postHostManageState();
}
return props.modelValue;
},
set(value) {
emit("update:modelValue", value);
},
});
const stateUUID = ref("");
const postHostManageState = () => {
const formData = new FormData();
formData.append("detection_type", props.checkStatusData.detection_type);
switch (props.checkStatusData.detection_type) {
case 1:
formData.append("id", props.checkStatusData.id);
break;
case 2:
formData.append("host_manage_list", JSON.stringify(props.checkStatusData.host_manage_list));
break;
case 3:
formData.append("file_name", props.checkStatusData.file_name);
break;
}
$api.autoMaintenance.postHostManageState(formData).then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
stateUUID.value = data;
stateValue.value = 1;
getTableRows();
} else {
stateValue.value = 2;
ElMessage.error(res.data.data);
}
});
};
const exportFile = () => {
let params = {
detection_type: props.enter == 0 ? 1 : 0,
};
switch (params.detection_type) {
case 1:
params.id = props.checkStatusData.id;
break;
case 0:
params.uuid = stateUUID.value;
break;
}
ElMessage.success("开始导出");
let url = `/v1/api/automated_mainten/host_manage/export?`;
const paramsArray = [];
for (const [key, value] of Object.entries(params)) {
paramsArray.push(`${key}=${value}`);
}
url += paramsArray.join("&");
const a = document.createElement("a");
const event = new MouseEvent("click");
a.href = url;
a.dispatchEvent(event);
};
const stateValue = ref(0);
const getIcon = (stateValue = 0) => {
const icons = ["#bg-ic-s-circle-restart", "#bg-ic-s-circle-check", "#bg-ic-s-circle-close"];
return icons[stateValue];
};
const getClassName = (stateValue = 0) => {
const classNames = ["pending", "success", "error"];
return classNames[stateValue];
};
const getText = (stateValue = 0) => {
const text = ["状态检测中", "状态检测完成", "状态检测失败"];
return text[stateValue];
};
const taskHeaders = [
{
prop: "ip",
label: "IP",
},
{
prop: "port",
label: "端口",
},
{
prop: "voucher_type",
label: "凭证类型",
},
{
prop: "user_name",
label: "用户名",
},
{
prop: "password",
label: "密码",
},
];
const taskRows = ref([]);
const filter = ref({
page: 1,
size: 10,
});
const tableTotal = ref(0);
const changePage = (page) => {
filter.value.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
filter.value.size = size;
changePage(1);
}; // 改变每页条数
const getTableRows = () => {
let params = {
detection_type: props.enter == 0 ? 1 : 2,
};
switch (params.detection_type) {
case 1:
params.id = props.checkStatusData.id;
params.page = filter.value.page;
params.page_size = filter.value.size;
break;
case 2:
params.uuid = stateUUID.value;
params.page = filter.value.page;
params.page_size = filter.value.size;
break;
}
$api.autoMaintenance.getHostManageIPExceptionList(params).then((res) => {
if (res.data.code == 200) {
let data = res.data.data || [];
taskRows.value = data;
tableTotal.value = res.data.total;
} else {
ElMessage.error(res.data.data);
}
});
};
const save = () => {
let data = {
uuid: stateUUID.value,
};
if (props.checkStatusData.detection_type == 3) {
data.host_file_url = props.checkStatusData.host_file_url;
}
if (route.query.id) {
// 编辑
data.id = Number(route.query.id);
$api.autoMaintenance.putHostManageEdit(data).then((res) => {
if (res.data.code == 200) {
ElMessage.success("保存成功");
router.back();
} else {
ElMessage.error(res.data.data);
}
});
} else {
// 新增
data.host_name = props.checkStatusData.host_name;
$api.autoMaintenance.postHostManageAdd(data).then((res) => {
if (res.data.code == 200) {
ElMessage.success("保存成功");
router.back();
} else {
ElMessage.error(res.data.data);
}
});
}
};
const resetDialog = () => {
stateValue.value = 0;
taskRows.value = [];
tableTotal.value = 0;
filter.value.page = 1;
filter.value.size = 10;
};
</script>
<style lang="scss" scoped>
.dialog_box {
.main {
.title {
text-align: left;
margin-bottom: 10px;
font-weight: bold;
font-size: 16px;
}
.loading-container {
margin: auto;
text-align: center;
width: 200px;
background-color: #eaedf5;
border-radius: 4px;
font-size: 14px;
color: #404a62;
padding: 10px 0;
.icon_box {
margin-right: 8px;
display: inline-block;
}
.pending {
font-size: 14px;
color: #3759be;
}
.success {
font-size: 14px;
color: #429e8a;
}
.error {
font-size: 14px;
color: #d75138;
}
.ic_animation {
animation: loading-rotate 1.5s linear infinite;
}
@keyframes loading-rotate {
100% {
transform: rotate(360deg);
}
}
}
.table-container {
.table-top {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 0;
font-weight: bold;
font-size: 16px;
}
.status-lists {
margin-top: 16px;
overflow: hidden;
padding-bottom: 10px;
}
}
}
}
</style>
<style lang="scss">
.check_status_dialog {
.el-dialog__footer {
border-top: 1px solid #e6e9ef;
}
.bg-table .el-table__empty-block {
height: unset !important;
.empty_container {
height: unset;
padding-top: 46px;
}
}
}
</style>
<template>
<el-form style="margin: 16px 0" ref="ruleFormRef" class="rule-form" :model="tableRows">
<bg-table-pro
class="input-table"
:headers="headers"
:data="tableRows"
ref="inputTable"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
row-key="id"
default-expand-all
:border="true"
:stripe="false">
<template #ip="{ row }">
<el-form-item
:rules="{
required: true,
message: 'IP不能为空',
trigger: 'blur',
}"
style="width: 100%"
:prop="`${row.$row_path}.ip`">
<el-input clearable placeholder="请输入IP" v-model="row.ip" />
</el-form-item>
</template>
<template #port="{ row }">
<el-form-item style="width: 100%">
<el-input clearable placeholder="请输入端口号" v-model="row.port" />
</el-form-item>
</template>
<template #voucher_type="{ row }">
<el-form-item
:rules="{
required: true,
message: '凭证类型不能为空',
trigger: 'change',
}"
style="width: 100%"
:prop="`${row.$row_path}.voucher_type`">
<el-select @change="(val) => changeType(val, row)" v-model="row.voucher_type" placeholder="请选择凭证类型">
<el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</template>
<template #user_name="{ row }">
<el-form-item
:rules="{
required: true,
message: '用户名不能为空',
trigger: 'blur',
}"
style="width: 100%"
:prop="`${row.$row_path}.user_name`">
<el-input clearable placeholder="请输入用户名" v-model="row.user_name" />
</el-form-item>
</template>
<template #password="{ row }">
<el-form-item
v-if="row.voucher_type != 1"
:rules="{
required: true,
message: '密码不能为空',
trigger: 'blur',
}"
style="width: 100%"
:prop="`${row.$row_path}.password`">
<el-input clearable placeholder="请输入密码" v-model="row.password" />
</el-form-item>
<el-form-item v-else required style="width: 100%">
<el-input disabled />
</el-form-item>
</template>
<template #action="{ row }">
<bg-table-btn
:click="
() => {
addInputConf(row);
}
"
:disabled="tableRows.length == 5">
新增
</bg-table-btn>
<bg-table-btn
:click="
() => {
removeInputConf(row);
}
"
:disabled="tableRows.length == 1">
删除
</bg-table-btn>
</template>
</bg-table-pro>
</el-form>
</template>
<script setup>
import { ref, reactive, toRefs, watch } from "vue";
import { v4 as uuidv4 } from "uuid";
const props = defineProps({
initTableData: {
default: () => {
return [];
},
},
});
const ruleFormRef = ref(null);
const inputTable = ref(null);
const headers = reactive([
{
label: "IP(IP之间用英文逗号分隔)",
required: true,
prop: "ip",
width: 300,
},
{
label: "端口号(不填写,默认为22)",
prop: "port",
},
{
label: "凭证类型",
required: true,
prop: "voucher_type",
},
{
label: "用户名",
required: true,
prop: "user_name",
},
{
label: "密码",
required: true,
prop: "password",
},
{
label: "操作",
prop: "action",
width: 120,
},
]);
const typeOptions = [
{
value: 0,
label: "密码验证",
},
{
value: 1,
label: "密钥验证",
},
];
const state = reactive({
inputTable,
tableRows: [],
});
const { tableRows } = toRefs(state);
const addInputConf = (row) => {
let tempRow = createRow();
if (row) {
let { index, rows } = getInputRowInfo(row);
rows.splice(index + 1, 0, tempRow);
} else {
state.tableRows = [tempRow];
}
updateInputConfRows();
}; //增加
const updateInputConfRows = () => {
let recursionItems = (items, parentType, parentPath) => {
for (let i = 0; i < items.length; i++) {
let item = items[i];
item.$parent_type = parentType;
item.$row_path = `${parentPath}[${i}]`;
if (item.children && item.children.length) {
let basePath = `${item.$row_path}.children.`;
recursionItems(item.children, item.paramType, basePath);
}
}
};
recursionItems(state.tableRows, "", "");
clearValidate();
}; // 更新 $parent_type 和 $row_path 字段
const clearValidate = () => {
ruleFormRef.value && ruleFormRef.value.clearValidate();
};
const createRow = () => {
return {
id: uuidv4(),
ip: "",
port: "22",
voucher_type: "",
user_name: "",
password: "",
};
};
const getInputRowInfo = (row) => {
return state.inputTable && state.inputTable.getRowInfo(row, `id`);
}; //获取当前行的数据信息
const removeInputConf = (row) => {
let { index, rows } = getInputRowInfo(row);
rows.splice(index, 1);
if (rows.length === 0) {
rows.push(createRow());
}
updateInputConfRows();
}; // 删除
const initTable = () => {
if (props.initTableData && props.initTableData.length >= 1) {
state.tableRows = props.initTableData;
updateInputConfRows();
} else {
addInputConf();
}
};
const changeType = (val, row) => {
if (val == 2) {
row.password = "";
}
};
const getData = () => {
ruleFormRef.value && ruleFormRef.value.validate((valid) => {});
let flag = true;
let list = state.tableRows.map((item) => {
if (
item.ip == "" ||
item.voucher_type === "" ||
item.user_name == "" ||
(item.voucher_type === 0 && item.password == "")
) {
flag = false;
}
return {
ip: item.ip,
port: item.port,
voucher_type: item.voucher_type,
user_name: item.user_name,
password: item.password,
};
});
return {
list,
flag,
};
};
watch(
() => {
return props.initTableData;
},
() => {
initTable();
},
{
immediate: true,
}
);
defineExpose({
getData,
clearValidate,
});
</script>
<style lang="scss" scoped>
.rule-form {
::v-deep(.bg-table .el-form-item .el-form-item__error) {
bottom: -13px;
}
}
</style>
<template>
<div class="my-business-detail">
<div class="breadcrumb">
<bg-breadcrumb />
</div>
<div class="content bg-scroll">
<div class="go-back">
<goBack />
</div>
<gap-title :hasLine="true" title="基本信息"></gap-title>
<div class="info">
<Info :labelData="labelData" :valueData="basicInfo"> </Info>
</div>
<gap-title :hasLine="true" title="主机列表"></gap-title>
<div class="info">
<div class="host-lists">
<bg-table border ref="hostTable" :headers="hostHeaders" :rows="hostRows" height="100%" :isIndex="true">
</bg-table>
</div>
<div style="margin-top: 10px" v-if="fileUrl">
<a download :href="fileUrl">{{ downloadFileFormat(fileUrl) }}</a>
</div>
</div>
<gap-title :hasLine="true" title="任务列表"></gap-title>
<div class="info">
<div class="task-lists">
<div class="table">
<bg-table ref="taskTable" :headers="taskHeaders" :rows="taskRows" :isIndex="true" :stripe="true">
</bg-table>
</div>
<!-- <bg-pagination
:page="filter.page"
:size="filter.size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
</bg-pagination> -->
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
import { useRouter, useRoute } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import Info from "@/components/warn-detail/info.vue";
import gapTitle from "@/components/gap-title.vue";
import goBack from "@/components/go-back/index.vue";
import { downloadFileFormat } from "@/services/helper.js";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const { $api } = proxy;
const router = useRouter();
const route = useRoute();
const labelData = [
[
{
label: "主机分组名称",
prop: "host_name",
},
],
[
{
label: "任务数量",
prop: "task_cnt",
},
{
label: "IP数量",
prop: "ip_cnt",
},
],
[
{
label: "创建人",
prop: "create_user",
},
{
label: "创建时间",
prop: "create_time",
},
],
];
const basicInfo = ref({
host_name: "",
task_cnt: "",
ip_cnt: "",
create_user: "",
create_time: "",
});
const hostHeaders = [
{
prop: "ip",
label: "IP",
},
{
prop: "port",
label: "端口",
},
];
const hostRows = ref([,]);
const taskHeaders = [
{
prop: "task_name",
label: "任务名称",
},
{
prop: "exec_cnt",
label: "执行次数",
},
{
prop: "task_desc",
label: "描述",
},
];
const taskRows = ref([]);
const filter = ref({
page: 1,
size: 10,
});
const tableTotal = ref(0);
const changePage = (page) => {
filter.value.page = page;
getTableRows();
}; // 改变页码
const changeSize = (size) => {
filter.value.size = size;
changePage(1);
}; // 改变每页条数
const getTableRows = () => {};
const fileUrl = ref("");
const downloadFile = (url) => {
if (url) {
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件
}
};
const getHostManageDetail = () => {
$api.autoMaintenance.getHostManageDetail(route.query.id).then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
// 基本信息
basicInfo.value.host_name = data.host_name;
basicInfo.value.task_cnt = data.task_cnt;
basicInfo.value.ip_cnt = data.ip_cnt;
basicInfo.value.create_user = data.create_user;
basicInfo.value.create_time = data.create_time.split("+")[0].replace("T", " ").replace("Z", " ");
// 主机列表
hostRows.value = data.host_list || [];
fileUrl.value = data.host_file_url;
// 任务列表
taskRows.value = data.task_list || [];
} else {
ElMessage.error(res.data.data);
}
});
};
onMounted(() => {
getHostManageDetail();
});
</script>
<style lang="scss" scoped>
.my-business-detail {
width: 100%;
height: 100%;
padding: 0 24px 16px;
.breadcrumb {
width: 100%;
height: 46px;
}
.content {
width: 100%;
height: calc(100% - 46px);
background-color: #ffffff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
padding: 24px;
.go-back {
margin-bottom: 24px;
}
:deep(.gap-title) {
margin-bottom: 16px;
}
.info,
.feedback-info {
max-width: 1072px;
width: 100%;
padding: 0 8px 0;
&:not(:last-child) {
padding-bottom: 24px;
}
.status {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
$statusObj: (
finish: #48ad97,
close: #9e9e9e,
info: #3759be,
);
@each $status, $color in $statusObj {
&-#{$status} {
background-color: $color;
}
}
}
.status-body {
display: flex;
align-items: center;
}
.host-lists {
margin-top: 16px;
}
.task-lists {
margin-top: 16px;
overflow: hidden;
padding-bottom: 10px;
}
}
}
}
</style>
......@@ -5,20 +5,29 @@
<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 }}
<bg-table :headers="headers" :rows="tableRows" :stripe="true">
<template v-slot:task_name="{ row }">
<span class="can_click_text" @click="gotoPage(row)">
{{ row.task_name }}
</span>
</template>
<template v-slot:state="{ row }">
<span> 执行中 </span>
<span>
<bg-icon
:style="{
color: ['#2b4695', '#429e8a', '#d75138'][row.state],
}"
:icon="
['#bg-ic-s-circle-restart', '#bg-ic-s-circle-check', '#bg-ic-s-circle-close'][row.state]
"></bg-icon>
{{ ["执行中", "成功", "失败"][row.state] }}
</span>
</template>
</bg-table>
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:size="filter.page_size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
......@@ -39,8 +48,6 @@ import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const router = useRouter();
const route = useRoute();
const bgForm = ref(null);
const dataTable = ref(null);
const headers = [
{
label: "状态",
......@@ -48,92 +55,34 @@ const headers = [
},
{
label: "任务名称",
prop: "name",
prop: "task_name",
},
{
label: "执行耗时",
prop: "workTime",
label: "执行耗时(s)",
prop: "exec_time",
},
{
label: "操作人",
prop: "person",
prop: "create_user",
},
];
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,
page_size: 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 gotoPage = (row) => {
router.push(`/auto-maintenance/task-history/list?id=${row.task_id}`);
};
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);
......@@ -145,9 +94,8 @@ const filterAction = () => {
const filterClear = () => {
state.filter = {
time: "",
search: "",
limit: 10,
page_size: 10,
page: 1,
};
changePage(1);
......@@ -155,9 +103,8 @@ const filterClear = () => {
const getTableRows = () => {
let params = { ...state.filter };
params.id = state.nodeId;
axios
.get(`/apaas/system/v5/dictionary/list`, {
.get(`/v1/api/automated_mainten/task_history/list`, {
params,
})
.then((res) => {
......@@ -177,32 +124,12 @@ const changePage = (page) => {
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
state.filter.page_size = 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();
getTableRows();
});
const { tableRows, tableTotal, filter } = toRefs(state);
......@@ -211,7 +138,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px;
min-height: 100%;
display: flex;
......@@ -240,9 +166,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
}
......
......@@ -17,19 +17,31 @@
<div class="table_container">
<div class="table bg-scroll">
<bg-table ref="dataTable" :headers="headers" :rows="tableRows" :stripe="true">
<template v-slot:desc="{ row }">
<template v-slot:exec_start_time="{ row }">
<span>{{ dateStringTransform(row.exec_start_time) }}</span>
</template>
<template v-slot:exec_desc="{ row }">
<span class="can_click_text" @click="gotoPage(`/auto-maintenance/task-history/list/record?id=${row.id}`)">
{{ row.desc }}
{{ row.exec_desc }}
</span>
</template>
<template v-slot:state="{ row }">
<span> 执行中 </span>
<span>
<bg-icon
:style="{
color: ['#2b4695', '#429e8a', '#d75138'][row.state],
}"
:icon="
['#bg-ic-s-circle-restart', '#bg-ic-s-circle-check', '#bg-ic-s-circle-close'][row.state]
"></bg-icon>
{{ ["执行中", "成功", "失败"][row.state] }}
</span>
</template>
</bg-table>
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:size="filter.page_size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
......@@ -46,6 +58,7 @@ 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";
import { dateStringTransform, downloadFile } from "@/services/helper.js";
const router = useRouter();
const route = useRoute();
......@@ -58,19 +71,19 @@ const headers = [
},
{
label: "执行说明",
prop: "desc",
prop: "exec_desc",
},
{
label: "执行开始时间",
prop: "begin",
prop: "exec_start_time",
},
{
label: "执行耗时",
prop: "workTime",
label: "执行耗时(s)",
prop: "exec_time",
},
{
label: "操作人",
prop: "person",
prop: "create_user",
},
];
......@@ -85,7 +98,7 @@ const state = reactive({
filter: {
search: "",
page: 1,
limit: 10,
page_size: 10,
}, // 表格筛选项
actionRow: null, // 当前操作的数据
});
......@@ -100,10 +113,12 @@ const changeSearch = (val) => {
}; // 表格关键字筛选
const getTableRows = () => {
let params = { ...state.filter };
params.id = state.nodeId;
let params = {
...state.filter,
task_id: route.query.id,
};
axios
.get(`/apaas/system/v5/dictionary/list`, {
.get(`/v1/api/automated_mainten/task_history/task_info_list`, {
params,
})
.then((res) => {
......@@ -123,11 +138,13 @@ const changePage = (page) => {
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
state.filter.page_size = size;
changePage(1);
}; // 改变每页条数
onBeforeMount(() => {});
onBeforeMount(() => {
getTableRows();
});
const { tableRows, tableTotal, filter } = toRefs(state);
</script>
......@@ -135,7 +152,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px;
min-height: 100%;
display: flex;
......@@ -163,10 +179,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
.table_container {
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
}
......
......@@ -7,7 +7,7 @@
执行ping命令 / 执行说明1
</div>
<div class="middle-container">
<finish-use :state="true" height="calc(100vh - 330px)" time="00:00:11"></finish-use>
<finish-use :state="true" height="calc(100vh - 330px)" :codes="state.logArr" :time="state.time"></finish-use>
</div>
<div class="bottom-container">
<el-button class="use-script" type="primary" @click="router.go(-1)"> 重新执行 </el-button>
......@@ -22,10 +22,29 @@ import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import finishUse from "@/page/main/auto-maintenance/task-manage/add/finish-use.vue";
import axios from "@/request/http.js";
import { secondeToHour } from "@/services/helper.js";
const router = useRouter();
const route = useRoute();
const state = reactive({ data: 1 });
const { data } = toRefs(state);
const state = reactive({
time: "",
logArr: [],
});
const getLog = () => {
axios.get(`/v1/api/automated_mainten/task_history/task_exec_log?id=${route.query.id}`).then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
state.time = secondeToHour(data.exec_time);
state.logArr = data.exec_log.split("\n");
}
});
};
onBeforeMount(() => {
getLog();
});
</script>
<style lang="scss" scoped>
......
......@@ -2,7 +2,12 @@
<div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-position="top" label-width="120px">
<el-form-item label="任务名称" prop="name">
<el-input v-model="state.ruleForm.name" maxlength="20" placeholder="请输入任务名称" show-word-limit />
<el-input
v-model="state.ruleForm.name"
maxlength="20"
:disabled="props.isEdit"
placeholder="请输入任务名称"
show-word-limit />
</el-form-item>
<el-form-item label="任务描述" prop="desc">
<el-input
......@@ -31,6 +36,10 @@ const props = defineProps({
type: Object,
default: () => {},
},
isEdit: {
type: Boolean,
default: false,
},
});
const ruleFormRef = ref(null);
......
......@@ -13,9 +13,9 @@
</div>
<div class="log-bg bg-scroll" :style="{ height: props.height }">
<div class="log-box">
<div v-for="(item, i) in stateData.codes" :key="i" class="codes-box">
<span class="codes-num">{{ item.pos + 1 }}</span>
<span class="codes-out" v-html="item.out"></span>
<div v-for="(item, i) in props.codes" :key="i" class="codes-box">
<span class="codes-num">{{ i + 1 }}</span>
<span class="codes-out" v-html="item"></span>
</div>
</div>
</div>
......@@ -26,6 +26,8 @@
import { reactive, ref, onBeforeMount, toRefs } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
const router = useRouter();
const route = useRoute();
......@@ -47,119 +49,6 @@ const props = defineProps({
default: "",
},
});
const stateData = reactive({
codes: [
{
pos: 0,
out: "SSH password:",
},
{
pos: 1,
out: "[WARNING]: Platform darwin on host 192.168.1.199 is using the discovered Pythoninterpreter at /usr/bin/python3, but future installation of another Pythoninterpreter could change ",
},
{
pos: 2,
out: "the meaning of that path. See",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 0,
out: "SSH password:",
},
{
pos: 1,
out: "[WARNING]: Platform darwin on host 192.168.1.199 is using the discovered Pythoninterpreter at /usr/bin/python3, but future installation of another Pythoninterpreter could change ",
},
{
pos: 2,
out: "the meaning of that path. See",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 0,
out: "SSH password:",
},
{
pos: 1,
out: "[WARNING]: Platform darwin on host 192.168.1.199 is using the discovered Pythoninterpreter at /usr/bin/python3, but future installation of another Pythoninterpreter could change ",
},
{
pos: 2,
out: "the meaning of that path. See",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 0,
out: "SSH password:",
},
{
pos: 1,
out: "[WARNING]: Platform darwin on host 192.168.1.199 is using the discovered Pythoninterpreter at /usr/bin/python3, but future installation of another Pythoninterpreter could change ",
},
{
pos: 2,
out: "the meaning of that path. See",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 0,
out: "SSH password:",
},
{
pos: 1,
out: "[WARNING]: Platform darwin on host 192.168.1.199 is using the discovered Pythoninterpreter at /usr/bin/python3, but future installation of another Pythoninterpreter could change ",
},
{
pos: 2,
out: "the meaning of that path. See",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
{
pos: 0,
out: "SSH password:",
},
{
pos: 1,
out: "[WARNING]: Platform darwin on host 192.168.1.199 is using the discovered Pythoninterpreter at /usr/bin/python3, but future installation of another Pythoninterpreter could change ",
},
{
pos: 2,
out: "the meaning of that path. See",
},
{
pos: 3,
out: "https://docs.ansible.com/ansible-",
},
],
});
</script>
<style lang="scss" scoped>
......
......@@ -2,11 +2,11 @@
<div class="step-container">
<div class="step-base">
<img src="@/assets/imgs/img_data-complete.png" />
<p class="tips" v-if="props.state">新增成功</p>
<p class="tips" v-else>新增失败</p>
<p class="tips" v-if="props.state">{{ ["新增", "编辑", "复制"][props.finishType] }}成功</p>
<p class="tips" v-else>{{ ["新增", "编辑", "复制"][props.finishType] }}失败</p>
<div class="apaas_button btns" v-if="props.state">
<el-button type="default" @click="goToList"> 返回列表 </el-button>
<el-button type="primary" @click="goStepOne"> 继续新增 </el-button>
<el-button type="primary" @click="goStepOne"> {{ props.finishType == 1 ? "重新提交" : "继续新增" }} </el-button>
</div>
</div>
</div>
......@@ -24,6 +24,10 @@ const props = defineProps({
type: Boolean,
default: true,
},
finishType: {
type: Number,
default: 0,
},
});
const emit = defineEmits(["clear"]);
......
......@@ -42,10 +42,28 @@
<div
class="content_main log_content_nor"
:style="step == 3 && state.isSave ? { height: 'calc(100vh - 234px)' } : {}">
<base-info v-show="step == 1" :data="state.data" ref="baseInfoRef"></base-info>
<use-content v-show="step == 2" :data="state.data" ref="useContentRef"></use-content>
<finish v-show="step == 3 && state.isSave" :state="true" @clear="clearData"></finish>
<finish-use v-show="step == 3 && !state.isSave" :state="true" time="00:00:11"></finish-use>
<base-info
v-show="step == 1"
v-if="state.loadComponents"
:isEdit="state.pageType == 1"
:data="state.data"
ref="baseInfoRef"></base-info>
<use-content
v-show="step == 2"
v-if="state.loadComponents"
:data="state.data"
ref="useContentRef"></use-content>
<finish
v-show="step == 3 && state.isSave"
:state="state.status"
:finishType="state.pageType"
v-if="state.loadComponents"
@clear="clearData"></finish>
<finish-use
v-show="step == 3 && !state.isSave"
v-if="state.loadComponents"
:state="state.status"
time="00:00:11"></finish-use>
</div>
<div class="content_foot apaas_button" v-if="step == 1 || step == 2 || (step == 3 && !state.isSave)">
<el-button type="default" v-if="step == 1 || step == 2" @click="cancel"> 取消 </el-button>
......@@ -104,6 +122,9 @@ const state = reactive({
useData: ["yaml", "json"],
useText: "",
isSave: true,
status: true,
pageType: 0, //0新增,1编辑,2复制
loadComponents: false, //控制子组件的加载
});
const cancel = () => {
......@@ -131,11 +152,55 @@ const saveTask = async () => {
.save()
.then(() => {
step.value = 3;
//todo:掉接口保存,并获取状态
if (state.pageType == 0 || state.pageType == 2) {
postTask();
} else if (state.pageType == 1) {
editTask();
}
})
.catch(() => {});
};
const editTask = () => {
axios
.put(`/v1/api/automated_mainten/task_manage/edit`, {
task_name: state.data.name,
task_desc: state.data.desc,
yaml_desc: state.data.useText,
yaml_url: JSON.stringify(state.data.doc_file),
host_group_id: state.data.pcName,
})
.then((res) => {
if (res.data.code == 200) {
state.status = true;
ElMessage.success("保存成功");
} else {
state.status = false;
ElMessage.error(res.data.msg);
}
});
};
const postTask = () => {
axios
.post(`/v1/api/automated_mainten/task_manage/add`, {
task_name: state.data.name,
task_desc: state.data.desc,
yaml_desc: state.data.useText,
yaml_url: JSON.stringify(state.data.doc_file),
host_group_id: state.data.pcName,
})
.then((res) => {
if (res.data.code == 200) {
state.status = true;
ElMessage.success("保存成功");
} else {
state.status = false;
ElMessage.error(res.data.msg);
}
});
};
const useScript = async () => {
//填写完成才可以进行执行
await useContentRef.value
......@@ -167,9 +232,53 @@ const clearData = () => {
useContentRef.value.clear();
state.data = {};
step.value = 1;
state.loadComponents = false;
init();
};
onBeforeMount(() => {});
const getDetails = () => {
axios
.get(`/v1/api/automated_mainten/task_manage/details`, {
params: {
id: route.query.id,
},
})
.then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
state.data = {
name: data.task_name,
desc: data.task_desc,
useText: data.yaml_desc,
doc_file: data.yaml_url ? JSON.parse(data.yaml_url) : [],
pcName: data.host_group_id,
};
//复制,名字置空
if (state.pageType == 2) {
state.data.name = "";
}
state.loadComponents = true;
}
});
};
const init = () => {
if (route.path.indexOf("edit") > -1) {
state.pageType = 1;
} else if (route.path.indexOf("copy") > -1) {
state.pageType = 2;
}
if (state.pageType !== 0) {
getDetails();
} else {
state.loadComponents = true;
}
};
onBeforeMount(() => {
state.loadComponents = false;
init();
});
</script>
<style scoped>
......
......@@ -17,9 +17,9 @@
<el-form ref="pcFormRef" :model="state.ruleForm" :rules="state.rules" label-position="top" label-width="120px">
<el-form-item label="主机分组名称" prop="pcName" style="width: 1100px">
<el-select v-model="state.ruleForm.pcName" style="width: 1020px" clearable placeholder="请选择">
<el-option v-for="item in state.options" :key="item.value" :label="item.label" :value="item.value" />
<el-option v-for="item in state.options" :key="item.id" :label="item.host_name" :value="item.id" />
</el-select>
<span class="add-pc can_click_text">去创建</span>
<span class="add-pc can_click_text" @click="gotoPage(`/auto-maintenance/host-manage/add`)">去创建</span>
</el-form-item>
</el-form>
</div>
......@@ -28,6 +28,7 @@
<script setup>
import { reactive, ref, onBeforeMount, toRefs, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const router = useRouter();
const route = useRoute();
......@@ -52,14 +53,13 @@ const state = reactive({
rules: {
pcName: [{ required: true, message: "请选择主机分组", trigger: "change" }],
},
options: [
{
label: "12",
value: "qwqw",
},
],
options: [],
});
const gotoPage = (url) => {
router.push(url);
};
const save = () => {
return new Promise((resolve, reject) => {
pcFormRef.value.validate((valid, fields) => {
......@@ -67,7 +67,9 @@ const save = () => {
props.data.pcName = state.ruleForm.pcName;
if (state.useType == 0) {
props.data.useText = state.useText;
props.data.doc_file = [];
} else {
props.data.useText = "";
props.data.doc_file = state.doc_file;
}
resolve();
......@@ -86,17 +88,26 @@ const clear = () => {
state.useType = 0;
};
const getPC = () => {
axios.get(`/v1/api/automated_mainten/host_manage/list`).then((res) => {
if (res.data.code == 200) {
state.options = res.data.data || [];
}
});
};
onMounted(() => {
if (
(props.data && props.data.useText == "" && props.data.doc_file.length == 0) ||
(!props.data.useText && !props.data.doc_file)
) {
state.useType = 0;
} else if (props.data && props.data.useText !== "") {
} else if (props.data && props.data.useText == "") {
state.useType = 1;
} else if (props.data && props.data.doc_file.length == 0) {
state.useType = 0;
}
getPC();
});
defineExpose({
......
......@@ -3,19 +3,15 @@
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<bg-form-gap title="基本信息"></bg-form-gap>
<bg-detail-table2 style="width: 1076px" :list="state.baseInfo">
<template #status>
<span> <i class="use"></i> 启用 </span>
</template>
</bg-detail-table2>
<bg-detail-table2 style="width: 1076px; margin-bottom: 20px" :list="state.baseInfo"> </bg-detail-table2>
<bg-form-gap title="执行脚本"></bg-form-gap>
<div style="height: 260px; margin-bottom: 20px; width: 1076px">
<bg-code-editor v-model="state.useText"></bg-code-editor>
<div v-if="state.docFile.length == 0" style="height: 260px; margin-bottom: 20px; width: 1076px">
<bg-code-editor :disabled="true" v-model="state.useText"></bg-code-editor>
</div>
<div class="file-box">
<bg-icon icon="#bg-ic-c-file-data"></bg-icon>&nbsp;&nbsp; 文件.yml
<el-button type="primary" @click="downloadFile(url)"
<div class="file-box" v-for="(item, index) in state.docFile">
<bg-icon icon="#bg-ic-c-file-data"></bg-icon>&nbsp;&nbsp; {{ item.name }}
<el-button type="primary" @click="download(item.url, item.name)"
><bg-icon icon="#bg-ic-to-bottom"></bg-icon>&nbsp;&nbsp;下载</el-button
>
</div>
......@@ -38,9 +34,20 @@
<bg-table style="width: 1076px" :headers="state.historyHeaders" :rows="state.historyTableRows" :stripe="true">
<template v-slot:state="{ row }">
<span>
{{ row.state }}
<bg-icon
:style="{
color: ['#2b4695', '#429e8a', '#d75138'][row.state],
}"
:icon="
['#bg-ic-s-circle-restart', '#bg-ic-s-circle-check', '#bg-ic-s-circle-close'][row.state]
"></bg-icon>
{{ ["执行中", "成功", "失败"][row.state] }}
</span>
</template>
<template v-slot:exec_start_time="{ row }">
<span>{{ dateStringTransform(row.exec_start_time) }}</span>
</template>
</bg-table>
<div style="width: 1076px" v-if="state.tableTotal > 10">
<bg-pagination
......@@ -60,45 +67,43 @@ import { reactive, ref, onBeforeMount, toRefs } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import axios from "@/request/http.js";
import { dateStringTransform, downloadFile } from "@/services/helper.js";
const router = useRouter();
const route = useRoute();
const state = reactive({
baseInfo: [
{
label: "预警规则名称",
value: "服务中断推送规则1",
label: "任务名称",
value: "",
},
{
label: "启用状态",
value: "启用",
childSlot: "status",
label: "执行次数",
value: "",
},
{
label: "预警对象",
value: "容器云",
label: "执行成功次数",
value: "",
},
{
label: "预警分类",
value: "容器集群",
label: "执行失败次数",
value: "",
},
{
label: "创建人",
value: "admin",
value: "",
},
{
label: "创建时间",
value: "2023-08-19 23:22:22",
value: "",
},
{
label: "更新时间",
value: "2023-08-19 23:22:22",
},
{
label: "预警指标",
value: "CPU使用率",
label: "任务描述",
value: "",
},
],
useText: "",
docFile: [],
historyHeaders: [
{
label: "状态",
......@@ -106,19 +111,19 @@ const state = reactive({
},
{
label: "执行说明",
prop: "desc",
prop: "exec_desc",
},
{
label: "执行开始时间",
prop: "begin",
prop: "exec_start_time",
},
{
label: "执行耗时",
prop: "time",
label: "执行耗时(s)",
prop: "exec_time",
},
{
label: "操作人",
prop: "person",
prop: "create_user",
},
],
historyTableRows: [],
......@@ -129,38 +134,77 @@ const state = reactive({
tableTotal: 0,
pcHeaders: [
{
label: "账号",
prop: "account",
label: "IP",
prop: "ip",
},
{
label: "端口",
prop: "port",
},
],
pcTableRows: [
{
account: "asasdd",
port: "8080",
},
{
account: "asasdd",
port: "8080",
},
],
pcTableRows: [],
});
const downloadFile = () => {};
const download = (url, name) => {
downloadFile(url, name);
};
const changePage = (page) => {
state.filter.page = page;
getTableRows();
};
const changeSize = (size) => {
state.filter.limit = size;
state.filter.size = size;
changePage(1);
};
const getTableRows = () => {};
const getTableRows = () => {
axios
.get(`/v1/api/automated_mainten/task_history/task_info_list`, {
params: {
task_id: route.query.id,
page: state.filter.page,
page_size: state.filter.size,
},
})
.then((res) => {
if (res.data.code == 200) {
state.historyTableRows = res.data.data;
state.tableTotal = res.data.total;
}
});
};
const getDetails = () => {
axios
.get(`/v1/api/automated_mainten/task_manage/details`, {
params: {
id: route.query.id,
},
})
.then((res) => {
if (res.data.code == 200) {
let data = res.data.data;
state.baseInfo[0].value = data.task_name;
state.baseInfo[1].value = data.exec_cnt;
state.baseInfo[2].value = data.success_cnt;
state.baseInfo[3].value = data.fail_cnt;
state.baseInfo[4].value = data.create_user;
state.baseInfo[5].value = data.create_time.split("+")[0].replace("T", " ").replace("Z", " ");
state.baseInfo[6].value = data.task_desc;
state.useText = data.yaml_desc;
state.docFile = data.yaml_url ? JSON.parse(data.yaml_url) : [];
state.pcTableRows = data.host_list || [];
}
});
};
onBeforeMount(() => {
getDetails();
getTableRows();
});
</script>
<style lang="scss" scoped>
......
......@@ -11,7 +11,7 @@
</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 style="color: #202531; font-weight: bold"> {{ state.selectedNum }} </span>
</span>
<span class="header_info can_click_text" @click="clearSelected">清空</span>
</div>
......@@ -23,7 +23,7 @@
<el-date-picker
v-model="filter.time"
type="daterange"
value-format="yyyy-MM-DD"
value-format="YYYY-MM-DD"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期" />
......@@ -45,13 +45,13 @@
:isIndex="true"
:select="true"
:stripe="true">
<template v-slot:name="{ row }">
<template v-slot:task_name="{ row }">
<span class="can_click_text" @click="gotoPage(`/auto-maintenance/task-manage/detail?id=${row.id}`)">
{{ row.name }}
{{ row.task_name }}
</span>
</template>
<template v-slot:updated_time="{ row }">
{{ row.updated_time.split("+")[0].replace("T", " ").replace("Z", " ") }}
<template v-slot:create_time="{ row }">
{{ row.create_time.split("+")[0].replace("T", " ").replace("Z", " ") }}
</template>
<template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :tableData="tableRows">
......@@ -65,7 +65,7 @@
</div>
<bg-pagination
:page="filter.page"
:size="filter.size"
:size="filter.page_size"
:total="tableTotal"
@change-page="changePage"
@change-size="changeSize">
......@@ -128,25 +128,26 @@ const dataTable = ref(null);
const headers = [
{
label: "任务名称",
prop: "name",
prop: "task_name",
width: 200,
},
{
label: "执行次数",
prop: "times",
prop: "exec_cnt",
},
{
label: "描述",
prop: "describe",
minWidth: 360,
prop: "task_desc",
minWidth: 300,
},
{
label: "创建人",
prop: "person",
prop: "create_user",
},
{
label: "创建时间",
prop: "updated_time",
width: 220,
prop: "create_time",
width: 180,
},
{
label: "操作",
......@@ -157,28 +158,22 @@ const headers = [
];
const state = reactive({
tableRows: [
{
name: 23123,
times: 1,
describe: 12313,
person: 21323,
updated_time: "2021-01-01+TZ",
},
], // 表格数据
tableRows: [], // 表格数据
selected: [], //选择数据
selectedNum: 0, //选择数据数量
tableTotal: 0, // 表格数据条数
filter: {
time: "",
search: "",
page: 1,
limit: 10,
page_size: 10,
}, // 表格筛选项
actionRow: null, // 当前操作的数据
dialogDelete: false, // 删除弹窗
useScriptShow: false,
useType: 0,
useData: ["yaml", "json"],
deleteType: 0, //0单个删除,1批量删除
});
const useRow = (row) => {
......@@ -197,13 +192,38 @@ const confirmUse = () => {
const deleteRow = (row) => {
state.actionRow = row;
state.dialogDelete = true;
state.deleteType = 0;
};
const deleteData = () => {
state.dialogDelete = false;
let ids = [];
if (state.deleteType == 0) {
ids = [state.actionRow.id];
} else {
let dealData = dataTable.value.dealSelectData();
for (const key in dealData) {
ids.push(dealData[key].id);
}
}
axios
.delete(`/v1/api/automated_mainten/task_manage/del`, {
data: {
id: ids,
},
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success("删除成功");
changePage(1);
} else {
ElMessage.error(res.data.msg);
}
});
};
const selectRows = (data) => {
state.selectedNum = data.allLength;
state.selected = data.selection;
};
......@@ -214,6 +234,7 @@ const clearSelected = () => {
const deleteAllTips = () => {
if (state.selected.length > 0) {
state.dialogDelete = true;
state.deleteType = 1;
} else {
ElMessage.error("请先选择要删除任务");
}
......@@ -236,21 +257,30 @@ const filterClear = () => {
state.filter = {
time: "",
search: "",
limit: 10,
page: 1,
page_size: 10,
};
changePage(1);
}; // 重置筛选项
const getTableRows = () => {
let params = { ...state.filter };
if (params.time) {
params.create_date_from = params.time[0];
params.create_date_to = params.time[1];
} else {
params.create_date_from = "";
params.create_date_to = "";
}
axios
.get(`/apaas/system/v5/dictionary/list`, {
.get(`/v1/api/automated_mainten/task_manage/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);
}
......@@ -263,11 +293,13 @@ const changePage = (page) => {
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
state.filter.page_size = size;
changePage(1);
}; // 改变每页条数
onBeforeMount(() => {});
onBeforeMount(() => {
getTableRows();
});
const { tableRows, tableTotal, filter } = toRefs(state);
</script>
......@@ -275,7 +307,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px;
min-height: 100%;
display: flex;
......@@ -304,9 +335,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
height: calc(100% - 70px);
width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
}
}
......
<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>
This diff is collapsed.
<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>
This diff is collapsed.
This diff is collapsed.
<!-- 角色管理新增 -->
<template>
<role-form></role-form>
</template>
<script setup>
import roleForm from "./role_form.vue";
</script>
This diff is collapsed.
<!-- 角色管理编辑 -->
<template>
<role-form></role-form>
</template>
<script setup>
import roleForm from "../add/role_form.vue";
</script>
This diff is collapsed.
import autoMaintenance from "./api/auto-maintenance";
export default {
autoMaintenance,
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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