Authored by 王涛

Merge branch 'master-v32-lushangqing' into 'master'

【#1162】 实现页面批量更改主辅负责人的操作,在各组更换业务相关负责人时,能在页面进行批量更改。-主页面搭建 #1



See merge request !616
@@ -193,7 +193,10 @@ layui.define(['table', 'form', 'admin', 'layer', 'upload', 'common', 'sessions', @@ -193,7 +193,10 @@ layui.define(['table', 'form', 'admin', 'layer', 'upload', 'common', 'sessions',
193 { 193 {
194 title: '操作', fixed: 'right', align: 'center',minWidth: 230, 194 title: '操作', fixed: 'right', align: 'center',minWidth: 230,
195 templet: '<div>' + 195 templet: '<div>' +
196 - '<button data-id="{{d.id}}" lay-tips="删除" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_delete_btn"><i class="layui-icon layui-icon-delete"></i></button>'+ 196 + //lsq 新增变更按钮 2022-05-30
  197 + '<button data-username="{{d.username}}" lay-tips="人员相关业务变更" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_batch_change_leaders_btn"><i class="layui-icon layui-icon-edit"></i></button>'+
  198 +
  199 + '<button data-id="{{d.id}}" lay-tips="删除" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_delete_btn"><i class="layui-icon layui-icon-delete"></i></button>'+
197 '<button data-id="{{d.id}}" data-username="{{d.username}}" lay-tips="重置密码" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_pass_btn"><i class="layui-icon layui-icon-password"></i></button>'+ 200 '<button data-id="{{d.id}}" data-username="{{d.username}}" lay-tips="重置密码" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_pass_btn"><i class="layui-icon layui-icon-password"></i></button>'+
198 '<button data-username="{{d.username}}" lay-tips="资源类型授权" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_resType_authorization_btn"><i class="layui-icon layui-icon-app"></i></button>'+ 201 '<button data-username="{{d.username}}" lay-tips="资源类型授权" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_resType_authorization_btn"><i class="layui-icon layui-icon-app"></i></button>'+
199 '<button data-username="{{d.username}}" lay-tips="业务授权" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_busType_authorization_btn"><i class="layui-icon layui-icon-menu-fill"></i></button>'+ 202 '<button data-username="{{d.username}}" lay-tips="业务授权" type="button" class="layui-btn layui-btn-xs layui-btn-normal user_busType_authorization_btn"><i class="layui-icon layui-icon-menu-fill"></i></button>'+
@@ -283,6 +286,37 @@ layui.define(['table', 'form', 'admin', 'layer', 'upload', 'common', 'sessions', @@ -283,6 +286,37 @@ layui.define(['table', 'form', 'admin', 'layer', 'upload', 'common', 'sessions',
283 } 286 }
284 }) 287 })
285 } 288 }
  289 + //start lsq 人员相关业务批量变更 2022-05-30
  290 + $('.user_batch_change_leaders_btn').unbind().on('click',function () {
  291 + if ($.inArray('back:user:impower',permissionList) == -1) {
  292 + layer.msg('暂无权限',{icon: 7,time:3000})
  293 + return false;
  294 + }
  295 + let param = {
  296 + username: $(this).data('username'),
  297 + resName: ''
  298 + }
  299 + let urlParams='';
  300 + for(let key in param){
  301 + if(param[key]){
  302 + urlParams+=key+'='+param[key]+'&'
  303 + }
  304 + }
  305 + urlParams=urlParams.substr(0,urlParams.length-1)
  306 + layer.open({
  307 + title: ['相关业务批量变更', 'font-size:18px;'],
  308 + type: 2,
  309 + area: ['80%', '90%'],
  310 + shadeClose: true,//开启遮罩层
  311 + id: 'kpi_line_chart_div',
  312 + content: ['/vue3/index.html#/vue3/batchChangeLeaders?'+urlParams, 'no'],
  313 + cancel: function () {
  314 + // clearTimeout(obj.lineTimer);
  315 + }
  316 + });
  317 + });
  318 + //end lsq 2022-05-30
  319 +
286 // 配置默认首页 320 // 配置默认首页
287 $('.user-config-default-index').unbind('click').on('click', function () { 321 $('.user-config-default-index').unbind('click').on('click', function () {
288 var username = $(this).data('username'); 322 var username = $(this).data('username');
@@ -83,6 +83,11 @@ const routes = [{ @@ -83,6 +83,11 @@ const routes = [{
83 name: 'connectScatter', 83 name: 'connectScatter',
84 component: () => myImport('views/connectScatter/index') 84 component: () => myImport('views/connectScatter/index')
85 }, 85 },
  86 + {
  87 + path: '/vue3/batchChangeLeaders',
  88 + name: 'batchChangeLeaders',
  89 + component: () => myImport('views/batchChangeLeaders/index')
  90 + }
86 ]; 91 ];
87 92
88 // hash模式: createWebHashHistory 93 // hash模式: createWebHashHistory
  1 +<div class="batchChange-container" style="padding:10px;">
  2 + <el-row >
  3 + <el-col :span="24">
  4 + <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
  5 + <el-tab-pane v-for="(item,index) in tabData" :key="index" :label="item.name" :name="item.code">
  6 +
  7 + <div class="table-container" v-if="item.code=='resourcePer'">
  8 +
  9 + <el-row>
  10 + <el-col :span="24" class="search">
  11 + <div class="condition" style="display: flex;">
  12 + <el-form-item style="margin-right: 6px;margin-bottom: 10px;">
  13 + <el-input v-model="search.keyword" placeholder="请输入关键字"></el-input>
  14 + </el-form-item>
  15 + <el-form-item style="margin-right: 6px;margin-bottom: 10px;">
  16 + <el-select clearable multiple v-model="search.resType" placeholder="请选择资源类型">
  17 + <el-option
  18 + v-for="item in resTypeOptions"
  19 + :key="item.kpiId"
  20 + :label="item.kpiName"
  21 + :value="item.kpiId">
  22 + <span style="float: left">{{ item.kpiId }}</span>
  23 + <span style="float: right;color: var(--el-text-color-secondary);font-size: 13px;">{{ item.kpiName }}</span>
  24 + </el-option>
  25 + </el-select>
  26 + </el-form-item>
  27 + <el-form-item style="margin-right: 6px;margin-bottom: 10px;">
  28 + <el-button @click="getListData">查询</el-button>
  29 + </el-form-item>
  30 + </div>
  31 + </el-col>
  32 + </el-row>
  33 + <el-row style="margin-bottom: 10px;">
  34 + <div class="flex-div-start">
  35 + <el-button type="primary" @click="save()" size="small">取消</el-button>
  36 + <el-button type="primary" @click="conserve()" size="small" style="margin-left: 6px">变更</el-button>
  37 + <el-button type="primary" @click="conserve()" size="small" style="margin-left: 6px">导出</el-button>
  38 + </div>
  39 + </el-row>
  40 + <el-row class="margin-bottom-50" style="margin-top: 3px">
  41 + <el-col :span="24" class="table-height">
  42 + <cm-table-page :columns="columns"
  43 + :dataList="portSenseConfigData"
  44 + :total="count"
  45 + :pageSize="pageSize"
  46 + @loaddata="loadTableDataList"
  47 + @selectionChange="selectionChange"
  48 + :showIndex="true"
  49 + :showSelection="true"
  50 + :showBorder="true"
  51 + :loading="loading"
  52 + :showPage="true"
  53 + :showTools="false"
  54 + :height="(height - 200)">
  55 + <template #default="{row,prop,column}">
  56 + <!-- <div v-if="prop == 'protocolType'">
  57 + <el-select placeholder="请选择" size="small" style="width: 100%"
  58 + @change="changePortSense(row,prop,column)" v-model="row.protocolType"
  59 + :multiple="false"
  60 + collapse-tags clearable filterable placeholder="请选择">
  61 + <el-option label="TCP协议" :value="'tcp-port'"></el-option>
  62 + <el-option label="UDP协议" :value="'udp-port'"></el-option>
  63 + </el-select>
  64 + </div>
  65 + <div v-else>
  66 + <el-input @blur="changePortSense(row,prop,column)"
  67 + :type="prop == intervalTime ? 'number' : 'text'"
  68 + size="small" placeholder="请填写"v-model="row[prop]">
  69 + <template #suffix>
  70 + <i class="el-icon-edit-outline"/>
  71 + </template>
  72 + </el-input>
  73 + </div>-->
  74 + </template>
  75 + <!-- <template #tools="{scope}">
  76 + <el-button type="text" size="small" @click.prevent="deleteItem(scope.row,scope.$index)">
  77 + <i class="el-icon-delete"/>
  78 + </el-button>
  79 + </template>-->
  80 + </cm-table-page>
  81 + </el-col>
  82 + </el-row>
  83 + </div>
  84 + <div class="table-container" v-else>{{item.name}}</div>
  85 + </el-tab-pane>
  86 + </el-tabs>
  87 +
  88 + </el-col>
  89 + </el-row>
  90 +</div>
  1 +export default {
  2 + name: 'portSense',
  3 + template: '',
  4 + components: {
  5 + //资源下拉框
  6 + 'port-sense-select': Vue.defineAsyncComponent(
  7 + () => myImport('views/portSenseSelect/index')
  8 + ),
  9 + },
  10 + data() {
  11 + },
  12 + props: {
  13 + parameter: {
  14 + type: Array,
  15 + default: []
  16 + }
  17 + },
  18 + setup: function (props, {attrs, slots, emit}) {
  19 + const {proxy} = Vue.getCurrentInstance();
  20 + const tabData=Vue.ref([
  21 + {name:'资源权限',code:'resourcePer'},
  22 + {name:'资源负责人',code:'resourceLeader'},
  23 + {name:'资源类型权限',code:'resourceTypePer'},
  24 + {name:'业务(乙方运维)权限',code:'bizPer'},
  25 + {name:'业务负责人',code:'bizLeader'},
  26 + {name:'告警订阅权限',code:'alarmSubPer'},
  27 + {name:'角色权限',code:'rolePer'},
  28 + {name:'拓扑负责人',code:'topoPer'},
  29 + {name:'自动化巡检报表权限',code:'autoPatrolPortPer'},
  30 + {name:'文档管理权限',code:'fileManagePer'}
  31 + ])
  32 + const activeName = Vue.ref(tabData.value[0].code)
  33 + const handleClick = (tab, event) => {
  34 + console.log(tab, event)
  35 + }
  36 + let showTypeList=Vue.ref([]);
  37 + let search = Vue.ref({
  38 + resType: '',
  39 + keyword: '',
  40 + page: 1,
  41 + limit: 20,
  42 + });
  43 + let resTypeOptions=Vue.ref([])
  44 +
  45 +
  46 + const columns = [
  47 + {
  48 + prop: 'resName',
  49 + label: '资源名称',
  50 + sortable: true,
  51 + align: 'center',
  52 + },
  53 + {
  54 + prop: 'ip',
  55 + label: 'IP地址',
  56 + sortable: true,
  57 + align: 'center',
  58 + },
  59 + {
  60 + prop: 'port',
  61 + label: '端口号',
  62 + sortable: true,
  63 + align: 'center',
  64 + },
  65 + {
  66 + prop: 'admin',
  67 + label: '负责人',
  68 + sortable: true,
  69 + align: 'center',
  70 + },
  71 + {
  72 + prop: 'resTypeName',
  73 + label: '资源类型',
  74 + sortable: true,
  75 + align: 'center',
  76 + },
  77 + {
  78 + prop: 'state',
  79 + label: '资源状态',
  80 + sortable: true,
  81 + align: 'center',
  82 + render: function (row) {
  83 + switch (row.state) {
  84 + case "new" :
  85 + return '<button type="button" class="layui-btn layui-btn-warm layui-bg-gray layui-btn-radius layui-btn-xs p-0-15">未监控</button>'
  86 + case "monitor" :
  87 + return '<button type="button" class="layui-btn layui-btn-radius layui-bg-green layui-btn-xs p-0-15" style="background-color: #0BAC33 !important;">监控中</button>'
  88 + case "stop" :
  89 + return '<button type="button" class="layui-btn layui-btn-warm layui-bg-red layui-btn-radius layui-btn-xs p-0-15">暂停</button>'
  90 + default :
  91 + return '<button type="button" class="layui-btn layui-btn-warm layui-bg-gray layui-btn-radius layui-btn-xs p-0-15">未监控</button>'
  92 + }
  93 + }
  94 + },
  95 + {
  96 + prop: 'paramDesc',
  97 + label: '展示类型',
  98 + sortable: true,
  99 + align: 'center',
  100 + render: function (row) {
  101 + if(row.resType == 'HOST_X86SERVER'){
  102 + //初始化select内容
  103 + /* var html='<div><select data-resId="'+d.resId+'" data-username="'+username+'" data-index="99" name="showType" class="layui-input user_showType" style="min-width: 150px;display: inline">';
  104 + showTypeList.value.map((v,i)=>{
  105 + if(d.showType == v.value){
  106 + html += '<option value="' + v.value + '" selected>' + v.name + '</option> '
  107 + }else{
  108 + html += '<option value="' + v.value + '">' + v.name + '</option> '
  109 + }
  110 + })
  111 + html+='</select></div>';
  112 + return html;*/
  113 + }else{
  114 + return '';
  115 + }
  116 + }
  117 + }
  118 + ];
  119 + //配置列表总数
  120 + let count = Vue.ref(0);
  121 + //列表数据
  122 + let portSenseConfigData = Vue.ref([]);
  123 + //数据库的数据
  124 + let portSenseConfigList = Vue.ref([]);
  125 + //资源数据
  126 + let resIdArr = Vue.ref([]);
  127 + //列表高度
  128 + let height = Vue.ref(window.innerHeight);
  129 + //列表分页
  130 + let pageSize = Vue.ref(400);
  131 + //加载
  132 + let loading = Vue.ref(true);
  133 + //选中数据
  134 + let pitch = Vue.ref([]);
  135 + //下拉框数据
  136 + let portSenseSelectData = Vue.ref([]);
  137 +
  138 + //获取列表数据
  139 + const getListData = ({page, limit}) => {
  140 + //获取传递过来的参数
  141 + resIdArr.value = JSON.parse(JSON.stringify(props.parameter));
  142 + //传递参数赋值给下拉框
  143 + portSenseSelectData.value = resIdArr.value;
  144 +
  145 + let username=proxy.$route.query.username;
  146 + let resName=proxy.$route.query.resName;
  147 + //定义列表参数
  148 + let getParams = {
  149 + resIds: resIdArr.value.join(','),
  150 + resName: resName,
  151 + userId: username,
  152 + page: page,
  153 + limit: limit
  154 + };
  155 + proxy.$http.get("/api-web/manage/resource/getAllResByUser", getParams, function (res) {
  156 + if (res && res.success) {
  157 + portSenseConfigData.value = res.data ? res.data : [];
  158 + count.value = res.count;
  159 + loading.value = false;
  160 + portSenseConfigList.value = res.data ? JSON.parse(JSON.stringify(res.data)) : [];
  161 + }
  162 + })
  163 + }
  164 +
  165 + //表格全选事件
  166 + let selectionChange = (val) => {
  167 + pitch.value = val;
  168 + proxy.portSenseConfigData.map((v, i) => {
  169 + v.checked = false;
  170 + });
  171 + let selectData = val;
  172 + if (selectData.length > 0) {
  173 + selectData.map((item, index) => {
  174 + proxy.portSenseConfigData.map((v, i) => {
  175 + if (item.id == v.id) {
  176 + v.checked = true;
  177 + }
  178 + })
  179 + })
  180 + } else {
  181 + proxy.portSenseConfigData.map((v, i) => {
  182 + v.checked = false;
  183 + })
  184 + }
  185 + }
  186 + //删除单个数据
  187 + let deleteItem = (row, index) => {
  188 + proxy.$global.confirm("确认删除吗?", function () {
  189 + deleteItems(row, index);
  190 + })
  191 + }
  192 + //删除多个或单个
  193 + let deleteItems = (row, index) => {
  194 + //新添加未保存的
  195 + let sign = deleteNotSave(row, index);
  196 + if (sign) {
  197 + return false;
  198 + }
  199 + proxy.$http.post('/api-web/bResourceExtendParam/deleteConfig', row, function (res) {
  200 + if (res && res.success) {
  201 + proxy.$global.showMsg('删除成功');
  202 + loadTableDataList({page: 1, limit: pageSize.value});
  203 + }
  204 + })
  205 + }
  206 + //删除新添加但未保存的
  207 + let deleteNotSave = (row, index) => {
  208 + let sign = false;
  209 + let list = portSenseConfigData.value;
  210 + if(row.id === ""){
  211 + portSenseConfigData.value = list.filter((item, i, array) => index !== i);
  212 + }
  213 + if (list.length > portSenseConfigData.value.length) {
  214 + proxy.$global.showMsg('删除成功');
  215 + sign = true;
  216 + }
  217 + return sign;
  218 + }
  219 + //新增 添加一行数据
  220 + let save = () => {
  221 + let data = {
  222 + id: "",
  223 + intervalTime: null,
  224 + paramCode: "",
  225 + paramDesc: "",
  226 + paramValue: "",
  227 + port: "",
  228 + portDesc: "",
  229 + protocolType: "",
  230 + resId: "",
  231 + resIdList: resIdArr.value,
  232 + }
  233 + portSenseConfigData.value.push(data);
  234 + }
  235 + //下拉框值改变事件
  236 + let changePortSense = () => {
  237 +
  238 + }
  239 + //保存
  240 + let conserve = () => {
  241 + //数据验证
  242 + let msg = verifyData();
  243 + if (msg !== "") {
  244 + proxy.$global.showMsg(msg, "warning");
  245 + return false;
  246 + }
  247 + //逻辑验证
  248 + let identifying = isSave();
  249 + if (identifying !== "") {
  250 + proxy.$global.showMsg(identifying, "warning");
  251 + return false;
  252 + }
  253 + proxy.$http.post("/api-web/bResourceExtendParam/conserve", portSenseConfigData.value, function (res) {
  254 + if (res && res.success) {
  255 + proxy.$global.showMsg("保存成功!");
  256 + loadTableDataList({page: 1, limit: pageSize.value});
  257 + }
  258 + })
  259 + }
  260 + //保存表单验证
  261 + let verifyData = () => {
  262 + let msg = "";
  263 + //协议类型不能为空,端口备注不能为空,端口号请输入数字,间隔时长请输入数字,
  264 + let list = portSenseConfigData.value;
  265 + let li = columns.filter(item => "paramDesc" !== item.prop);
  266 + list.forEach(function (item, index, arr) {
  267 + li.forEach(function (e, i, array) {
  268 + if (item[e.prop] == null || item[e.prop] === '') {
  269 + msg = e.label + '不能为空';
  270 + } else {
  271 + if (['protocolType', 'portDesc'].indexOf(e.prop) === -1 && !/^\d+$/.test(item[e.prop])) {
  272 + msg = e.label + '请输入数字';
  273 + }else{
  274 + if(['protocolType', 'portDesc'].indexOf(e.prop) === -1 && item[e.prop].length>=8){
  275 + msg = e.label + '不能超过8位';
  276 + }else{
  277 + if(['protocolType', 'portDesc'].indexOf(e.prop) === -1 && item[e.prop]<=0){
  278 + msg = e.label + '只能大于零';
  279 + }
  280 + }
  281 + }
  282 + }
  283 + })
  284 + })
  285 + return msg
  286 + }
  287 + //是否可以保存
  288 + let isSave = () => {
  289 + let msg = "";
  290 + //零个资源不用判断
  291 + if (resIdArr.value.length === 0) {
  292 + return "必须选中资源";
  293 + }
  294 + //单个资源不用判断
  295 + if (resIdArr.value.length === 1) {
  296 + return msg;
  297 + }
  298 + //多个资源时,如果当前已选资源中存在列表新增加的协议类型和端口号对应的数据时,提示不允许进行保存,提示信息中必须包含资源名称+端口类型、端口号,
  299 + let list = [];
  300 + let arr = [];
  301 + portSenseConfigData.value.forEach(item => {
  302 + item.resIdList.forEach(map => {
  303 + let obj = Object.assign({}, item);
  304 + obj["resId"] = map;
  305 + obj["resIdList"] = [map];
  306 + list.push(obj);
  307 + })
  308 + });
  309 + //查看当前页面数据是否重复
  310 + groupByCount(list, arr);
  311 + if (arr.length > 0) {
  312 + return arr.join(',');
  313 + }
  314 + //查看当前页面数据跟数据库是否重复
  315 + let presentArray = [];
  316 + //过滤不是新增的数据
  317 + list = list.filter(item => item.id === "");
  318 + resIdArr.value.forEach(item => {
  319 + let li = [];
  320 + let getParams = {
  321 + resIds: item,
  322 + page: 1,
  323 + limit: 9999
  324 + };
  325 + proxy.$http.get("/api-web/bResourceExtendParam/portSensePage", getParams, function (res) {
  326 + if (res && res.success) {
  327 + li = res.data ? res.data : [];
  328 + list.forEach(e => {
  329 + li.forEach(map => {
  330 + if (map.resId === e.resId && map.paramCode === e.protocolType && map.port === e.port) {
  331 + let obj = Object.assign({}, e);
  332 + obj["resName"] = map.resName;
  333 + presentArray.push(obj);
  334 + }
  335 + });
  336 + });
  337 + }
  338 + }, null, null, null, false);
  339 + });
  340 + presentArray.forEach(item => {
  341 + let str = item.resName + "的" + item.paramCode.split("-")[0] + "协议" + "侦测的" + item.port + "端口号已侦测";
  342 + arr.push(str);
  343 + })
  344 + msg = arr.join(',');
  345 + return msg;
  346 + }
  347 + //重新加载表格数据
  348 + let loadTableDataList = ({page, limit}) => {
  349 + getListData({page, limit});
  350 + }
  351 + //修改父组件的值
  352 + let selectRes = (item) => {
  353 + portSenseConfigData.value = item;
  354 + }
  355 + //数组查找重复数据并统计行数
  356 + let groupByCount = (arr, array) => {
  357 + let list = [];
  358 + arr.sort((a, b) => {
  359 + if (a.resId !== b.resId) {
  360 + return a.resId < b.resId ? -1 : 1;
  361 + } else {
  362 + return a.name < b.name ? -1 : 1;
  363 + }
  364 + });
  365 + for (let i = 0; i < arr.length;) {
  366 + let count = 0;
  367 + for (let j = i; j < arr.length; j++) {
  368 + if (arr[i].resId === arr[j].resId && arr[i].protocolType === arr[j].protocolType && arr[i].port === arr[j].port) {
  369 + count++;
  370 + }
  371 + }
  372 + list.push({array: arr[i], count: count});
  373 + i += count;
  374 + }
  375 + list.forEach(item => {
  376 + if (item.count > 1) {
  377 + let str = item.array.resName + "的" + item.array.paramCode.split("-")[0] + "协议" + "侦测的" + item.array.port + "端口号已侦测";
  378 + array.push(str);
  379 + }
  380 + })
  381 + }
  382 +
  383 +
  384 + //获取展示类型的字典数据
  385 + let initShowType=()=>{
  386 + proxy.$http.get("/api-web/manage/resource/getAllResByUser", getParams, function (res) {
  387 + if (res && res.success) {
  388 + let arr=res.data;
  389 + if(arr && arr.length>0){
  390 + arr.map(v=>{
  391 + showTypeList.value.push({
  392 + name: v.ddicName
  393 + ,value: v.ddicCode.substring(v.ddicCode.lastIndexOf("_")+1,v.ddicCode.length)
  394 + });
  395 + })
  396 + }
  397 +
  398 + }
  399 + })
  400 + }
  401 + // 挂载完
  402 + Vue.onMounted(() => {
  403 + getListData({page: 1, limit: pageSize.value});
  404 + })
  405 + return {
  406 + activeName,
  407 + handleClick,
  408 + tabData,
  409 + initShowType,
  410 + showTypeList,
  411 + search,
  412 + resTypeOptions,
  413 +
  414 + count,
  415 + portSenseConfigData,
  416 + columns,
  417 + height,
  418 + pageSize,
  419 + loading,
  420 +
  421 + selectionChange,
  422 + deleteItem,
  423 + save,
  424 + getListData,
  425 + loadTableDataList,
  426 + changePortSense,
  427 + conserve,
  428 + selectRes,
  429 +
  430 + portSenseSelectData
  431 + }
  432 + }
  433 +}