Bladeren bron

feat: 优化自定义表格组件及选择器功能

- 为部门选择器和人员选择器添加 selectList 属性及 init 控制初始化
- 自定义表格支持单元格标题,调整文本对齐方式
- 优化打印逻辑,支持按模式生成展示内容
- 新增单元格人员与部门选择模式
yusheng 6 dagen geleden
bovenliggende
commit
de96b1e4f5

+ 25 - 1
src/components/CommomSelect/dept-select.vue

@@ -47,6 +47,14 @@
       isBindPlan: {
         type: Boolean,
         default: false
+      },
+      init: {
+        type: Boolean,
+        default: true
+      },
+      selectList: {
+        type: Array,
+        default: () => []
       }
     },
     data() {
@@ -55,7 +63,22 @@
       };
     },
     created() {
-      this.getData();
+      if (this.init) {
+        this.getData();
+      }
+    },
+    watch: {
+      selectList: {
+        handler(val) {
+          this.treeData = this.$util.toTreeData({
+            data: val || [],
+            idField: 'id',
+            parentIdField: 'parentId'
+          });
+          console.log(this.treeData, 'dsdsd');
+        },
+        deep: true
+      }
     },
     methods: {
       async getData(params = {}) {
@@ -66,6 +89,7 @@
           parentIdField: 'parentId'
         });
       },
+
       /* 更新选中数据 */
       updateValue(value) {
         this.$emit('input', value);

+ 13 - 0
src/components/CommomSelect/person-select.vue

@@ -18,6 +18,7 @@
 
 <script>
   import { getUserPage } from '@/api/system/organization';
+
   export default {
     model: {
       prop: 'value',
@@ -31,6 +32,10 @@
       init: {
         type: Boolean,
         default: true
+      },
+      selectList: {
+        type: Array,
+        default: () => []
       }
     },
     data() {
@@ -38,6 +43,14 @@
         dictList: []
       };
     },
+    watch: {
+      selectList: {
+        handler(val) {
+          this.dictList = val;
+        },
+        deep: true
+      }
+    },
     computed: {
       selectVal: {
         set(val) {

+ 7 - 0
src/views/rulesManagement/releaseRules/components/experimentationProcessNew.vue

@@ -87,6 +87,13 @@
               @change="editInputChange"
             ></el-input>
           </el-form-item>
+          <el-form-item label="标题:" prop="label">
+            <el-input
+              v-model="domObj.label"
+              placeholder="请输入标题"
+              @change="editInputChange"
+            ></el-input>
+          </el-form-item>
           <el-form-item label="宽度:" prop="width" v-if="!domObj.isNoWidth">
             <el-input
               v-model="domObj.width"

+ 175 - 146
src/views/rulesManagement/releaseRules/components/templateDiv/customTableNew.vue

@@ -40,102 +40,127 @@
                 <!-- 表头操作图标(已注释) -->
                 <!-- <i ... ></i> -->
 
-                <!-- ========== 复选框模式 ========== -->
-                <template v-if="cell.mode === 'checkbox'">
-                  <div class="checkbox-group">
+                <div style="display: flex; align-items: center">
+                  <span>{{ cell.label }}</span>
+                  <template v-if="cell.mode === 'checkbox'">
+                    <div class="checkbox-group" style="flex: 1">
+                      <div
+                        v-for="cb in cell.checkboxes"
+                        :key="cb.id"
+                        class="checkbox-item"
+                      >
+                        <input type="checkbox" v-model="cb.checked" />
+                        <input
+                          v-if="edit"
+                          type="text"
+                          v-model="cb.label"
+                          class="checkbox-label-input"
+                          @input="
+                            onCheckboxLabelInput(rowIndex, colIndex, cb.id)
+                          "
+                        />
+                        <span v-else>{{ cb.label }}</span>
+                        <i
+                          v-if="edit"
+                          class="el-icon-delete"
+                          @click.stop="
+                            removeCheckbox(rowIndex, colIndex, cb.id)
+                          "
+                        ></i>
+                      </div>
+                      <div
+                        v-if="edit"
+                        class="add-checkbox"
+                        @click="addCheckbox(rowIndex, colIndex)"
+                      >
+                        <i class="el-icon-circle-plus-outline"></i> 新增选项
+                      </div>
+                    </div>
+                  </template>
+
+                  <!-- ========== 🆕 人员选择模式 ========== -->
+                  <template v-else-if="cell.mode === 'person'">
                     <div
-                      v-for="cb in cell.checkboxes"
-                      :key="cb.id"
-                      class="checkbox-item"
+                      style="
+                        width: 100%;
+                        position: relative;
+                        min-height: 30px;
+                        flex: 1;
+                      "
                     >
-                      <input type="checkbox" v-model="cb.checked" />
-                      <input
-                        v-if="edit"
-                        type="text"
-                        v-model="cb.label"
-                        class="checkbox-label-input"
-                        @input="onCheckboxLabelInput(rowIndex, colIndex, cb.id)"
+                      <!-- 人员选择组件 -->
+                      <personSelect
+                        v-model="cell.value"
+                          :disabled="readonly || cell.readonly === 2"
+                        :readonly="readonly || cell.readonly === 2"
+                        @change="onPersonChange(rowIndex, colIndex)"
+                        style="width: 95%"
+                        :init="false"
+                        :selectList="userPage"
                       />
-                      <span v-else>{{ cb.label }}</span>
+                      <!-- 编辑图标(仅在编辑模式下显示) -->
                       <i
                         v-if="edit"
-                        class="el-icon-delete"
-                        @click.stop="removeCheckbox(rowIndex, colIndex, cb.id)"
+                        class="el-icon-edit person-edit-icon"
+                        @click.stop="openPersonConfig(cell, rowIndex, colIndex)"
                       ></i>
                     </div>
+                  </template>
+                  <!-- ========== 🆕 部门选择模式 ========== -->
+                  <template v-else-if="cell.mode === 'dept'">
                     <div
-                      v-if="edit"
-                      class="add-checkbox"
-                      @click="addCheckbox(rowIndex, colIndex)"
+                      style="
+                        width: 100%;
+                        position: relative;
+                        min-height: 30px;
+                        flex: 1;
+                      "
                     >
-                      <i class="el-icon-circle-plus-outline"></i> 新增选项
+                      <deptSelect
+                        v-model="cell.value"
+                        :disabled="readonly || cell.readonly === 2"
+                        :isBindPlan="readonly || cell.readonly === 2"
+                        @change="onDeptChange(rowIndex, colIndex)"
+                        style="width: 95%"
+                        placeholder="请选择部门"
+                        :init="false"
+                        :selectList="deptList"
+                      />
+                      <i
+                        v-if="edit"
+                        class="el-icon-edit person-edit-icon"
+                        @click.stop="openPersonConfig(cell, rowIndex, colIndex)"
+                      ></i>
                     </div>
-                  </div>
-                </template>
-
-                <!-- ========== 🆕 人员选择模式 ========== -->
-                <template v-else-if="cell.mode === 'person'">
-                  <div
-                    style="width: 100%; position: relative; min-height: 30px"
-                  >
-                    <!-- 人员选择组件 -->
-                    <personSelect
-                      v-model="cell.value"
-                      :disabled="!edit"
-                      :readonly="readonly || cell.readonly === 2"
-                      @change="onPersonChange(rowIndex, colIndex)"
-                      style="width: 95%"
-                    />
-                    <!-- 编辑图标(仅在编辑模式下显示) -->
-                    <i
-                      v-if="edit"
-                      class="el-icon-edit person-edit-icon"
-                      @click.stop="openPersonConfig(cell, rowIndex, colIndex)"
-                    ></i>
-                  </div>
-                </template>
-                <!-- ========== 🆕 部门选择模式 ========== -->
-                <template v-else-if="cell.mode === 'dept'">
-                  <div
-                    style="width: 100%; position: relative; min-height: 30px"
-                  >
-                    <deptSelect
+                  </template>
+
+                  <!-- ========== 文本模式 ========== -->
+                  <template v-else>
+                    <textarea
                       v-model="cell.value"
-                      :disabled="!edit"
-                      :isBindPlan="readonly || cell.readonly === 2"
-                      @change="onDeptChange(rowIndex, colIndex)"
-                      style="width: 95%"
-                      placeholder="请选择部门"
-                    />
-                    <i
-                      v-if="edit"
-                      class="el-icon-edit person-edit-icon"
-                      @click.stop="openPersonConfig(cell, rowIndex, colIndex)"
-                    ></i>
-                  </div>
-                </template>
-
-                <!-- ========== 文本模式 ========== -->
-                <template v-else>
-                  <textarea
-                    v-model="cell.value"
-                    class="templateInput"
-                    :style="{ textAlign: cell.textAlign || 'center' }"
-                    :id="cell.id"
-                    :ref="cell.id + 'ref'"
-                    :readonly="cell.readonly === 2 || readonly"
-                    @mousedown="onCellMouseDown"
-                    @click="
-                      inputClick(
-                        cell,
-                        rowIndex === 0 ? 'columns' : null,
-                        $event
-                      )
-                    "
-                    @input="onInput($event)"
-                    autocomplete="off"
-                  ></textarea>
-                </template>
+                      class="templateInput"
+                      :style="{
+                        textAlign: cell.textAlign || 'left',
+                        flex: 1
+                      }"
+                      :id="cell.id"
+                      :ref="cell.id + 'ref'"
+                      :readonly="cell.readonly === 2 || readonly"
+                      @mousedown="onCellMouseDown"
+                      @click="
+                        inputClick(
+                          cell,
+                          rowIndex === 0 ? 'columns' : null,
+                          $event
+                        )
+                      "
+                      @input="onInput($event)"
+                      autocomplete="off"
+                    ></textarea>
+                  </template>
+                </div>
+
+                <!-- ========== 复选框模式 ========== -->
               </td>
             </template>
           </tr>
@@ -161,6 +186,8 @@
     },
     data() {
       return {
+        userPage: [],
+        deptList: [],
         form: null,
         valueObj: {},
         tableData: [],
@@ -258,6 +285,14 @@
         this.menuCloseHandler = null;
       }
     },
+    created() {
+      getUserPage({ pageNum: 1, size: -1 }).then((res) => {
+        this.userPage = res.list;
+      });
+      listOrganizations({ pageNum: 1, size: -1 }).then((res) => {
+        this.deptList = res
+      });
+    },
     methods: {
       getTransitions(key) {
         return [
@@ -287,7 +322,7 @@
         return {
           ...cell.style,
           width: width + 'px',
-          'text-align': cell.textAlign || 'center' // 默认居中
+          'text-align': cell.textAlign || 'left' // 默认居中
         };
       },
 
@@ -299,11 +334,12 @@
           value: '',
           rowspan: 1,
           colspan: 1,
+          label: '',
           width: safeWidth,
           style: { width: safeWidth },
           readonly: 1,
           mode: 'text', // 'text' | 'checkbox' | 'person'
-          textAlign: 'center',
+          textAlign: 'left',
           checkboxes: []
         };
       },
@@ -940,9 +976,8 @@
       },
       // ========== 🆕 打印(异步 + 人员名称映射) ==========
       async printTable() {
-        // 1. 先获取用户映射(如果未加载)
         await this.fetchUserMap();
-        await this.fetchDeptMap(); // 🆕 加载部门映射
+        await this.fetchDeptMap();
         const tableEl = this.$el.querySelector('.custom-table');
         if (!tableEl) return;
 
@@ -953,16 +988,7 @@
           )
           .forEach((el) => el.remove());
 
-        // 处理 textarea
-        clone.querySelectorAll('textarea').forEach((ta) => {
-          const div = document.createElement('div');
-          div.textContent = ta.value;
-          div.style.cssText =
-            'text-align:center;word-break:break-all;padding:4px;white-space:pre-wrap;';
-          ta.parentNode.replaceChild(div, ta);
-        });
-
-        // 处理复选框和人员选择
+        // 遍历所有单元格,根据模式重新构建显示内容(保留 label)
         for (let r = 0; r < this.tableData.length; r++) {
           for (let c = 0; c < this.tableData[r].length; c++) {
             const cell = this.tableData[r][c];
@@ -971,65 +997,68 @@
             );
             if (!td) continue;
 
+            const label = cell.label || '';
+            let displayHtml = '';
+            td.style.padding = '3px';
             if (cell.mode === 'checkbox' && Array.isArray(cell.checkboxes)) {
-              const container = document.createElement('div');
-              container.style.cssText =
-                'display:flex; flex-wrap:wrap; gap:5px; justify-content:center;';
-              cell.checkboxes.forEach((cb) => {
-                const item = document.createElement('div');
-                item.style.cssText =
-                  'display:inline-flex; align-items:center; gap:5px; white-space:nowrap;';
-                const symbolSpan = document.createElement('span');
-                symbolSpan.textContent = cb.checked ? '☑' : '☐';
-                symbolSpan.style.fontSize = '14px';
-                const labelSpan = document.createElement('span');
-                labelSpan.textContent = cb.label || '';
-                item.appendChild(symbolSpan);
-                item.appendChild(labelSpan);
-                container.appendChild(item);
-              });
-              td.innerHTML = '';
-              td.appendChild(container);
+              const items = cell.checkboxes
+                .map((cb) => {
+                  const symbol = cb.checked ? '☑' : '☐';
+                  return `<span style="margin:0 4px;">${symbol} ${
+                    cb.label || ''
+                  }</span>`;
+                })
+                .join('');
+              displayHtml = `<div style="display:flex; align-items:center; justify-content:center; gap:5px; flex-wrap:wrap;">${
+                label ? `<span >${label}</span>` : ''
+              }${items}</div>`;
             } else if (cell.mode === 'person') {
-              // 🆕 使用映射显示人员名称
-              const userId = cell.value;
-              const userName = this.userMap[userId] || userId || '';
-              const div = document.createElement('div');
-              div.textContent = userName;
-              div.style.cssText = 'text-align:center;padding:4px;';
-              td.innerHTML = '';
-              td.appendChild(div);
+              const userName = this.userMap[cell.value] || cell.value || '';
+              displayHtml = `<div style="display:flex; align-items:center; justify-content:center; gap:5px;">${
+                label ? `<span >${label}</span>` : ''
+              }<span style="flex:1">${userName}</span></div>`;
             } else if (cell.mode === 'dept') {
-              // 🆕
-              const deptId = cell.value;
-              const deptName = this.deptMap[deptId] || deptId || '';
-              const div = document.createElement('div');
-              div.textContent = deptName;
-              div.style.cssText = 'text-align:center;padding:4px;';
-              td.innerHTML = '';
-              td.appendChild(div);
+              const deptName = this.deptMap[cell.value] || cell.value || '';
+              displayHtml = `<div style="display:flex; align-items:center; justify-content:center; gap:5px;">${
+                label ? `<span >${label}</span>` : ''
+              }<span style="flex:1">${deptName}</span></div>`;
+            } else {
+              console.log(cell.textAlign);
+              // 文本模式
+              displayHtml = `<div style="display:flex; align-items:center; justify-content:${
+                cell.textAlign == 'left'
+                  ? 'flex-start'
+                  : cell.textAlign == 'right'
+                  ? 'flex-end'
+                  : 'center'
+              };">${label ? `<span >${label}</span>` : ''}<span>${
+                cell.value || ''
+              }</span></div>`;
             }
+
+            td.innerHTML = displayHtml;
           }
         }
 
+        // 打印 iframe(保持不变)
         const iframe = document.createElement('iframe');
         iframe.style.cssText = 'position:absolute;width:0;height:0;border:0;';
         document.body.appendChild(iframe);
         const doc = iframe.contentWindow.document;
         doc.write(`
-          <!DOCTYPE html>
-          <html>
-            <head>
-              <meta charset="utf-8">
-              <style>
-                body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
-                table { width: 100%; border-collapse: collapse; table-layout: auto; }
-                td { border: 1px solid #000; vertical-align: middle; text-align: center; padding: 1px; font-size: 12px; padding:0px; }
-              </style>
-            </head>
-            <body>${clone.outerHTML}</body>
-          </html>
-        `);
+    <!DOCTYPE html>
+    <html>
+      <head>
+        <meta charset="utf-8">
+        <style>
+          body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
+          table { width: 100%; border-collapse: collapse; table-layout: auto; }
+          td { border: 1px solid #000; vertical-align: middle;  padding: 1px; font-size: 12px; padding:0px; }
+        </style>
+      </head>
+      <body>${clone.outerHTML}</body>
+    </html>
+  `);
         doc.close();
         iframe.contentWindow.focus();
         iframe.contentWindow.print();