Bladeren bron

修改查询窗口

YangZhiJie 1 jaar geleden
bovenliggende
commit
1e85ee911c
4 gewijzigde bestanden met toevoegingen van 742 en 461 verwijderingen
  1. 230 0
      packages/info/src/InfoWindowState.js
  2. 77 459
      packages/info/src/QueryPage.vue
  3. 432 0
      packages/info/src/QueryPageTable.vue
  4. 3 2
      webpack.dev.js

+ 230 - 0
packages/info/src/InfoWindowState.js

@@ -0,0 +1,230 @@
+import { reactive, ref } from 'vue';
+
+import InfoUtil from './InfoUtil.js';
+
+
+export function useSort() {
+  const sortSetting = reactive({
+    fieldName: null,      // 排序的字段
+    direction: null,    // 排序的方向 ASC, DESC, null
+  });
+
+  /**
+     * 修改排序方向
+     */
+  function changeDirection() {
+    sortSetting.direction = (sortSetting.direction == 'ASC' ? 'DESC' : 'ASC');
+  }
+
+  /**
+     * 初始化排序方向
+     */
+  function initDirection() {
+    sortSetting.direction = 'ASC';
+  }
+
+  /**
+     * 修改排序字段的名称
+     * @param {*} newFieldName 新的排序字段名称
+     */
+  function changeFieldName(newFieldName) {
+    // 如果字段相同,那么就修改排序方向
+    // 如果字段不相同,那么设置排序方向ASC
+    if (sortSetting.fieldName === newFieldName) {
+      changeDirection();
+    } else {
+      initDirection();
+    }
+
+    sortSetting.fieldName = newFieldName;
+  }
+
+  /**
+     * 获取排序字符串
+     */
+  function getSortString() {
+    return sortSetting.fieldName + ' ' + (sortSetting.direction == null ? 'ASC' : sortSetting.direction);
+  }
+
+  return {
+    sortSetting,
+    changeFieldName,
+    getSortString,
+  };
+}
+
+/**
+ * 查询窗口表格字段
+ */
+export function useInfoGridFields() {
+  let infoWindowNo = null;
+  const infoGridFields = reactive([]);
+
+  /**
+     * 根据用户的上次操作,还原列宽等属性
+     * @param {*} infoWindowNo1 查询窗口编号
+     * @param {*} infoGridFields1 查询窗口列定义
+     */
+  function init(infoWindowNo1, infoGridFields1) {
+    // 每列的宽度设置成150
+    infoGridFields1.forEach(function (item) {
+      item.width = 150;
+    });
+
+    infoGridFields.splice(0, infoGridFields.length);
+
+    infoGridFields.push(...infoGridFields1);
+
+    infoWindowNo = infoWindowNo1;
+
+    // 从后端获取列的属性
+    InfoUtil.restoreInfoGridFields(
+      infoWindowNo,
+      infoGridFields,
+    );
+  }
+
+  /**
+     * 保存用户对列属性(如:列宽)等属性的配置
+     * @param {*} infoWindowNo1 查询窗口编号
+     * @param {*} infoGridFields1 查询窗口列定义
+     */
+  function saveInfoGridFields(infoWindowNo1, infoGridFields1) {
+    InfoUtil.saveInfoGridFields(
+      infoWindowNo1,
+      infoGridFields1,
+    ).then(
+      successData => {
+        InfoUtil.restoreInfoGridFields(
+          infoWindowNo1,
+          infoGridFields,
+        );
+      },
+      errorData => {
+        console.log(errorData);
+      },
+    );
+  }
+
+  /**
+     * 修改列宽度
+     * @param {*} gridFieldItem 
+     * @param {*} newWidth 
+     */
+  function changeGridFieldWidth(gridFieldItem, newWidth) {
+    gridFieldItem.width = newWidth;
+    InfoUtil.saveInfoGridFields(infoWindowNo, infoGridFields);
+  }
+
+
+
+  return {
+    infoGridFields,
+    init,
+    saveInfoGridFields,
+    changeGridFieldWidth,
+  };
+}
+
+
+export function useInfoWindowData() {
+  const timestamp = ref(0);
+  const dataList = reactive([]);
+
+  function init(datas) {
+    dataList.splice(0, dataList.length);
+    dataList.push(...datas);
+    timestamp.value = new Date().getTime();
+  }
+
+  /**
+     * 获取选择的数据
+     * @returns 
+     */
+  function getSelected() {
+    const tempSelectedModelDatas = [];
+    if (dataList != null && dataList.length > 0) {
+      dataList.forEach(function (item) {
+        if (item.select == true) {
+          tempSelectedModelDatas.push(item);
+        }
+      });
+    }
+    return tempSelectedModelDatas;
+  }
+
+    
+  /**
+     * 获取第一行选择的数据
+     * @returns 
+     */
+  function getFirstSelected() {
+    if (dataList != null && dataList.length > 0) {
+      for(let i = 0, length = dataList.length; i < length; i++){
+        if(dataList[i].select == true){
+          return dataList[i];
+        }
+      }
+    }
+    return null;
+  }
+
+
+  /**
+     * 获取选择数据的Id集合
+     */
+  function getSelectedRecordIds() {
+    const recordIds = [];
+    if (dataList != null && dataList.length > 0) {
+      dataList.forEach(function (item) {
+        if (item.select == true) {
+          recordIds.push(item.id);
+        }
+      });
+    }
+    return recordIds;
+  }
+
+  /**
+     * 设置全部选中
+     */
+  function setAllSelect(){
+    if (dataList != null && dataList.length > 0) {
+      dataList.forEach(function (item) {
+        item.select = true;
+      });
+    }
+  }
+
+  /**
+     * 设置全部未选中
+     */
+  function setAllUnSelect(){
+    if (dataList != null && dataList.length > 0) {
+      dataList.forEach(function (item) {
+        item.select = false;
+      });
+    }
+  }
+
+  /**
+     * 设置单条数据的选择状态
+     * @param {*} data 单行数据
+     * @param {*} selectState 选择状态
+     */
+  function selectSelectState(data, selectState){
+    data.select = selectState;
+  }
+
+  return {
+    timestamp,
+    dataList,
+    init,
+    getSelected,
+    getFirstSelected,
+    getSelectedRecordIds,
+    setAllSelect,
+    setAllUnSelect,
+    selectSelectState,
+  };
+}

+ 77 - 459
packages/info/src/QueryPage.vue

@@ -11,7 +11,7 @@
         <div class="panel-heading" style="padding: 0px">
           <InfoHeader
             :html-help-url="infoWindowDto.htmlHelpUrl"
-            :info-grid-fields="infoGridFields"
+            :info-grid-fields="infoGridFieldsInstance.infoGridFields"
             :header-name="Language.getNameTrl($i18n.locale, infoWindowDto)"
             :info-filter-fields="infoFilterFields"
             :info-window-no="infoWindowDto.no"
@@ -39,117 +39,19 @@
         </div>
       </div>
     </div>
+    <!-- xx -->
+     
     <div class="flex-content">
-      <div :id="tableOutDivId" class="flex-main table-fix-head">
-        <table
-          class="fixed-table table-striped table-bordered"
-          :width="tableWidth"
-          height="40px"
-        >
-          <thead>
-            <tr height="40px">
-              <th width="50px">{{ $t("lang.QueryPage.serialNumber") }}</th>
-              <th
-                width="30px"
-                class="text-center"
-                :class="{ 'mulitiple-select': multipleSelect }"
-                @click.self="changeSelectMode"
-              >
-                <input
-                  v-model="isSelectAll"
-                  autocomplete="off"
-                  type="checkbox"
-                />
-              </th>
-              <template v-for="infoGridField in infoGridFields">
-                <th
-                  v-if="infoGridField.simpleDisplayType != 'OperateButton'"
-                  v-show="infoGridField.isShow"
-                  :key="infoGridField.fieldName"
-                  :width="infoGridField.width + 'px'"
-                  @dragover="ondragover($event, infoGridField)"
-                  @click="onSort(infoGridField)"
-                >
-                  <div
-                    :id="'infoGridFieldId_' + infoGridField.fieldName"
-                    class="rz-handle"
-                    draggable="true"
-                    @dragstart="ondragstart($event, infoGridField)"
-                    @drag="ondrag($event, infoGridField)"
-                    @dragend="ondragend($event, infoGridField)"
-                  />
-
-                  <div
-                    v-tooltip.right="
-                      Language.getHelpTrl($i18n.locale, infoGridField)
-                    "
-                    class="td-max"
-                  >
-                    {{ Language.getNameTrl($i18n.locale, infoGridField) }}
-                  </div>
-                </th>
-              </template>
-              <th v-if="operateButtons != null && operateButtons.length > 0" style="width: 160px;">
-                操作
-              </th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr
-              v-for="(item1, index) in infoWindowData.dataList"
-              :key="'tr' + item1.id"
-              height="40px"
-              :class="{ warning: item1.select }"
-              @dblclick="selectNode(item1)"
-            >
-              <td style="text-align: center">
-                {{
-                  index +
-                    1 +
-                    (pagination.current_page - 1) * pagination.per_page
-                }}
-              </td>
-
-              <td class="text-center">
-                <input
-                  autocomplete="off"
-                  type="checkbox"
-                  :checked="item1.select"
-                  @click.self="selectNodeForSearch(item1)"
-                />
-              </td>
-              <template v-for="item2 in infoGridFields">
-                <td
-                  v-show="item2.isShow"
-                  v-if="item2.simpleDisplayType != 'OperateButton'"
-                  id="item.id"
-                  :key="'td-' + item2.id"
-                >
-                  <span v-if="item2.simpleDisplayType == 'Image'">
-                    <QueryPageImage
-                      v-if="item1.data[item2.fieldName] != undefined"
-                      :class-name="item2.selectClause"
-                      :image-names="item1.data[item2.fieldName].displayValue[0]"
-                    />
-                  </span>
-                  <span v-else>
-                    {{
-                      item1.data[item2.fieldName] != undefined
-                        ? item1.data[item2.fieldName].displayValue[0]
-                        : ""
-                    }}
-                  </span>
-                </td>
-              </template>
-              <td v-if="operateButtons != null && operateButtons.length > 0">
-                <template v-for="item in operateButtons" :key="item">
-                  <a-button @click="executeCallout(item1,item)">{{ item.name }}</a-button>
-                </template>
-              </td>
-            </tr>
-          </tbody>
-        </table>
-      </div>
+      <QueryPageTable 
+        :info-grid-fields-instance="infoGridFieldsInstance"
+        :sort-instance="sortInstance"
+        :info-window-data-instance="infoWindowDataInstance"
+        :pagination="pagination"
+        :multiple="multiple"
+        :call-out-js-url="infoWindowDto.callOutJsUrl"
+        @data-selected="$emit('dataSelected', $event)"
+        @delete-selected="$emit('deleteSelected', $event)"
+      />
     </div>
     <div class="flex-footer" style="margin-top: 10px">
       <div class="pull-left">
@@ -206,7 +108,6 @@ import Notify from '../../common/Notify.js';
 import Loading from '../../loading/src/Loading.vue';
 import ProcessReportResult from '../../process/src/ProcessReportResult.vue';
 import Uuid from '../../common/Uuid.js';
-import QueryPageImage from './QueryPageImage.vue';
 
 import DownloadService from '../../common/DownloadService.js';
 import HtmlWindowResource from '../../html-window/src/api/HtmlWindowResource.js';
@@ -216,11 +117,12 @@ import ProcessReportResource from '../../process/src/api/ProcessReportResource.j
 import UserStorageResource from '../../common/UserStorageResource.js';
 
 import Language from '../../common/Language.js';
-import JsUtil from '../../common/JsUtil.js';
 
 import dayjs from 'dayjs';
 
-import Context from './Context.js';
+import QueryPageTable from './QueryPageTable.vue';
+
+import { useSort, useInfoGridFields, useInfoWindowData } from './InfoWindowState.js';
 
 export default {
   name: 'QueryPage',
@@ -233,7 +135,7 @@ export default {
     Loading,
     ProcessReportResult,
     PageSizeSelect,
-    QueryPageImage,
+    QueryPageTable,
   },
 
   props: {
@@ -265,13 +167,6 @@ export default {
         return null;
       },
     },
-    /**
-     * 是否多选
-     */
-    multiple: {
-      type: Boolean,
-      default: false,
-    },
     /**
      * 查询窗口编号
      */
@@ -279,105 +174,63 @@ export default {
       type: String,
       default: null,
     },
+    
+    /**
+     * 是否多选
+     */
+    multiple: {
+      type: Boolean,
+      default: false,
+    },
   },
 
-  emits: ['dataSelected'],
+  emits: ['dataSelected', 'deleteSelected'],
 
   data: function () {
     this.Language = Language;
     return {
       infoWindowDto: {},
       queryResult: {},
-      infoWindowData: {},
       pagination: {
         total: 0,
         per_page: Common.pageSize, // required
         current_page: 1, // required
         last_page: 10, // required
       },
-      isSelectAll: false,
       infoQueryParam: [],
       processReportResult: [],
-      multipleSelect: false,
       uuid: Uuid.createUUID(),
-      sortStr: '', // 排序
-      sortStyle: ' ASC',
       currentIsSimpleSearch: true,
       startX: '',
       startWidth: '',
       processReportDto: '',
       pdfOnly: '',
       excelOnly: '',
-      infoGridFields: [],
       infoFilterFields: [],
-      // 表格外面的DIV的id
-      tableOutDivId: Uuid.createUUID(),
       loading: false,
       modal: false,
       isComplex:false,
       searchType:'simple',
+      sortInstance: useSort(),
+      infoGridFieldsInstance: useInfoGridFields(),
+      infoWindowDataInstance: useInfoWindowData(),
     };
   },
-  computed: {
-    tableWidth: function () {
-      var totalWidth = 50;
-      if (this.infoWindowDto != undefined && this.infoGridFields != undefined) {
-        this.infoGridFields.forEach(function (item) {
-          if (item.isShow) {
-            totalWidth += Number(item.width);
-          }
-        });
-      }
-      return totalWidth + 'px';
-    },
-    operateButtons:function(){
-      let buttons = [];
-      this.infoGridFields.forEach(item =>{
-        if(item.simpleDisplayType == 'OperateButton'){
-          buttons.push(item);
-        }
-      });
-      return buttons;
-    },
-  },
+
   watch: {
-    /**
-     * 是否选择了全部的数据
-     */
-    isSelectAll: function (val) {
-      var _self = this;
-      if (_self.multipleSelect) {
-        if (_self.isSelectAll) {
-          if (val) {
-            _self.infoWindowData.dataList.forEach(function (item) {
-              item.select = true;
-            });
-          }
+    'sortInstance.sortSetting': {
+      handler(newValue, oldValue) {
+        this.infoQueryParam.sortClause = this.sortInstance.getSortString();
+        if (this.currentIsSimpleSearch) {
+          this.queryInfoWindowDataSimple();
         } else {
-          _self.infoWindowData.dataList.forEach(function (item) {
-            item.select = false;
-          });
+          this.queryInfoWindowDataComplex();
         }
-      } else {
-        _self.isSelectAll = false;
-      }
-    },
-
-    // /**
-    //  * 路由发生改变
-    //  */
-    // $route: function (to, from) {
-    //   var _self = this;
-    //   _self.infoWindowData = {};
-    // },
-
-    multiple: {
-      handler: function (newValue, oldValue) {
-        this.multipleSelect = newValue;
       },
-      immediate: true,
+      deep: true,
     },
   },
+  
   created: function () {
     const infoPageSize = localStorage.getItem(
       `InfoWindowPageSize${this.windowNo}`,
@@ -386,90 +239,24 @@ export default {
       this.pagination.per_page = infoPageSize;
     }
   },
-  methods: {
-
-    getContext: Context,
 
-    executeCallout:function(rowData,filedItem){
-      let _self = this;
-      const methodName = filedItem.callOutJsMethod;
-      const callOutJsUrl = this.infoWindowDto.callOutJsUrl;
-
-      let functionName = methodName.replace('.', '_') + '_calloutjs';
-
-      let executeFunction = function(){
-        
-        let context = new _self.getContext(rowData, {});
-        try {
-          _self[functionName](context);
-        } catch (e) {
-          console.error(e);
-          Notify.error('数据字典定义异常',` 【 ${methodName} 】前端列显示逻辑定义异常,请联系管理员检查数据字典的定义。`, false);
-        }
-      };
 
-      if (_self[functionName] == null) {
-        // 执行服务端的脚本
-        const jsUrl = callOutJsUrl;
-        if (jsUrl == null || jsUrl == undefined) {
-          Notify.error('数据字典定义异常', `【 ${methodName} 】Callout前端逻辑的JS文件不存在,请联系管理员检查数据字典是否JS文件。`, false);
-          return;
-        }
-        let promise = JsUtil.dynamicLoadJsFunction(jsUrl,methodName);
-        promise.then(targetFunction => {
-          if (targetFunction == null) {
-            Notify.error('数据字典定义异常', `【 ${methodName} 】Callout前端逻辑定义异常,请联系管理员检查数据字典的定义。`, false);
-            return;
-          }
+  methods: {
 
-          _self[functionName] = targetFunction;
-          executeFunction();
-          
-        }, errorData => {
-          console.error(errorData);
-        });
-      } else {
-        executeFunction();
-      }
-    },
     openComplex:function(value){
       this.isComplex = value;
     },
-    // 页码数量改变
+
+    /**
+     * 页面显示数量改变
+     * @param newPageSize 
+     */
     gridSizeSelect: function (newPageSize) {
       this.pagination.current_page = 1;
       this.pagination.per_page = newPageSize;
       localStorage.setItem(`InfoWindowPageSize${this.windowNo}`, newPageSize);
     },
 
-    ondragstart: function (event, gridFieldItem) {
-      var _self = this;
-      _self.startX = event.pageX;
-      _self.startWidth = Number(gridFieldItem.width);
-      event.dataTransfer.setDragImage(event.target, 0, 20);
-      event.dataTransfer.effectAllowed = 'move';
-    },
-
-    ondrag: function (event, gridFieldItem) {
-      var _self = this;
-      gridFieldItem.width = _self.startWidth + (event.pageX - _self.startX);
-    },
-
-    ondragend: function (event, gridFieldItem, index) {
-      var _self = this;
-      let newWidth = _self.startWidth + (event.pageX - _self.startX);
-      if (newWidth < 50) {
-        newWidth = 50;
-      }
-      gridFieldItem.width = newWidth;
-
-      InfoUtil.saveInfoGridFields(_self.infoWindowDto.no, _self.infoGridFields);
-    },
-
-    ondragover: function (event, gridFieldItem) {
-      event.preventDefault();
-      event.dataTransfer.dropEffect = 'move';
-    },
 
     // 初始化数据
     initWidget: function (data) {
@@ -480,11 +267,9 @@ export default {
 
       _self.infoWindowDto = data;
       _self.infoFilterFields = data.infoFilterFields;
-      _self.infoGridFields = data.infoGridFields;
-      // var sortNo = 10;
-      _self.infoGridFields.forEach(function (item) {
-        item.width = 150;
-      });
+
+      _self.infoGridFieldsInstance.init(_self.infoWindowDto.no, data.infoGridFields);
+
       _self.infoFilterFields.forEach(function (item) {
         item.value = {
           infoFilterFieldId: item.id,
@@ -496,14 +281,14 @@ export default {
         _self.infoWindowDto.no,
         _self.infoFilterFields,
       );
-      InfoUtil.restoreInfoGridFields(
-        _self.infoWindowDto.no,
-        _self.infoGridFields,
-      );
 
       _self.simpleSearch();
     },
 
+    /**
+     * 高级查询
+     * @param value 
+     */
     complexSearch: function (value) {
       var _self = this;
       _self.searchType = value;
@@ -524,14 +309,16 @@ export default {
       _self.queryInfoWindowDataComplex();
     },
 
+    /**
+     * 分页查询
+     */
     pageSearch: function () {
       var _self = this;
       _self.infoQueryParam.start =
         (_self.pagination.current_page - 1) * _self.pagination.per_page;
       _self.infoQueryParam.length = _self.pagination.per_page;
       _self.infoQueryParam.infoFilterFieldValues =
-        _self.$refs.queryCondition.getQueryCondition();
-      // var isSimpleQuery = _self.$refs.queryCondition.isSimpleQuery();
+      _self.$refs.queryCondition.getQueryCondition();
       if (_self.searchType === 'complex') {
         _self.queryInfoWindowDataComplex();
       } else {
@@ -563,6 +350,9 @@ export default {
       _self.queryInfoWindowDataSimple();
     },
 
+    /**
+     * 调用后端高级查询的接口
+     */
     queryInfoWindowDataComplex: function () {
       var _self = this;
       _self.loading = true;
@@ -578,14 +368,13 @@ export default {
         success: function (data) {
           _self.loading = false;
           _self.setSelectedFlag(data);
-          _self.infoWindowData = data;
+          _self.infoWindowDataInstance.init(data.dataList);
 
           _self.pagination.total = data.totalSize;
           _self.pagination.last_page = Math.ceil(
             data.totalSize / data.range.length,
           );
 
-          _self.fixedTableHeader();
         },
         error: function (XMLHttpRequest, textStatus, errorThrown) {
           _self.loading = false;
@@ -618,6 +407,9 @@ export default {
       });
     },
 
+    /**
+     * 调用后端简单查询接口
+     */
     queryInfoWindowDataSimple: function () {
       var _self = this;
       if (_self.$refs.loading) {
@@ -639,14 +431,14 @@ export default {
             _self.loading = false;
           }
           _self.setSelectedFlag(data);
-          _self.infoWindowData = data;
+          
+          _self.infoWindowDataInstance.init(data.dataList);
 
           _self.pagination.total = data.totalSize;
           _self.pagination.last_page = Math.ceil(
             data.totalSize / data.range.length,
           );
 
-          _self.fixedTableHeader();
         },
         error: function (XMLHttpRequest, textStatus, errorThrown) {
           if (_self.$refs.loading) {
@@ -657,54 +449,13 @@ export default {
       });
     },
 
-    /**
-     * 双击表格行事件
-     */
-    selectNode: function (modelData) {
-      this.$emit('dataSelected', modelData);
-    },
 
-    /**
-     * 选择/取消选择表格行中的复选框事件
-     */
-    selectNodeForSearch: function (modelData) {
-      var _self = this;
-
-      var currentStatus = modelData.select;
-      if (!_self.multipleSelect) {
-        _self.infoWindowData.dataList.forEach(function (item) {
-          item.select = false;
-        });
-      }
-
-      modelData.select = !currentStatus;
-
-      if (modelData.select === true) {
-        _self.$emit('dataSelected', modelData);
-      } else {
-        _self.$emit('deleteSelected', modelData);
-      }
-    },
 
     /**
      * 获取选择的数据
      */
-    getSelectedModelDatas: function (data) {
-      var _self = this;
-      var tempSelectedModelDatas = [];
-
-      if (
-        _self.infoWindowData != null &&
-        _self.infoWindowData.dataList != null
-      ) {
-        _self.infoWindowData.dataList.forEach(function (item) {
-          if (item.select == true) {
-            tempSelectedModelDatas.push(item);
-          }
-        });
-      }
-
-      return tempSelectedModelDatas;
+    getSelectedModelDatas: function () {
+      return this.infoWindowDataInstance.getSelected();
     },
 
     /**
@@ -733,19 +484,10 @@ export default {
      */
     gridFieldPropertyChanged: function (infoGridFieldsClone) {
       let _self = this;
-      InfoUtil.saveInfoGridFields(
+
+      _self.infoGridFieldsInstance.saveInfoGridFields(
         _self.infoWindowDto.no,
         infoGridFieldsClone,
-      ).then(
-        successData => {
-          InfoUtil.restoreInfoGridFields(
-            _self.infoWindowDto.no,
-            _self.infoGridFields,
-          );
-        },
-        errorData => {
-          console.log(errorData);
-        },
       );
     },
 
@@ -1022,21 +764,8 @@ export default {
      * 获取选择数据的Id集合
      */
     getSelectedRecordIds: function () {
-      var _self = this;
-      var recordIds = [];
-
-      if (
-        _self.infoWindowData != null &&
-        _self.infoWindowData.dataList != null
-      ) {
-        _self.infoWindowData.dataList.forEach(function (item) {
-          if (item.select == true) {
-            recordIds.push(item.id);
-          }
-        });
-      }
-
-      return recordIds;
+      return this.infoWindowDataInstance.getSelectedRecordIds();
+     
     },
 
     /**
@@ -1055,67 +784,15 @@ export default {
      * 获取选中的第一个数据的FieldValue
      */
     getFirstSelectModelDataFieldValue: function (name) {
-      var _self = this;
-
-      if (
-        _self.infoWindowData != null &&
-        _self.infoWindowData.dataList != null
-      ) {
-        for (let i = 0; i < _self.infoWindowData.dataList.length; i++) {
-          let item = _self.infoWindowData.dataList[i];
-          if (item.select == true) {
-            return item.data[name].displayValue[0];
-          }
+      const firstData = this.infoWindowDataInstance.getFirstSelected();
+      if(firstData == null){
+        return null;
+      }else{
+        if(firstData.data[name] != null){
+          return firstData.data[name].displayValue[0];
         }
       }
-
-      return undefined;
-    },
-
-    /**
-     * 切换全选/单选
-     */
-    changeSelectMode: function () {
-      this.multipleSelect = !this.multipleSelect;
-    },
-
-    /**
-     * 排序
-     */
-    onSort: function (infoGridField) {
-      var _self = this;
-      var fieldName = null;
-      if (
-        infoGridField.sortFieldName != undefined &&
-        infoGridField.sortFieldName != ''
-      ) {
-        fieldName = infoGridField.sortFieldName;
-      } else {
-        fieldName = infoGridField.fieldName;
-      }
-      var sortStr = fieldName + _self.sortStyle;
-
-      _self.infoQueryParam.sortClause = sortStr;
-      if (_self.currentIsSimpleSearch) {
-        _self.queryInfoWindowDataSimple();
-      } else {
-        _self.queryInfoWindowDataComplex();
-      }
-
-      _self.sortStyle = _self.sortStyle == ' ASC' ? ' DESC' : ' ASC';
-    },
-
-    /**
-     * 冻结表头
-     */
-    fixedTableHeader: function () {
-      let _self = this;
-      _self.$nextTick(function () {
-        var $th = $('#' + _self.tableOutDivId).find('thead');
-        $('#' + _self.tableOutDivId).on('scroll', function () {
-          $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
-        });
-      });
+      return null;
     },
   },
 };
@@ -1126,17 +803,6 @@ export default {
   float: left;
 }
 
-.fixed-table {
-  table-layout: fixed;
-}
-table.fixed-table tr th {
-  text-align: center;
-}
-table.fixed-table td {
-  text-align: center;
-  word-wrap: break-word;
-  word-break: normal;
-}
 .btn-process {
   float: right;
   margin-left: 15px;
@@ -1145,49 +811,6 @@ table.fixed-table td {
   background-color: #6699cc !important;
 }
 
-table.fixed-table th {
-  position: relative;
-  min-width: 25px;
-}
-
-table.fixed-table th,
-table.fixed-table td {
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  border-right: 1px solid rgba(0, 0, 0, 0.05);
-}
-
-table.fixed-table th {
-  min-width: 10px;
-  background-color: #f8f8f8;
-}
-
-table.fixed-table th .rz-handle {
-  width: 10px;
-  height: 100%;
-  position: absolute;
-  top: 0;
-  right: 0;
-  background: repeating-linear-gradient(
-    45deg,
-    transparent,
-    transparent 2px,
-    rgba(0, 0, 0, 0.05) 2px,
-    rgba(0, 0, 0, 0.05) 4px
-  );
-  cursor: ew-resize !important;
-}
-
-table.fixed-table th .rz-handle.rz-handle-active {
-  border-right: 2px solid #000;
-  transform: scaleX(100);
-  background: rgba(0, 0, 0, 0.05) 2px;
-}
-
-.rz-handle:hover {
-  background: rgba(0, 0, 0, 0.2) 4px;
-}
 
 .flex-container {
   display: flex;
@@ -1224,11 +847,6 @@ table.fixed-table th .rz-handle.rz-handle-active {
   height: 0;
 }
 
-.flex-main {
-  overflow: scroll;
-  flex: 1;
-  margin-bottom: 0px;
-}
 </style>
 
 

+ 432 - 0
packages/info/src/QueryPageTable.vue

@@ -0,0 +1,432 @@
+<template>
+  <div :id="tableOutDivId" class="flex-main table-fix-head">
+    <table class="fixed-table table-striped table-bordered" :width="tableWidth" height="40px">
+      <thead>
+        <tr height="40px">
+          <th width="50px">{{ $t("lang.QueryPage.serialNumber") }}</th>
+          <th
+            width="30px" class="text-center" :class="{ 'mulitiple-select': multipleSelect }"
+            @click.self="changeSelectMode"
+          >
+            <input v-model="isSelectAll" autocomplete="off" type="checkbox" />
+          </th>
+          <template v-for="infoGridField in infoGridFieldsInstance.infoGridFields">
+            <th
+              v-if="infoGridField.simpleDisplayType != 'OperateButton'" v-show="infoGridField.isShow"
+              :key="infoGridField.fieldName" :width="infoGridField.width + 'px'"
+              @dragover="ondragover($event, infoGridField)" @click="onSort(infoGridField)"
+            >
+              <div
+                :id="'infoGridFieldId_' + infoGridField.fieldName" class="rz-handle" draggable="true"
+                @dragstart="ondragstart($event, infoGridField)" @drag="ondrag($event, infoGridField)"
+                @dragend="ondragend($event, infoGridField)"
+              />
+
+              <div
+                v-tooltip.right="Language.getHelpTrl($i18n.locale, infoGridField)
+                " class="td-max"
+              >
+                {{ Language.getNameTrl($i18n.locale, infoGridField) }}
+              </div>
+            </th>
+          </template>
+          <th v-if="operateButtons != null && operateButtons.length > 0" style="width: 160px;">
+            操作
+          </th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr
+          v-for="(item1, index) in infoWindowDataInstance.dataList" :key="'tr' + item1.id" height="40px"
+          :class="{ warning: item1.select }" @dblclick="selectNode(item1)"
+        >
+          <td style="text-align: center">
+            {{
+              index +
+                1 +
+                (pagination.current_page - 1) * pagination.per_page
+            }}
+          </td>
+
+          <td class="text-center">
+            <input
+              autocomplete="off" type="checkbox" :checked="item1.select"
+              @click.self="selectNodeForSearch(item1)"
+            />
+          </td>
+          <template v-for="item2 in infoGridFieldsInstance.infoGridFields">
+            <td
+              v-show="item2.isShow" v-if="item2.simpleDisplayType != 'OperateButton'" id="item.id"
+              :key="'td-' + item2.id"
+            >
+              <span v-if="item2.simpleDisplayType == 'Image'">
+                <QueryPageImage
+                  v-if="item1.data[item2.fieldName] != undefined"
+                  :class-name="item2.selectClause"
+                  :image-names="item1.data[item2.fieldName].displayValue[0]"
+                />
+              </span>
+              <span v-else>
+                {{
+                  item1.data[item2.fieldName] != undefined
+                    ? item1.data[item2.fieldName].displayValue[0]
+                    : ""
+                }}
+              </span>
+            </td>
+          </template>
+          <td v-if="operateButtons != null && operateButtons.length > 0">
+            <template v-for="item in operateButtons" :key="item">
+              <a-button @click="executeCallout(item1, item)">{{ item.name }}</a-button>
+            </template>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</template>
+
+
+<script>
+
+import Context from './Context.js';
+import JsUtil from '../../common/JsUtil.js';
+import Language from '../../common/Language.js';
+import QueryPageImage from './QueryPageImage.vue';
+
+import Uuid from '../../common/Uuid.js';
+import Notify from '../../common/Notify.js';
+
+
+
+export default {
+  name: 'QueryPageTable',
+
+  components: {
+    QueryPageImage,
+  },
+
+  props: {
+    callOutJsUrl:{
+      type: String,
+      default() {
+        return null;
+      },
+    },
+    infoWindowDataInstance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+    pagination: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+    infoGridFieldsInstance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+    /**
+         * 是否多选
+         */
+    multiple: {
+      type: Boolean,
+      default: false,
+    },
+
+    /**
+         * 排序对象实例
+         */
+    sortInstance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  
+  emits: ['dataSelected', 'deleteSelected'],
+  data: function () {
+    this.Language = Language;
+    return {
+      isSelectAll: false,
+      multipleSelect: false,
+      // 表格外面的DIV的id
+      tableOutDivId: Uuid.createUUID(),
+    };
+  },
+  
+  computed: {
+    tableWidth: function () {
+      var totalWidth = 50;
+      if (this.infoGridFieldsInstance != undefined
+                && this.infoGridFieldsInstance.infoGridFields != undefined) {
+        this.infoGridFieldsInstance.infoGridFields.forEach(function (item) {
+          if (item.isShow) {
+            totalWidth += Number(item.width);
+          }
+        });
+      }
+      return totalWidth + 'px';
+    },
+    operateButtons: function () {
+      let buttons = [];
+      this.infoGridFieldsInstance.infoGridFields.forEach(item => {
+        if (item.simpleDisplayType == 'OperateButton') {
+          buttons.push(item);
+        }
+      });
+      return buttons;
+    },
+  },
+
+
+  watch: {
+    /**
+         * 是否选择了全部的数据
+         */
+    isSelectAll: function (val) {
+      var _self = this;
+      if (_self.multipleSelect) {
+        if (_self.isSelectAll) {
+          if (val) {                        
+            _self.infoWindowDataInstance.setAllSelect();                       
+          }
+        } else {
+          _self.infoWindowDataInstance.setAllUnSelect();
+        }
+      } else {
+        _self.isSelectAll = false;
+      }
+    },
+    multiple: {
+      handler: function (newValue, oldValue) {
+        this.multipleSelect = newValue;
+      },
+      immediate: true,
+    },
+    'infoWindowDataInstance.timestamp': function (newValue, oldValue) {
+      this.fixedTableHeader();
+    },
+  },
+
+  methods: {
+
+    getContext: Context,
+
+    executeCallout: function (rowData, filedItem) {
+      let _self = this;
+
+      const methodName = filedItem.callOutJsMethod;
+
+      const callOutJsUrl = this.infoWindowDto.callOutJsUrl;
+
+      let functionName = methodName.replace('.', '_') + '_calloutjs';
+
+      let executeFunction = function () {
+
+        let context = new _self.getContext(rowData, {});
+        try {
+          _self[functionName](context);
+        } catch (e) {
+          console.error(e);
+          Notify.error('数据字典定义异常', ` 【 ${methodName} 】前端列显示逻辑定义异常,请联系管理员检查数据字典的定义。`, false);
+        }
+      };
+
+      if (_self[functionName] == null) {
+        // 执行服务端的脚本
+        const jsUrl = callOutJsUrl;
+        if (jsUrl == null || jsUrl == undefined) {
+          Notify.error('数据字典定义异常', `【 ${methodName} 】Callout前端逻辑的JS文件不存在,请联系管理员检查数据字典是否JS文件。`, false);
+          return;
+        }
+        let promise = JsUtil.dynamicLoadJsFunction(jsUrl, methodName);
+        promise.then(targetFunction => {
+          if (targetFunction == null) {
+            Notify.error('数据字典定义异常', `【 ${methodName} 】Callout前端逻辑定义异常,请联系管理员检查数据字典的定义。`, false);
+            return;
+          }
+
+          _self[functionName] = targetFunction;
+          executeFunction();
+
+        }, errorData => {
+          console.error(errorData);
+        });
+      } else {
+        executeFunction();
+      }
+    },
+
+
+    /**
+         * 切换全选/单选
+         */
+    changeSelectMode: function () {
+      this.multipleSelect = !this.multipleSelect;
+    },
+
+
+    ondragstart: function (event, gridFieldItem) {
+      var _self = this;
+      _self.startX = event.pageX;
+      _self.startWidth = Number(gridFieldItem.width);
+      event.dataTransfer.setDragImage(event.target, 0, 20);
+      event.dataTransfer.effectAllowed = 'move';
+    },
+
+    ondrag: function (event, gridFieldItem) {
+      var _self = this;
+      gridFieldItem.width = _self.startWidth + (event.pageX - _self.startX);
+    },
+
+    ondragend: function (event, gridFieldItem, index) {
+      var _self = this;
+      let newWidth = _self.startWidth + (event.pageX - _self.startX);
+      if (newWidth < 50) {
+        newWidth = 50;
+      }
+      _self.infoGridFieldsInstance.changeGridFieldWidth(gridFieldItem, newWidth);
+    },
+
+    ondragover: function (event, gridFieldItem) {
+      event.preventDefault();
+      event.dataTransfer.dropEffect = 'move';
+    },
+
+
+    /**
+         * 选择/取消选择表格行中的复选框事件
+         */
+    selectNodeForSearch: function (modelData) {
+      var _self = this;
+
+      var currentStatus = modelData.select;
+      if (!_self.multipleSelect) {
+        _self.infoWindowDataInstance.setAllUnSelect();
+      }
+
+      _self.infoWindowDataInstance.selectSelectState(modelData, !currentStatus);
+
+      if (modelData.select === true) {
+        _self.$emit('dataSelected', modelData);
+      } else {
+        _self.$emit('deleteSelected', modelData);
+      }
+    },
+
+
+    /**
+         * 双击表格行事件
+         */
+    selectNode: function (modelData) {
+      this.$emit('dataSelected', modelData);
+    },
+
+
+    /**
+         * 冻结表头
+         */
+    fixedTableHeader: function () {
+      let _self = this;
+      _self.$nextTick(function () {
+        var $th = $('#' + _self.tableOutDivId).find('thead');
+        $('#' + _self.tableOutDivId).on('scroll', function () {
+          $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
+        });
+      });
+    },
+
+
+    /**
+         * 排序
+         */
+    onSort: function (infoGridField) {
+      var _self = this;
+      var fieldName = null;
+      if (
+        infoGridField.sortFieldName != undefined &&
+                infoGridField.sortFieldName != ''
+      ) {
+        fieldName = infoGridField.sortFieldName;
+      } else {
+        fieldName = infoGridField.fieldName;
+      }
+      _self.sortInstance.changeFieldName(fieldName);
+    },
+  },
+};
+</script>
+
+<style scoped>
+.flex-main {
+    overflow: scroll;
+    flex: 1;
+    margin-bottom: 0px;
+}
+
+
+.fixed-table {
+    table-layout: fixed;
+}
+
+table.fixed-table tr th {
+    text-align: center;
+}
+
+table.fixed-table td {
+    text-align: center;
+    word-wrap: break-word;
+    word-break: normal;
+}
+
+
+
+table.fixed-table th {
+    position: relative;
+    min-width: 25px;
+}
+
+table.fixed-table th,
+table.fixed-table td {
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    border-right: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+table.fixed-table th {
+    min-width: 10px;
+    background-color: #f8f8f8;
+}
+
+table.fixed-table th .rz-handle {
+    width: 10px;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    right: 0;
+    background: repeating-linear-gradient(45deg,
+            transparent,
+            transparent 2px,
+            rgba(0, 0, 0, 0.05) 2px,
+            rgba(0, 0, 0, 0.05) 4px);
+    cursor: ew-resize !important;
+}
+
+table.fixed-table th .rz-handle.rz-handle-active {
+    border-right: 2px solid #000;
+    transform: scaleX(100);
+    background: rgba(0, 0, 0, 0.05) 2px;
+}
+
+.rz-handle:hover {
+    background: rgba(0, 0, 0, 0.2) 4px;
+}
+</style>

+ 3 - 2
webpack.dev.js

@@ -14,17 +14,18 @@ module.exports = WebpackMerge.merge(baseConfig, {
   devServer: {
     port: 8086,
     historyApiFallback: true,
+    allowedHosts: 'all',
     proxy: {
       '/api': {
           //要访问的跨域的域名
-          target: 'http://192.168.1.129:10022/',
+          target: 'http://192.168.1.5:10023/',
           ws: true, // 是否启用websockets
           //开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样客户端端和服务端进行数据的交互就不会有跨域问题
           changOrigin: true,
       },
       '/content': {
           //要访问的跨域的域名
-          target: 'http://192.168.1.129:10022/',
+          target: 'http://192.168.1.5:10023/',
           ws: true, // 是否启用websockets
           //开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样客户端端和服务端进行数据的交互就不会有跨域问题
           changOrigin: true,