Browse Source

配置项编辑

zhangjie 2 năm trước cách đây
mục cha
commit
b7a6db1ed1

+ 3 - 0
src/assets/styles/base.scss

@@ -456,6 +456,9 @@ body {
 .mb-4 {
   margin-bottom: 20px;
 }
+.width-full {
+  width: 100%;
+}
 
 // other
 .tips-info {

+ 82 - 0
src/assets/styles/home.scss

@@ -298,3 +298,85 @@
     }
   }
 }
+
+.table-part {
+  margin-bottom: 30px;
+
+  &-title {
+    margin-bottom: 10px;
+    font-size: 16px;
+
+    &::before {
+      content: "";
+      display: inline-block;
+      vertical-align: middle;
+      width: 0;
+      height: 0;
+      border: 5px solid $--color-primary;
+      margin-right: 10px;
+    }
+  }
+}
+
+// config-manage-dialog
+.config-manage-dialog {
+  .el-dialog__body {
+    height: 100%;
+    overflow: hidden;
+    display: flex;
+    justify-content: space-between;
+    align-items: stretch;
+    flex-direction: column;
+  }
+
+  .part-box-filter,
+  .tab-btns {
+    flex-shrink: 0;
+    flex-grow: 0;
+  }
+  .config-table {
+    flex-grow: 2;
+
+    display: flex;
+    justify-content: space-between;
+    align-items: stretch;
+
+    &-guide {
+      width: 300px;
+      flex-shrink: 0;
+      flex-grow: 0;
+      margin-bottom: 0;
+      li {
+        padding: 10px 5px;
+        line-height: 20px;
+        border-bottom: 1px dashed $--color-text-gray-5;
+        cursor: pointer;
+
+        &:first-child {
+          border-top: 1px dashed $--color-text-gray-5;
+        }
+
+        &:hover {
+          color: $--color-primary;
+        }
+      }
+    }
+
+    &-body {
+      flex-grow: 2;
+      margin-bottom: 0;
+      margin-left: 20px;
+      overflow-x: hidden;
+      overflow-y: auto;
+      position: relative;
+      &::after {
+        content: "";
+        display: block;
+        height: 100%;
+      }
+    }
+    .table-part {
+      position: relative;
+    }
+  }
+}

+ 137 - 34
src/modules/admin/components/AppConfigManage.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-config-manage">
     <el-dialog
-      class="page-dialog"
+      class="page-dialog config-manage-dialog"
       :visible.sync="modalIsShow"
       title="应用配置管理"
       :close-on-click-modal="false"
@@ -61,25 +61,66 @@
         </el-button>
       </div>
 
-      <div class="part-box part-box-pad">
-        <el-table ref="TableList" :data="configList">
-          <el-table-column prop="key" label="配置项"> </el-table-column>
-          <el-table-column prop="value" label="配置值"> </el-table-column>
-          <el-table-column prop="mode" label="模式">
-            <span slot-scope="scope">{{ modeMap[scope.row.mode] }}</span>
-          </el-table-column>
-          <el-table-column prop="comment" label="注释"> </el-table-column>
-          <el-table-column label="操作" width="80" class-name="action-column">
-            <template slot-scope="scope">
+      <div class="config-table">
+        <div class="part-box part-box-pad config-table-guide">
+          <ul>
+            <li
+              v-for="group in groupConfigList"
+              :key="group.name"
+              @click="scrollTo(group)"
+            >
+              {{ group.name }}
+            </li>
+          </ul>
+        </div>
+
+        <div
+          ref="ConfigTableBody"
+          class="part-box part-box-pad config-table-body"
+        >
+          <div
+            v-for="group in groupConfigList"
+            :key="group.name"
+            class="table-part"
+            :id="group.name"
+          >
+            <div class="box-justify mb-2">
+              <h3 class="table-part-title">
+                {{ group.name | groupNameFilter }}
+              </h3>
               <el-button
-                class="btn-primary"
-                type="text"
-                @click="toEdit(scope.row)"
-                >编辑</el-button
+                v-if="group.name !== 'custom' && !IS_BASELINE"
+                size="mini"
+                type="primary"
+                @click="toAddGroupConfigItem(group)"
+                >新增</el-button
+              >
+            </div>
+            <el-table ref="TableList" :data="group.children" border>
+              <el-table-column prop="key" label="配置项"> </el-table-column>
+              <el-table-column prop="value" label="配置值"> </el-table-column>
+              <el-table-column prop="mode" label="模式" width="100">
+                <span slot-scope="scope">{{ modeMap[scope.row.mode] }}</span>
+              </el-table-column>
+              <el-table-column prop="comment" label="注释"> </el-table-column>
+              <el-table-column
+                label="操作"
+                width="80"
+                class-name="action-column"
               >
-            </template>
-          </el-table-column>
-        </el-table>
+                <template slot-scope="scope">
+                  <el-button
+                    v-if="scope.row.mode !== 'READONLY'"
+                    class="btn-primary"
+                    type="text"
+                    @click="toEdit(scope.row)"
+                    >编辑</el-button
+                  >
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </div>
       </div>
     </el-dialog>
 
@@ -93,12 +134,14 @@
     <modify-app-baseline-item
       ref="ModifyAppBaselineItem"
       :instance="curBaselineItem"
+      :modes="configModes"
       @modified="baselineItemModified"
     ></modify-app-baseline-item>
     <!-- ModifyAppConfigItem -->
     <modify-app-config-item
       ref="ModifyAppConfigItem"
       :instance="curConfigItem"
+      :group="curGroupForAdd"
     ></modify-app-config-item>
   </div>
 </template>
@@ -126,6 +169,11 @@ export default {
       }
     }
   },
+  filters: {
+    groupNameFilter(val) {
+      return val === "custom" ? "应用配置自定义" : val;
+    }
+  },
   data() {
     return {
       modalIsShow: false,
@@ -159,12 +207,19 @@ export default {
       baselineCaches: {},
       baselineList: [],
       curBaselineItem: {},
+      configModes: [],
       modeMap: {},
       envList: [],
       configGroups: [],
+      curGroupForAdd: null,
       groupConfigList: []
     };
   },
+  computed: {
+    IS_BASELINE() {
+      return this.filter.envId === null;
+    }
+  },
   methods: {
     async visibleChange() {
       await this.getConfigModes();
@@ -207,6 +262,7 @@ export default {
       if (Object.keys(this.modeMap).length) return;
 
       const data = await appConfigModes();
+      this.configModes = data;
       let modeMap = {};
       data.forEach(({ code, name }) => {
         modeMap[code] = name;
@@ -236,6 +292,7 @@ export default {
         await this.getBaselineList();
         this.buildGroupConfigList(this.baselineList);
       }
+      this.$refs.ConfigTableBody.scrollTop = 0;
     },
     getCacheBaselineList() {
       const k = [
@@ -262,16 +319,26 @@ export default {
 
       const data = await appConfigBaseline(this.searchFilter);
       this.setCacheBaselineList(data);
+      this.baselineList = data;
     },
     async getConfigList() {
       await this.getBaselineList();
       const data = await appConfigList(this.searchFilter);
-      // TODO:merge config data
-      this.configList = data;
+
+      let configList = this.baselineList.map(item => {
+        return { ...item };
+      });
+      data.forEach(item => {
+        let bIndex = configList.findIndex(citem => citem.key === item.key);
+        if (bIndex !== -1) {
+          configList[bIndex] = { ...item };
+        } else {
+          configList.push({ ...item });
+        }
+      });
+      this.configList = configList;
     },
     buildGroupConfigList(dataList) {
-      console.log(dataList);
-
       let groupConfigList = [];
       dataList.forEach(configItem => {
         const info = this.getConfigItemGroupPosInfo(configItem.key);
@@ -280,7 +347,10 @@ export default {
             gitem => gitem.name === info.group.name
           );
           if (!group) {
-            group.children = [];
+            group = {
+              ...info.group,
+              children: []
+            };
             groupConfigList.push(group);
           }
           group.children.push({
@@ -290,20 +360,18 @@ export default {
           return;
         }
 
-        let group = groupConfigList.find(gitem => gitem.name === "other");
+        let group = groupConfigList.find(gitem => gitem.name === "custom");
         if (!group) {
-          group = [
-            {
-              name: "other",
-              prefix: "",
-              children: []
-            }
-          ];
+          group = {
+            name: "custom",
+            prefix: "",
+            children: []
+          };
           groupConfigList.push(group);
         }
         group.children.push({
           ...configItem,
-          available: info.available
+          available: null
         });
       });
 
@@ -311,7 +379,7 @@ export default {
     },
     getConfigItemGroupPosInfo(configItemKey) {
       const curGroup = this.configGroups.find(group =>
-        configItemKey.include(group.prefix)
+        configItemKey.includes(group.prefix)
       );
       if (!curGroup) return;
       let groupData = {
@@ -321,7 +389,7 @@ export default {
 
       for (let i = 0; i < curGroup.available.length; i++) {
         const avai = { ...curGroup.available[i] };
-        if (avai.key.include(".*.")) {
+        if (avai.key.includes(".*.")) {
           const regCont = avai.key
             .split(".")
             .join("\\.")
@@ -342,6 +410,10 @@ export default {
           };
         }
       }
+      return {
+        group: groupData,
+        available: null
+      };
     },
     async toUpdate() {
       const valid = await this.$refs.FilterForm.validate().catch(() => {});
@@ -349,6 +421,33 @@ export default {
 
       this.$refs.UpdateAppBaseline.open();
     },
+    toAddGroupConfigItem(group) {
+      const ginfo = this.configGroups.find(item => item.name === group.name);
+      if (!ginfo) {
+        this.$message.error("当前分组不存在!");
+        return;
+      }
+
+      const unvalidKeys = group.children.map(item => item.key);
+      this.curGroupForAdd = { ...ginfo, unvalidKeys };
+      this.curGroupForAdd.available = this.curGroupForAdd.available.filter(
+        item => !unvalidKeys.includes(item.key)
+      );
+      if (!this.curGroupForAdd.available.length && ginfo.available.length) {
+        this.$message.error("当前分组不可添加配置项!");
+        return;
+      }
+
+      this.curConfigItem = { ...this.filter };
+      this.$refs.ModifyAppConfigItem.open();
+    },
+    toEdit(row) {
+      if (this.filter.envId) {
+        this.toEditConfigItem(row);
+      } else {
+        this.toEditBaseline(row);
+      }
+    },
     toEditBaseline(row) {
       this.curBaselineItem = { ...row, ...this.filter };
       this.$refs.ModifyAppBaselineItem.open();
@@ -362,6 +461,10 @@ export default {
     },
     baselineModified(data) {
       this.setCacheBaselineList(data);
+    },
+    scrollTo(group) {
+      this.$refs.ConfigTableBody.scrollTop =
+        document.getElementById(group.name).offsetTop - 20;
     }
   }
 };

+ 98 - 18
src/modules/admin/components/ModifyAppConfigItem.vue

@@ -2,7 +2,7 @@
   <el-dialog
     class="modify-app-config-item"
     :visible.sync="modalIsShow"
-    title="应用配置配置项修改"
+    :title="title"
     top="10vh"
     width="600px"
     :close-on-click-modal="false"
@@ -10,27 +10,52 @@
     append-to-body
     @opened="visibleChange"
   >
-    <el-form ref="modalFormComp" :model="modalForm" label-width="80px">
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      label-width="100px"
+    >
+      <el-form-item
+        v-if="!isEdit"
+        prop="selectAvailableKey"
+        label="可选配置项:"
+      >
+        <el-select
+          v-model="selectAvailableKey"
+          placeholder="请选择未配置的配置项"
+          class="width-full"
+          @change="availableKeyChange"
+        >
+          <el-option
+            v-for="item in group.available"
+            :key="item.key"
+            :value="item.key"
+            :label="item.key"
+          ></el-option>
+        </el-select>
+      </el-form-item>
       <el-form-item prop="key" label="配置项:">
+        <span v-if="isEdit || isStrictKey">
+          {{ modalForm.key }}
+        </span>
         <el-input
+          v-else
           v-model.trim="modalForm.key"
-          placeholder="请输入编码"
+          placeholder="请输入配置项"
           clearable
         ></el-input>
       </el-form-item>
       <el-form-item prop="value" label="配置值:">
         <el-input
           v-model.trim="modalForm.value"
-          placeholder="请输入编码"
+          placeholder="请输入配置值"
           clearable
         ></el-input>
       </el-form-item>
-      <el-form-item prop="comment" label="注释:">
-        <el-input
-          v-model.trim="modalForm.comment"
-          placeholder="请输入编码"
-          clearable
-        ></el-input>
+
+      <el-form-item v-if="modalForm.comment" label="注释:">
+        {{ modalForm.comment }}
       </el-form-item>
     </el-form>
     <div slot="footer">
@@ -63,14 +88,54 @@ export default {
       default() {
         return {};
       }
+    },
+    group: {
+      type: Object,
+      default: null
     }
   },
   data() {
+    const keyValidator = (rule, value, callback) => {
+      if (this.isEdit) return callback();
+
+      if (this.selectAvailableKey.includes(".*.")) {
+        const regCont = this.selectAvailableKey
+          .split(".")
+          .join("\\.")
+          .replace("*", ".*");
+        const reg = new RegExp(`^${regCont}$`);
+        if (!reg.test(value)) {
+          return callback(
+            new Error(`配置项需要满足${this.selectAvailableKey}的格式。`)
+          );
+        }
+      }
+
+      if (this.group.unvalidKeys.includes(value)) {
+        return callback(new Error("配置项已经存在"));
+      }
+
+      callback();
+    };
+
     return {
       modalIsShow: false,
       isSubmit: false,
       modalForm: { ...initModalForm },
       rules: {
+        selectAvailableKey: [
+          {
+            required: true,
+            validator: (rule, value, callback) => {
+              if (!this.selectAvailableKey) {
+                callback(new Error("请选择未配置的配置项"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "change"
+          }
+        ],
         key: [
           {
             required: true,
@@ -81,6 +146,10 @@ export default {
             max: 100,
             message: "配置项不能超过100字符",
             trigger: "change"
+          },
+          {
+            validator: keyValidator,
+            trigger: "change"
           }
         ],
         value: [
@@ -94,17 +163,21 @@ export default {
             message: "配置值不能超过200字符",
             trigger: "change"
           }
-        ],
-        comment: [
-          {
-            max: 200,
-            message: "编码不能超过200字符",
-            trigger: "change"
-          }
         ]
-      }
+      },
+      selectAvailableKey: "",
+      selectAvailable: {},
+      isStrictKey: true
     };
   },
+  computed: {
+    isEdit() {
+      return !!this.instance.key;
+    },
+    title() {
+      return this.instance.key ? "编辑" : "添加" + "应用配置配置项";
+    }
+  },
   methods: {
     initData(val) {
       this.modalForm = this.$objAssign(initModalForm, val);
@@ -119,6 +192,13 @@ export default {
     open() {
       this.modalIsShow = true;
     },
+    availableKeyChange() {
+      this.selectAvailable = this.group.available.find(
+        item => item.key === this.selectAvailableKey
+      );
+      this.isStrictKey = !this.selectAvailableKey.includes(".*.");
+      this.modalForm.key = this.selectAvailableKey;
+    },
     async submit() {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;