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

Merge branch 'dev' into zy

parents c1620424 1cd8c8bf
...@@ -29,9 +29,11 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行 ...@@ -29,9 +29,11 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
- name: build # 项目打包 - name: build # 项目打包
image: registry.cn-qingdao.aliyuncs.com/wod/devops-node:16.16.0-slim image: registry.cn-qingdao.aliyuncs.com/wod/devops-node:16.16.0-slim
# 将宿主机中文件夹挂载到容器中,宿主机文件夹中的文件会被容器访问并修改,起到使用缓存的作用,避免每次运行都要重现下载依赖,提高运行速度 # 将宿主机中文件夹挂载到容器中,宿主机文件夹中的文件会被容器访问并修改,起到使用缓存的作用,避免每次运行都要重现下载依赖,提高运行速度
commands: commands:
- yarn # - npm install -g cnpm --registry=https://registry.npm.taobao.org
# - cnpm install
# - yarn
- export NODE_ENV=production - export NODE_ENV=production
- yarn build - yarn build
...@@ -51,12 +53,12 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行 ...@@ -51,12 +53,12 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
- name: docker-amd64 - name: docker-amd64
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker:1.0 image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker:1.0
# 将宿主机的 docker和配置挂载到运行的 docker 容器中,那么在容器中运行 docker 命令时,等同于在宿主机中运行该docker命令 # 将宿主机的 docker和配置挂载到运行的 docker 容器中,那么在容器中运行 docker 命令时,等同于在宿主机中运行该docker命令
volumes: volumes:
- name: docker-sock - name: docker-sock
path: /var/run/docker.sock # 将下载依赖的目录挂载出来,防止重复下载 path: /var/run/docker.sock # 将下载依赖的目录挂载出来,防止重复下载
settings: # 当前设置 settings: # 当前设置
base: registry.cn-qingdao.aliyuncs.com/wod/nginx:1.19.5-amd64 # 基础镜像 base: registry.cn-qingdao.aliyuncs.com/wod/nginx:1.19.5-amd64 # 基础镜像
dockerfile: .beagle/dockerfile dockerfile: .beagle/dockerfile
repo: smart-operation/so-manage-ui # 生成镜像的 分组/名称 repo: smart-operation/so-manage-ui # 生成镜像的 分组/名称
version: "v3.0.1" # 版本号 version: "v3.0.1" # 版本号
...@@ -80,7 +82,7 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行 ...@@ -80,7 +82,7 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
from_secret: KUBERNETES_SERVER from_secret: KUBERNETES_SERVER
KUBERNETES_TOKEN: KUBERNETES_TOKEN:
from_secret: KUBERNETES_TOKEN from_secret: KUBERNETES_TOKEN
- name: docker-arm64 - name: docker-arm64
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker:1.0 image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker:1.0
volumes: volumes:
...@@ -153,7 +155,6 @@ trigger: ...@@ -153,7 +155,6 @@ trigger:
branch: branch:
- master - master
kind: pipeline kind: pipeline
name: master name: master
steps: steps:
...@@ -195,7 +196,7 @@ steps: ...@@ -195,7 +196,7 @@ steps:
- name: docker-sock - name: docker-sock
path: /var/run/docker.sock path: /var/run/docker.sock
pull: always pull: always
environment: environment:
REGISTRY_USER: REGISTRY_USER:
from_secret: REGISTRY_USER from_secret: REGISTRY_USER
REGISTRY_PASSWORD: REGISTRY_PASSWORD:
...@@ -224,7 +225,7 @@ steps: ...@@ -224,7 +225,7 @@ steps:
- name: harbor-arch - name: harbor-arch
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker-manifest:1.0 image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker-manifest:1.0
settings: settings:
platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/mips64le platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/mips64le
template: hub.wodcloud.com/smart-operation/so-manage-ui:v3.0-ARCH template: hub.wodcloud.com/smart-operation/so-manage-ui:v3.0-ARCH
target: hub.wodcloud.com/smart-operation/so-manage-ui:v3.0 target: hub.wodcloud.com/smart-operation/so-manage-ui:v3.0
username: username:
...@@ -269,4 +270,4 @@ kind: secret ...@@ -269,4 +270,4 @@ kind: secret
name: SECRET_KEY_MINIO name: SECRET_KEY_MINIO
get: get:
name: SECRET_KEY_MINIO name: SECRET_KEY_MINIO
path: devops-secrets path: devops-secrets
\ No newline at end of file
...@@ -13,5 +13,6 @@ ...@@ -13,5 +13,6 @@
"editor.formatOnSave": true, "editor.formatOnSave": true,
"[vue]": { "[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
} },
"vue.codeActions.enabled": false
} }
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"element-plus": "^2.2.19", "element-plus": "^2.2.19",
"github-markdown-css": "^5.1.0", "github-markdown-css": "^5.1.0",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"install": "^0.13.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"mavon-editor": "^3.0.1", "mavon-editor": "^3.0.1",
...@@ -36,4 +37,4 @@ ...@@ -36,4 +37,4 @@
"@vue/compiler-sfc": "^3.2.31", "@vue/compiler-sfc": "^3.2.31",
"vite": "^3.0.0" "vite": "^3.0.0"
} }
} }
\ No newline at end of file
...@@ -143,9 +143,9 @@ const { content } = toRefs(states); ...@@ -143,9 +143,9 @@ const { content } = toRefs(states);
right: 0 !important; right: 0 !important;
} }
/* 光标颜色 */ /* 光标颜色 */
.vue-ace-editor :deep() .ace_cursor { /* .vue-ace-editor :deep() .ace_cursor {
color: #fff; color: #fff;
} } */
.vue-ace-editor-disable :deep() .ace_scrollbar-v { .vue-ace-editor-disable :deep() .ace_scrollbar-v {
width: 6px !important; width: 6px !important;
right: 2px; right: 2px;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</template> </template>
<script setup> <script setup>
import { reactive, ref, onBeforeMount, toRefs, watch } from "vue"; import { reactive, ref, onBeforeMount, watch } from "vue";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: [String, Number], type: [String, Number],
......
...@@ -178,4 +178,9 @@ const getRowInfo = (row, key) => { ...@@ -178,4 +178,9 @@ const getRowInfo = (row, key) => {
$_prop_path: propPath, $_prop_path: propPath,
}; };
}; };
defineExpose({
clearSelection,
getRowInfo,
});
</script> </script>
<template> <template>
<el-table <el-table
:height="height"
ref="table" ref="table"
class="bg-table" class="bg-table"
:data="rows" :data="rows"
...@@ -14,7 +13,7 @@ ...@@ -14,7 +13,7 @@
<template v-slot:empty> <template v-slot:empty>
<div class="empty_container"> <div class="empty_container">
<img src="../assets/imgs/img-no-data.png" alt="" /> <img src="../assets/imgs/img-no-data.png" alt="" />
<div class="text">暂无数据</div> <div class="text">{{ emptyText }}</div>
</div> </div>
</template> </template>
<el-table-column v-if="paddingLeft > 10 && !border" :width="paddingLeft - 10"></el-table-column> <el-table-column v-if="paddingLeft > 10 && !border" :width="paddingLeft - 10"></el-table-column>
...@@ -57,10 +56,6 @@ const { nowSelectData, allSelectData, initAllSelectData, selectData, initSelectT ...@@ -57,10 +56,6 @@ const { nowSelectData, allSelectData, initAllSelectData, selectData, initSelectT
selectTableMixin(); selectTableMixin();
const props = defineProps({ const props = defineProps({
height: {
type: [Number, String],
default: "auto",
},
headers: { headers: {
type: Array, type: Array,
require: true, require: true,
...@@ -81,6 +76,10 @@ const props = defineProps({ ...@@ -81,6 +76,10 @@ const props = defineProps({
type: String, type: String,
default: "序号", default: "序号",
}, },
emptyText: {
type: String,
default: "暂无数据",
},
stripe: { stripe: {
type: Boolean, type: Boolean,
default: false, default: false,
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
directory: 'file', directory: 'file',
uniqueCode: false, uniqueCode: false,
}" }"
:limit="limit"
:http-request="httpRequest"
:before-upload="handleBeforeUpload" :before-upload="handleBeforeUpload"
:on-exceed="handleExceed" :on-exceed="handleExceed"
:on-success="handleSuccess" :on-success="handleSuccess"
...@@ -95,6 +97,9 @@ const props = defineProps({ ...@@ -95,6 +97,9 @@ const props = defineProps({
type: String, type: String,
default: "", default: "",
}, },
httpRequest: {
type: Function,
},
limit: { limit: {
type: Number, type: Number,
default: 9999, default: 9999,
...@@ -123,10 +128,6 @@ watch( ...@@ -123,10 +128,6 @@ watch(
} }
); );
const handleBeforeUpload = (file) => { const handleBeforeUpload = (file) => {
if (state.fileList && state.fileList.length >= props.limit) {
ElMessage.error(`只允许上传${props.limit}个文件`);
return false;
}
let temp = file.name.split("."); let temp = file.name.split(".");
let type = temp[temp.length - 1].toLocaleLowerCase(); let type = temp[temp.length - 1].toLocaleLowerCase();
let fileTypesOk = props.fileTypes.indexOf(type) > -1 || props.fileTypes.length == 0; let fileTypesOk = props.fileTypes.indexOf(type) > -1 || props.fileTypes.length == 0;
...@@ -143,7 +144,7 @@ const handleBeforeUpload = (file) => { ...@@ -143,7 +144,7 @@ const handleBeforeUpload = (file) => {
return fileTypesOk && fileMaxSizeOk; return fileTypesOk && fileMaxSizeOk;
}; };
const handleExceed = (file, fileList) => { const handleExceed = (file, fileList) => {
console.log(file, fileList); ElMessage.error(`只允许上传${props.limit}个文件`);
}; };
const handlePreview = (val) => { const handlePreview = (val) => {
let a = document.createElement("a"); // 生成一个a元素 let a = document.createElement("a"); // 生成一个a元素
......
<template> <template>
<div> <div>
<el-table <el-table :data="tableData" style="width: 100%">
:data="tableData" <el-table-column
style="width: 100%"> v-for="(item, index) in header"
<el-table-column :key="'header' + index"
v-for="(item,index) in header" prop="date"
:key="'header'+index" :label="item.name"
prop="date" :width="item.width">
:label="item.name" <template v-slot:default="scope">
:width="item.width"> <span class="table-span" v-for="(it, idx) in item.value" :key="'it' + idx">
<template v-slot:default="scope"> <el-input
<span class="table-span" v-for="(it,idx) in item.value" :key="'it'+idx"> v-if="it.type == 'input'"
<el-input v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
v-if="it.type == 'input'" @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" v-model="scope.row[it.value]"
@change="changeData({...scope,type:it.value,check:it.check||null})" :style="{ width: it.width }"
v-model="scope.row[it.value]" :placeholder="it.placeholder"
:style="{width:it.width}" :disabled="it.disabled"></el-input>
:placeholder="it.placeholder" <el-select
:disabled="it.disabled" v-if="it.type == 'select'"
></el-input> v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
<el-select @change="changeData({ ...scope, type: it.value, check: it.check || null })"
v-if="it.type == 'select'" :multiple="it.multiple || false"
v-show="it.show==undefined?true:typeof(it.show)=='function'?it.show(scope):it.show" v-model="scope.row[it.value]"
@change="changeData({...scope,type:it.value,check:it.check||null})" :style="{ width: it.width }"
:multiple="it.multiple || false" :disabled="it.disabled"
v-model="scope.row[it.value]" :placeholder="it.placeholder">
:style="{width:it.width}" <el-option
:disabled="it.disabled" v-for="(itx, idxm) in it.arr"
:placeholder="it.placeholder" :key="idxm + 600"
> :label="itx.label"
<el-option :value="itx.value"
v-for="(itx, idxm) in it.arr" :disabled="itx.disabled"></el-option>
:key="idxm + 600" </el-select>
:label="itx.label" <span
:value="itx.value" v-if="it.type == 'text'"
:disabled="itx.disabled" v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
></el-option> >{{ it.value }}</span
</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
<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> v-if="it.type == 'value'"
<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> v-show="it.show == undefined ? true : typeof it.show == 'function' ? it.show(scope) : it.show"
</span> >{{ scope.row[it.value] }}</span
</template> >
</el-table-column> <span
</el-table> class="button"
</div> 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>
</el-table>
</div>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
header:{ header: {
type:Array, type: Array,
default:()=>[] default: () => [],
},
tableData:{
type:Array,
default:()=>[]
}
}, },
components: { tableData: {
type: Array,
}, default: () => [],
data() {
return {
};
},
watch: {
},
computed: {
},
created() {
},
mounted() {
}, },
methods: { },
changeData(val){ components: {},
this.$emit('change',val) data() {
} return {};
},
watch: {},
computed: {},
created() {},
mounted() {},
methods: {
changeData(val) {
this.$emit("change", val);
}, },
},
}; };
</script> </script>
<style scoped> <style scoped>
.table-span{ .table-span {
float: left; float: left;
margin-right: 10px; margin-right: 10px;
line-height: 40px; line-height: 40px;
} }
.button{ .button {
cursor: pointer; cursor: pointer;
color: #2b4695; color: #2b4695;
} }
</style> </style>
...@@ -120,9 +120,7 @@ const login = () => { ...@@ -120,9 +120,7 @@ const login = () => {
ElMessage.error(data.data); ElMessage.error(data.data);
} }
}) })
.catch((error) => { .catch((error) => {});
console.log(error);
});
}; };
const getUserInfo = () => { const getUserInfo = () => {
return axios.get(`/v1/api/user/getUserInfo`); return axios.get(`/v1/api/user/getUserInfo`);
......
...@@ -30,7 +30,7 @@ import store from "@/store"; ...@@ -30,7 +30,7 @@ import store from "@/store";
import i18n from "./i18n/i18n.js"; import i18n from "./i18n/i18n.js";
import axios from "./request/http.js"; import axios from "./request/http.js";
import api from "./request/api.js";
import config from "../package.json"; import config from "../package.json";
import { menuData } from "@/components/menu.js"; import { menuData } from "@/components/menu.js";
...@@ -61,6 +61,7 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) { ...@@ -61,6 +61,7 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
} }
createVue.config.globalProperties.$axios = axios; createVue.config.globalProperties.$axios = axios;
createVue.config.globalProperties.$api = api;
import menu from "./router/function.js"; import menu from "./router/function.js";
......
...@@ -77,7 +77,7 @@ const treeProps = { ...@@ -77,7 +77,7 @@ const treeProps = {
disabled: "disabled", disabled: "disabled",
}; };
const getOrgTree = () => { const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => { axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
const orgDataTemp = res.data.data || []; const orgDataTemp = res.data.data || [];
orgDataTemp.shift(); orgDataTemp.shift();
......
...@@ -149,7 +149,7 @@ const formatFile = (url) => { ...@@ -149,7 +149,7 @@ const formatFile = (url) => {
const getDetail = () => { const getDetail = () => {
axios 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) => { .then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
const detail = res.data.data.org_info; const detail = res.data.data.org_info;
......
...@@ -22,16 +22,6 @@ ...@@ -22,16 +22,6 @@
<el-form-item label="组织介绍" prop="description"> <el-form-item label="组织介绍" prop="description">
<el-input type="textarea" :rows="3" v-model="orgForm.description" maxlength="300" show-word-limit /> <el-input type="textarea" :rows="3" v-model="orgForm.description" maxlength="300" show-word-limit />
</el-form-item> </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> </el-form>
</template> </template>
...@@ -51,7 +41,6 @@ const orgForm = reactive({ ...@@ -51,7 +41,6 @@ const orgForm = reactive({
name: "", name: "",
organization_code: "", organization_code: "",
description: "", description: "",
attachment: [],
}); });
const checkCode = (rule, value, callback) => { const checkCode = (rule, value, callback) => {
...@@ -115,7 +104,7 @@ const treeProps = { ...@@ -115,7 +104,7 @@ const treeProps = {
disabled: "disabled", disabled: "disabled",
}; };
const getOrgTree = () => { const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => { axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
const orgDataTemp = res.data.data || []; const orgDataTemp = res.data.data || [];
orgDataTemp.shift(); orgDataTemp.shift();
......
...@@ -198,7 +198,7 @@ const treeProps = { ...@@ -198,7 +198,7 @@ const treeProps = {
value: "organization_id", value: "organization_id",
}; };
const getOrgTree = () => { const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => { axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
orgData.value = res.data.data || []; orgData.value = res.data.data || [];
} else { } else {
......
...@@ -211,7 +211,7 @@ const cancel = () => { ...@@ -211,7 +211,7 @@ const cancel = () => {
}; };
const getOrgTree = () => { const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => { axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
orgId.value = res.data.data[0].organization_id; orgId.value = res.data.data[0].organization_id;
} else { } else {
......
...@@ -20,10 +20,7 @@ ...@@ -20,10 +20,7 @@
@click.stop="showAction($event, data, node)"> @click.stop="showAction($event, data, node)">
<bg-icon class="tree-more" icon="#bg-ic-s-more"></bg-icon> <bg-icon class="tree-more" icon="#bg-ic-s-more"></bg-icon>
</span> </span>
<span <span v-else class="tree-action-box" @click.stop="showAction($event, data, node)">
v-else
class="tree-action-box"
@click.stop="showAction($event, data, node)">
<bg-icon class="tree-more" icon="#bg-ic-s-more"></bg-icon> <bg-icon class="tree-more" icon="#bg-ic-s-more"></bg-icon>
</span> </span>
</div> </div>
...@@ -141,8 +138,8 @@ ...@@ -141,8 +138,8 @@
</template> </template>
<script setup> <script setup>
import { reactive, toRefs, ref, computed, onBeforeMount, onBeforeUnmount, watch, nextTick } from "vue"; import { ref, onBeforeMount, onBeforeUnmount, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute } from "vue-router";
import axios from "@/request/http.js"; import axios from "@/request/http.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const route = useRoute(); const route = useRoute();
...@@ -174,10 +171,9 @@ const defaultProps = { ...@@ -174,10 +171,9 @@ const defaultProps = {
}; };
const getOrgTree = (data) => { 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) { if (res.data.code == 200) {
orgData.value = res.data.data || []; orgData.value = res.data.data || [];
console.log(route.query.id);
if (route.query.id) { if (route.query.id) {
searchItem(orgData.value, route.query.id); searchItem(orgData.value, route.query.id);
data = selectNodeObj.value; data = selectNodeObj.value;
......
...@@ -18,14 +18,6 @@ ...@@ -18,14 +18,6 @@
:autosize="{ minRows: 5 }" :autosize="{ minRows: 5 }"
:disabled="rowType != 0"></el-input> :disabled="rowType != 0"></el-input>
</el-form-item> </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"> <el-form-item label="菜单功能权限" prop="permission_arr">
<bg-permission <bg-permission
:values="formData.permission_arr" :values="formData.permission_arr"
...@@ -76,14 +68,11 @@ const roleState = reactive({ ...@@ -76,14 +68,11 @@ const roleState = reactive({
formData: { formData: {
role_name: "", role_name: "",
role_desc: "", role_desc: "",
data_purview: 3,
state: 1, state: 1,
permission_arr: [], permission_arr: [],
}, // 表单项 }, // 表单项
rules: { rules: {
role_name: [{ required: true, message: "请输入角色名称", trigger: "blur" }], role_name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
data_purview: [{ required: true, message: "请选择数据权限", trigger: "change" }],
state: [{ required: true, message: "请选择是否启用", trigger: "change" }], state: [{ required: true, message: "请选择是否启用", trigger: "change" }],
permission_arr: [{ required: true, type: "array", validator: checkMenuLength, trigger: "change" }], permission_arr: [{ required: true, type: "array", validator: checkMenuLength, trigger: "change" }],
}, // 表单校验规则 }, // 表单校验规则
...@@ -97,7 +86,7 @@ const roleState = reactive({ ...@@ -97,7 +86,7 @@ const roleState = reactive({
rowType: 0, rowType: 0,
}); });
const getMenuTree = () => { const getMenuTree = () => {
axios.get(`/apaas/system/v5/menu/tree`).then((res) => { axios.get(`/v1/api/menu/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
roleState.permissionData = res.data.data || []; roleState.permissionData = res.data.data || [];
} else { } else {
...@@ -111,9 +100,9 @@ const changeMenu = (val) => { ...@@ -111,9 +100,9 @@ const changeMenu = (val) => {
}; // 修改选中的菜单 }; // 修改选中的菜单
const getRoleDetail = () => { 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) { 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; roleState.rowType = res.data.data.role_type;
let permission_arr = []; let permission_arr = [];
if (menus && menus.length > 0) { if (menus && menus.length > 0) {
...@@ -124,11 +113,9 @@ const getRoleDetail = () => { ...@@ -124,11 +113,9 @@ const getRoleDetail = () => {
roleState.formData = { roleState.formData = {
role_name, role_name,
role_desc, role_desc,
data_purview,
state, state,
permission_arr: [...permission_arr], permission_arr: [...permission_arr],
}; };
console.log(roleState.formData.permission_arr);
} else { } else {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
} }
...@@ -142,15 +129,14 @@ const saveRole = () => { ...@@ -142,15 +129,14 @@ const saveRole = () => {
role_name: roleState.formData.role_name, role_name: roleState.formData.role_name,
role_desc: roleState.formData.role_desc, role_desc: roleState.formData.role_desc,
state: roleState.formData.state, state: roleState.formData.state,
data_purview: roleState.formData.data_purview,
menu_ids: [...roleState.formData.permission_arr], menu_ids: [...roleState.formData.permission_arr],
}; };
if (!route.query.id) { 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
router.push("/system/role"); router.push("/authority/role");
} else { } else {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
} }
...@@ -158,10 +144,10 @@ const saveRole = () => { ...@@ -158,10 +144,10 @@ const saveRole = () => {
} else { } else {
// 编辑 // 编辑
params.id = +route.query.id; 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
router.push("/system/role"); router.push("/authority/role");
} else { } else {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
} }
...@@ -171,7 +157,7 @@ const saveRole = () => { ...@@ -171,7 +157,7 @@ const saveRole = () => {
}); });
}; // 新增或编辑角色的保存 }; // 新增或编辑角色的保存
const goList = () => { const goList = () => {
router.push("/system/role"); router.push("/authority/role");
}; };
onBeforeMount(() => { onBeforeMount(() => {
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
delete_row(row); 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> </bg-table-btn>
</template> </template>
...@@ -105,14 +105,6 @@ ...@@ -105,14 +105,6 @@
<span class="can_click_text" @click="clearUserSelection">清空</span> <span class="can_click_text" @click="clearUserSelection">清空</span>
</div> </div>
<div class="right"> <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 <el-cascader
v-model="userFilter.organization_id" v-model="userFilter.organization_id"
:options="orgList" :options="orgList"
...@@ -127,7 +119,7 @@ ...@@ -127,7 +119,7 @@
}" }"
:clearable="true" :clearable="true"
collapse-tags collapse-tags
style="width: 200px"> style="width: 200px; margin-right: 30px">
<template #default="{ data }"> <template #default="{ data }">
<span>{{ data.name }}</span> <span>{{ data.name }}</span>
</template> </template>
...@@ -135,9 +127,9 @@ ...@@ -135,9 +127,9 @@
<el-input <el-input
v-model.trim="userFilter.search" v-model.trim="userFilter.search"
placeholder="请输入内容" placeholder="请输入内容"
style="width: 200px" style="width: 200px; margin-right: 30px"
:prefix-icon="Search" /> :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> <el-button type="default" @click="clearAction">重置</el-button>
</div> </div>
</div> </div>
...@@ -236,26 +228,11 @@ const state = reactive({ ...@@ -236,26 +228,11 @@ const state = reactive({
}); });
const userState = reactive({ const userState = reactive({
userFilter: { userFilter: {
is_admin: "",
organization_id: "", organization_id: "",
search: "", search: "",
limit: 10, limit: 10,
page: 1, page: 1,
}, },
userTypeList: [
{
name: "全部类型",
value: "",
},
{
name: "组织管理员账号",
value: 2,
},
{
name: "平台用户账号",
value: 3,
},
],
orgList: [], orgList: [],
userHeaders: [ userHeaders: [
{ {
...@@ -280,10 +257,10 @@ const userState = reactive({ ...@@ -280,10 +257,10 @@ const userState = reactive({
userSelection: [], userSelection: [],
distributeDialog: false, // 分配用户弹窗 distributeDialog: false, // 分配用户弹窗
}); });
// 获取角色列表
const getRoleRows = () => { const getRoleRows = () => {
let params = { ...state.filter }; let params = { ...state.filter };
console.log(params); axios.get(`/v1/api/role/list`, { params }).then((res) => {
axios.get(`/apaas/system/v5/role/list`, { params }).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
state.tableRows = res.data.data || []; state.tableRows = res.data.data || [];
state.tableTotal = res.data.total; state.tableTotal = res.data.total;
...@@ -291,12 +268,11 @@ const getRoleRows = () => { ...@@ -291,12 +268,11 @@ const getRoleRows = () => {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
} }
}); });
}; // 获取角色列表 };
//获取组织树
const getOrgList = () => { const getOrgList = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => { axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
console.log(res.data.data);
userState.orgList = res.data.data || []; userState.orgList = res.data.data || [];
} else { } else {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
...@@ -319,10 +295,11 @@ const changeSearch = (val) => { ...@@ -319,10 +295,11 @@ const changeSearch = (val) => {
}; // 表格关键字筛选 }; // 表格关键字筛选
const changeUseRow = (row) => { const changeUseRow = (row) => {
//内置角色不能删除和编辑
if (row.role_type == 1 || row.role_type == 2) { if (row.role_type == 1 || row.role_type == 2) {
return; 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
changePage(1); changePage(1);
...@@ -370,10 +347,9 @@ const getUserList = () => { ...@@ -370,10 +347,9 @@ const getUserList = () => {
page: userState.userFilter.page, page: userState.userFilter.page,
search: userState.userFilter.search, search: userState.userFilter.search,
organization_id: userState.userFilter.organization_id, organization_id: userState.userFilter.organization_id,
is_admin: userState.userFilter.is_admin,
role_id: state.actionRow.id, 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) { if (res.data.code == 200) {
console.log(res.data.data); console.log(res.data.data);
userState.userRows = res.data.data || []; userState.userRows = res.data.data || [];
...@@ -381,7 +357,6 @@ const getUserList = () => { ...@@ -381,7 +357,6 @@ const getUserList = () => {
nextTick(() => { nextTick(() => {
userState.userRows.forEach((e) => { userState.userRows.forEach((e) => {
if (e.is_bind == 1) { if (e.is_bind == 1) {
console.log(userTable);
userTable.value.toggleRowSelection(e, true); userTable.value.toggleRowSelection(e, true);
} }
}); });
...@@ -402,13 +377,11 @@ const changeUserSize = (val) => { ...@@ -402,13 +377,11 @@ const changeUserSize = (val) => {
}; };
const searchAction = () => { const searchAction = () => {
console.log(userState.userFilter);
changeUserPage(1); changeUserPage(1);
}; };
const clearAction = (type) => { const clearAction = (type) => {
userState.userFilter = { userState.userFilter = {
is_admin: "",
organization_id: "", organization_id: "",
search: "", search: "",
limit: 10, limit: 10,
...@@ -420,7 +393,6 @@ const clearAction = (type) => { ...@@ -420,7 +393,6 @@ const clearAction = (type) => {
}; };
const clearUserSelection = () => { const clearUserSelection = () => {
console.log(userTable.value);
userTable.value.clearTable(); userTable.value.clearTable();
}; };
...@@ -437,7 +409,7 @@ const distribute = () => { ...@@ -437,7 +409,7 @@ const distribute = () => {
id: state.actionRow.id, id: state.actionRow.id,
user_ids: user_ids, 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
userState.distributeDialog = false; userState.distributeDialog = false;
...@@ -475,7 +447,7 @@ const deleteData = () => { ...@@ -475,7 +447,7 @@ const deleteData = () => {
let params = { let params = {
ids: [...ids], 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
state.delDialog = false; state.delDialog = false;
...@@ -492,8 +464,7 @@ onBeforeMount(() => { ...@@ -492,8 +464,7 @@ onBeforeMount(() => {
const { filter, headers, tableRows, tableTotal, delDialog, selection } = toRefs(state); const { filter, headers, tableRows, tableTotal, delDialog, selection } = toRefs(state);
const { userFilter, userTypeList, orgList, userHeaders, userRows, total, userSelection, distributeDialog } = const { userFilter, orgList, userHeaders, userRows, total, userSelection, distributeDialog } = toRefs(userState);
toRefs(userState);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -569,7 +540,7 @@ const { userFilter, userTypeList, orgList, userHeaders, userRows, total, userSel ...@@ -569,7 +540,7 @@ const { userFilter, userTypeList, orgList, userHeaders, userRows, total, userSel
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: flex-end;
.el-button { .el-button {
margin: 0; margin: 0;
width: 64px; 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 @@ ...@@ -3,88 +3,17 @@
<bg-breadcrumb></bg-breadcrumb> <bg-breadcrumb></bg-breadcrumb>
<div class="page_content flex_cloumn"> <div class="page_content flex_cloumn">
<div class="content_top apaas_scroll"> <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"> <div class="content_main">
<systemForm <systemForm
v-show="step === 1"
ref="systemFormRef" ref="systemFormRef"
:form-type="route.query.id ? true : false" :form-type="route.query.id ? true : false"
:id="route.query.id" :id="route.query.id"
@action="getSystemFormData"></systemForm> @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> </div>
<div class="content_bottom" v-if="step !== 3"> <div class="content_bottom">
<div v-show="step === 1"> <div>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="nextStep">下一步</el-button>
</div>
<div v-show="step === 2">
<el-button @click="cancel">取消</el-button> <el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="previousStep">上一步</el-button>
<el-button type="primary" @click="submit">保存</el-button> <el-button type="primary" @click="submit">保存</el-button>
</div> </div>
</div> </div>
...@@ -95,17 +24,14 @@ ...@@ -95,17 +24,14 @@
<script setup> <script setup>
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import systemForm from "./system-form.vue"; import systemForm from "./system-form.vue";
import contactForm from "./contact-form.vue";
import { reactive, ref, onBeforeUnmount, onMounted } from "vue"; import { reactive, ref, onBeforeUnmount, onMounted } from "vue";
import CryptoJS from "crypto-js";
import axios from "@/request/http.js"; import axios from "@/request/http.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const step = ref(1);
const systemFormRef = ref(null); const systemFormRef = ref(null);
const contactFormRef = ref(null); //业务系统表单
const formData = reactive({ const formData = reactive({
organization_id: "", organization_id: "",
business_code: "", business_code: "",
...@@ -120,82 +46,51 @@ const formData = reactive({ ...@@ -120,82 +46,51 @@ const formData = reactive({
access_address: "", access_address: "",
develop_id: "", develop_id: "",
state: 1, state: 1,
});
contact_name: "",
contact_phone: "",
contact_email: "",
remark: "",
}); //业务系统表单+联系人表单
const successFlag = ref(false);
// 下一步
const nextStep = () => {
systemFormRef.value.submitForm();
};
//业务系统表单检验触发事件 data为null 校验失败 //业务系统表单检验触发事件 data为null 校验失败
const getSystemFormData = (data) => { const getSystemFormData = (data) => {
if (data) { if (data) {
Object.assign(formData, data); Object.assign(formData, data);
step.value = 2;
} else { } else {
} }
}; };
//联系人表单检验触发事件 data为null 校验失败
const getContactFormData = (data) => {
if (data) {
Object.assign(formData, data);
if (route.query.id) {
console.log(formData);
let params = {
...formData,
id: parseInt(route.query.id),
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
};
axios.post(`/apaas/system/v5/user/update`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
} else {
let params = {
...formData,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
password: CryptoJS.AES.encrypt(formData.password, "swuE9cmCZQwrkYRV").toString(),
};
axios.put(`/apaas/system/v5/user/create`, params).then((res) => {
if (res.data.code == 200) {
successFlag.value = true;
step.value = 3;
} else {
ElMessage.error(res.data.data);
}
});
}
}
};
//上一步
const previousStep = () => {
step.value--;
};
//提交表单 //提交表单
const submit = () => { const submit = () => {
contactFormRef.value.submitForm(); if (route.query.id) {
}; let params = {
//继续创建 清空表单 ...formData,
const continueCreate = () => { logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
systemFormRef.value.clearForm(); };
contactFormRef.value.clearForm(); axios.put(`/v1/api/user/${route.query.id}`, params).then((res) => {
step.value = 1; if (res.data.code == 200) {
successFlag.value = false; ElMessage.success(res.data.msg);
cancel();
} else {
ElMessage.error(res.data.data);
}
});
} else {
let params = {
...formData,
logo: formData.logo && formData.logo.length > 0 ? formData.logo[0].url : "",
password: CryptoJS.AES.encrypt(formData.password, "swuE9cmCZQwrkYRV").toString(),
};
axios.put(`/v1/api/user/add`, params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(res.data.msg);
cancel();
} else {
ElMessage.error(res.data.data);
}
});
}
}; };
//取消 //取消
const cancel = () => { const cancel = () => {
// router.go(-1); // router.go(-1);
router.push({ router.push({
path: "/develop/account", path: "/authority/user",
query: { query: {
id: formData.organization_id, id: formData.organization_id,
}, },
...@@ -203,7 +98,7 @@ const cancel = () => { ...@@ -203,7 +98,7 @@ const cancel = () => {
}; };
const getDetail = () => { 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) { if (res.data.code == 200) {
const form = res.data.data; const form = res.data.data;
systemFormRef.value.setForm({ systemFormRef.value.setForm({
...@@ -221,13 +116,6 @@ const getDetail = () => { ...@@ -221,13 +116,6 @@ const getDetail = () => {
appid: form.app_id, appid: form.app_id,
appsecret: form.app_secret, 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 { } else {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
} }
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
:data="orgData" :data="orgData"
:props="defaultProps" :props="defaultProps"
@node-click="handleNodeClick" @node-click="handleNodeClick"
node-key="id" node-key="organization_id"
:highlight-current="true" :highlight-current="true"
:filter-node-method="filterNode" :filter-node-method="filterNode"
:default-expand-all="true"> :default-expand-all="true">
...@@ -276,7 +276,7 @@ const route = useRoute(); ...@@ -276,7 +276,7 @@ const route = useRoute();
const getTableRows = () => { const getTableRows = () => {
let params = { ...filter, organization_id: selectNode.value }; let params = { ...filter, organization_id: selectNode.value };
axios axios
.get(`/apaas/system/v5/user/list`, { .get(`/v1/api/org/detail`, {
params, params,
}) })
.then((res) => { .then((res) => {
...@@ -297,7 +297,7 @@ const addAccount = (params) => { ...@@ -297,7 +297,7 @@ const addAccount = (params) => {
const handleNodeClick = (data) => { const handleNodeClick = (data) => {
if (data.data_type == 1) { if (data.data_type == 1) {
selectNode.value = data.id; selectNode.value = data.organization_id;
changePage(1); changePage(1);
} else { } else {
nextTick(() => { nextTick(() => {
...@@ -321,18 +321,19 @@ const defaultProps = { ...@@ -321,18 +321,19 @@ const defaultProps = {
class: customNodeClass, class: customNodeClass,
}; };
const getOrgTree = () => { const getOrgTree = () => {
axios.get(`/apaas/system/v5/org/tree`).then((res) => { axios.get(`/v1/api/org/tree`).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
orgData.value = res.data.data || []; orgData.value = res.data.data || [];
orgData.value.shift(); // orgData.value.shift();
const orgList = searchOrg(orgData.value); const orgList = searchOrg(orgData.value);
if (route.query.id) { console.log("orgList", orgList);
searchItem(orgData.value, route.query.id); if (route.query.organization_id) {
searchItem(orgData.value, route.query.organization_id);
} else { } else {
selectNode.value = orgList.length > 0 ? orgList[0].id : ""; selectNode.value = orgList.length > 0 ? orgList[0].organization_id : "";
} }
nextTick(() => { nextTick(() => {
if (route.query.id) { if (route.query.organization_id) {
treeRef.value.setCurrentNode(selectNodeObj.value); treeRef.value.setCurrentNode(selectNodeObj.value);
} else { } else {
if (orgList.length > 0) { if (orgList.length > 0) {
...@@ -346,14 +347,14 @@ const getOrgTree = () => { ...@@ -346,14 +347,14 @@ const getOrgTree = () => {
} }
}); });
}; };
const searchItem = (data, id) => { const searchItem = (data, organization_id) => {
data.forEach((e) => { data.forEach((e) => {
if (e.organization_id == id) { if (e.organization_id == organization_id) {
selectNodeObj.value = e; selectNodeObj.value = e;
selectNode.value = e.id; selectNode.value = e.organization_id;
} else { } else {
if (e.Child) { if (e.Child) {
searchItem(e.Child, id); searchItem(e.Child, organization_id);
} }
} }
}); });
...@@ -361,7 +362,7 @@ const searchItem = (data, id) => { ...@@ -361,7 +362,7 @@ const searchItem = (data, id) => {
const searchOrg = (data) => { const searchOrg = (data) => {
const arr = []; const arr = [];
data.forEach((item) => { data.forEach((item) => {
if (item.data_type === 1) { if (item.data_type > 0) {
arr.push(item); arr.push(item);
return; return;
} else { } else {
...@@ -385,8 +386,11 @@ const filterNode = (value, data) => { ...@@ -385,8 +386,11 @@ const filterNode = (value, data) => {
}; };
const stateChange = (row) => { const stateChange = (row) => {
const state = row.state.toString(); const params = {
axios.post(`/apaas/system/v5/user/state/${row.id}/${state}`).then((res) => { id: row.id,
state: row.state == 1 ? 0 : 1,
};
axios.post(`/v1/api/user/updateState`, params).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
getTableRows(); getTableRows();
...@@ -449,7 +453,7 @@ const handleCloseRowDelete = () => { ...@@ -449,7 +453,7 @@ const handleCloseRowDelete = () => {
const deleteConfirm = () => { const deleteConfirm = () => {
const ids = selected.value.map((item) => item.id); 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
getTableRows(); getTableRows();
...@@ -461,7 +465,7 @@ const deleteConfirm = () => { ...@@ -461,7 +465,7 @@ const deleteConfirm = () => {
}; };
const deleteRowConfirm = () => { 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
getTableRows(); getTableRows();
...@@ -494,7 +498,7 @@ const resetPsd = () => { ...@@ -494,7 +498,7 @@ const resetPsd = () => {
const resetConfirm = () => { const resetConfirm = () => {
const ids = selected.value.map((item) => item.id); 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) { if (res.data.code == 200) {
ElMessage.success(res.data.msg); ElMessage.success(res.data.msg);
getTableRows(); getTableRows();
...@@ -522,7 +526,7 @@ const editConfirm = () => { ...@@ -522,7 +526,7 @@ const editConfirm = () => {
passwordRef.value.validate((valid, fields) => { passwordRef.value.validate((valid, fields) => {
if (valid) { if (valid) {
axios axios
.post(`/apaas/system/v5/user/editpwd`, { .post(`/v1/api/user/updatePwd`, {
id: selectedRow.value.id, id: selectedRow.value.id,
password: CryptoJS.AES.encrypt(passwordForm.password, "swuE9cmCZQwrkYRV").toString(), 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 @@ ...@@ -5,20 +5,29 @@
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字"> </bg-filter-group> <bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入关键字"> </bg-filter-group>
<div class="table_container"> <div class="table_container">
<div class="table bg-scroll"> <div class="table bg-scroll">
<bg-table ref="dataTable" :headers="headers" :rows="tableRows" :stripe="true"> <bg-table :headers="headers" :rows="tableRows" :stripe="true">
<template v-slot:name="{ row }"> <template v-slot:task_name="{ row }">
<span class="can_click_text" @click="getChildren(row)"> <span class="can_click_text" @click="gotoPage(row)">
{{ row.name }} {{ row.task_name }}
</span> </span>
</template> </template>
<template v-slot:state="{ row }"> <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> </template>
</bg-table> </bg-table>
</div> </div>
<bg-pagination <bg-pagination
:page="filter.page" :page="filter.page"
:size="filter.size" :size="filter.page_size"
:total="tableTotal" :total="tableTotal"
@change-page="changePage" @change-page="changePage"
@change-size="changeSize"> @change-size="changeSize">
...@@ -39,8 +48,6 @@ import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; ...@@ -39,8 +48,6 @@ import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const bgForm = ref(null);
const dataTable = ref(null);
const headers = [ const headers = [
{ {
label: "状态", label: "状态",
...@@ -48,92 +55,34 @@ const headers = [ ...@@ -48,92 +55,34 @@ const headers = [
}, },
{ {
label: "任务名称", label: "任务名称",
prop: "name", prop: "task_name",
}, },
{ {
label: "执行耗时", label: "执行耗时(s)",
prop: "workTime", prop: "exec_time",
}, },
{ {
label: "操作人", label: "操作人",
prop: "person", prop: "create_user",
}, },
]; ];
const state = reactive({ const state = reactive({
bgForm,
typeList: [], // 分类数据
typeKeyword: "", // 分类删选关键词
nodeClassifyId: null, // 当前选中分类的uuid 用于新增字典
nodeId: null, // 当前选中分类的id 用于请求列表
timer: null, // 定时器
tableRows: [], // 表格数据 tableRows: [], // 表格数据
selected: [], //选择数据
tableTotal: 0, // 表格数据条数 tableTotal: 0, // 表格数据条数
filter: { filter: {
time: "",
search: "", search: "",
page: 1, 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 deleteAllTips = () => {};
const getChildren = (row) => { const gotoPage = (row) => {
router.push(`/auto-maintenance/task-history/list`); 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) => { const changeSearch = (val) => {
state.filter.search = val; state.filter.search = val;
changePage(1); changePage(1);
...@@ -145,9 +94,8 @@ const filterAction = () => { ...@@ -145,9 +94,8 @@ const filterAction = () => {
const filterClear = () => { const filterClear = () => {
state.filter = { state.filter = {
time: "",
search: "", search: "",
limit: 10, page_size: 10,
page: 1, page: 1,
}; };
changePage(1); changePage(1);
...@@ -155,9 +103,8 @@ const filterClear = () => { ...@@ -155,9 +103,8 @@ const filterClear = () => {
const getTableRows = () => { const getTableRows = () => {
let params = { ...state.filter }; let params = { ...state.filter };
params.id = state.nodeId;
axios axios
.get(`/apaas/system/v5/dictionary/list`, { .get(`/v1/api/automated_mainten/task_history/list`, {
params, params,
}) })
.then((res) => { .then((res) => {
...@@ -177,32 +124,12 @@ const changePage = (page) => { ...@@ -177,32 +124,12 @@ const changePage = (page) => {
}; // 改变页码 }; // 改变页码
const changeSize = (size) => { const changeSize = (size) => {
state.filter.limit = size; state.filter.page_size = size;
changePage(1); 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(() => { onBeforeMount(() => {
getTypeList(); getTableRows();
}); });
const { tableRows, tableTotal, filter } = toRefs(state); const { tableRows, tableTotal, filter } = toRefs(state);
...@@ -211,7 +138,6 @@ const { tableRows, tableTotal, filter } = toRefs(state); ...@@ -211,7 +138,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
<style lang="scss" scoped> <style lang="scss" scoped>
.detail_container { .detail_container {
width: 100%; width: 100%;
height: calc(100vh - 56px);
padding: 0 24px; padding: 0 24px;
min-height: 100%; min-height: 100%;
display: flex; display: flex;
...@@ -240,9 +166,6 @@ const { tableRows, tableTotal, filter } = toRefs(state); ...@@ -240,9 +166,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
height: calc(100% - 70px); height: calc(100% - 70px);
width: 100%; width: 100%;
padding: 0 16px; padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
} }
} }
......
...@@ -17,19 +17,31 @@ ...@@ -17,19 +17,31 @@
<div class="table_container"> <div class="table_container">
<div class="table bg-scroll"> <div class="table bg-scroll">
<bg-table ref="dataTable" :headers="headers" :rows="tableRows" :stripe="true"> <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}`)"> <span class="can_click_text" @click="gotoPage(`/auto-maintenance/task-history/list/record?id=${row.id}`)">
{{ row.desc }} {{ row.exec_desc }}
</span> </span>
</template> </template>
<template v-slot:state="{ row }"> <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> </template>
</bg-table> </bg-table>
</div> </div>
<bg-pagination <bg-pagination
:page="filter.page" :page="filter.page"
:size="filter.size" :size="filter.page_size"
:total="tableTotal" :total="tableTotal"
@change-page="changePage" @change-page="changePage"
@change-size="changeSize"> @change-size="changeSize">
...@@ -46,6 +58,7 @@ import { ElMessage } from "element-plus"; ...@@ -46,6 +58,7 @@ import { ElMessage } from "element-plus";
import axios from "@/request/http.js"; import axios from "@/request/http.js";
import { Search } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import { dateStringTransform, downloadFile } from "@/services/helper.js";
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
...@@ -58,19 +71,19 @@ const headers = [ ...@@ -58,19 +71,19 @@ const headers = [
}, },
{ {
label: "执行说明", label: "执行说明",
prop: "desc", prop: "exec_desc",
}, },
{ {
label: "执行开始时间", label: "执行开始时间",
prop: "begin", prop: "exec_start_time",
}, },
{ {
label: "执行耗时", label: "执行耗时(s)",
prop: "workTime", prop: "exec_time",
}, },
{ {
label: "操作人", label: "操作人",
prop: "person", prop: "create_user",
}, },
]; ];
...@@ -85,7 +98,7 @@ const state = reactive({ ...@@ -85,7 +98,7 @@ const state = reactive({
filter: { filter: {
search: "", search: "",
page: 1, page: 1,
limit: 10, page_size: 10,
}, // 表格筛选项 }, // 表格筛选项
actionRow: null, // 当前操作的数据 actionRow: null, // 当前操作的数据
}); });
...@@ -100,10 +113,12 @@ const changeSearch = (val) => { ...@@ -100,10 +113,12 @@ const changeSearch = (val) => {
}; // 表格关键字筛选 }; // 表格关键字筛选
const getTableRows = () => { const getTableRows = () => {
let params = { ...state.filter }; let params = {
params.id = state.nodeId; ...state.filter,
task_id: route.query.id,
};
axios axios
.get(`/apaas/system/v5/dictionary/list`, { .get(`/v1/api/automated_mainten/task_history/task_info_list`, {
params, params,
}) })
.then((res) => { .then((res) => {
...@@ -123,11 +138,13 @@ const changePage = (page) => { ...@@ -123,11 +138,13 @@ const changePage = (page) => {
}; // 改变页码 }; // 改变页码
const changeSize = (size) => { const changeSize = (size) => {
state.filter.limit = size; state.filter.page_size = size;
changePage(1); changePage(1);
}; // 改变每页条数 }; // 改变每页条数
onBeforeMount(() => {}); onBeforeMount(() => {
getTableRows();
});
const { tableRows, tableTotal, filter } = toRefs(state); const { tableRows, tableTotal, filter } = toRefs(state);
</script> </script>
...@@ -135,7 +152,6 @@ const { tableRows, tableTotal, filter } = toRefs(state); ...@@ -135,7 +152,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
<style lang="scss" scoped> <style lang="scss" scoped>
.detail_container { .detail_container {
width: 100%; width: 100%;
height: calc(100vh - 56px);
padding: 0 24px; padding: 0 24px;
min-height: 100%; min-height: 100%;
display: flex; display: flex;
...@@ -163,10 +179,6 @@ const { tableRows, tableTotal, filter } = toRefs(state); ...@@ -163,10 +179,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
.table_container { .table_container {
height: calc(100% - 70px); height: calc(100% - 70px);
width: 100%; width: 100%;
padding: 0 16px;
.table {
max-height: calc(100% - 64px);
}
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
执行ping命令 / 执行说明1 执行ping命令 / 执行说明1
</div> </div>
<div class="middle-container"> <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>
<div class="bottom-container"> <div class="bottom-container">
<el-button class="use-script" type="primary" @click="router.go(-1)"> 重新执行 </el-button> <el-button class="use-script" type="primary" @click="router.go(-1)"> 重新执行 </el-button>
...@@ -22,10 +22,29 @@ import { useRouter, useRoute } from "vue-router"; ...@@ -22,10 +22,29 @@ import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import finishUse from "@/page/main/auto-maintenance/task-manage/add/finish-use.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 router = useRouter();
const route = useRoute(); const route = useRoute();
const state = reactive({ data: 1 }); const state = reactive({
const { data } = toRefs(state); 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -2,7 +2,12 @@ ...@@ -2,7 +2,12 @@
<div> <div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-position="top" label-width="120px"> <el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-position="top" label-width="120px">
<el-form-item label="任务名称" prop="name"> <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>
<el-form-item label="任务描述" prop="desc"> <el-form-item label="任务描述" prop="desc">
<el-input <el-input
...@@ -31,6 +36,10 @@ const props = defineProps({ ...@@ -31,6 +36,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
isEdit: {
type: Boolean,
default: false,
},
}); });
const ruleFormRef = ref(null); const ruleFormRef = ref(null);
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
</div> </div>
<div class="log-bg bg-scroll" :style="{ height: props.height }"> <div class="log-bg bg-scroll" :style="{ height: props.height }">
<div class="log-box"> <div class="log-box">
<div v-for="(item, i) in stateData.codes" :key="i" class="codes-box"> <div v-for="(item, i) in props.codes" :key="i" class="codes-box">
<span class="codes-num">{{ item.pos + 1 }}</span> <span class="codes-num">{{ i + 1 }}</span>
<span class="codes-out" v-html="item.out"></span> <span class="codes-out" v-html="item"></span>
</div> </div>
</div> </div>
</div> </div>
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
import { reactive, ref, onBeforeMount, toRefs } from "vue"; import { reactive, ref, onBeforeMount, toRefs } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
...@@ -47,119 +49,6 @@ const props = defineProps({ ...@@ -47,119 +49,6 @@ const props = defineProps({
default: "", 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
<div class="step-container"> <div class="step-container">
<div class="step-base"> <div class="step-base">
<img src="@/assets/imgs/img_data-complete.png" /> <img src="@/assets/imgs/img_data-complete.png" />
<p class="tips" v-if="props.state">新增成功</p> <p class="tips" v-if="props.state">{{ ["新增", "编辑", "复制"][props.finishType] }}成功</p>
<p class="tips" v-else>新增失败</p> <p class="tips" v-else>{{ ["新增", "编辑", "复制"][props.finishType] }}失败</p>
<div class="apaas_button btns" v-if="props.state"> <div class="apaas_button btns" v-if="props.state">
<el-button type="default" @click="goToList"> 返回列表 </el-button> <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> </div>
</div> </div>
...@@ -24,6 +24,10 @@ const props = defineProps({ ...@@ -24,6 +24,10 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: true, default: true,
}, },
finishType: {
type: Number,
default: 0,
},
}); });
const emit = defineEmits(["clear"]); const emit = defineEmits(["clear"]);
......
...@@ -42,10 +42,28 @@ ...@@ -42,10 +42,28 @@
<div <div
class="content_main log_content_nor" class="content_main log_content_nor"
:style="step == 3 && state.isSave ? { height: 'calc(100vh - 234px)' } : {}"> :style="step == 3 && state.isSave ? { height: 'calc(100vh - 234px)' } : {}">
<base-info v-show="step == 1" :data="state.data" ref="baseInfoRef"></base-info> <base-info
<use-content v-show="step == 2" :data="state.data" ref="useContentRef"></use-content> v-show="step == 1"
<finish v-show="step == 3 && state.isSave" :state="true" @clear="clearData"></finish> v-if="state.loadComponents"
<finish-use v-show="step == 3 && !state.isSave" :state="true" time="00:00:11"></finish-use> :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>
<div class="content_foot apaas_button" v-if="step == 1 || step == 2 || (step == 3 && !state.isSave)"> <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> <el-button type="default" v-if="step == 1 || step == 2" @click="cancel"> 取消 </el-button>
...@@ -104,6 +122,9 @@ const state = reactive({ ...@@ -104,6 +122,9 @@ const state = reactive({
useData: ["yaml", "json"], useData: ["yaml", "json"],
useText: "", useText: "",
isSave: true, isSave: true,
status: true,
pageType: 0, //0新增,1编辑,2复制
loadComponents: false, //控制子组件的加载
}); });
const cancel = () => { const cancel = () => {
...@@ -131,11 +152,55 @@ const saveTask = async () => { ...@@ -131,11 +152,55 @@ const saveTask = async () => {
.save() .save()
.then(() => { .then(() => {
step.value = 3; step.value = 3;
//todo:掉接口保存,并获取状态 if (state.pageType == 0 || state.pageType == 2) {
postTask();
} else if (state.pageType == 1) {
editTask();
}
}) })
.catch(() => {}); .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 () => { const useScript = async () => {
//填写完成才可以进行执行 //填写完成才可以进行执行
await useContentRef.value await useContentRef.value
...@@ -167,9 +232,53 @@ const clearData = () => { ...@@ -167,9 +232,53 @@ const clearData = () => {
useContentRef.value.clear(); useContentRef.value.clear();
state.data = {}; state.data = {};
step.value = 1; 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> </script>
<style scoped> <style scoped>
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
<el-form ref="pcFormRef" :model="state.ruleForm" :rules="state.rules" label-position="top" label-width="120px"> <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-form-item label="主机分组名称" prop="pcName" style="width: 1100px">
<el-select v-model="state.ruleForm.pcName" style="width: 1020px" clearable placeholder="请选择"> <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> </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-item>
</el-form> </el-form>
</div> </div>
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
<script setup> <script setup>
import { reactive, ref, onBeforeMount, toRefs, onMounted } from "vue"; import { reactive, ref, onBeforeMount, toRefs, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
...@@ -52,14 +53,13 @@ const state = reactive({ ...@@ -52,14 +53,13 @@ const state = reactive({
rules: { rules: {
pcName: [{ required: true, message: "请选择主机分组", trigger: "change" }], pcName: [{ required: true, message: "请选择主机分组", trigger: "change" }],
}, },
options: [ options: [],
{
label: "12",
value: "qwqw",
},
],
}); });
const gotoPage = (url) => {
router.push(url);
};
const save = () => { const save = () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
pcFormRef.value.validate((valid, fields) => { pcFormRef.value.validate((valid, fields) => {
...@@ -67,7 +67,9 @@ const save = () => { ...@@ -67,7 +67,9 @@ const save = () => {
props.data.pcName = state.ruleForm.pcName; props.data.pcName = state.ruleForm.pcName;
if (state.useType == 0) { if (state.useType == 0) {
props.data.useText = state.useText; props.data.useText = state.useText;
props.data.doc_file = [];
} else { } else {
props.data.useText = "";
props.data.doc_file = state.doc_file; props.data.doc_file = state.doc_file;
} }
resolve(); resolve();
...@@ -86,17 +88,26 @@ const clear = () => { ...@@ -86,17 +88,26 @@ const clear = () => {
state.useType = 0; 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(() => { onMounted(() => {
if ( if (
(props.data && props.data.useText == "" && props.data.doc_file.length == 0) || (props.data && props.data.useText == "" && props.data.doc_file.length == 0) ||
(!props.data.useText && !props.data.doc_file) (!props.data.useText && !props.data.doc_file)
) { ) {
state.useType = 0; state.useType = 0;
} else if (props.data && props.data.useText !== "") { } else if (props.data && props.data.useText == "") {
state.useType = 1; state.useType = 1;
} else if (props.data && props.data.doc_file.length == 0) { } else if (props.data && props.data.doc_file.length == 0) {
state.useType = 0; state.useType = 0;
} }
getPC();
}); });
defineExpose({ defineExpose({
......
...@@ -3,19 +3,15 @@ ...@@ -3,19 +3,15 @@
<bg-breadcrumb></bg-breadcrumb> <bg-breadcrumb></bg-breadcrumb>
<div class="main_container"> <div class="main_container">
<bg-form-gap title="基本信息"></bg-form-gap> <bg-form-gap title="基本信息"></bg-form-gap>
<bg-detail-table2 style="width: 1076px" :list="state.baseInfo"> <bg-detail-table2 style="width: 1076px; margin-bottom: 20px" :list="state.baseInfo"> </bg-detail-table2>
<template #status>
<span> <i class="use"></i> 启用 </span>
</template>
</bg-detail-table2>
<bg-form-gap title="执行脚本"></bg-form-gap> <bg-form-gap title="执行脚本"></bg-form-gap>
<div style="height: 260px; margin-bottom: 20px; width: 1076px"> <div v-if="state.docFile.length == 0" style="height: 260px; margin-bottom: 20px; width: 1076px">
<bg-code-editor v-model="state.useText"></bg-code-editor> <bg-code-editor :disabled="true" v-model="state.useText"></bg-code-editor>
</div> </div>
<div class="file-box"> <div class="file-box" v-for="(item, index) in state.docFile">
<bg-icon icon="#bg-ic-c-file-data"></bg-icon>&nbsp;&nbsp; 文件.yml <bg-icon icon="#bg-ic-c-file-data"></bg-icon>&nbsp;&nbsp; {{ item.name }}
<el-button type="primary" @click="downloadFile(url)" <el-button type="primary" @click="download(item.url, item.name)"
><bg-icon icon="#bg-ic-to-bottom"></bg-icon>&nbsp;&nbsp;下载</el-button ><bg-icon icon="#bg-ic-to-bottom"></bg-icon>&nbsp;&nbsp;下载</el-button
> >
</div> </div>
...@@ -38,9 +34,20 @@ ...@@ -38,9 +34,20 @@
<bg-table style="width: 1076px" :headers="state.historyHeaders" :rows="state.historyTableRows" :stripe="true"> <bg-table style="width: 1076px" :headers="state.historyHeaders" :rows="state.historyTableRows" :stripe="true">
<template v-slot:state="{ row }"> <template v-slot:state="{ row }">
<span> <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> </span>
</template> </template>
<template v-slot:exec_start_time="{ row }">
<span>{{ dateStringTransform(row.exec_start_time) }}</span>
</template>
</bg-table> </bg-table>
<div style="width: 1076px" v-if="state.tableTotal > 10"> <div style="width: 1076px" v-if="state.tableTotal > 10">
<bg-pagination <bg-pagination
...@@ -60,45 +67,43 @@ import { reactive, ref, onBeforeMount, toRefs } from "vue"; ...@@ -60,45 +67,43 @@ import { reactive, ref, onBeforeMount, toRefs } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import axios from "@/request/http.js";
import { dateStringTransform, downloadFile } from "@/services/helper.js";
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const state = reactive({ const state = reactive({
baseInfo: [ baseInfo: [
{ {
label: "预警规则名称", label: "任务名称",
value: "服务中断推送规则1", value: "",
}, },
{ {
label: "启用状态", label: "执行次数",
value: "启用", value: "",
childSlot: "status",
}, },
{ {
label: "预警对象", label: "执行成功次数",
value: "容器云", value: "",
}, },
{ {
label: "预警分类", label: "执行失败次数",
value: "容器集群", value: "",
}, },
{ {
label: "创建人", label: "创建人",
value: "admin", value: "",
}, },
{ {
label: "创建时间", label: "创建时间",
value: "2023-08-19 23:22:22", value: "",
}, },
{ {
label: "更新时间", label: "任务描述",
value: "2023-08-19 23:22:22", value: "",
},
{
label: "预警指标",
value: "CPU使用率",
}, },
], ],
useText: "", useText: "",
docFile: [],
historyHeaders: [ historyHeaders: [
{ {
label: "状态", label: "状态",
...@@ -106,19 +111,19 @@ const state = reactive({ ...@@ -106,19 +111,19 @@ const state = reactive({
}, },
{ {
label: "执行说明", label: "执行说明",
prop: "desc", prop: "exec_desc",
}, },
{ {
label: "执行开始时间", label: "执行开始时间",
prop: "begin", prop: "exec_start_time",
}, },
{ {
label: "执行耗时", label: "执行耗时(s)",
prop: "time", prop: "exec_time",
}, },
{ {
label: "操作人", label: "操作人",
prop: "person", prop: "create_user",
}, },
], ],
historyTableRows: [], historyTableRows: [],
...@@ -129,38 +134,77 @@ const state = reactive({ ...@@ -129,38 +134,77 @@ const state = reactive({
tableTotal: 0, tableTotal: 0,
pcHeaders: [ pcHeaders: [
{ {
label: "账号", label: "IP",
prop: "account", prop: "ip",
}, },
{ {
label: "端口", label: "端口",
prop: "port", prop: "port",
}, },
], ],
pcTableRows: [ pcTableRows: [],
{
account: "asasdd",
port: "8080",
},
{
account: "asasdd",
port: "8080",
},
],
}); });
const downloadFile = () => {}; const download = (url, name) => {
downloadFile(url, name);
};
const changePage = (page) => { const changePage = (page) => {
state.filter.page = page; state.filter.page = page;
getTableRows(); getTableRows();
}; };
const changeSize = (size) => { const changeSize = (size) => {
state.filter.limit = size; state.filter.size = size;
changePage(1); 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
</el-button> </el-button>
<el-button type="default" @click="deleteAllTips"> 批量删除 </el-button> <el-button type="default" @click="deleteAllTips"> 批量删除 </el-button>
<span class="header_info" <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>
<span class="header_info can_click_text" @click="clearSelected">清空</span> <span class="header_info can_click_text" @click="clearSelected">清空</span>
</div> </div>
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<el-date-picker <el-date-picker
v-model="filter.time" v-model="filter.time"
type="daterange" type="daterange"
value-format="yyyy-MM-DD" value-format="YYYY-MM-DD"
range-separator="至" range-separator="至"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" /> end-placeholder="结束日期" />
...@@ -45,13 +45,13 @@ ...@@ -45,13 +45,13 @@
:isIndex="true" :isIndex="true"
:select="true" :select="true"
:stripe="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}`)"> <span class="can_click_text" @click="gotoPage(`/auto-maintenance/task-manage/detail?id=${row.id}`)">
{{ row.name }} {{ row.task_name }}
</span> </span>
</template> </template>
<template v-slot:updated_time="{ row }"> <template v-slot:create_time="{ row }">
{{ row.updated_time.split("+")[0].replace("T", " ").replace("Z", " ") }} {{ row.create_time.split("+")[0].replace("T", " ").replace("Z", " ") }}
</template> </template>
<template v-slot:action="{ row }"> <template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :tableData="tableRows"> <bg-table-btns2 :limit="3" :tableData="tableRows">
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
</div> </div>
<bg-pagination <bg-pagination
:page="filter.page" :page="filter.page"
:size="filter.size" :size="filter.page_size"
:total="tableTotal" :total="tableTotal"
@change-page="changePage" @change-page="changePage"
@change-size="changeSize"> @change-size="changeSize">
...@@ -128,25 +128,26 @@ const dataTable = ref(null); ...@@ -128,25 +128,26 @@ const dataTable = ref(null);
const headers = [ const headers = [
{ {
label: "任务名称", label: "任务名称",
prop: "name", prop: "task_name",
width: 200,
}, },
{ {
label: "执行次数", label: "执行次数",
prop: "times", prop: "exec_cnt",
}, },
{ {
label: "描述", label: "描述",
prop: "describe", prop: "task_desc",
minWidth: 360, minWidth: 300,
}, },
{ {
label: "创建人", label: "创建人",
prop: "person", prop: "create_user",
}, },
{ {
label: "创建时间", label: "创建时间",
prop: "updated_time", prop: "create_time",
width: 220, width: 180,
}, },
{ {
label: "操作", label: "操作",
...@@ -157,28 +158,22 @@ const headers = [ ...@@ -157,28 +158,22 @@ const headers = [
]; ];
const state = reactive({ const state = reactive({
tableRows: [ tableRows: [], // 表格数据
{
name: 23123,
times: 1,
describe: 12313,
person: 21323,
updated_time: "2021-01-01+TZ",
},
], // 表格数据
selected: [], //选择数据 selected: [], //选择数据
selectedNum: 0, //选择数据数量
tableTotal: 0, // 表格数据条数 tableTotal: 0, // 表格数据条数
filter: { filter: {
time: "", time: "",
search: "", search: "",
page: 1, page: 1,
limit: 10, page_size: 10,
}, // 表格筛选项 }, // 表格筛选项
actionRow: null, // 当前操作的数据 actionRow: null, // 当前操作的数据
dialogDelete: false, // 删除弹窗 dialogDelete: false, // 删除弹窗
useScriptShow: false, useScriptShow: false,
useType: 0, useType: 0,
useData: ["yaml", "json"], useData: ["yaml", "json"],
deleteType: 0, //0单个删除,1批量删除
}); });
const useRow = (row) => { const useRow = (row) => {
...@@ -197,13 +192,38 @@ const confirmUse = () => { ...@@ -197,13 +192,38 @@ const confirmUse = () => {
const deleteRow = (row) => { const deleteRow = (row) => {
state.actionRow = row; state.actionRow = row;
state.dialogDelete = true; state.dialogDelete = true;
state.deleteType = 0;
}; };
const deleteData = () => { const deleteData = () => {
state.dialogDelete = false; 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) => { const selectRows = (data) => {
state.selectedNum = data.allLength;
state.selected = data.selection; state.selected = data.selection;
}; };
...@@ -214,6 +234,7 @@ const clearSelected = () => { ...@@ -214,6 +234,7 @@ const clearSelected = () => {
const deleteAllTips = () => { const deleteAllTips = () => {
if (state.selected.length > 0) { if (state.selected.length > 0) {
state.dialogDelete = true; state.dialogDelete = true;
state.deleteType = 1;
} else { } else {
ElMessage.error("请先选择要删除任务"); ElMessage.error("请先选择要删除任务");
} }
...@@ -236,21 +257,30 @@ const filterClear = () => { ...@@ -236,21 +257,30 @@ const filterClear = () => {
state.filter = { state.filter = {
time: "", time: "",
search: "", search: "",
limit: 10,
page: 1, page: 1,
page_size: 10,
}; };
changePage(1); changePage(1);
}; // 重置筛选项 }; // 重置筛选项
const getTableRows = () => { const getTableRows = () => {
let params = { ...state.filter }; 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 axios
.get(`/apaas/system/v5/dictionary/list`, { .get(`/v1/api/automated_mainten/task_manage/list`, {
params, params,
}) })
.then((res) => { .then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
let data = res.data.data || []; let data = res.data.data || [];
state.tableRows = data;
state.tableTotal = res.data.total;
} else { } else {
ElMessage.error(res.data.data); ElMessage.error(res.data.data);
} }
...@@ -263,11 +293,13 @@ const changePage = (page) => { ...@@ -263,11 +293,13 @@ const changePage = (page) => {
}; // 改变页码 }; // 改变页码
const changeSize = (size) => { const changeSize = (size) => {
state.filter.limit = size; state.filter.page_size = size;
changePage(1); changePage(1);
}; // 改变每页条数 }; // 改变每页条数
onBeforeMount(() => {}); onBeforeMount(() => {
getTableRows();
});
const { tableRows, tableTotal, filter } = toRefs(state); const { tableRows, tableTotal, filter } = toRefs(state);
</script> </script>
...@@ -275,7 +307,6 @@ const { tableRows, tableTotal, filter } = toRefs(state); ...@@ -275,7 +307,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
<style lang="scss" scoped> <style lang="scss" scoped>
.detail_container { .detail_container {
width: 100%; width: 100%;
height: calc(100vh - 56px);
padding: 0 24px; padding: 0 24px;
min-height: 100%; min-height: 100%;
display: flex; display: flex;
...@@ -304,9 +335,6 @@ const { tableRows, tableTotal, filter } = toRefs(state); ...@@ -304,9 +335,6 @@ const { tableRows, tableTotal, filter } = toRefs(state);
height: calc(100% - 70px); height: calc(100% - 70px);
width: 100%; width: 100%;
padding: 0 16px; 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>
This diff is collapsed.
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.
...@@ -65,9 +65,9 @@ export default { ...@@ -65,9 +65,9 @@ export default {
changeOrigin: true, // true/false, Default: false - changes the origin of the host header to the target URL changeOrigin: true, // true/false, Default: false - changes the origin of the host header to the target URL
secure: false, //解决证书缺失问题 secure: false, //解决证书缺失问题
}, },
"/v1/api": { "/v1": {
target: "https://so.wodcloud.com/v1/api", // 所要代理的目标地址 target: "https://so.wodcloud.com/v1", // 所要代理的目标地址
rewrite: (path) => path.replace(/^\/v1\/api/, ""), // 重写传过来的path路径,比如 `/api/index/1?id=10&name=zs`(注意:path路径最前面有斜杠(/),因此,正则匹配的时候不要忘了是斜杠(/)开头的;选项的 key 也是斜杠(/)开头的) rewrite: (path) => path.replace(/^\/v1/, ""), // 重写传过来的path路径,比如 `/api/index/1?id=10&name=zs`(注意:path路径最前面有斜杠(/),因此,正则匹配的时候不要忘了是斜杠(/)开头的;选项的 key 也是斜杠(/)开头的)
changeOrigin: true, // true/false, Default: false - changes the origin of the host header to the target URL changeOrigin: true, // true/false, Default: false - changes the origin of the host header to the target URL
secure: false, //解决证书缺失问题 secure: false, //解决证书缺失问题
}, },
......
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