xxyy
2025-03-10 ffe8ac13ba8bc9426f8b5f5b88f094a05b31b7ff
增强功能与修复错误,更新缓存服务

更新多个文件以增强功能和修复错误,包括添加新的缓存服务、更新任务处理逻辑、改进日志记录、以及调整路由和组件配置。新增了对 Redis 缓存的支持,并更新了相关的配置和连接字符串。修复了表格显示逻辑,增强了用户界面的交互性,添加了新的 API 路由和节流过滤器。更新了 `.gitignore` 文件以排除特定的临时文件和数据库文件。
已修改27个文件
已添加33个文件
5204 ■■■■ 文件已修改
.gitignore 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/config/buttons.js 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/public/index.html 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/components/basic/ViewGrid/methods.js 1684 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/components/basic/VolTable.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/basicinfo/router.js 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/deviceInfo.js 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/deviceProtocol.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/deviceProtocolDetail.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/dispatchInfo.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Dictionary.js 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_DictionaryList.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Log.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Role.js 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Role1.js 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_User.js 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/widesea_wms/MOM/MOMMessage.js 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/extension/widesea_wms/stock/DtBoxingInfo.js 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/router/index.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/router/tables.js 86 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/router/viewGird.js 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/src/views/widesea_wms/MOM/ErrorMessage/Message.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/tests/unit/example.spec.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSClient/vue.config.js 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/LogLibrary/Log/Log.cs 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Const/CacheConst.cs 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Extension/LinqExtension.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Extension/ObjectExtension.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/GlobalUsing.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Interface/ISimpleCacheHashService.cs 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Interface/ISimpleCacheService.cs 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Options/CacheSettingsOptions.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/MemoryCacheHashService.cs 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/MemoryCacheService.cs 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/RedisCacheHashService.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/RedisCacheService.cs 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/WIDESEA_Cache.csproj 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Core/DB/Models/BaseEntity.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Services/Sys_CompanyRegistrationService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MCS/MCSService.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MCS/Partial/NotifyFinishTest.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/CellState/CellStateService.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/ProcessApply/ProcessApplyService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/Unbind/UnbindService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/WIDESEA_StoragIntegrationServices.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageBasicServices/Location/LocationInfoService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/AspNetCoreSchedule.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs 665 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Partial/Dt_TaskService.cs 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/WIDESEA_StorageTaskServices.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer.sln 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Filter/CheckingStockOutMiddleware.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Filter/ThrottleFilter.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/WIDESEA_WMSServer.csproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/obj/Debug/net6.0/WIDESEA_WMSServer.MvcApplicationPartsAssemblyInfo.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -1687,6 +1687,13 @@
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/SemanticSymbols.db
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/SemanticSymbols.db-shm
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/SemanticSymbols.db-wal
/Code Management/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/copilot-chat/bef6627e/sessions/4a99214b-9f9f-4ab7-8ce9-83d07cd22a77
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/CodeChunks.db
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/CodeChunks.db-shm
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/CodeChunks.db-wal
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/SemanticSymbols.db
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/SemanticSymbols.db-shm
/Code Management/.vs/Code Management/CopilotIndices/17.13.433.20974/SemanticSymbols.db-wal
/3F/Code Management/WCS/WIDESEAWCS_Server/.vs/ProjectEvaluation/wideseawcs_server.metadata.v7.bin
/3F/Code Management/WCS/WIDESEAWCS_Server/.vs/ProjectEvaluation/wideseawcs_server.projects.v7.bin
/3F/Code Management/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/DesignTimeBuild/.dtbcache.v2
Code Management/WMS/WIDESEA_WMSClient/config/buttons.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,143 @@
let buttons = [{
    name: "查 è¯¢",
    value: 'Search',
    icon: 'el-icon-search',
    class: '',
    type: 'primary',
    onClick: function () {
        this.search();
    }
},
{
    name: "新 å»º",
    icon: 'el-icon-plus',
    value: 'Add',
    class: '',
    //  plain:true,
    type: 'success',
    // plain:true,
    onClick: function () {
        this.add();
    }
},
{
    name: "编 è¾‘",
    icon: 'el-icon-edit',
    value: 'Update',
    // plain:true,
    class: '',
    type: 'primary',
    onClick: function () {
        this.edit();
    }
},
{
    name: "任务完成",
    icon: '',
    class: '',
    value: 'TaskCompleted',
    type: 'primary',
    onClick: function () {
    }
},
{
    name: "任务取消",
    icon: '',
    class: '',
    value: 'TaskCancel',
    type: 'danger',
    onClick: function () {
    }
},
{
    name: "任务恢复",
    icon: '',
    class: '',
    value: 'TaskRecovery',
    type: 'danger',
    onClick: function () {
    }
},
{
    name: "查看完整路由",
    icon: '',
    class: '',
    value: 'ViewAllRouter',
    type: 'info',
    onClick: function () {
    }
},
{
    name: "路由配置",
    icon: '',
    class: '',
    value: 'AddRouters',
    type: 'success',
    onClick: function () {
    }
},
{
    name: "回滚到上一步",
    icon: '',
    class: '',
    value: 'Previous',
    type: 'danger',
    onClick: function () {
    }
},
{
    name: "跳转到下一步",
    icon: '',
    class: '',
    value: 'Next',
    type: 'warning',
    onClick: function () {
    }
},
{
    name: "删 é™¤",
    icon: 'el-icon-delete',
    class: '',
    value: 'Delete',
    type: 'danger',
    onClick: function () {
        this.del();
    }
},
{
    name: "审 æ ¸",
    icon: 'el-icon-check',
    class: '',
    value: 'Audit',
    plain: true,
    type: 'primary',
    onClick: function () {
        this.audit();
    }
},
{
    name: "导 å…¥",
    icon: 'el-icon-top',
    class: '',
    type: 'success',
    plain: true,
    value: 'Import',
    onClick: function () {
        this.import();
    }
},
{
    name: "导 å‡º",
    icon: 'el-icon-bottom',
    type: 'success',
    plain: true,
    value: 'Export',
    onClick: function () {
        this.export();
    }
}
]
export default buttons
Code Management/WMS/WIDESEA_WMSClient/public/index.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,135 @@
<!DOCTYPE html>
<html lang="">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <meta name="keywords" content=".netccore,dotnet core,vue,element,element plus,vue3" />
  <meta name="description" content="" />
  <link rel="icon" href="<%= BASE_URL %>wcslogo.png">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
      Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>
</html>
<style>
  html,
  body {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
  }
  * {
    box-sizing: border-box;
  }
  .el-loading {
    z-index: 999999;
  }
  .el-table th {
    display: table-cell !important;
  }
  .el-loading .el-loading-spinner {
    padding: 7px;
    background: #ececec;
    width: 200px;
    color: red;
    left: 0;
    right: 0;
    margin: 0 auto;
    border-radius: 5px;
    border: 1px solid #a0a0a0;
  }
  h1,
  h2,
  h3,
  h4 {
    margin: 0;
  }
  .v-dialog {
    border-radius: 5px;
    top: 50%;
    /* margin-top: -220px !important; */
  }
  .v-dialog .el-dialog__header {
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    padding: 0px 13px;
    line-height: 53px;
    border-bottom: 1px solid #e2e2e2;
    height: 50px;
    color: white;
    font-weight: bold;
    font-size: 14px;
    background-image: linear-gradient(135deg, #0cd7bd 10%, #50c3f7);
  }
  .v-dialog .el-dialog__header .el-dialog__headerbtn {
    top: 3px;
    right: 0px;
  }
  .v-dialog .el-dialog__header .el-dialog__headerbtn .el-dialog__close {
    font-size: 19px;
    color: white;
  }
  .v-dialog .el-dialog__body {
    padding: 0;
  }
  .el-message {
    z-index: 3500 !important;
  }
  .v-date-range .el-input__inner {
    padding: 0 15px 0 8px
  }
  .v-date-range .el-input__suffix .el-input__icon {
    display: table-caption;
    background: white;
    margin: 1px;
    height: auto;
    margin-right: -4px;
    height: 33px;
    width: 19px;
    font-size: 13px;
    border-top-right-radius: 3px;
    border-bottom-right-radius: 3px;
  }
  .v-date-range .el-icon-circle-check {
    display: none !important;
  }
  .v-dialog .el-dialog__header {
    margin-right: 0;
  }
  .el-button {
    font-size: 12px !important;
  }
  .el-button--small {
    padding: 0px 15px !important;
    height: 32px;
  }
</style>
Code Management/WMS/WIDESEA_WMSClient/src/components/basic/ViewGrid/methods.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1684 @@
import detailMethods from './detailMethods.js';
//业务处理方法,全部可以由开发覆盖
import serviceFilter from './serviceFilter.js';
let methods = {
  //当添加扩展组件gridHeader/gridBody/gridFooter及明细modelHeader/modelBody/modelFooter时,
  //如果要获取父级Vue对象,请使用此方法进行回调
  parentCall(fun) {
    if (typeof fun != 'function') {
      return console.log('扩展组件需要传入一个回调方法才能获取父级Vue对象');
    }
    fun(this);
  },
  getCurrentAction() {
    if (this.currentReadonly) {
      return '';
    }
    return '--' + (this.currentAction == this.const.ADD ? '新增' : '编辑');
  },
  quickSearchKeyPress($event) {
    //查询字段为input时,按回车查询
    if ($event.keyCode == 13) {
      if (this.searchFormFields[this.singleSearch.field] != '') {
        this.search();
      }
    }
  },
  getButtons() {
    //生成ViewGrid界面的操作按钮及更多选项
    let searchIndex = this.buttons.findIndex((x) => {
      return x.value == 'Search';
    });
    //添加高级查询
    let hasOneFormItem =
      this.searchFormOptions.length == 1 &&
      this.searchFormOptions[0].length == 1;
    if (searchIndex != -1 && !hasOneFormItem) {
      this.buttons.splice(searchIndex + 1, 0, {
        icon: this.fiexdSearchForm ? 'el-icon-refresh-left' : 'el-icon-search',
        name: this.fiexdSearchForm ? '重置' : '高级查询',
        plain: true,
        type: this.buttons[searchIndex].type,
        onClick: () => {
          if (this.fiexdSearchForm) {
            return this.resetSearch();
          }
          this.searchBoxShow = !this.searchBoxShow;
        }
      });
    }
    if (hasOneFormItem) {
      this.fiexdSearchForm = false;
    }
    this.maxBtnLength += searchIndex == -1 ? 0 : 1;
    // if (this.buttons.length <= this.maxBtnLength) {
    //   return this.buttons;
    // }
    // let btns = this.buttons.slice(0, this.maxBtnLength);
    // btns[this.maxBtnLength - 1].last = true;
    // return btns;
  },
  extendBtn(btns, source) {
    //btns权限按钮,source为扩展按钮
    if (!btns || !(source && source instanceof Array)) {
      return;
    }
    //source通过在表的扩展js文件中buttons对应按钮的属性index决定按钮所放位置
    source.forEach((x) => {
      //通过按钮的Index属性,放到指定的位置
      btns.splice(x.index == undefined ? btns.length : x.index, 0, x);
    });
    // if (this.extend.buttons.view) {
    //     this.extend.buttons.view.forEach((x) => {
    //         //通过按钮的Index属性,放到指定的位置
    //         this.buttons.splice(x.index == undefined ? this.buttons.length : x.index, 0, x);
    //     })
    // }
  },
  initBoxButtons() {
    //初始化ViewGird与弹出框/明细表按钮
    let path = this.$route.path;
    //通过菜单获取用户所对应菜单需要显示的按钮
    let permissionButtons = this.permission.getButtons(
      path,
      null,
      this.extend.tableAction,
      this.table.name
    );
    if (permissionButtons) {
      //2020.03.31添加深拷贝按钮组
      permissionButtons.forEach((p) => {
        let _obj = {};
        for (const key in p) {
          _obj[key] = p[key];
        }
        this.buttons.push(_obj);
      });
      // this.buttons.push(...permissionButtons);
    }
    if (!this.extend) {
      this.extend = {};
    }
    if (!this.extend.buttons) {
      this.extend.buttons = {};
    }
    //查询界面扩展按钮(扩展按钮可自行通过设置按钮的Index属性显示到具体位置)
    if (this.extend.buttons.view) {
      this.extendBtn(this.buttons, this.extend.buttons.view);
    }
    //弹出框按钮
    let boxButtons = [];
    let saveBtn = this.buttons.some((x) => {
      if (
        x.value &&
        (x.value.toLowerCase() == this.const.ADD.toLowerCase() ||
          x.value.toLowerCase() == this.const.EDIT.toLowerCase())
      )
        return true;
    });
    this.currentReadonly = !saveBtn;
    //从表表格操作按钮
    let detailGridButtons = {
      name: '刷新',
      type: 'info',
      icon: 'el-icon-refresh',
      onClick() {
        //如果明细表当前的状态为新建时,禁止刷新
        if (this.currentAction == this.const.ADD) {
          return;
        }
        this.refreshRow();
      }
    };
    let importExcel = this.buttons.some((x) => {
      if (x.value == this.const.IMPORT) return true;
    });
    //如果有导入权限,则需要初始化导入组件
    if (importExcel) {
      this.upload.url = this.getUrl(this.const.IMPORT);
      //定义下载模板的文件名
      this.upload.template.fileName = this.table.cnName;
      //定义下载模板的Url路径
      this.upload.template.url =
        this.http.ipAddress + this.getUrl(this.const.DOWNLOADTEMPLATE, true);
    }
    // disabled
    //如果当前角色没有编辑或新建功能,查看明细时字段设置全部只读
    //只有明细表,将明细表也设置为不可能编辑,并且不显示添加行、删除行
    if (!saveBtn) {
      this.editFormOptions.forEach((row) => {
        row.forEach((x) => {
          x.disabled = true;
        });
      });
      //没有新增编辑权限的,弹出框都设置为只读
      this.detail.columns.forEach((column) => {
        if (column.hasOwnProperty('edit')) {
          column.readonly = true;
          // row['edit'] = false;
        }
      });
      //弹出框扩展按钮
      this.extendBtn(boxButtons, this.extend.buttons.box);
      //弹出弹框按钮(2020.04.21),没有编辑或新建权限时,也可以通过buttons属性添加自定义弹出框按钮
      this.boxButtons.push(...boxButtons);
      this.detailOptions.buttons.push(detailGridButtons);
      this.detailOptions.buttons.forEach((button) => {
        if (!button.hasOwnProperty('hidden')) {
          button.hidden = false;
        }
      });
      //弹出框扩展明细表按钮
      this.extendBtn(this.detailOptions.buttons, this.extend.buttons.detail);
      return boxButtons;
    }
    this.detailOptions.edit = true;
    boxButtons.push(
      ...[
        {
          name: '保 å­˜',
          icon: 'el-icon-check',
          type: 'danger',
          disabled: false,
          value: 'save',
          onClick() {
            this.save();
          }
        }
        // {
        //   name: '重 ç½®',
        //   icon: 'el-icon-refresh-right',
        //   type: 'primary',
        //   disabled: false,
        //   onClick() {
        //     this.resetEdit();
        //   }
        // }
      ]
    );
    //从表表格操作按钮
    this.detailOptions.buttons.push(
      ...[
        {
          name: '添加行',
          icon: 'el-icon-plus',
          type: 'primary',
          hidden: false,
          plain: true,
          onClick() {
            this.addRow();
          }
        },
        {
          type: 'danger',
          plain: true,
          name: '删除行',
          hidden: false,
          icon: 'el-icon-delete',
          onClick() {
            this.delRow();
          }
        },
        //2022.01.08增加明细表导入导出功能
        //注意需要重写后台明细表接口的导入与下载模板、导出的权限,Sys_DictionaryListController.cs/SellOrderListController.cs
        {
          type: 'danger',
          plain: true,
          name: '导入',
          value: 'import',
          hidden: false,
          icon: 'el-icon-upload2',
          onClick() {
            this.upload.url = `${this.http.ipAddress}api/${this.detail.table}/${this.const.IMPORT}?table=1`;
            this.upload.template.url = `${this.http.ipAddress}api/${this.detail.table}/${this.const.DOWNLOADTEMPLATE}`;
            //定义下载模板的文件名
            this.upload.template.fileName = this.detail.cnName;
            this.upload.excel = true;
          }
        },
        {
          type: 'danger',
          plain: true,
          name: '导出',
          value: 'export',
          icon: 'el-icon-download',
          hidden: false,
          onClick() {
            this.export(true);
          }
        }
      ]
    );
    this.detailOptions.buttons.forEach((button) => {
      if (button.hasOwnProperty('hidden')) {
        button.hidden = false;
      }
    });
    //弹出框扩展按钮
    this.extendBtn(boxButtons, this.extend.buttons.box);
    //弹出框扩展明细表按钮
    this.detailOptions.buttons.push(detailGridButtons);
    this.extendBtn(this.detailOptions.buttons, this.extend.buttons.detail);
    //弹出弹框按钮
    this.boxButtons.push(...boxButtons);
  },
  onClick(click) {
    click.apply(this);
  },
  changeDropdown(btnName, v1) {
    let button = this.buttons.filter((x) => {
      return x.name == btnName;
    });
    if (button && button.length > 0) {
      button[0].onClick.apply(this);
    }
  },
  emptyValue(value) {
    if (typeof value == 'string' && value.trim() === '') {
      return true;
    }
    if (value instanceof Array && !value.length) {
      return true;
    }
    return value === null || value === undefined || value === '';
  },
  getSearchParameters() {
    //获取查询参数
    // 2020.09.11增加固定查询表单,如果设置固定了查询表单,点击查询时,不再关闭
    if (!this.fiexdSearchForm) {
      this.searchBoxShow = false;
    }
    let query = { wheres: [] };
    for (const key in this.searchFormFields) {
      let value = this.searchFormFields[key];
      if (this.emptyValue(value)) continue;
      if (typeof value == 'number') {
        value = value + '';
      }
      let displayType = this.getSearchItem(key);
      //联级只保留选中节点的最后一个值
      if (displayType == 'cascader') {
        //查询下面所有的子节点,如:选中的是父节点,应该查询下面所有的节点数据--待完
        value = value.length ? value[value.length - 1] + '' : '';
      }
      //2021.05.02增加区间查询
      if (
        typeof value == 'string' ||
        ['date', 'datetime', 'range'].indexOf(displayType) == -1
      ) {
        query.wheres.push({
          name: key,
          value:
            typeof value == 'string' ? (value + '').trim() : value.join(','),
          displayType: displayType
        });
        continue;
      }
      for (let index = 0; index < value.length; index++) {
        if (!this.emptyValue(value[index])) {
          query.wheres.push({
            name: key,
            value: (value[index] + '').trim(),
            displayType: (() => {
              if (['date', 'datetime', 'range'].indexOf(displayType) != -1) {
                return index ? 'lessorequal' : 'thanorequal';
              }
              return displayType;
            })()
          });
        }
      }
    }
    return query;
  },
  search() {
    //查询
    // let query = this.getSearchParameters();
    // this.$refs.table.load(query, true);
    this.$refs.table.load(null, true);
  },
  loadTableBefore(param, callBack) {
    //查询前设置查询条件及分页信息
    let query = this.getSearchParameters();
    if (query) {
      param = Object.assign(param, query);
    }
    if (this.$route.query.viewflow && this.$route.query.id) {
      param.wheres.push({
        name: this.table.key,
        value: this.$route.query.id
      });
    }
    // if (this.isViewFlow() && data && data.length) {
    //   let query = JSON.parse(JSON.stringify(this.$route.query));
    //   query.viewflow = 0;
    //   this.$router.replace({ path: this.$route.path, query: query });
    //   this.$nextTick(() => {
    //     this.getWorkFlowSteps(data[0]);
    //   });
    // }
    let status = this.searchBefore(param);
    callBack(status);
  },
  loadTableAfter(data, callBack, result) {
    //查询后
    //2020.10.30增加查询后返回所有的查询信息
    let status = this.searchAfter(data, result);
    callBack(status);
    //自动弹出框审批详情
  },
  loadDetailTableBefore(param, callBack) {
    //明细查询前
    //新建时禁止加载明细
    if (this.currentAction == this.const.ADD) {
      callBack(false);
      return false;
    }
    let status = this.searchDetailBefore(param);
    callBack(status);
  },
  loadDetailTableAfter(data, callBack) {
    //明细查询后
    let status = this.searchDetailAfter(data);
    callBack(status);
  },
  getSearchItem(field) {
    //获取查询的参数
    let data;
    for (let index = 0; index < this.searchFormOptions.length; index++) {
      if (data) return data.type;
      const item = this.searchFormOptions[index];
      data = item.find((x) => {
        return x.field == field;
      });
    }
    return (data || {}).type;
  },
  resetSearch() {
    //重置查询对象
    this.resetSearchForm();
    //2020.10.17增加重置后方法
    this.resetSearchFormAfter && this.resetSearchFormAfter();
  },
  resetEdit() {
    //重置编辑的数据
    let isEdit = this.currentAction != this.const.ADD;
    //重置之前
    if (!this[isEdit ? 'resetUpdateFormBefore' : 'resetAddFormBefore']()) {
      return;
    }
    let objKey = {};
    //编辑状态下,不需要重置主键,创建时间创建人
    if (isEdit) {
      objKey[this.table.key] = this.editFormFields[this.table.key];
    }
    this.resetEditForm(objKey);
    //重置之后
    if (!this[isEdit ? 'resetUpdateFormAfter' : 'resetAddFormAfter']()) {
      return;
    }
  },
  resetSearchForm(sourceObj) {
    //重置查询表
    this.resetForm('searchForm', sourceObj);
  },
  resetEditForm(sourceObj) {
    if (this.hasDetail && this.$refs.detail) {
      // this.$refs.detail.rowData.splice(0);
      this.$refs.detail.reset();
    }
    this.resetForm('form', sourceObj);
    if (this.$refs.form && this.$refs.form.$refs.volform) {
      setTimeout(() => {
        this.$refs.form.$refs.volform.clearValidate();
      }, 100);
    }
  },
  getKeyValueType(formData, isEditForm) {
    try {
      let keyLeft = (isEditForm ? 'e' : 's') + '_b_';
      formData.forEach((item) => {
        item.forEach((x) => {
          if (this.keyValueType.hasOwnProperty(keyLeft + x.field)) {
            return true;
          }
          let data;
          if (x.type == 'switch') {
            this.keyValueType[x.field] = 1;
          } else if (x.bind && x.bind.data) {
            data = x.bind.data;
          } else if (x.data) {
            if (x.data instanceof Array) {
              data = x.data;
            } else if (x.data.data && x.data.data instanceof Array) {
              data = x.data.data;
            }
          }
          if (
            data &&
            data.length > 0 &&
            !this.keyValueType.hasOwnProperty(x.field)
          ) {
            this.keyValueType[x.field] = data[0].key;
            this.keyValueType[keyLeft + x.field] = x.type;
          }
        });
      });
    } catch (error) {
      console.log(error.message);
    }
  },
  resetForm(formName, sourceObj) {
    //   return;
    //重置表单数据
    if (this.$refs[formName]) {
      this.$refs[formName].reset();
    }
    if (!sourceObj) return;
    let form, keyLeft;
    if (formName == 'searchForm') {
      form = this.searchFormFields;
      keyLeft = 's' + '_b_';
    } else {
      form = this.editFormFields;
      keyLeft = 'e' + '_b_';
    }
    //获取数据源的data类型,否则如果数据源data的key是数字,重置的值是字符串就无法绑定值
    if (!this.keyValueType._dinit) {
      this.getKeyValueType(this.editFormOptions, true);
      this.getKeyValueType(this.searchFormOptions, false);
      this.keyValueType._dinit = true;
    }
    var _cascaderParentTree;
    for (const key in form) {
      if (sourceObj.hasOwnProperty(key)) {
        let newVal = sourceObj[key];
        let kv_type = this.keyValueType[keyLeft + key];
        if (
          kv_type == 'selectList' ||
          kv_type == 'checkbox' ||
          kv_type == 'cascader' ||
          kv_type == 'treeSelect'
        ) {
          // 2020.05.31增加iview组件Cascader
          // 2020.11.01增加iview组件Cascader表单重置时查询所有的父节点
          if (kv_type == 'cascader' || kv_type == 'treeSelect') {
            var treeDic = this.dicKeys.find((dic) => {
              return dic.fileds && dic.fileds.indexOf(key) != -1;
            });
            if (treeDic && treeDic.orginData && treeDic.orginData.length) {
              let keyIsNum = typeof treeDic.orginData[0].id == 'number';
              if (kv_type == 'cascader') {
                newVal = keyIsNum ? newVal * 1 || 0 : newVal + '';
                if (kv_type == 'cascader') {
                  _cascaderParentTree = this.base.getTreeAllParent(
                    newVal,
                    treeDic.orginData
                  );
                  if (_cascaderParentTree) {
                    newVal = _cascaderParentTree.map((x) => {
                      return x.id;
                    });
                  }
                }
              } else {
                if (newVal === null || newVal === undefined) {
                  newVal = [];
                } else if (typeof newVal == 'string') {
                  newVal = newVal.split(',');
                }
                if (keyIsNum) {
                  if (Array.isArray(newVal)) {
                    newVal = newVal.map((x) => {
                      return x * 1 || 0;
                    });
                  }
                } else if (typeof newVal == 'number') {
                  newVal = [newVal + ''];
                }
              }
            } else {
              newVal = [newVal];
            }
          } else if (
            newVal != '' &&
            newVal != undefined &&
            typeof newVal == 'string'
          ) {
            newVal = newVal.split(',');
          } else if (kv_type == 'checkbox') {
            newVal = [];
          }
        } else if (
          this.keyValueType.hasOwnProperty(key) &&
          typeof this.keyValueType[key] == 'number' &&
          newVal * 1 == newVal
        ) {
          newVal = newVal * 1;
        } else {
          if (newVal == null || newVal == undefined) {
            newVal = '';
          } else if (this.numberFields.indexOf(key) != -1) {
            newVal = newVal * 1 || 0;
          } else {
            newVal += '';
          }
        }
        if (newVal instanceof Array) {
          if (form[key]) {
            form[key] = [];
          }
          form[key] = newVal;
        } else {
          form[key] = newVal;
        }
      } else {
        form[key] = form[key] instanceof Array ? [] : '';
      }
    }
  },
  onBtnClick(param) {
    this[param.method](param.data);
  },
  refresh() {
    //刷新
    this.search();
    // this.$refs.table.load();
  },
  saveBefore(formData) {
    return true;
  },
  saveAfter(formData, result) {
    return true;
  },
  save() {
    //新增或编辑时保存
    // if (!this.$refs.form.validate()) return;
    this.$refs.form.validate((result) => {
      if (result) {
        this.saveExecute();
      }
    });
  },
  async saveExecute() {
    let editFormFields = {};
    //上传文件以逗号隔开
    for (const key in this.editFormFields) {
      if (
        this.uploadfiled &&
        this.uploadfiled.length > 0 &&
        this.uploadfiled.indexOf(key) != -1 &&
        this.editFormFields[key] instanceof Array
      ) {
        let allPath = this.editFormFields[key].map((x) => {
          return x.path;
        });
        editFormFields[key] = allPath.join(',');
      } else if (typeof this.editFormFields[key] == 'function') {
        try {
          editFormFields[key] = this.editFormFields[key]();
        } catch (error) { }
      } else {
        //2021.05.30修复下拉框清除数据后后台不能保存的问题
        if (
          this.editFormFields[key] === undefined &&
          this.dicKeys.some((x) => {
            return x.fileds && x.fileds.indexOf(key) != -1;
          })
        ) {
          editFormFields[key] = null;
        } else {
          editFormFields[key] = this.editFormFields[key];
        }
      }
    }
    //将数组转换成string
    //2020.11.01增加级联处理
    for (const key in editFormFields) {
      if (editFormFields[key] instanceof Array) {
        var iscascader = this.dicKeys.some((x) => {
          return (
            x.type == 'cascader' && x.fileds && x.fileds.indexOf(key) != -1
          );
        });
        if (iscascader && editFormFields[key].length) {
          editFormFields[key] =
            editFormFields[key][editFormFields[key].length - 1];
        } else {
          editFormFields[key] = editFormFields[key].join(',');
        }
      }
    }
    let formData = {
      mainData: editFormFields,
      detailData: null,
      delKeys: null
    };
    //获取明细数据(前台数据明细未做校验,待完.后台已经校验)
    if (this.hasDetail) {
      formData.detailData = this.$refs.detail.rowData;
      let _fields = this.detail.columns
        .filter((c) => {
          return (
            c.type == 'selectList' || (c.edit && c.edit.type == 'selectList')
          );
        })
        .map((c) => {
          return c.field;
        });
      //2022.06.20增加保存时对明细表下拉框多选的判断
      if (_fields.length) {
        formData.detailData = JSON.parse(JSON.stringify(formData.detailData));
        formData.detailData.forEach((row) => {
          for (let index = 0; index < _fields.length; index++) {
            const _field = _fields[index];
            if (Array.isArray(row[_field])) {
              row[_field] = row[_field].join(',');
            }
          }
        });
      }
    }
    if (this.detailOptions.delKeys.length > 0) {
      formData.delKeys = this.detailOptions.delKeys;
    }
    //保存前拦截
    let _currentIsAdd = this.currentAction == this.const.ADD;
    if (_currentIsAdd) {
      //2020.12.06增加新建前异步处理方法
      //2021.08.16修复异步语法写错的问题
      if (!this.addBefore(formData) || !(await this.addBeforeAsync(formData)))
        return;
    } else {
      //2020.12.06增加修改前异步处理方法
      if (
        !this.updateBefore(formData) ||
        !(await this.updateBeforeAsync(formData))
      )
        return;
    }
    let url = this.getUrl(this.currentAction);
    this.http.post(url, formData, true).then((x) => {
      //保存后
      if (_currentIsAdd) {
        if (!this.addAfter(x)) return;
        //连续添加
        if (this.continueAdd && x.status) {
          this.$success(x.message);
          //新建
          this.currentAction = this.const.ADD;
          this.currentRow = {};
          this.resetAdd();
          this.refresh();
          return;
        }
      } else {
        if (!this.updateAfter(x)) return;
      }
      if (!x.status) return this.$error(x.message);
      this.$success(x.message || '操作成功');
      //如果保存成功后需要关闭编辑框,直接返回不处理后面
      if (this.boxOptions.saveClose) {
        this.boxModel = false;
        //2020.12.27如果是编辑保存后不重置分页页数,刷新页面时还是显示当前页的数据
        this.$refs.table.load(null, _currentIsAdd);
        //this.refresh();
        return;
      }
      let resultRow;
      if (typeof x.data == 'string' && x.data != '') {
        resultRow = JSON.parse(x.data);
      } else {
        resultRow = x.data;
      }
      if (this.currentAction == this.const.ADD) {
        //  this.currentRow=x.data;
        this.editFormFields[this.table.key] = '';
        this.currentAction = this.const.EDIT;
        this.currentRow = resultRow.data;
      }
      this.resetEditForm(resultRow.data);
      // console.log(resultRow);
      if (this.hasDetail) {
        this.detailOptions.delKeys = [];
        if (resultRow.list) {
          this.$refs.detail.rowData.push(...resultRow.list);
        }
      }
      this.$refs.table.load(null, _currentIsAdd);
      // this.refresh();
    });
  },
  del(rows) {
    if (rows) {
      if (!(rows instanceof Array)) {
        rows = [rows];
      }
    } else {
      rows = this.$refs.table.getSelected();
    }
    //删除数据
    if (!rows || rows.length == 0) return this.$error('请选择要删除的行!');
    let delKeys = rows.map((x) => {
      return x[this.table.key];
    });
    if (!delKeys || delKeys.length == 0)
      return this.$error('没有获取要删除的行数据!');
    //删除前
    if (!this.delBefore(delKeys, rows)) {
      return;
    }
    let tigger = false;
    this.$confirm('确认要删除选择的数据吗?', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
      center: true
    }).then(() => {
      if (tigger) return;
      tigger = true;
      let url = this.getUrl(this.const.DEL);
      this.http.post(url, delKeys, '正在删除数据....').then((x) => {
        if (!x.status) return this.$error(x.message);
        this.$success("删除成功");
        //删除后
        if (!this.delAfter(x)) {
          return;
        }
        this.refresh();
      });
    });
  },
  async modelOpenBeforeAsync(row) {
    return true;
  },
  async initBox() {
    //2022.01.08增加新建时隐藏明细表导出功能
    this.detailOptions.buttons.forEach((x) => {
      if (x.value == 'export') {
        x.hidden = this.currentAction == 'Add';
      }
    });
    //初始化新建、编辑的弹出框
    if (!(await this.modelOpenBeforeAsync(this.currentRow))) return false;
    this.modelOpenBefore(this.currentRow);
    if (!this.boxInit) {
      this.boxInit = true;
      this.boxModel = true;
      // this.detailUrl = this.url;
    }
    return true;
  },
  setEditForm(row) {
    // if (this.remoteColumns.length == 0 || !rows || rows.length == 0) return;
    let remoteColumns = this.$refs.table.remoteColumns;
    remoteColumns.forEach((column) => {
      this.editFormOptions.forEach((option) => {
        option.forEach((x) => {
          if (x.field == column.field) {
            x.data.data = Object.assign([], x.data, column.bind.data);
          }
        });
      });
    });
    this.editFormFields;
    //重置编辑表单数据
    this.editFormFields[this.table.key] = row[this.table.key];
    this.resetEditForm(row);
    this.currentAction = this.const.EDIT;
    this.boxModel = true;
  },
  async linkData(row, column) {
    this.boxOptions.title = this.table.cnName + '(编辑)';
    //点击table单元格快捷链接显示编辑数据
    this.currentAction = this.const.EDIT;
    this.currentRow = row;
    if (!(await this.initBox())) return;
    this.resetDetailTable(row);
    this.setEditForm(row);
    this.setContinueAdd(false);
    //设置远程查询表单的默认key/value
    this.getRemoteFormDefaultKeyValue();
    //点击编辑按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
    this.modelOpenProcess(row);
  },
  setContinueAdd(isAdd) {
    if (!this.continueAdd) return;
    var _button = this.boxButtons.find((x) => {
      return x.value == 'save';
    });
    if (_button) {
      _button.name = isAdd ? this.continueAddName : '保 å­˜';
    }
  },
  resetAdd() {
    if (this.hasDetail) {
      this.$refs.detail &&
        //  this.$refs.detail.rowData &&
        this.$refs.detail.reset();
    }
    let obj = {};
    //如果有switch标签,默认都设置为否
    this.editFormOptions.forEach((x) => {
      x.forEach((item) => {
        if (item.type == 'switch') {
          obj[item.field] = 0;
        }
      });
    });
    this.resetEditForm(obj);
  },
  async add() {
    this.boxOptions.title = this.table.cnName + '(新建)';
    //新建
    this.currentAction = this.const.ADD;
    this.currentRow = {};
    if (!(await this.initBox())) return;
    this.resetAdd();
    this.setContinueAdd(true);
    //  this.resetEditForm();
    this.boxModel = true;
    //点击新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
    this.modelOpenProcess();
    // this.modelOpenAfter();
  },
  async edit(rows) {
    this.boxOptions.title = '编辑';
    //编辑
    this.currentAction = this.const.EDIT;
    if (rows) {
      if (!(rows instanceof Array)) {
        rows = [rows];
      }
    } else {
      rows = this.$refs.table.getSelected();
    }
    if (rows.length == 0) {
      return this.$error('请选择要编辑的行!');
    }
    if (rows.length != 1) {
      return this.$error('只能选择一行数据进行编辑!');
    }
    //记录当前编辑的行
    this.currentRow = rows[0];
    //初始化弹出框
    if (!(await this.initBox())) return;
    this.setContinueAdd(false);
    //重置表单
    this.resetDetailTable();
    //设置当前的数据到表单上
    this.setEditForm(rows[0]);
    //设置远程查询表单的默认key/value
    this.getRemoteFormDefaultKeyValue();
    //点击编辑按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
    this.modelOpenProcess(rows[0]);
    // this.modelOpenAfter(rows[0]);
  },
  getRemoteFormDefaultKeyValue() {
    //设置表单远程数据源的默认key.value
    if (this.currentAction != this.const.EDIT || this.remoteKeys.length == 0)
      return;
    this.editFormOptions.forEach((x, xIndex) => {
      x.forEach((item, yIndex) => {
        if (item.remote) {
          let column = this.columns.find((x) => {
            return x.bind && x.bind.key == item.dataKey;
          });
          if (!column) return;
          let key = this.currentRow[item.field];
          let obj = column.bind.data.find((x) => {
            return x.key == key;
          });
          // obj ? obj.value : key如果没有查到数据源,直接使用原数据
          item.data = [{ key: key, value: obj ? obj.value : key }];
          this.editFormOptions[xIndex].splice(yIndex, 1, item);
          // this.$set(item, 'data', [{ key: key + '', value: obj.value }])
          //  item.data = [{ key: key + '', value: obj.value }];
        }
      });
    });
  },
  modelOpenProcess(row) {
    this.$nextTick(() => {
      this.modelOpenAfter(row);
    });
    return;
    // if (!this.$refs.form) {
    //     let timeOut = setTimeout(x => {
    //         this.modelOpenAfter(row);
    //     }, 500)
    //     return;
    // }
    // this.modelOpenAfter(row);
  },
  import() {
    //导入(上传excel),弹出导入组件UploadExcel.vue
    this.upload.excel = true;
    this.$refs.upload_excel && this.$refs.upload_excel.reset();
  },
  download(url, fileName) {
    //下载导出的文件
    let xmlResquest = new XMLHttpRequest();
    xmlResquest.open('GET', url, true);
    xmlResquest.setRequestHeader('Content-type', 'application/json');
    xmlResquest.setRequestHeader(
      'Authorization',
      this.$store.getters.getToken()
    );
    let elink = this.$refs.export;
    xmlResquest.responseType = 'blob';
    xmlResquest.onload = function (oEvent) {
      if (xmlResquest.status != 200) {
        this.$error('下载文件出错了..');
        return;
      }
      let content = xmlResquest.response;
      //  let elink = this.$refs.export;//document.createElement("a");
      elink.download = fileName; //+".xlsx";
      // elink.style.display = "none";
      let blob = new Blob([content]);
      elink.href = URL.createObjectURL(blob);
      //  document.body.appendChild(elink);
      elink.click();
      //  document.body.removeChild(elink);
    };
    xmlResquest.send();
  },
  getFileName(isDetail) {
    //2021.01.08增加导出excel时自定义文件名
    if (isDetail) {
      return this.detail.cnName + '.xlsx';
    }
    return this.table.cnName + '.xlsx';
  },
  export(isDetail) {
    //导出
    let url, query, param;
    if (isDetail) {
      //明细表导出时如果是新建状态,禁止导出
      if (this.currentAction == 'Add') {
        return;
      }
      url = `api/${this.detail.table}/${this.const.EXPORT}`;
      param = {
        wheres: [
          { name: this.table.key, value: this.editFormFields[this.table.key] }
        ]
      };
    } else {
      //主表导出
      url = this.getUrl(this.const.EXPORT);
      query = this.getSearchParameters();
      param = { order: this.pagination.order, wheres: query.wheres || [] };
    }
    //2020.06.25增加导出前处理
    if (!isDetail && !this.exportBefore(param)) {
      return;
    }
    if (param.wheres && typeof param.wheres == 'object') {
      param.wheres = JSON.stringify(param.wheres);
    }
    let $http = this.http;
    //2022.09.26增加自定义导出文件名
    let fileName = this.downloadFileName || this.getFileName(isDetail);
    //2021.01.08优化导出功能
    $http
      .post(url, param, '正在导出数据....', { responseType: 'blob' })
      .then((content) => {
        const blob = new Blob([content]);
        if ('download' in document.createElement('a')) {
          // éžIE下载
          const elink = document.createElement('a');
          elink.download = fileName;
          elink.style.display = 'none';
          elink.href = URL.createObjectURL(blob);
          document.body.appendChild(elink);
          elink.click();
          URL.revokeObjectURL(elink.href);
          document.body.removeChild(elink);
        } else {
          // IE10+下载
          navigator.msSaveBlob(blob, fileName);
        }
      });
    //.then(result => {
    // if (!result.status) {
    //   return this.$error(result.message);
    // }
    // let path = this.getUrl(this.const.DOWNLOAD);
    // path = path[0] == "/" ? path.substring(1) : path;
    // this.download(
    //   $http.ipAddress + path + "?path=" + result.data,
    //   this.table.cnName + ".xlsx" // filePath
    // );
    ///  window.open($http.ipAddress + path + "?fileName=" + filePath, "_self");
    // });
  },
  getSelectRows() {
    //获取选中的行
    return this.$refs.table.getSelected();
  },
  getDetailSelectRows() {
    //或获取明细选中的行
    if (!this.$refs.detail) {
      return [];
    }
    return this.$refs.detail.getSelected();
  },
  audit() {
    //审核弹出框
    let rows = this.$refs.table.getSelected();
    if (rows.length == 0) return this.$error('请选择要审核的行!');
    let auditStatus = Object.keys(rows[0]).find(x => { return x.toLowerCase() === 'auditstatus' });
    if (!auditStatus) {
      return this.$message.error(`表必须包括审核字段【AuditStatus】,并且是int类型`)
    }
    // let checkStatus = rows.every((x) => {
    //   return this.$global.audit.status.some(c => { return c === x[auditStatus] || !x[auditStatus] })
    // });
    // if (!checkStatus) return this.$error('只能选择待审批或审核中的数据!');
    this.$refs.audit.open(rows);
  },
  saveAudit(params, rows, callback) {
    //保存审核
    let keys = rows.map(x => { return x[this.table.key] });
    if (!this.auditBefore(keys, rows)) {
      return;
    }
    let url = `${this.getUrl(this.const.AUDIT)}?auditReason=${params.reason}&auditStatus=${params.value}`
    this.http.post(url, keys, '审核中....').then((x) => {
      if (!this.auditAfter(x, keys)) {
        return;
      }
      if (!x.status) return this.$error(x.message);
      callback && callback(x);
      this.$success(x.message);
      this.refresh();
    });
  },
  viewModelCancel() {
    //查看表结构
    this.viewModel = false;
  },
  initFormOptions(formOptions, keys, formFields, isEdit) {
    //初始化查询、编辑对象的下拉框数据源、图片上传链接地址
    //let defaultOption = { key: "", value: "请选择" };
    //有上传的字段
    //2020.05.03新增
    //编辑数据源的类型
    formOptions.forEach((item) => {
      item.forEach((d) => {
        if (d.type == 'number') {
          //2022.08.22优化表单类型为number时的默认值
          if (formFields[d.field] === '') {
            formFields[d.field] = undefined;
          }
          this.numberFields.push(d.field);
        }
        if (
          d.type == 'img' ||
          d.type == 'excel' ||
          d.type == 'file' ||
          d.columnType == 'img'
        ) {
          d.url = this.http.ipAddress + 'api' + this.table.url + 'Upload';
          this.uploadfiled.push(d.field);
        }
        if (!d.dataKey) return true;
        //2022.02.20强制开启联级可以选择某个节点
        if (d.type == 'cascader' && !d.hasOwnProperty('changeOnSelect')) {
          //强制开启联级可以选择某个节点
          d.changeOnSelect = true;
        }
        //开启远程搜索
        if (d.remote) {
          this.remoteKeys.push(d.dataKey);
          d.data = []; //{ dicNo: d.dataKey, data: [] };
          return true;
        }
        //2020.05.03增加编辑表单对checkbox的支持
        if (d.type == 'checkbox' && !(formFields[d.field] instanceof Array)) {
          formFields[d.field] = [];
        }
        if (keys.indexOf(d.dataKey) == -1) {
          //2020.05.03增加记录编辑字段的数据源类型
          keys.push(d.dataKey);
          //2020.05.03修复查询表单与编辑表单type类型变成强一致性的问题
          //this.dicKeys.push({ dicNo: d.dataKey, data: [], type: d.type });
          //  2020.11.01增加iview组件Cascader数据源存储
          let _dic = {
            dicNo: d.dataKey,
            data: [],
            fileds: [d.field],
            orginData: []
          };
          if (d.type == 'cascader') {
            _dic.type = 'cascader';
          }
          if (isEdit) {
            _dic['e_type'] = d.type;
          }
          this.dicKeys.push(_dic);
        } else if (d.type == 'cascader') {
          this.dicKeys.forEach((x) => {
            if (x.dicNo == d.dataKey) {
              x.type = 'cascader';
              x.fileds.push(d.field);
            }
          });
        }
        if (d.type != 'cascader') {
          //2020.01.30移除内部表单formOptions数据源配置格式data.data,所有参数改为与组件api格式相同
          Object.assign(
            d,
            this.dicKeys.filter((f) => {
              return f.dicNo == d.dataKey;
            })[0],
            { type: d.type }
          );
        }
      });
    });
  },
  //初始table与明细表的数据源指向dicKeys对象,再去后台加载数据源
  initColumns(scoure, dicKeys, keys) {
    if (!scoure || !(scoure instanceof Array)) return;
    scoure.forEach((item) => {
      if (!item.bind || (item.bind.data && item.bind.data.length > 0))
        return true;
      let key = item.bind.key || item.bind.dicNo;
      if (this.remoteKeys.indexOf(key) != -1) {
        item.bind.remote = true;
        return true;
      }
      if (this.hasKeyField.indexOf(item.field) == -1) {
        this.hasKeyField.push(item.field);
      }
      var dic = dicKeys.filter((x) => {
        return x.dicNo == key;
      });
      if (!dic || dic.length == 0) {
        dicKeys.push({ dicNo: key, data: [] });
        dic = [dicKeys[dicKeys.length - 1]];
        keys.push(key);
      }
      //2020.11.01增加级联处理
      if (dic[0].type == 'cascader' || dic[0].type == 'treeSelect') {
        item.bind = { data: dic[0].orginData, type: 'select', key: key };
      } else {
        item.bind = dic[0];
      }
      //2020.05.03优化table数据源checkbox与select类型从编辑列中选取
      item.bind.type = item.bind.e_type || 'string';
    });
  },
  bindOptions(dic) {
    //绑定下拉框的数据源
    //绑定后台的字典数据
    dic.forEach((d) => {
      if (d.data.length >= (this.select2Count || 500)) {
        if (
          !this.dicKeys.some((x) => {
            return (
              x.dicNo == d.dicNo &&
              (x.type == 'cascader' || x.type == 'treeSelect')
            );
          })
        ) {
          d.data.forEach((item) => {
            item.label = item.value;
            item.value = item.key;
          });
        }
      }
      this.dicKeys.forEach((x) => {
        if (x.dicNo != d.dicNo) return true;
        //2020.10.26增加级联数据源绑定处理
        if (x.type == 'cascader' || x.type == 'treeSelect') {
          // x.data=d.data;
          //生成tree结构
          let _data = JSON.parse(JSON.stringify(d.data));
          //2022.04.04增加级联字典数据源刷新后table没有变化的问题
          this.columns.forEach((column) => {
            if (column.bind && column.bind.key == d.dicNo) {
              column.bind.data = d.data;
            }
          });
          let arr = this.base.convertTree(_data, (node, data, isRoot) => {
            if (!node.inited) {
              node.inited = true;
              node.label = node.value;
              node.value = node.key;
            }
          });
          x.data.push(...arr);
          x.orginData.push(...d.data);
          //2021.10.17修复查询级联不能绑定数据源的问题
          this.searchFormOptions.forEach((searhcOption) => {
            searhcOption.forEach((_option) => {
              if (_option.type == 'cascader' && _option.dataKey == x.dicNo) {
                _option.data = arr;
                _option.orginData = d.data;
              }
            });
          });
          //2021.10.17修复级联不能二级刷新的问题
          this.editFormOptions.forEach((editOption) => {
            editOption.forEach((_option) => {
              if (
                (_option.type == 'cascader' || _option.type == 'treeSelect') &&
                _option.dataKey == x.dicNo
              ) {
                _option.data = arr;
                _option.orginData = d.data;
              }
            });
          });
        } else if (d.data.length > 0 && !d.data[0].hasOwnProperty('key')) {
          let source = d.data,
            newSource = new Array(source.length);
          for (let index = 0; index < source.length; index++) {
            newSource[index] = {
              //默认从字典数据读出来的key都是string类型,但如果数据从sql中查询的可能为非string,否是async-validator需要重置设置格式
              key: source['key'] + '', //source[index][x.config.valueField] + "",
              value: source['value'] //source[index][x.config.textField]
            };
          }
          x.data.push(...newSource);
        } else {
          //2020.06.06,如果是selectList数据源使用的自定义sql并且key是数字,强制转换成字符串
          if (
            x.e_type == 'selectList' &&
            d.data.length > 0 &&
            typeof d.data[0].key == 'number'
          ) {
            d.data.forEach((c) => {
              c.key = c.key + '';
            });
          }
          x.data.push(...d.data);
        }
        if (
          this.singleSearch &&
          this.singleSearch.dataKey &&
          this.singleSearch.dataKey == x.dicNo
        ) {
          this.singleSearch.data.splice(0, 1, ...x.data);
        }
      });
    });
  },
  getUrl(action, ingorPrefix) {
    //是否忽略前缀/  èŽ·å–æ“ä½œçš„url
    return (!ingorPrefix ? '/' : '') + 'api' + this.table.url + action;
  },
  initDicKeys() {
    //初始化字典数据
    let keys = [];
    //2022.04.17优化重新加载数据源
    this.dicKeys.forEach((item) => {
      item.data.splice(0);
      item.orginData && item.orginData.splice(0);
    });
    //this.dicKeys.splice(0);
    //初始化编辑数据源,默认为一个空数组,如果要求必填设置type=number/decimal的最小值
    this.initFormOptions(this.editFormOptions, keys, this.editFormFields, true);
    //初始化查询数据源,默认为一个空数组
    this.initFormOptions(
      this.searchFormOptions,
      keys,
      this.searchFormFields,
      false
    );
    //查询日期设置为可选开始与结果日期
    this.searchFormOptions.forEach((item) => {
      item.forEach((x) => {
        if (x.type == 'date' || x.type == 'datetime') x.range = true;
      });
    });
    //初始化datatable表数据源,默认为一个空数组,dicKeys为界面所有的数据字典编号
    this.initColumns(this.columns, this.dicKeys, keys);
    //2021.05.23默认开启查询页面所有字段排序,如果不需要排序,在onInited遍历columns设置sort=false
    //2021.09.25移除强制排序功能
    // this.columns.forEach(x => {
    //   x.sort = x.render ? false : true;
    // })
    if (this.detailOptions && this.detailOptions.columns) {
      this.initColumns(this.detailOptions.columns, this.dicKeys, keys);
    }
    //初始化快速查询字段,默认使用代码生成器配置的第一个查询字段
    if (this.searchFormOptions.length > 0) {
      this.singleSearch = {
        dataKey: this.searchFormOptions[0][0].dataKey,
        dicNo: this.searchFormOptions[0][0].dicNo,
        field: this.searchFormOptions[0][0].field,
        title: this.searchFormOptions[0][0].title,
        type: this.searchFormOptions[0][0].type,
        data: []
      };
      // this.singleSearch = this.searchFormOptions[0][0];
    }
    if (keys.length == 0) return;
    let $this = this;
    this.http.post('/api/Sys_Dictionary/GetVueDictionary', keys).then((dic) => {
      $this.bindOptions(dic);
      //2022.04.04增加字典加载完成方法
      $this.dicInited && $this.dicInited(dic);
    });
  },
  setFiexdColumn(columns, containerWidth) {
    //计算整个table的宽度,根据宽度决定是否启用第一行显示的列为固定列
    //2021.09.21移除强制固定第一列
    // let columnsWidth = 0;
    // columns.forEach(x => {
    //   if (!x.hidden && x.width) {
    //     columnsWidth += x.width;
    //   }
    // });
    // //启用第一列为固定列
    // if (columnsWidth > containerWidth) {
    //   let firstColumn = columns.find(x => !x.hidden);
    //   if (firstColumn) {
    //     firstColumn.fixed = true;
    //   }
    // }
  },
  initBoxHeightWidth() {
    //初始化弹出框的高度与宽度
    let clientHeight = document.documentElement.clientHeight;
    //弹出框高度至少250px
    clientHeight = clientHeight < 250 ? 250 : clientHeight;
    let clientWidth = document.documentElement.clientWidth;
    if (
      this.editFormOptions.some((x) => {
        return x.some((item) => {
          return item.type == 'editor';
        });
      })
    ) {
      this.editor.uploadImgUrl = this.getUrl('upload');
      this.boxOptions.height = clientHeight * 0.8;
      this.boxOptions.width = clientWidth * 0.8;
    } else {
      if (this.boxOptions.height) {
        //如果高度与宽度超过了获取到的可见高宽度,则设为默认的90%高宽
        if (this.boxOptions.height > clientHeight * 0.8) {
          this.boxOptions.height = clientHeight * 0.8;
        }
      }
      if (this.boxOptions.width) {
        //如果高度与宽度超过了获取到的可见高宽度,则设为默认的90%高宽
        if (this.boxOptions.width > clientWidth * 0.8) {
          this.boxOptions.width = clientWidth * 0.8;
        }
      }
    }
    //计算整个table的宽度,根据宽度决定是否启用第一行显示的列为固定列
    let maxTableWidth = clientWidth - 270;
    this.setFiexdColumn(this.columns, maxTableWidth);
    this.height = this.tableHeight || clientHeight - 206;
    this.url = this.getUrl(this.const.PAGE);
    //计算弹出框的高与宽度
    //如果有明细表,高度与宽带设置为0.9/0.82
    if (this.detail.columns && this.detail.columns.length > 0) {
      this.hasDetail = true;
      clientWidth = clientWidth * 0.8;
      clientHeight = clientHeight * 0.85;
      if (!this.detailOptions.height) {
        this.detailOptions.height =
          clientHeight - this.editFormOptions.length * 36 - 234;
        this.detailOptions.height =
          this.detailOptions.height < 240 ? 240 : this.detailOptions.height;
      }
      this.detailOptions.columns = this.detail.columns;
      this.detailOptions.pagination.sortName = this.detail.sortName;
      this.detailOptions.cnName = this.detail.cnName;
      this.detailOptions.key = this.detail.key;
      this.detailOptions.url = this.getUrl('getDetailPage');
      //计算弹出框整个table的宽度,根据宽度决定是否启用第一行显示的列为固定列
      this.setFiexdColumn(this.detail.columns, clientWidth);
    } else {
      let maxColumns = 1; //最大列数,根据列计算弹框的宽度
      this.editFormOptions.forEach((x) => {
        if (x.length > maxColumns) maxColumns = x.length;
      });
      let maxHeightRate = 0.7,
        maxWidthRate = 0.5;
      maxWidthRate = maxColumns / 10 + 0.3;
      maxHeightRate = (this.editFormOptions.length || 1) * 0.1 + 0.03;
      maxHeightRate = maxHeightRate > 0.9 ? 0.9 : maxHeightRate;
      clientWidth = clientWidth * maxWidthRate;
      clientHeight = clientHeight * maxHeightRate;
      // this.boxOptions.width = clientWidth * maxWidthRate;
      // this.boxOptions.height = clientHeight * maxHeightRate;
    }
    if (!this.boxOptions.height) {
      this.boxOptions.height = clientHeight + 10;
    }
    if (!this.boxOptions.width) {
      this.boxOptions.width = clientWidth + 30;
    }
  },
  rowOnChange(row) {
    this.rowChange(row);
  },
  rowChange(row) {
    //选中行checkbox行事件
  },
  rowOnClick({ row, column, event }) {
    this.rowClick({ row, column, event });
  },
  rowClick({ row, column, event }) {
    // ç‚¹å‡»è¡Œäº‹ä»¶(2020.11.07)
  },
  rowOnDbClick({ row, column, event }) {
    this.rowDbClick({ row, column, event });
  },
  rowDbClick({ row, column, event }) {
    // åŒå‡»å‡»è¡Œäº‹ä»¶(2021.05.23)
  },
  $error(message) {
    this.$message.error(message);
    // this.$message({
    //   type: 'error',
    //   content: message,
    //   duration: 5
    // });
  },
  $success(message) {
    this.$message.success(message);
  },
  setFiexdSearchForm(visiable) {
    //2020.09.011增加固定查询表单功能,visiable=true默认将查询表单展开
    this.fiexdSearchForm = true;
    let refreshBtn = this.buttons.find((x) => x.name == '刷 æ–°');
    if (visiable) {
      this.searchBoxShow = true;
    }
    if (refreshBtn) {
      refreshBtn.name = '重 ç½®';
      refreshBtn.onClick = function () {
        this.resetSearch();
      };
    }
  },
  tableBeginEdit(row, column, index) {
    //2021.03.19是否开启查询界面表格双击编辑结束方法,返回false不会结束编辑
    return this.beginEdit(row, column, index);
  },
  beginEdit(row, column, index) {
    //2021.03.19是否开启查询界面表格双击编辑结束方法,返回false不会结束编辑
    return true;
  },
  tableEndEditBefore(row, column, index) {
    return this.endEditBefore(row, column, index);
  },
  endEditBefore(row, column, index) {
    //2021.03.19是否开启查询界面表格双击编辑结束方法,返回false不会结束编辑
    return true;
  },
  filterPermission(tableName, permission) {
    //2021.03.19判断是否有某个表的按钮权限
    //:["Search","Add","Delete","Update","Import","Export","Upload","Audit"]
    const _result = (this.$store.state.permission || []).find((x) => {
      return x.url == '/' + tableName;
    });
    return _result && _result.permission.some((x) => x == permission);
  },
  destroyed() {
    //2021.04.11增加vue页面销毁方法,路由必须设置keepLive:false,设置方法见:前端开发文档-》[禁用页面缓存keepAlive]
  },
  loadTreeTableChildren(tree, treeNode, resolve) {
    this.loadTreeChildren.call(this, tree, treeNode, resolve);
  },
  loadTreeChildren(tree, treeNode, resolve) {
    //树形结构加载子节点(2021.05.02),在onInit中设置了rowKey主键字段后才会生效
    return resolve([]);
  },
  importDetailAfter(data) {
    //2022.01.08增加明细表导入后处理
  },
  importExcelAfter(data) {
    //2022.01.08增加明细表导入后方法判断
    if (!data.status) {
      return; // this.$message.error(data.message);
    }
    //明细表导入
    if (this.boxModel) {
      if (data.data) {
        data.data = JSON.parse(data.data);
      } else {
        data.data = [];
      }
      data.data.forEach((x) => {
        x[this.detail.key] = undefined;
        x[this.table.key] = undefined;
      });
      this.importDetailAfter(data); //增加明细表导入后处理
      this.$refs.detail.rowData.unshift(...data.data);
      this.upload.excel = false;
      return;
    }
    this.importAfter(data);
  },
  onGridModelClose(iconClick) {
    if (this.isBoxAudit) {
      this.initFormOptionType(false);
    }
    this.isBoxAudit = false;
    this.onModelClose(iconClick);
  },
  initAuditColumn() {
  },
  getWorkFlowSteps(row) {
    let table = this.table.url.replaceAll('/', '');
    let url = `api/Sys_WorkFlow/getSteps?tableName=${table}&id=${row[this.table.key]
      }`;
    this.http.get(url, {}, true).then((result) => {
      this.workFlowSteps.splice(0);
      //有可能没有配置审批流程
      if (!result.list || !result.list.length) {
        result.list = [];
        this.auditParam.showAction = true;
        this.auditParam.height = 240;
        this.auditParam.showViewButton = row.AuditStatus == 0;
      } else {
        this.auditParam.showAction = result.list.some((c) => {
          return c.isCurrentUser;
        });
        this.auditParam.height = 511;
        this.auditParam.showViewButton = true;
      }
      this.auditParam.reason = '';
      this.auditParam.status = -1;
      this.auditParam.value = -1;
      if (result.his) {
        result.his.forEach((item) => {
          item.auditStatus = this.getAuditStatus(item.auditStatus);
        });
      }
      this.auditParam.auditHis = result.his;
      this.workFlowSteps.push(...result.list);
      this.isBoxAudit = true;
      this.initFormOptionType(true);
      this.edit(row);
      this.boxOptions.title = '审核';
    });
  },
  initFormOptionType(isReadonly) {
    this.editFormOptions.forEach((options) => {
      options.forEach((option) => {
        if (isReadonly) {
          if (!option.readonly) {
            this.formFieldsType.push(option.field);
            option.readonly = true;
          }
        } else {
          if (this.formFieldsType.indexOf(option.field) != -1) {
            option.readonly = false;
          }
        }
      });
    });
  },
  getAuditStatus(status) {
    let data = this.auditParam.data.find((x) => {
      return x.value == status;
    });
    if (!data) {
      return '-';
      //   return `审核值不正确:${status}`
    }
    return data.text;
  },
  initFlowQuery() {
    if (this.$route.query.viewflow) {
      this.$refs.table && this.search();
    }
  },
  fullscreen(full) { //弹出框全屏方法
  }
};
import customColumns from './ViewGridCustomColumn.js';
//合并扩展方法
methods = Object.assign(methods, detailMethods, serviceFilter, customColumns);
export default methods;
Code Management/WMS/WIDESEA_WMSClient/src/components/basic/VolTable.vue
@@ -22,8 +22,7 @@
      <!-- 2020.10.10移除table第一行强制排序 -->
      <el-table-column v-for="(column, cindex) in filterColumns" :prop="column.field" :label="column.title"
        :min-width="column.width" :formatter="formatter" :fixed="column.fixed" :key="column.field + cindex"
        :align="column.align" :sortable="column.sort ? 'custom' : false"
        :show-overflow-tooltip="column.showOverflowTooltip">
        :align="column.align" :sortable="column.sort ? 'custom' : false" :show-overflow-tooltip=true>
        <template #header>
          <span v-if="(column.require || column.required) && column.edit" class="column-required">*</span>{{
            column.title }}
@@ -103,7 +102,7 @@
                    column.onChange &&
                      column.onChange(scope.row, column, val);
                  }
                    " :type="column.edit.type" :placeholder="column.placeholder || column.title"
                  " :type="column.edit.type" :placeholder="column.placeholder || column.title"
                  :disabledDate="(val) => getDateOptions(val, column)" :value-format="getDateFormat(column)"
                  :disabled="initColumnDisabled(scope.row, column)">
                </el-date-picker>
@@ -112,7 +111,7 @@
                    column.onChange &&
                      column.onChange(scope.row, column, val);
                  }
                    " :placeholder="column.placeholder || column.title" :value-format="column.format || 'HH:mm:ss'"
                  " :placeholder="column.placeholder || column.title" :value-format="column.format || 'HH:mm:ss'"
                  :disabled="initColumnDisabled(scope.row, column)">
                </el-time-picker>
                <el-switch v-else-if="column.edit.type == 'switch'" v-model="scope.row[column.field]"
@@ -120,17 +119,17 @@
                  inline-prompt @change="(val) => {
                    switchChange(val, scope.row, column);
                  }
                    " :active-value="typeof scope.row[column.field] == 'boolean'
                  " :active-value="typeof scope.row[column.field] == 'boolean'
                      ? true
                      : typeof scope.row[column.field] == 'string'
                        ? '1'
                        : 1
                      " :inactive-value="typeof scope.row[column.field] == 'boolean'
                      ? false
                      : typeof scope.row[column.field] == 'string'
                        ? '0'
                        : 0
                      " :disabled="initColumnDisabled(scope.row, column)">
                        ? false
                        : typeof scope.row[column.field] == 'string'
                          ? '0'
                          : 0
                        " :disabled="initColumnDisabled(scope.row, column)">
                </el-switch>
                <template v-else-if="
                  ['select', 'selectList'].indexOf(column.edit.type) != -1
@@ -234,7 +233,7 @@
            <div @click="() => {
              column.click && formatterClick(scope.row, column);
            }
              " v-else-if="column.bind">
            " v-else-if="column.bind">
              <el-tag v-if="useTag" class="cell-tag" :class="[isEmptyTag(scope.row, column)]"
                :type="getColor(scope.row, column)" :effect="column.effect">{{ formatter(scope.row, column, true)
                }}</el-tag>
Code Management/WMS/WIDESEA_WMSClient/src/extension/basicinfo/router.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import gridBody from './extend/routerview.vue';
import gridHeader from './extend/addrouters.vue';
let extension = {
    components: {
      //查询界面扩展组件
      gridHeader: gridHeader,
      gridBody: gridBody,
      gridFooter: '',
      //新建、编辑弹出框扩展组件
      modelHeader: '',
      modelBody: '',
      modelFooter: ''
    },
    tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
    buttons: { view: [], box: [], detail: [] }, //扩展的按钮
    methods: {
       //下面这些方法可以保留也可以删除
      onInit() {
        var viewButton = this.buttons.find((x) => x.value == "ViewAllRouter");
        if (viewButton) {
            viewButton.onClick = ()=>{
                this.$refs.gridBody.open();
            }
        }
        var addRoutersButton = this.buttons.find((x) => x.value == "AddRouters");
        if (addRoutersButton) {
          addRoutersButton.onClick = ()=>{
                this.$refs.gridHeader.open();
            }
        }
      },
      onInited() {
        //框架初始化配置后
        //如果要配置明细表,在此方法操作
        //this.detailOptions.columns.forEach(column=>{ });
      },
      searchBefore(param) {
        //界面查询前,可以给param.wheres添加查询参数
        //返回false,则不会执行查询
        return true;
      },
      searchAfter(result) {
        //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
        return true;
      },
      addBefore(formData) {
        //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
        return true;
      },
      updateBefore(formData) {
        //编辑保存前formData为对象,包括明细表、删除行的Id
        return true;
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
        //(1)判断是编辑还是新建操作: this.currentAction=='Add';
        //(2)给弹出框设置默认值
        //(3)this.editFormFields.字段='xxx';
        //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
        //看不懂就把输出看:console.log(this.editFormOptions)
      }
    }
  };
  export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/deviceInfo.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
import gridBody from "./extend/importDevicePro.vue";
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: "",
    gridBody: gridBody,
    gridFooter: "",
    //新建、编辑弹出框扩展组件
    modelHeader: "",
    modelBody: "",
    modelFooter: "",
  },
  tableAction: "", //指定某张表的权限(这里填写表名,默认不用填写)
  buttons: { view: [], box: [], detail: [] }, //扩展的按钮
  methods: {
    //下面这些方法可以保留也可以删除
    onInit() {
      // console.log(this.detailOptions.buttons);
      // console.log(this.$refs.detail)
      var detailImport = this.detailOptions.buttons.find(
        (item) => item.value == "import"
      );
      if (detailImport) {
        detailImport.onClick = function () {
          this.$refs.gridBody.open();
        };
      }
      this.buttons.unshift({
        //也可以用push或者splice方法来修改buttons数组
        name: "开启服务", //按钮名称
        icon: "el-icon-document", //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
        type: "primary", //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
        onClick: function () {
          this.$Message.success("开启服务");
        },
      });
    },
    onInited() {
      //框架初始化配置后
      //如果要配置明细表,在此方法操作
      // this.detailOptions.columns.forEach(column=>{ });
      // console.log(this)
    },
    searchBefore(param) {
      //界面查询前,可以给param.wheres添加查询参数
      //返回false,则不会执行查询
      return true;
    },
    searchAfter(result) {
      //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
      return true;
    },
    addBefore(formData) {
      //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
      return true;
    },
    updateBefore(formData) {
      //编辑保存前formData为对象,包括明细表、删除行的Id
      return true;
    },
    rowClick({ row, column, event }) {
      //查询界面点击行事件
      // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
    },
    modelOpenAfter(row) {
      //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
      //(1)判断是编辑还是新建操作: this.currentAction=='Add';
      //(2)给弹出框设置默认值
      //(3)this.editFormFields.字段='xxx';
      //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
      //看不懂就把输出看:console.log(this.editFormOptions)
    },
    updated() {
      //console.log(this.$refs)
      this.$nextTick(() => {
        if (this.$refs.upload_excel) {
          alert("点击了上传按钮");
          this.$refs.upload_excel.upload = function () {
            console.log("点击了上传按钮");
          };
        }
        // alert(1)
      });
    },
  },
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/deviceProtocol.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
let extension = {
    components: {
      //查询界面扩展组件
      gridHeader: '',
      gridBody: '',
      gridFooter: '',
      //新建、编辑弹出框扩展组件
      modelHeader: '',
      modelBody: '',
      modelFooter: ''
    },
    tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
    buttons: { view: [], box: [], detail: [] }, //扩展的按钮
    methods: {
       //下面这些方法可以保留也可以删除
      onInit() {
      },
      onInited() {
        //框架初始化配置后
        //如果要配置明细表,在此方法操作
        //this.detailOptions.columns.forEach(column=>{ });
      },
      searchBefore(param) {
        //界面查询前,可以给param.wheres添加查询参数
        //返回false,则不会执行查询
        return true;
      },
      searchAfter(result) {
        //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
        return true;
      },
      addBefore(formData) {
        //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
        return true;
      },
      updateBefore(formData) {
        //编辑保存前formData为对象,包括明细表、删除行的Id
        return true;
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
        //(1)判断是编辑还是新建操作: this.currentAction=='Add';
        //(2)给弹出框设置默认值
        //(3)this.editFormFields.字段='xxx';
        //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
        //看不懂就把输出看:console.log(this.editFormOptions)
      }
    }
  };
  export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/deviceProtocolDetail.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
let extension = {
    components: {
      //查询界面扩展组件
      gridHeader: '',
      gridBody: '',
      gridFooter: '',
      //新建、编辑弹出框扩展组件
      modelHeader: '',
      modelBody: '',
      modelFooter: ''
    },
    tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
    buttons: { view: [], box: [], detail: [] }, //扩展的按钮
    methods: {
       //下面这些方法可以保留也可以删除
      onInit() {
      },
      onInited() {
        //框架初始化配置后
        //如果要配置明细表,在此方法操作
        //this.detailOptions.columns.forEach(column=>{ });
      },
      searchBefore(param) {
        //界面查询前,可以给param.wheres添加查询参数
        //返回false,则不会执行查询
        return true;
      },
      searchAfter(result) {
        //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
        return true;
      },
      addBefore(formData) {
        //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
        return true;
      },
      updateBefore(formData) {
        //编辑保存前formData为对象,包括明细表、删除行的Id
        return true;
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
        //(1)判断是编辑还是新建操作: this.currentAction=='Add';
        //(2)给弹出框设置默认值
        //(3)this.editFormFields.字段='xxx';
        //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
        //看不懂就把输出看:console.log(this.editFormOptions)
      }
    }
  };
  export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/quartzJob/dispatchInfo.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
let extension = {
    components: {
      //查询界面扩展组件
      gridHeader: '',
      gridBody: '',
      gridFooter: '',
      //新建、编辑弹出框扩展组件
      modelHeader: '',
      modelBody: '',
      modelFooter: ''
    },
    tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
    buttons: { view: [], box: [], detail: [] }, //扩展的按钮
    methods: {
       //下面这些方法可以保留也可以删除
      onInit() {
      },
      onInited() {
        //框架初始化配置后
        //如果要配置明细表,在此方法操作
        //this.detailOptions.columns.forEach(column=>{ });
      },
      searchBefore(param) {
        //界面查询前,可以给param.wheres添加查询参数
        //返回false,则不会执行查询
        return true;
      },
      searchAfter(result) {
        //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
        return true;
      },
      addBefore(formData) {
        //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
        return true;
      },
      updateBefore(formData) {
        //编辑保存前formData为对象,包括明细表、删除行的Id
        return true;
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
        //(1)判断是编辑还是新建操作: this.currentAction=='Add';
        //(2)给弹出框设置默认值
        //(3)this.editFormFields.字段='xxx';
        //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
        //看不懂就把输出看:console.log(this.editFormOptions)
      }
    }
  };
  export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Dictionary.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
import { h, resolveComponent } from 'vue';
let extension = {
    components: { //动态扩充组件或组件路径
        //表单header、content、footer对应位置扩充的组件
        //扩展组件引入方式
        gridHeader: '',
        gridBody: '',
        gridFooter: '',
        //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
        modelHeader: '',
        modelBody: '',
        modelFooter: ''
    },
    buttons: [], //扩展的按钮
    methods: { //事件扩展
        onInit() {
            //点击单元格编辑与结束编辑(默认是点击单元格编辑,鼠标离开结束编辑)
            this.detailOptions.clickEdit = true;
            this.editFormOptions.forEach(x => {
                x.forEach(item => {
                    if (item.field == 'ParentId') {
                        item.min = 0;
                    }
                    if (item.field == "DbSql") {
                        item.placeholder = "如果从数据库加载数据源,请按此格式配置sql语句:select orderType as key,orderName as value from order  å¦‚果需要根据用户信息加载数据源,请配置好此sql,再修改后台DictionaryHandler.GetCustomDBSql方法";
                    }
                })
            })
            this.detailOptions.columns.forEach(x => {
                if (x.field == 'OrderNo') {
                    x.summary = true;
                }
            })
            //保存后不关闭编辑框
            this.boxOptions.saveClose = false;
        },
        onInited() {
            this.boxOptions.height = document.body.clientHeight * 0.87
            this.height = this.height - 45;
        },
        addBefore(formData) {
            return this.saveBefore(formData);
        },
        updateBefore(formData) {
            return this.saveBefore(formData);
        },
        saveBefore(formData) {
            if (this.editFormFields.DbSql &&
                (this.editFormFields.DbSql.indexOf('value') == -1 ||
                    this.editFormFields.DbSql.indexOf('key') == -1)
            ) {
                this.$message.error("sql语句必须包括key/value字段,如:select orderType as key,orderName as value from order");
                return false;
            }
            return true;
        },
        searchBefore(param) {
            return true;
        },
        searchAfter(result) {
            return true;
        }
    }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_DictionaryList.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
let extension = {
    components: {//动态扩充组件或组件路径
        //表单header、content、footer对应位置扩充的组件
        gridHeader:'',
        gridbody:'',
        gridFooter: '',
        //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
        modelHeader: '',
        modelBody: '',
        modelFooter: ''
    },
    buttons: [],//扩展的按钮
    methods: {//事件扩展
        onInit() {
        },
        onInited() {
        }
    }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Log.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
import { h, resolveComponent } from 'vue';
let extension = {
  components: {
    //动态扩充组件或组件路径
    //表单header、content、footer对应位置扩充的组件
    gridHeader: "", //{ template: "<div>扩展组xxä»¶</div>" },
    gridBody: '',
    gridFooter: "",
    //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
    modelHeader: "",
    modelBody: "",
    modelFooter: ""
  },
  buttons: [], //扩展的按钮
  methods: {
    //事件扩展
    onInit() {
      console.log("sys_log")
      this.setFiexdSearchForm(true);
    },
    onInited() {
      this.height = this.height - 170;
    }
  }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Role.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
let extension = {
  components: {//动态扩充组件或组件路径
    //表单header、content、footer对应位置扩充的组件
    gridHeader: '',
    gridBody: '',
    gridFooter: '',
    //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
    modelHeader: '',
    modelBody: '',
    modelFooter: ''
  },
  buttons: [],//扩展的按钮
  tableAction:"Sys_Role",
  methods: {//事件扩展
    onInited () {
      this.height = this.height - 80;
       this.editFormOptions.forEach(x => {
        x.forEach(item => {
          if (item.field == 'ParentId') {
            item.title = "上级角色";
            //设置任意节点都能选中(默认只能选中最后一个节点)
            item.changeOnSelect = true;
          }
        })
      })
    },
    onInit() {
      //设置treetable的唯一值字段(这个字段的值在表里面必须是唯一的)
      this.rowKey="Role_Id";
    },
    /***加载后台数据见Sys_RoleController.cs文件***/
    loadTreeChildren(tree, treeNode, resolve) { //加载子节点
      let url=`api/role/getTreeTableChildrenData?roleId=${tree.Role_Id}`;
      this.http.post(url,{}).then(result=>{
        resolve(result.rows)
      })
    },
      /***加载后台数据见Sys_RoleController.cs文件***/
    searchBefore(params){//判断加载根节点或子节点
      //没有查询条件,默认查询返回所有根节点数据
      if (!params.wheres.length) {
        params.value=1;
      }
      return true;
    }
  }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_Role1.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
import { h, resolveComponent } from 'vue';
let extension = {
  components: {//动态扩充组件或组件路径
    //表单header、content、footer对应位置扩充的组件
    gridHeader: '',
    gridBody: {
      render () {
          return [
              h(resolveComponent('el-alert'), {
                  style: { 'margin-bottom': '12px' },
                  'show-icon': true, type: 'error',
                  closable: false, title: '关于TreeTable使用'
              }, ' treetable同样全部代码自动生成,页面生成后设置this.rowKe="xxx" tree主键字段,即可完成树形table配置,具体说明见Sys_Role1.js'),
          ]
      }
  },
    gridFooter: '',
    //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
    modelHeader: '',
    modelBody: '',
    modelFooter: ''
  },
  buttons: [],//扩展的按钮
  tableAction:"Sys_Role",
  methods: {//事件扩展
    onInited () {
      this.height = this.height - 80;
       this.editFormOptions.forEach(x => {
        x.forEach(item => {
          if (item.field == 'ParentId') {
            item.title = "上级角色";
            //设置任意节点都能选中(默认只能选中最后一个节点)
            item.changeOnSelect = true;
          }
        })
      })
    },
    onInit() {
      //设置treetable的唯一值字段(这个字段的值在表里面必须是唯一的)
      this.rowKey="Role_Id";
    },
    /***加载后台数据见Sys_RoleController.cs文件***/
    loadTreeChildren(tree, treeNode, resolve) { //加载子节点
      let url=`api/role/getTreeTableChildrenData?roleId=${tree.Role_Id}`;
      this.http.post(url,{}).then(result=>{
        resolve(result.rows)
      })
    },
      /***加载后台数据见Sys_RoleController.cs文件***/
    searchBefore(params){//判断加载根节点或子节点
      //没有查询条件,默认查询返回所有根节点数据
      if (!params.wheres.length) {
        params.value=1;
      }
      return true;
    }
  }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/system/Sys_User.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
import {  defineAsyncComponent } from "vue";
let extension = {
    components: { //动态扩充组件或组件路径
        //表单header、content、footer对应位置扩充的组件
        gridHeader: defineAsyncComponent(() =>
            import("./Sys_User/Sys_UserGridHeader.vue")),
        gridBody: '',
        gridFooter: '',
        //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
        modelHeader: '',
        modelBody: '',
        modelFooter: ''
    },
    text: "只能看到当前角色下的所有帐号",
    buttons: [], //扩展的按钮
    methods: { //事件扩展
        onInit() {
            this.boxOptions.height = 530;
            this.columns.push({
                title: '操作',
                hidden: false,
                align: "center",
                fixed: 'right',
                width: 120,
                render: (h, { row, column, index }) => {
                    return h(
                        "div", { style: { 'font-size': '13px', 'cursor': 'pointer', 'color': '#409eff' } }, [
                        h(
                            "a", {
                            style: { 'margin-right': '15px' },
                            onClick: (e) => {
                                e.stopPropagation()
                                this.$refs.gridHeader.open(row);
                            }
                        }, "修改密码"
                        ),
                        h(
                            "a", {
                            style: {},
                            onClick: (e) => {
                                e.stopPropagation()
                                this.edit(row);
                            }
                        },
                            "编辑"
                        ),
                    ])
                }
            })
        },
        onInited() { },
        addAfter(result) { //用户新建后,显示随机生成的密码
            if (!result.status) {
                return true;
            }
            //显示新建用户的密码
            //2020.08.28优化新建成后提示方式
            this.$confirm(result.message, '新建用户成功', {
                confirmButtonText: '确定',
                type: 'success',
                center: true
            }).then(() => { })
            this.boxModel = false;
            this.refresh();
            return false;
        },
        modelOpenAfter() {
            //点击弹出框后,如果是编辑状态,禁止编辑用户名,如果新建状态,将用户名字段设置为可编辑
            let isEDIT = this.currentAction == this.const.EDIT;
            this.editFormOptions.forEach(item => {
                item.forEach(x => {
                    if (x.field == "UserName") {
                        x.disabled=isEDIT;
                    }
                })
                //不是新建,性别默认值设置为男
                if (!isEDIT) {
                    this.editFormFields.Gender = "0";
                }
            })
        }
    }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import gridBody from './extend/taskExecuteDetail.vue'
let extension = {
    components: {
        //查询界面扩展组件
        gridHeader: '',
        gridBody: gridBody,
        gridFooter: '',
        //新建、编辑弹出框扩展组件
        modelHeader: '',
        modelBody: '',
        modelFooter: ''
    },
    tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
    buttons: { view: [], box: [], detail: [] }, //扩展的按钮
    methods: {
        //下面这些方法可以保留也可以删除
        onInit() {
            // this.$Notice.success({ title: this.detailOptions.cnName + ',查询结果', desc: '返回的对象:' + JSON.stringify(data) });
            var previousButton = this.buttons.find((x) => x.value == "Previous");
            if (previousButton) previousButton.hidden = true;
            var nextButton = this.buttons.find((x) => x.value == "Next");
            if (nextButton) nextButton.hidden = true;
            var recoveryButton = this.buttons.find((x) => x.value == "TaskRecovery");
            if (recoveryButton) recoveryButton.hidden = true;
            //扩展页面初始化操作
            this.columns.push({
                field: '操作',
                title: '操作',
                width: 70,
                fixed: 'right',
                align: 'center',
                formatter: (row) => {
                    return (
                        '<i style="cursor: pointer;color: #2d8cf0;"class="el-icon-view">查看</i>'
                    );
                },
                click: (row) => {
                    this.$refs.gridBody.open(row);
                }
            });
        },
        onInited() {
            //框架初始化配置后
            //如果要配置明细表,在此方法操作
            //this.detailOptions.columns.forEach(column=>{ });
        },
        searchBefore(param) {
            //界面查询前,可以给param.wheres添加查询参数
            //返回false,则不会执行查询
            return true;
        },
        searchAfter(result) {
            //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
            return true;
        },
        addBefore(formData) {
            //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
            return true;
        },
        updateBefore(formData) {
            //编辑保存前formData为对象,包括明细表、删除行的Id
            return true;
        },
        rowClick({ row, column, event }) {
            //查询界面点击行事件
            // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
        },
        modelOpenAfter(row) {
            //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
            //(1)判断是编辑还是新建操作: this.currentAction=='Add';
            //(2)给弹出框设置默认值
            //(3)this.editFormFields.字段='xxx';
            //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
            //看不懂就把输出看:console.log(this.editFormOptions)
        }
    }
};
export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/widesea_wms/MOM/MOMMessage.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
/*****************************************************************************************
**  Author:jxx 2022
**  QQ:283591387
**完整文档见:http://v2.volcore.xyz/document/api ã€ä»£ç ç”Ÿæˆé¡µé¢ViewGrid】
**常用示例见:http://v2.volcore.xyz/document/vueDev
**后台操作见:http://v2.volcore.xyz/document/netCoreDev
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
let extension = {
    components: {
      //查询界面扩展组件
      gridHeader: '',
      gridBody: '',
      gridFooter: '',
      //新建、编辑弹出框扩展组件
      modelHeader: '',
      modelBody: '',
      modelFooter: ''
    },
    tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
    buttons: { view: [], box: [], detail: [] }, //扩展的按钮
    methods: {
       //下面这些方法可以保留也可以删除
      onInit() {  //框架初始化配置前,
          //示例:在按钮的最前面添加一个按钮
          //   this.buttons.unshift({  //也可以用push或者splice方法来修改buttons数组
          //     name: '按钮', //按钮名称
          //     icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
          //     type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
          //     onClick: function () {
          //       this.$Message.success('点击了按钮');
          //     }
          //   });
          //示例:设置修改新建、编辑弹出框字段标签的长度
          this.boxOptions.labelWidth = 150;
      },
      onInited() {
        //框架初始化配置后
        //如果要配置明细表,在此方法操作
        //this.detailOptions.columns.forEach(column=>{ });
      },
      searchBefore(param) {
        //界面查询前,可以给param.wheres添加查询参数
        //返回false,则不会执行查询
        return true;
      },
      searchAfter(result) {
        //查询后,result返回的查询数据,可以在显示到表格前处理表格的值
        return true;
      },
      addBefore(formData) {
        //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
        return true;
      },
      updateBefore(formData) {
        //编辑保存前formData为对象,包括明细表、删除行的Id
        return true;
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
        //(1)判断是编辑还是新建操作: this.currentAction=='Add';
        //(2)给弹出框设置默认值
        //(3)this.editFormFields.字段='xxx';
        //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
        //看不懂就把输出看:console.log(this.editFormOptions)
      }
    }
  };
  export default extension;
Code Management/WMS/WIDESEA_WMSClient/src/extension/widesea_wms/stock/DtBoxingInfo.js
@@ -6,6 +6,7 @@
**后台操作见:http://v2.volcore.xyz/document/netCoreDev
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
let extension = {
  components: {
    //查询界面扩展组件
@@ -21,9 +22,18 @@
  buttons: { view: [], box: [], detail: [] }, //扩展的按钮
  methods: {
     //下面这些方法可以保留也可以删除
    onInit() {
      //框架初始化配置前,
      //设置查询界面弹出框的label宽度
    onInit() {  //框架初始化配置前,
        //示例:在按钮的最前面添加一个按钮
        //   this.buttons.unshift({  //也可以用push或者splice方法来修改buttons数组
        //     name: '按钮', //按钮名称
        //     icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
        //     type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
        //     onClick: function () {
        //       this.$Message.success('点击了按钮');
        //     }
        //   });
        //示例:设置修改新建、编辑弹出框字段标签的长度
        this.boxOptions.labelWidth = 150;
    },
    onInited() {
@@ -53,7 +63,7 @@
    },
    rowClick({ row, column, event }) {
      //查询界面点击行事件
      //this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
    },
    modelOpenAfter(row) {
      //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
Code Management/WMS/WIDESEA_WMSClient/src/router/index.js
@@ -22,7 +22,7 @@
        name: 'UserInfo',
        component: () => import('@/views/system/UserInfo.vue'),
        meta: {
          keepAlive: false
        }
      },
      {
@@ -30,7 +30,7 @@
        name: 'sysMenu',
        component: () => import('@/views/system/Sys_Menu.vue'),
        meta: {
          keepAlive: false
        }
      },
      {
@@ -38,7 +38,6 @@
        name: 'signalR',
        component: () => import('@/views/signalR/Index.vue'),
        meta:{
          keepAlive:false
        }
      },
    ]
Code Management/WMS/WIDESEA_WMSClient/src/router/tables.js
@@ -3,24 +3,21 @@
    path: '/Dt_AreaInfo',
    name: 'Dt_AreaInfo',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_AreaInfo.vue'),
    // meta: {
    //   keepAlive: true
    // }
    meta: {
    }
  },
  {
    path: '/Dt_BillGroupStock',
    name: 'Dt_BillGroupStock',
    component: () => import('@/views/widesea_wms/stock/Dt_BillGroupStock.vue'),
    // meta: {
    //   keepAlive: true
    // }
  },
  // {
  //   path: '/Dt_BillGroupStockDetail',
  //   name: 'Dt_BillGroupStockDetail',
  //   component: () => import('@/views/widesea_wms/stock/Dt_BillGroupStockDetail.vue'),
  //   meta: {
  //     keepAlive: true
  //
  //   }
  // },
  {
@@ -28,7 +25,7 @@
    name: 'Dt_InboundOrder',
    component: () => import('@/views/widesea_wms/invoices/Dt_InboundOrder.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -36,7 +33,7 @@
    name: 'Dt_InboundOrderDetail',
    component: () => import('@/views/widesea_wms/invoices/Dt_InboundOrderDetail.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -44,7 +41,7 @@
    name: 'Dt_LocationInfo',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_LocationInfo.vue'),
    meta: {
      keepAlive: true
    }
  },
  {
@@ -52,7 +49,7 @@
    name: 'Dt_MaterielAttribute',
    component: () => import('@/views/widesea_wms/material/Dt_MaterielAttribute.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -60,7 +57,7 @@
    name: 'Dt_MaterielInfo',
    component: () => import('@/views/widesea_wms/material/Dt_MaterielInfo.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -68,7 +65,7 @@
    name: 'Dt_OutOrder',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrder.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -76,7 +73,7 @@
    name: 'Dt_OutOrderAndStock',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderAndStock.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -84,7 +81,7 @@
    name: 'Dt_OutOrderDetail',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderDetail.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -92,7 +89,7 @@
    name: 'Dt_OutOrderProduction',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderProduction.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -100,7 +97,7 @@
    name: 'Dt_OutOrderProductionDetail',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderProductionDetail.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -108,7 +105,7 @@
    name: 'Dt_OutOrderTransfer',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderTransfer.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -116,7 +113,7 @@
    name: 'Dt_OutOrderTransferDetail',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderTransferDetail.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -124,38 +121,38 @@
    name: 'Dt_RoadWayInfo',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_RoadWayInfo.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
    path: '/Dt_Strategy',
    name: 'Dt_Strategy',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_Strategy.vue'),
    // meta: {
    //   keepAlive: false
    // }
    meta: {
    }
  },
  {
    path: '/Dt_Task',
    name: 'Dt_Task',
    component: () => import('@/views/widesea_wms/taskinfo/Dt_Task.vue'),
    // meta: {
    //   keepAlive: true
    // }
    meta: {
    }
  },{
    path: '/Dt_Task_Hty',
    name: 'Dt_Task_Hty',
    component: () => import('@/views/widesea_wms/taskinfo/Dt_Task_Hty.vue'),
    // meta: {
    //   keepAlive: true
    // }
    meta: {
    }
  },
  // {
  //   path: '/Dt_TaskOut',
  //   name: 'Dt_TaskOut',
  //   component: () => import('@/views/widesea_wms/taskinfo/Dt_TaskOut.vue'),
  //   meta: {
  //     keepAlive: false
  //
  //   }
  // },
  // {
@@ -163,7 +160,7 @@
  //   name: 'Dt_TaskExecuteDetail',
  //   component: () => import('@/views/widesea_wms/taskinfo/Dt_TaskExecuteDetail.vue'),
  //   meta: {
  //     keepAlive: false
  //
  //   }
  // },
  {
@@ -171,7 +168,7 @@
    name: 'Dt_UnitInfo',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_UnitInfo.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -179,7 +176,7 @@
    name: 'Dt_WareAreaInfo',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_WareAreaInfo.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -187,7 +184,7 @@
    name: 'Dt_OutOrderSorting',
    component: () => import('@/views/widesea_wms/invoices/Dt_OutOrderSorting.vue'),
    meta: {
      keepAlive: false
    }
  },
  // {
@@ -200,7 +197,7 @@
    name: 'PointStackerRelation',
    component: () => import('@/views/widesea_wms/basicinfo/PointStackerRelation.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -208,7 +205,7 @@
    name: 'LocationStatusChange',
    component: () => import('@/views/widesea_wms/basicinfo/LocationStatusChange.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -216,7 +213,7 @@
    name: 'DtBoxing',
    component: () => import('@/views/widesea_wms/stock/DtBoxingInfo.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -224,7 +221,7 @@
    name: 'momTest',
    component: () => import('@/views/widesea_wms/MOM/momTest.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -232,7 +229,7 @@
    name: 'ProductionModel',
    component: () => import('@/views/widesea_wms/MOM/ProductionModel.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -240,14 +237,21 @@
    name: 'Dt_StationManager',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_StationManager.vue'),
    meta: {
      keepAlive: false
    }
  },{
    path: '/Dt_needBarcode',
    name: 'Dt_needBarcode',
    component: () => import('@/views/widesea_wms/basicinfo/Dt_needBarcode.vue'),
    meta: {
      keepAlive: false
    }
  },{
    path: '/Message',
    name: 'Message',
    component: () => import('@/views/widesea_wms/MOM/ErrorMessage/Message.vue'),
    meta: {
    }
  },
]
Code Management/WMS/WIDESEA_WMSClient/src/router/viewGird.js
@@ -4,7 +4,7 @@
    name: 'sys_Log',
    component: () => import('@/views/system/Sys_Log.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -12,7 +12,7 @@
    name: 'Sys_User',
    component: () => import('@/views/system/Sys_User.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -20,7 +20,7 @@
    name: 'permission',
    component: () => import('@/views/system/Permission.vue'),
    meta: {
      keepAlive: false
    }
  },
@@ -29,7 +29,7 @@
    name: 'Sys_Dictionary',
    component: () => import('@/views/system/Sys_Dictionary.vue'),
    meta: {
      keepAlive: false
    }
  },
  {
@@ -37,77 +37,22 @@
    name: 'Sys_Role',
    component: () => import('@/views/system/Sys_Role.vue'),
    meta: {
      keepAlive: false
    }
  },
  //  {
  //   path: '/Sys_Role1',
  //   name: 'Sys_Role1',
  //   component: () => import('@/views/system/Sys_Role1.vue')
  // }
  // ,
  {
    path: '/Sys_DictionaryList',
    name: 'Sys_DictionaryList',
    component: () => import('@/views/system/Sys_DictionaryList.vue'),
    meta: {
      keepAlive: false
    }
  },
  // {
  //   path: '/FormDesignOptions',
  //   name: 'FormDesignOptions',
  //   component: () => import('@/views/system/form/FormDesignOptions.vue'),
  //   meta: {
  //     keepAlive: false
  //   }
  // },
  // {
  //   path: '/FormCollectionObject',
  //   name: 'FormCollectionObject',
  //   component: () => import('@/views/system/form/FormCollectionObject.vue'),
  //   meta: {
  //     keepAlive: false
  //   }
  // },
  // {
  //   path: '/Sys_WorkFlow',
  //   name: 'Sys_WorkFlow',
  //   component: () => import('@/views/system/flow/Sys_WorkFlow.vue'),
  //   meta: {
  //     keepAlive: false
  //   }
  // },
  // {
  //   path: '/Sys_WorkFlowTable',
  //   name: 'Sys_WorkFlowTable',
  //   component: () => import('@/views/system/flow/Sys_WorkFlowTable.vue'),
  //   meta: {
  //     keepAlive: false
  //   }
  // },
  // {
  //   path: '/Sys_QuartzOptions',
  //   name: 'Sys_QuartzOptions',
  //   component: () => import('@/views/system/quartz/Sys_QuartzOptions.vue'),
  //   meta: {
  //     keepAlive: false
  //   }
  // },
  // {
  //   path: '/Sys_QuartzLog',
  //   name: 'Sys_QuartzLog',
  //   component: () => import('@/views/system/quartz/Sys_QuartzLog.vue'),
  //   meta: {
  //     keepAlive: false
  //   }
  // },
  {
  },{
    path: '/Sys_Department',
    name: 'Sys_Department',
    component: () => import('@/views/system/system/Sys_Department.vue'),
    meta: {
      keepAlive: false
    }
  }
]
Code Management/WMS/WIDESEA_WMSClient/src/views/widesea_wms/MOM/ErrorMessage/Message.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
<!--
*Author:jxx
 *Contact:283591387@qq.com
 *代码由框架生成,任何更改都可能导致被代码生成器覆盖
 *业务请在@/extension/widesea_wms/basicinfo/Dt_AreaInfo.js此处编写
 -->
 <template>
    <view-grid ref="grid" :columns="columns" :detail="detail" :editFormFields="editFormFields"
        :editFormOptions="editFormOptions" :searchFormFields="searchFormFields" :searchFormOptions="searchFormOptions"
        :table="table" :extend="extend">
    </view-grid>
</template>
<script>
import extend from "@/extension/widesea_wms/MOM/MOMMessage.js";
import { ref, defineComponent } from "vue";
export default defineComponent({
    setup() {
        const table = ref({
            key: 'id',
            footer: "Foots",
            cnName: 'MOM消息',
            name: 'MOM/MOMErrorMessage',
            url: "/MOMErrorMessage/",
            sortName: "CreateTime"
        });
        const editFormFields = ref({});
        const editFormOptions = ref([]);
        const searchFormFields = ref({});
        const searchFormOptions = ref([
            [
                { "title": "托盘号", "field": "palletCode", type: "text" },
                { "title": "任务号", "field": "taskNum", type: "text" , hidden: true},
                { "title": "异常消息", "field": "errorMessage", type: "text" },
            ],
            [
                { "title": "api名称", "field": "apiName", type: "text" },
                { "title": "创建时间", "field": "createTime", type: "text" },
            ]
        ]);
        const columns = ref([{ field: 'id', title: '主键', type: 'int', sort: true, hidden: true, width: 110, readonly: true, require: true, align: 'left' },
        { field: 'taskNum', title: '任务号', type: 'string', sort: true, width: 110, require: true, align: 'left', sort: true , hidden: true},
        { field: 'palletCode', title: '托盘号', type: 'string', sort: true, width: 110, align: 'left' },
        { field: 'errorMessage', title: '异常消息', type: 'string', sort: true, width: 200, align: 'left' },
        { field: 'apiName', title: 'api名称', type: 'string', sort: true, width: 110, align: 'left'  },
        { field: 'createTime', title: '创建时间', type: 'string', sort: true, width: 110, align: 'left' },]);
        const detail = ref({
            cnName: "#detailCnName",
            table: "#detailTable",
            columns: [],
            sortName: "",
            key: ""
        });
        return {
            table,
            extend,
            editFormFields,
            editFormOptions,
            searchFormFields,
            searchFormOptions,
            columns,
            detail,
        };
    },
});
</script>
Code Management/WMS/WIDESEA_WMSClient/tests/unit/example.spec.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
import { expect } from 'chai'
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
describe('HelloWorld.vue', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      props: { msg }
    })
    expect(wrapper.text()).to.include(msg)
  })
})
Code Management/WMS/WIDESEA_WMSClient/vue.config.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
// const webpack = require("webpack");
module.exports = {
  productionSourceMap: false,
  lintOnSave: false,
  devServer: {
    port: 8080,
    overlay: {
      warning: false,
      errors: false
    }
  },
  css: {
    //查看CSS属于哪个css文件
    sourceMap: true
  },
  configureWebpack: {
    module: {
      rules: [
        {
          test: /\.mjs$/,
          include: /node_modules/,
          type: "javascript/auto"
        },
      ]
    }
  },
  //https://cli.vuejs.org/zh/guide/html-and-static-assets.html#html
  chainWebpack: (config) => {
    // ç§»é™¤ prefetch æ’ä»¶
    config.plugins.delete('prefetch');
    //自下定义title
    config.plugin('html').tap((args) => {
      args[0].title = 'WCS';
      return args;
    });
    // æˆ–者
    // ä¿®æ”¹å®ƒçš„选项:
    // config.plugin('prefetch').tap(options => {
    //   options[0].fileBlacklist = options[0].fileBlacklist || []
    //   options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
    //   return options
    // })
  }
  // configureWebpack: {
  //     plugins: [
  //         new webpack.optimize.MinChunkSizePlugin({
  //             minChunkSize: 100000 // é€šè¿‡åˆå¹¶å°äºŽ minChunkSize å¤§å°çš„ chunk,将 chunk ä½“积保持在指定大小限制以上
  //         })
  //     ]
  // }
};
Code Management/WMS/WIDESEA_WMSServer/LogLibrary/Log/Log.cs
@@ -398,7 +398,7 @@
        public void FatalFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(provider, format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
@@ -415,7 +415,7 @@
        public void FatalFormat(bool isWriteFile, string format, object arg0, object arg1)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
@@ -433,7 +433,7 @@
        public void FatalFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1, arg2));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
@@ -448,7 +448,7 @@
        public void Info(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
@@ -464,7 +464,7 @@
        public void Info(bool isWriteFile, object message, Exception exception)
        {
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
@@ -480,7 +480,7 @@
        public void InfoFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format("\n{0}\n{1}\n-----------------------------------------------------------\n\n", format, arg0));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
@@ -570,7 +570,7 @@
        public void Warn(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
@@ -586,7 +586,7 @@
        public void Warn(bool isWriteFile, object message, Exception exception)
        {
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
@@ -602,7 +602,7 @@
        public void WarnFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format(format, arg0));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Const/CacheConst.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
namespace WIDESEA_Cache;
/// <summary>
/// Redis常量
/// </summary>
public class CacheConst
{
    /// <summary>
    /// Redis Key前缀(可删除)
    /// </summary>
    public const string Cache_Prefix_Web = "WIDESEA_WMSServerWeb:";
    /// <summary>
    /// Redis Key前缀(需要持久化,不随系统重启删除)
    /// </summary>
    public const string Cache_Prefix = "WIDESEA_WMSServer:";
    /// <summary>
    /// Redis Hash类型
    /// </summary>
    public const string Cache_Hash = "Hash";
    /// <summary>
    /// ç³»ç»Ÿé…ç½®è¡¨ç¼“å­˜Key
    /// </summary>
    public const string Cache_DevConfig = Cache_Prefix_Web + "DevConfig:";
    /// <summary>
    /// ç™»å½•验证码缓存Key
    /// </summary>
    public const string Cache_Captcha = Cache_Prefix_Web + "Captcha:";
    /// <summary>
    /// ç”¨æˆ·è¡¨ç¼“å­˜Key
    /// </summary>
    public const string Cache_SysUser = Cache_Prefix_Web + "SysUser";
    /// <summary>
    /// ç”¨æˆ·æ‰‹æœºå·å…³ç³»ç¼“å­˜Key
    /// </summary>
    public const string Cache_SysUserPhone = Cache_Prefix_Web + "SysUserPhone";
    /// <summary>
    /// ç”¨æˆ·Token缓存Key
    /// </summary>
    public const string Cache_UserToken = Cache_Prefix + "UserToken";
    /// <summary>
    /// WMS库存缓存Key
    /// </summary>Cache_AutoModel
    public const string Cache_DtStockInfo = Cache_Prefix + "DtStockInfo";
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Extension/LinqExtension.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
namespace WIDESEA_Cache;
/// <summary>
/// Linq扩展
/// </summary>
public static class LinqExtension
{
    /// <summary>
    /// æ˜¯å¦éƒ½åŒ…含
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first">第一个列表</param>
    /// <param name="secend">第二个列表</param>
    /// <returns></returns>
    public static bool ContainsAll<T>(this List<T> first, List<T> secend)
    {
        return secend.All(s => first.Any(f => f.Equals(s)));
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Extension/ObjectExtension.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace WIDESEA_Cache;
/// <summary>
/// object拓展
/// </summary>
public static class ObjectExtension
{
    /// <summary>
    /// json字符串序列化
    /// </summary>
    /// <param name="json"></param>
    /// <returns></returns>
    public static object ToObject(this string json)
    {
        return string.IsNullOrEmpty(json) ? null : JsonConvert.DeserializeObject(json);
    }
    /// <summary>
    /// json字符串序列化
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="json"></param>
    /// <returns></returns>
    public static T ToObject<T>(this string json)
    {
        if (json != null)
        {
            json = json.Replace("&nbsp;", "");
            return JsonConvert.DeserializeObject<T>(json);
        }
        else return default;
    }
    /// <summary>
    /// json字符串序列化
    /// </summary>
    /// <param name="json"></param>
    /// <returns></returns>
    public static JObject ToJObject(this string json)
    {
        return json == null ? JObject.Parse("{}") : JObject.Parse(json.Replace("&nbsp;", ""));
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/GlobalUsing.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
global using Masuit.Tools;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.Extensions.DependencyInjection;
global using NewLife.Caching;
global using NewLife.Serialization;
global using SimpleRedis;
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Interface/ISimpleCacheHashService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
namespace WIDESEA_Cache;
/// <summary>
/// ç¼“存服务
/// </summary>
public partial interface ISimpleCacheService
{
    /// <summary>
    /// æ·»åŠ ä¸€æ¡æ•°æ®åˆ°HashMap
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">键</param>
    /// <param name="hashKey">hash列表里的Key</param>
    /// <param name="value">值</param>
    void HashAdd<T>(string key, string hashKey, T value);
    /// <summary>
    /// æ·»åŠ å¤šæ¡æ•°æ®åˆ°HashMap
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">键</param>
    /// <param name="dic">键值对字典</param>
    /// <returns></returns>
    bool HashSet<T>(string key, Dictionary<string, T> dic);
    /// <summary>
    /// ä»ŽHashMap中删除数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">键</param>
    /// <param name="fields">hash键列表</param>
    /// <returns>执行结果</returns>
    int HashDel<T>(string key, params string[] fields);
    /// <summary>
    /// æ ¹æ®é”®èŽ·å–hash列表中的值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">键</param>
    /// <param name="fields">hash键列表</param>
    /// <returns>数据列表</returns>
    List<T> HashGet<T>(string key, params string[] fields);
    /// <summary>
    /// æ ¹æ®é”®èŽ·å–hash列表中的值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">键</param>
    /// <param name="field">hash键</param>
    /// <returns></returns>
    T HashGetOne<T>(string key, string field);
    /// <summary>
    /// èŽ·å–æ‰€æœ‰é”®å€¼å¯¹
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key">键</param>
    /// <returns>数据字典</returns>
    IDictionary<string, T> HashGetAll<T>(string key);
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Interface/ISimpleCacheService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,180 @@
namespace WIDESEA_Cache;
/// <summary>
/// ç¼“存服务
/// </summary>
public partial interface ISimpleCacheService
{
    #region åŸºç¡€æ“ä½œ
    /// <summary>是否包含缓存项</summary>
    /// <param name="key"></param>
    /// <returns></returns>
    bool ContainsKey(string key);
    /// <summary>设置缓存项</summary>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expire">过期时间,秒。小于0时采用默认缓存时间</param>
    /// <returns></returns>
    bool Set<T>(string key, T value, int expire = -1);
    /// <summary>设置缓存项</summary>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expire">过期时间</param>
    /// <returns></returns>
    bool Set<T>(string key, T value, TimeSpan expire);
    /// <summary>获取缓存项</summary>
    /// <param name="key">键</param>
    /// <returns></returns>
    T Get<T>(string key);
    /// <summary>批量移除缓存项</summary>
    /// <param name="keys">键集合</param>
    /// <returns></returns>
    int Remove(params string[] keys);
    /// <summary>清空所有缓存项</summary>
    void Clear();
    /// <summary>设置缓存项有效期</summary>
    /// <param name="key">键</param>
    /// <param name="expire">过期时间</param>
    bool SetExpire(string key, TimeSpan expire);
    /// <summary>获取缓存项有效期</summary>
    /// <param name="key">键</param>
    /// <returns></returns>
    TimeSpan GetExpire(string key);
    /// <summary>
    /// æ¨¡ç³Šåˆ é™¤
    /// </summary>
    /// <param name="pattern">匹配关键字</param>
    void DelByPattern(string pattern);
    #endregion åŸºç¡€æ“ä½œ
    #region é›†åˆæ“ä½œ
    /// <summary>批量获取缓存项</summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="keys"></param>
    /// <returns></returns>
    IDictionary<string, T> GetAll<T>(IEnumerable<string> keys);
    /// <summary>批量设置缓存项</summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="values"></param>
    /// <param name="expire">过期时间,秒。小于0时采用默认缓存时间</param>
    void SetAll<T>(IDictionary<string, T> values, int expire = -1);
    /// <summary>获取列表</summary>
    /// <typeparam name="T">元素类型</typeparam>
    /// <param name="key">键</param>
    /// <returns></returns>
    IList<T> GetList<T>(string key);
    /// <summary>获取哈希</summary>
    /// <typeparam name="T">元素类型</typeparam>
    /// <param name="key">键</param>
    /// <returns></returns>
    IDictionary<string, T> GetDictionary<T>(string key);
    /// <summary>获取队列</summary>
    /// <typeparam name="T">元素类型</typeparam>
    /// <param name="key">键</param>
    /// <returns></returns>
    IProducerConsumer<T> GetQueue<T>(string key);
    /// <summary>获取栈</summary>
    /// <typeparam name="T">元素类型</typeparam>
    /// <param name="key">键</param>
    /// <returns></returns>
    IProducerConsumer<T> GetStack<T>(string key);
    /// <summary>获取Set</summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    ICollection<T> GetSet<T>(string key);
    #endregion é›†åˆæ“ä½œ
    #region é«˜çº§æ“ä½œ
    /// <summary>添加,已存在时不更新</summary>
    /// <typeparam name="T">值类型</typeparam>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expire">过期时间,秒。小于0时采用默认缓存时间</param>
    /// <returns></returns>
    bool Add<T>(string key, T value, int expire = -1);
    /// <summary>设置新值并获取旧值,原子操作</summary>
    /// <remarks>
    /// å¸¸å¸¸é…åˆIncrement使用,用于累加到一定数后重置归零,又避免多线程冲突。
    /// </remarks>
    /// <typeparam name="T">值类型</typeparam>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    T Replace<T>(string key, T value);
    /// <summary>尝试获取指定键,返回是否包含值。有可能缓存项刚好是默认值,或者只是反序列化失败,解决缓存穿透问题</summary>
    /// <typeparam name="T">值类型</typeparam>
    /// <param name="key">键</param>
    /// <param name="value">值。即使有值也不一定能够返回,可能缓存项刚好是默认值,或者只是反序列化失败</param>
    /// <returns>返回是否包含值,即使反序列化失败</returns>
    bool TryGetValue<T>(string key, out T value);
    /// <summary>累加,原子操作</summary>
    /// <param name="key">键</param>
    /// <param name="value">变化量</param>
    /// <returns></returns>
    long Increment(string key, long value);
    /// <summary>累加,原子操作</summary>
    /// <param name="key">键</param>
    /// <param name="value">变化量</param>
    /// <returns></returns>
    double Increment(string key, double value);
    /// <summary>递减,原子操作</summary>
    /// <param name="key">键</param>
    /// <param name="value">变化量</param>
    /// <returns></returns>
    long Decrement(string key, long value);
    /// <summary>递减,原子操作</summary>
    /// <param name="key">键</param>
    /// <param name="value">变化量</param>
    /// <returns></returns>
    double Decrement(string key, double value);
    #endregion é«˜çº§æ“ä½œ
    #region äº‹åŠ¡
    /// <summary>提交变更。部分提供者需要刷盘</summary>
    /// <returns></returns>
    int Commit();
    /// <summary>申请分布式锁</summary>
    /// <param name="key">要锁定的key</param>
    /// <param name="msTimeout">锁等待时间,单位毫秒</param>
    /// <returns></returns>
    IDisposable AcquireLock(string key, int msTimeout);
    /// <summary>申请分布式锁</summary>
    /// <param name="key">要锁定的key</param>
    /// <param name="msTimeout">锁等待时间,申请加锁时如果遇到冲突则等待的最大时间,单位毫秒</param>
    /// <param name="msExpire">锁过期时间,超过该时间如果没有主动释放则自动释放锁,必须整数秒,单位毫秒</param>
    /// <param name="throwOnFailure">失败时是否抛出异常,如果不抛出异常,可通过返回null得知申请锁失败</param>
    /// <returns></returns>
    IDisposable AcquireLock(string key, int msTimeout, int msExpire, bool throwOnFailure);
    #endregion äº‹åŠ¡
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Options/CacheSettingsOptions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
//using Furion.ConfigurableOptions;
using WIDESEA_Core.Core;
namespace WIDESEA_Cache;
/// <summary>
/// ç¼“存设置
/// </summary>
public class CacheSettingsOptions : IConfigurableOptions
{
    /// <summary>
    /// ä½¿ç”¨Redis
    /// </summary>
    public bool UseRedis { get; set; }
    /// <summary>
    /// æ˜¯å¦æ¯æ¬¡å¯åŠ¨éƒ½æ¸…ç©º
    /// </summary>
    public RedisSettings RedisSettings { get; set; }
}
/// <summary>
/// Redis设置
/// </summary>
public class RedisSettings
{
    /// <summary>
    /// è¿žæŽ¥åœ°å€
    /// </summary>
    public string Address { get; set; }
    /// <summary>
    /// å¯†ç 
    /// </summary>
    public string Password { get; set; }
    /// <summary>
    /// æ•°æ®åº“
    /// </summary>
    public int Db { get; set; } = 0;
    /// <summary>
    /// æ˜¯å¦æ¯æ¬¡å¯åŠ¨éƒ½æ¸…ç©º
    /// </summary>
    public bool ClearRedis { get; set; } = false;
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/MemoryCacheHashService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
namespace WIDESEA_Cache;
/// <summary>
/// <inheritdoc cref="ISimpleCacheService"/>
/// å†…存缓存
/// </summary>
public partial class MemoryCacheService : ISimpleCacheService
{
    /// <inheritdoc/>
    public void HashAdd<T>(string key, string hashKey, T value)
    {
        //获取字典
        var exist = _memoryCache.GetDictionary<T>(key);
        if (exist.ContainsKey(hashKey))//如果包含Key
            exist[hashKey] = value;//重新赋值
        else exist.Add(hashKey, value);//加上新的值
        _memoryCache.Set(key, exist);
    }
    //private IDictionary<string,T> GetDictionary(string key,string)
    /// <inheritdoc/>
    public bool HashSet<T>(string key, Dictionary<string, T> dic)
    {
        //获取字典
        var exist = _memoryCache.GetDictionary<T>(key);
        dic.ForEach(it =>
        {
            if (exist.ContainsKey(it.Key))//如果包含Key
                exist[it.Key] = it.Value;//重新赋值
            else exist.Add(it.Key, it.Value);//加上新的值
        });
        return true;
    }
    /// <inheritdoc/>
    public int HashDel<T>(string key, params string[] fields)
    {
        int result = 0;
        //获取字典
        var exist = _memoryCache.GetDictionary<T>(key);
        foreach (var field in fields)
        {
            if (field != null && exist.ContainsKey(field))//如果包含Key
            {
                exist.Remove(field);//删除
                result++;
            }
        }
        return result;
    }
    /// <inheritdoc/>
    public List<T> HashGet<T>(string key, params string[] fields)
    {
        List<T> list = new List<T>();
        //获取字典
        var exist = _memoryCache.GetDictionary<T>(key);
        foreach (var field in fields)
        {
            if (exist.ContainsKey(field))//如果包含Key
            {
                list.Add(exist[field]);
            }
            else { list.Add(default); }
        }
        return list;
    }
    /// <inheritdoc/>
    public T HashGetOne<T>(string key, string field)
    {
        //获取字典
        var exist = _memoryCache.GetDictionary<T>(key);
        exist.TryGetValue(field, out T result);
        var data = result.DeepClone();
        return data;
    }
    /// <inheritdoc/>
    public IDictionary<string, T> HashGetAll<T>(string key)
    {
        var data = _memoryCache.GetDictionary<T>(key);
        return data;
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/MemoryCacheService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,219 @@
namespace WIDESEA_Cache;
/// <summary>
/// <inheritdoc cref="ISimpleCacheService"/>
/// å†…存缓存
/// </summary>
public partial class MemoryCacheService : ISimpleCacheService
{
    public readonly MemoryCache _memoryCache;
    public MemoryCacheService()
    {
        _memoryCache = new MemoryCache();
    }
    #region æ™®é€šæ“ä½œ
    /// <inheritdoc/>
    public T Get<T>(string key)
    {
        var data = _memoryCache.Get<string>(key);
        return data.ToObject<T>();
    }
    /// <inheritdoc/>
    public int Remove(params string[] keys)
    {
        return _memoryCache.Remove(keys);
    }
    /// <inheritdoc/>
    public bool Set<T>(string key, T value, int expire = -1)
    {
        return _memoryCache.Set(key, value.ToJson(), expire);
    }
    /// <inheritdoc/>
    public bool Set<T>(string key, T value, TimeSpan expire)
    {
        return _memoryCache.Set(key, value.ToJson(), expire);
    }
    /// <inheritdoc/>
    public bool SetExpire(string key, TimeSpan expire)
    {
        return _memoryCache.SetExpire(key, expire);
    }
    /// <inheritdoc/>
    public TimeSpan GetExpire(string key)
    {
        return _memoryCache.GetExpire(key);
    }
    /// <inheritdoc/>
    public bool ContainsKey(string key)
    {
        return _memoryCache.ContainsKey(key);
    }
    /// <inheritdoc/>
    public void Clear()
    {
        _memoryCache.Clear();
    }
    /// <inheritdoc/>
    public void DelByPattern(string pattern)
    {
        var keys = _memoryCache.Keys.ToList();//获取所有key
        keys.ForEach(it =>
        {
            if (it.Contains(pattern))//如果匹配
                _memoryCache.Remove(pattern);
        });
    }
    #endregion æ™®é€šæ“ä½œ
    #region é›†åˆæ“ä½œ
    /// <inheritdoc/>
    public IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
    {
        IDictionary<string, T>? result = default;//定义集合
        IDictionary<string, string>? data = _memoryCache.GetAll<string>(keys);//获取数据
        data.ForEach(it =>
        {
            result.Add(it.Key, it.Value.ToObject<T>());//遍历数据,格式化并加到新的数据集合
        });
        return result;
    }
    /// <inheritdoc/>
    public void SetAll<T>(IDictionary<string, T> values, int expire = -1)
    {
        IDictionary<string, string>? result = default;//定义集合
        values.ForEach(it =>
        {
            result.Add(it.Key, it.Value.ToJson());//遍历数据,格式化并加到新的数据集合
        });
        _memoryCache.SetAll(values, expire);
    }
    /// <inheritdoc/>
    public IDictionary<string, T> GetDictionary<T>(string key)
    {
        IDictionary<string, T>? result = default;//定义集合
        var data = _memoryCache.GetDictionary<string>(key);
        data.ForEach(it =>
        {
            result.Add(it.Key, it.Value.ToObject<T>());//遍历数据,格式化并加到新的数据集合
        });
        return result;
    }
    /// <inheritdoc/>
    public IProducerConsumer<T> GetQueue<T>(string key)
    {
        return _memoryCache.GetQueue<T>(key);
    }
    /// <inheritdoc/>
    public IProducerConsumer<T> GetStack<T>(string key)
    {
        return _memoryCache.GetStack<T>(key);
    }
    /// <inheritdoc/>
    public ICollection<T> GetSet<T>(string key)
    {
        return _memoryCache.GetSet<T>(key);
    }
    #endregion é›†åˆæ“ä½œ
    #region é«˜çº§æ“ä½œ
    /// <inheritdoc/>
    public bool Add<T>(string key, T value, int expire = -1)
    {
        return _memoryCache.Add(key, value.ToJson(), expire);
    }
    /// <inheritdoc/>
    public IList<T> GetList<T>(string key)
    {
        IList<T> result = default;//定义集合
        var data = _memoryCache.GetList<string>(key);
        data.ForEach(it =>
        {
            result.Add(it.ToObject<T>());//遍历数据,格式化并加到新的数据集合
        });
        return result;
    }
    /// <inheritdoc/>
    public T Replace<T>(string key, T value)
    {
        return _memoryCache.Replace(key, value);
    }
    /// <inheritdoc/>
    public bool TryGetValue<T>(string key, out T value)
    {
        var result = string.Empty;
        _ = _memoryCache.TryGetValue<string>(key, out result);
        value = result.ToObject<T>();
        return value == null;
    }
    /// <inheritdoc/>
    public long Decrement(string key, long value)
    {
        return _memoryCache.Decrement(key, value);
    }
    /// <inheritdoc/>
    public double Decrement(string key, double value)
    {
        return _memoryCache.Decrement(key, value);
    }
    /// <inheritdoc/>
    public long Increment(string key, long value)
    {
        return _memoryCache.Increment(key, value);
    }
    /// <inheritdoc/>
    public double Increment(string key, double value)
    {
        return _memoryCache.Increment(key, value);
    }
    #endregion é«˜çº§æ“ä½œ
    #region äº‹åŠ¡
    /// <inheritdoc/>
    public int Commit()
    {
        return _memoryCache.Commit();
    }
    /// <inheritdoc/>
    public IDisposable AcquireLock(string key, int msTimeout)
    {
        return _memoryCache.AcquireLock(key, msTimeout);
    }
    /// <inheritdoc/>
    public IDisposable AcquireLock(string key, int msTimeout, int msExpire, bool throwOnFailure)
    {
        return _memoryCache.AcquireLock(key, msTimeout, msExpire, throwOnFailure);
    }
    #endregion äº‹åŠ¡
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/RedisCacheHashService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
namespace WIDESEA_Cache;
/// <summary>
/// <inheritdoc cref="ISimpleCacheService"/>
/// Redis缓存
/// </summary>
public partial class RedisCacheService : ISimpleCacheService
{
    /// <inheritdoc/>
    public void HashAdd<T>(string key, string hashKey, T value)
    {
        _simpleRedis.HashAdd<T>(key, hashKey, value);
    }
    /// <inheritdoc/>
    public bool HashSet<T>(string key, Dictionary<string, T> dic)
    {
        return _simpleRedis.HashSet<T>(key, dic);
    }
    /// <inheritdoc/>
    public int HashDel<T>(string key, params string[] fields)
    {
        return _simpleRedis.HashDel<T>(key, fields);
    }
    /// <inheritdoc/>
    public List<T> HashGet<T>(string key, params string[] fields)
    {
        return _simpleRedis.HashGet<T>(key, fields);
    }
    /// <inheritdoc/>
    public T HashGetOne<T>(string key, string field)
    {
        return _simpleRedis.HashGetOne<T>(key, field);
    }
    /// <inheritdoc/>
    public IDictionary<string, T> HashGetAll<T>(string key)
    {
        return _simpleRedis.HashGetAll<T>(key);
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/Service/RedisCacheService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,187 @@
namespace WIDESEA_Cache;
/// <summary>
/// <inheritdoc cref="ISimpleCacheService"/>
/// Redis缓存
/// </summary>
public partial class RedisCacheService : ISimpleCacheService
{
    private readonly ISimpleRedis _simpleRedis;
    public RedisCacheService(ISimpleRedis simpleRedis)
    {
        this._simpleRedis = simpleRedis;
    }
    #region æ™®é€šæ“ä½œ
    /// <inheritdoc/>
    public T Get<T>(string key)
    {
        return _simpleRedis.Get<T>(key);
    }
    /// <inheritdoc/>
    public int Remove(params string[] keys)
    {
        return _simpleRedis.GetFullRedis().Remove(keys);
    }
    /// <inheritdoc/>
    public bool Set<T>(string key, T value, int expire = -1)
    {
        return _simpleRedis.Set(key, value, expire);
    }
    /// <inheritdoc/>
    public bool Set<T>(string key, T value, TimeSpan expire)
    {
        return _simpleRedis.Set(key, value, expire);
    }
    /// <inheritdoc/>
    public bool SetExpire(string key, TimeSpan expire)
    {
        return _simpleRedis.GetFullRedis().SetExpire(key, expire);
    }
    /// <inheritdoc/>
    public TimeSpan GetExpire(string key)
    {
        return _simpleRedis.GetFullRedis().GetExpire(key);
    }
    /// <inheritdoc/>
    public bool ContainsKey(string key)
    {
        return _simpleRedis.ContainsKey(key);
    }
    /// <inheritdoc/>
    public void Clear()
    {
        _simpleRedis.Clear();
    }
    /// <inheritdoc/>
    public void DelByPattern(string pattern)
    {
        _simpleRedis.DelByPattern(pattern);
    }
    #endregion æ™®é€šæ“ä½œ
    #region é›†åˆæ“ä½œ
    /// <inheritdoc/>
    public IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
    {
        return _simpleRedis.GetFullRedis().GetAll<T>(keys);
    }
    /// <inheritdoc/>
    public void SetAll<T>(IDictionary<string, T> values, int expire = -1)
    {
        _simpleRedis.GetFullRedis().SetAll(values, expire);
    }
    /// <inheritdoc/>
    public IDictionary<string, T> GetDictionary<T>(string key)
    {
        return _simpleRedis.GetFullRedis().GetDictionary<T>(key);
    }
    /// <inheritdoc/>
    public IProducerConsumer<T> GetQueue<T>(string key)
    {
        return _simpleRedis.GetFullRedis().GetQueue<T>(key);
    }
    /// <inheritdoc/>
    public IProducerConsumer<T> GetStack<T>(string key)
    {
        return _simpleRedis.GetFullRedis().GetStack<T>(key);
    }
    /// <inheritdoc/>
    public ICollection<T> GetSet<T>(string key)
    {
        return _simpleRedis.GetFullRedis().GetSet<T>(key);
    }
    #endregion é›†åˆæ“ä½œ
    #region é«˜çº§æ“ä½œ
    /// <inheritdoc/>
    public bool Add<T>(string key, T value, int expire = -1)
    {
        return _simpleRedis.GetFullRedis().Add(key, value, expire);
    }
    /// <inheritdoc/>
    public IList<T> GetList<T>(string key)
    {
        return _simpleRedis.GetFullRedis().GetList<T>(key);
    }
    /// <inheritdoc/>
    public T Replace<T>(string key, T value)
    {
        return _simpleRedis.GetFullRedis().Replace(key, value);
    }
    /// <inheritdoc/>
    public bool TryGetValue<T>(string key, out T value)
    {
        return _simpleRedis.GetFullRedis().TryGetValue(key, out value);
    }
    /// <inheritdoc/>
    public long Decrement(string key, long value)
    {
        return _simpleRedis.GetFullRedis().Decrement(key, value);
    }
    /// <inheritdoc/>
    public double Decrement(string key, double value)
    {
        return _simpleRedis.GetFullRedis().Decrement(key, value);
    }
    /// <inheritdoc/>
    public long Increment(string key, long value)
    {
        return _simpleRedis.GetFullRedis().Increment(key, value);
    }
    /// <inheritdoc/>
    public double Increment(string key, double value)
    {
        return _simpleRedis.GetFullRedis().Increment(key, value);
    }
    #endregion é«˜çº§æ“ä½œ
    #region äº‹åŠ¡
    /// <inheritdoc/>
    public int Commit()
    {
        return _simpleRedis.GetFullRedis().Commit();
    }
    /// <inheritdoc/>
    public IDisposable AcquireLock(string key, int msTimeout)
    {
        return _simpleRedis.GetFullRedis().AcquireLock(key, msTimeout);
    }
    /// <inheritdoc/>
    public IDisposable AcquireLock(string key, int msTimeout, int msExpire, bool throwOnFailure)
    {
        return _simpleRedis.GetFullRedis().AcquireLock(key, msTimeout, msExpire, throwOnFailure);
    }
    #endregion äº‹åŠ¡
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Cache/WIDESEA_Cache.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="SimpleRedis" Version="1.1.9" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEA_Core\WIDESEA_Core.csproj" />
  </ItemGroup>
</Project>
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Core/DB/Models/BaseEntity.cs
@@ -50,7 +50,7 @@
        [ImporterHeader(Name = "创建者")]
        [ExporterHeader(DisplayName = "创建者")]
        [SugarColumn(IsNullable = false, IsOnlyIgnoreUpdate = true, ColumnDescription = "创建者")]
        public string Creater { get; set; } = "Systeam";
        public string Creater { get; set; } = "System";
        /// <summary>
        /// åˆ›å»ºæ—¶é—´
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_Services/Sys_CompanyRegistrationService.cs
@@ -74,7 +74,7 @@
            // è®¾ç½®é»˜è®¤å€¼
            registration.RegistrationStatus = "待审核";
            registration.Creater = "Systeam";
            registration.Creater = "System";
            // åˆ›å»º HTML æ ¼å¼çš„邮件内容
            var bodyBuilder = new BodyBuilder();
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MCS/MCSService.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Cache;
using WIDESEA_IBusinessesRepository;
using WIDESEA_IServices;
using WIDESEA_IStorageBasicRepository;
@@ -22,9 +23,11 @@
        private readonly ISys_ConfigService _configService;
        private readonly IDt_StationManagerRepository _stationManagerRepository;
        private readonly IDt_AreaInfoRepository _areaInfoRepository;
        private readonly ISimpleCacheService _simpleCacheService;
        private readonly LogFactory LogFactory = new LogFactory();
        public MCSService(ILocationInfoRepository locationRepository,IDt_TaskRepository taskRepository,IStockInfoRepository stockInfoRepository, ISys_ConfigService configService, IDt_StationManagerRepository stationManagerRepository,IDt_AreaInfoRepository dt_AreaInfoRepository)
        public MCSService(ILocationInfoRepository locationRepository,IDt_TaskRepository taskRepository,IStockInfoRepository stockInfoRepository, ISys_ConfigService configService, IDt_StationManagerRepository stationManagerRepository,IDt_AreaInfoRepository dt_AreaInfoRepository, ISimpleCacheService simpleCacheService)
        {
            _locationRepository = locationRepository;
            _taskRepository = taskRepository;
@@ -32,6 +35,7 @@
            _configService = configService;
            _stationManagerRepository = stationManagerRepository;
            _areaInfoRepository = dt_AreaInfoRepository;
            _simpleCacheService = simpleCacheService;
        }
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MCS/Partial/NotifyFinishTest.cs
@@ -105,6 +105,10 @@
                    if (respone.Status)
                    {
                        var taskId = _taskRepository.AddData(task);
                        location.LocationStatus = (int) LocationEnum.InStockDisable;
                        _locationRepository.UpdateData(location);
                        _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { taskDTO.PalletCode });
                    }
                    else
@@ -116,6 +120,7 @@
                {
                    throw new Exception("WCS处理失败");
                }
                //WMSTaskDTO taskDTO = new WMSTaskDTO
                //{
                //    Id = 0,
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs
@@ -35,7 +35,7 @@
            input.SessionId = Guid.NewGuid().ToString();
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input); // Specify the namespace explicitly
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
            var ipAddress = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.AgingInput)?.ConfigValue;
@@ -64,8 +64,8 @@
        }
        catch (Exception err)
        {
            MoMErrorMsg.AddMoMErrorMsg(0, input.TrayBarcode, err.Message, SysConfigConst.AgingInput);
            Console.WriteLine(err.Message.ToString());
            //MoMErrorMsg.AddMoMErrorMsg(0, input.TrayBarcode, err.Message, SysConfigConst.AgingInput);
            //Console.WriteLine(err.Message.ToString());
            LogFactory.GetLog("静置陈化入库(整托盘)").Error(true, $"\r\r--------------------------------------");
            LogFactory.GetLog("静置陈化入库(整托盘)").Error(true, err.StackTrace);
        }
@@ -85,7 +85,7 @@
            input.SessionId = Guid.NewGuid().ToString();
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input); // Specify the namespace explicitly
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
            var ipAddress = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.AgingOutput)?.ConfigValue;
@@ -114,8 +114,8 @@
        }
        catch (Exception err)
        {
            MoMErrorMsg.AddMoMErrorMsg(0, input.TrayBarcode, err.Message, SysConfigConst.AgingOutput);
            Console.WriteLine(err.Message.ToString());
            //MoMErrorMsg.AddMoMErrorMsg(0, input.TrayBarcode, err.Message, SysConfigConst.AgingOutput);
            //Console.WriteLine(err.Message.ToString());
            LogFactory.GetLog("静置陈化出库(整托盘)").Error(true, $"\r\r--------------------------------------");
            LogFactory.GetLog("静置陈化出库(整托盘)").Error(true, err.StackTrace);
            content.Error(err.Message);
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/CellState/CellStateService.cs
@@ -42,7 +42,7 @@
            input.SessionId = Guid.NewGuid().ToString();
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input);
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
            var ipAddress = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.CellState)?.ConfigValue; 
@@ -60,7 +60,7 @@
        }
        catch (Exception err)
        {
            Console.WriteLine(err.Message.ToString());
            //Console.WriteLine(err.Message.ToString());
            LogFactory.GetLog("单电芯属性获取").Error(true, $"\r\r--------------------------------------");
            LogFactory.GetLog("单电芯属性获取").Error(true, $"请求参数: {JsonConvert.SerializeObject(input)}");
            LogFactory.GetLog("单电芯属性获取").Error(true, err.Message);
@@ -82,7 +82,7 @@
            input.SessionId = Guid.NewGuid().ToString();
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input);
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
            var ipAddress = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.TrayCellsStatus)?.ConfigValue;
@@ -111,9 +111,9 @@
        }
        catch (Exception err)
        {
            MoMErrorMsg.AddMoMErrorMsg(0, input.TrayBarcode, err.Message, SysConfigConst.TrayCellsStatus);
            //MoMErrorMsg.AddMoMErrorMsg(0, input.TrayBarcode, err.Message, SysConfigConst.TrayCellsStatus);
            Console.WriteLine(err.Message.ToString());
            //Console.WriteLine(err.Message.ToString());
            LogFactory.GetLog("整盘电芯属性获取").Error(true, $"\r\r--------------------------------------");
            LogFactory.GetLog("整盘电芯属性获取").Error(true, $"请求参数: {JsonConvert.SerializeObject(input)}");
            LogFactory.GetLog("整盘电芯属性获取").Error(true, err.Message);
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/ProcessApply/ProcessApplyService.cs
@@ -47,7 +47,7 @@
            input.SessionId = Guid.NewGuid().ToString();
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input);
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
            var ipAddress = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.ProcessApply)?.ConfigValue;
@@ -78,7 +78,7 @@
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            //Console.WriteLine(ex.Message);
            LogFactory.GetLog("工艺路线申请").Error(true, $"\r\r--------------------------------------");
            LogFactory.GetLog("工艺路线申请").Error(true, ex.StackTrace);
        }
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/Unbind/UnbindService.cs
@@ -38,7 +38,7 @@
            input.EquipmentCode = "24MEJQ08-1091";
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input);
            LogFactory.GetLog("托盘单电芯解绑1").Info(true, JsonConvert.SerializeObject(inputJson));
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
@@ -77,7 +77,7 @@
            input.EquipmentCode = "24MEJQ08-1091";
            input.EmployeeNo = "MITest";
            input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            var inputJson = input.ToDictionary();
            var inputJson = Masuit.Tools.ObjectExtensions.ToDictionary(input);
            Console.WriteLine(inputJson);
            var configs = _configService.GetConfigsByCategory(CateGoryConst.SYS_MOMIPAddress);
            var wmsBase = configs.FirstOrDefault(x => x.ConfigKey == SysConfigConst.MOMBaseIP)?.ConfigValue;
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/WIDESEA_StoragIntegrationServices.csproj
@@ -8,6 +8,7 @@
  <ItemGroup>
    <ProjectReference Include="..\LogLibrary\LogLibrary.csproj" />
    <ProjectReference Include="..\WIDESEA_Cache\WIDESEA_Cache.csproj" />
    <ProjectReference Include="..\WIDESEA_Common\WIDESEA_Common.csproj" />
    <ProjectReference Include="..\WIDESEA_IStoragIntegrationServices\WIDESEA_IStoragIntegrationServices.csproj" />
    <ProjectReference Include="..\WIDESEA_Services\WIDESEA_Services.csproj" />
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageBasicServices/Location/LocationInfoService.cs
@@ -201,7 +201,7 @@
                        RoadwayNo = locType > 1 ? $"GWSC{((line - 1) / 4) + 1}" : $"GWSC{((line - 1) / 2) + 1}",
                        LocationStatus = LocationEnum.Free.ObjToInt(),
                        AreaId = areaId,
                        Creater = "systeam",
                        Creater = "System",
                        EnalbeStatus = 2,
                    });
                }
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/AspNetCoreSchedule.cs
@@ -1,6 +1,7 @@
using Masuit.Tools;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using WIDESEA_Cache;
using WIDESEA_Core.Const;
using WIDESEA_DTO.WMS;
using WIDESEA_IServices;
@@ -17,10 +18,11 @@
        private readonly IDt_StationManagerRepository _stationManagerRepository;
        private readonly ISys_ConfigService _configService;
        private readonly ILocationInfoRepository _locationRepository;
        private readonly ISimpleCacheService _simpleCacheService;
        private Timer _timer;
        public MyBackgroundService(ILogger<MyBackgroundService> logger, ILocationInfoRepository locationRepository, IStockInfoRepository stockInfoRepository, IDt_AreaInfoRepository areaInfoRepository, IDt_TaskRepository taskRepository, IDt_StationManagerRepository stationManagerRepository, ISys_ConfigService configService)
        public MyBackgroundService(ILogger<MyBackgroundService> logger, ILocationInfoRepository locationRepository, IStockInfoRepository stockInfoRepository, IDt_AreaInfoRepository areaInfoRepository, IDt_TaskRepository taskRepository, IDt_StationManagerRepository stationManagerRepository, ISys_ConfigService configService, ISimpleCacheService simpleCacheService)
        {
            _logger = logger;
            _locationRepository = locationRepository;
@@ -29,11 +31,12 @@
            _taskRepository = taskRepository;
            _stationManagerRepository = stationManagerRepository;
            _configService = configService;
            _simpleCacheService = simpleCacheService;
        }
        public Task StartAsync(CancellationToken cancellationToken)
        {
            _timer = new Timer(DoWork, null, 0, 10000);
            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
            return Task.CompletedTask;
        }
@@ -44,11 +47,12 @@
                var area = _areaInfoRepository.QueryFirst(x => x.AreaCode == "GWSC1");
                if (area == null) { return; }
                var stockInfo = _stockInfoRepository.Db.Queryable<DtStockInfo>()
                     .Includes(x => x.LocationInfo) // é¢„加载LocationInfo
                     .Includes(x => x.StockInfoDetails) // é¢„加载StockInfoDetails
                     .Where(x => x.AreaCode == area.AreaCode && x.OutboundTime < DateTime.Now && x.IsFull == true) // è¿‡æ»¤æ¡ä»¶
                     .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID) // è¿‡æ»¤æ¡ä»¶
                IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
                List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
                var stockInfo = stockInfoList.Where(x => x.AreaCode == area.AreaCode && x.OutboundTime < DateTime.Now && x.IsFull == true) // è¿‡æ»¤æ¡ä»¶
                     .Where(x => x.LocationInfo != null && x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID) // è¿‡æ»¤æ¡ä»¶
                     .OrderBy(x => x.OutboundTime) // æŽ’序
                     .ToList(); // èŽ·å–ç¬¬ä¸€ä¸ªå…ƒç´ 
@@ -135,7 +139,7 @@
                Creater = "System", // ä¿®æ­£æ‹¼å†™é”™è¯¯
                CreateDate = DateTime.Now,
                TaskId = 0,
                ProductionLine= stockInfo.ProductionLine,
                ProductionLine = stockInfo.ProductionLine,
                ProcessCode = stockInfo.ProcessCode,
            };
        }
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs
@@ -1,7 +1,8 @@
using Autofac.Core;
using Mapster;
using Mapster;
using Masuit.Tools;
using SqlSugar;
using System.Text.RegularExpressions;
using WIDESEA_Cache;
using WIDESEA_Core.Const;
using WIDESEA_DTO.MOM;
using WIDESEA_DTO.WMS;
@@ -9,7 +10,6 @@
using WIDESEA_IStoragIntegrationServices;
using WIDESEAWCS_BasicInfoRepository;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEA_StorageTaskServices;
@@ -31,6 +31,7 @@
    private readonly IAgingInOrOutInputService _agingInOrOutInputService; //静置\陈化
    private readonly IDt_StationManagerRepository _stationManagerRepository;
    private readonly ISys_ConfigService _configService;
    private readonly ISimpleCacheService _simpleCacheService;
    public Dt_TaskService(IDt_TaskRepository BaseDal,
                                IUnitOfWorkManage unitOfWorkManage,
@@ -48,7 +49,8 @@
                                IAgingInOrOutInputService agingInOrOutInputService,
                                IStockInfoDetailRepository stockInfoDetailRepository,
                                IDt_StationManagerRepository stationManagerRepository,
                                ISys_ConfigService configService) : base(BaseDal)
                                ISys_ConfigService configService,
                                ISimpleCacheService simpleCacheService) : base(BaseDal)
    {
        _unitOfWorkManage = unitOfWorkManage;
        _stockInfoRepository = stockInfoRepository;
@@ -65,6 +67,7 @@
        _stockInfoDetailRepository = stockInfoDetailRepository;
        _stationManagerRepository = stationManagerRepository;
        _configService = configService;
        _simpleCacheService = simpleCacheService;
    }
    #region å¤–部接口方法
@@ -78,86 +81,6 @@
        {
            if (task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
            {
                #region è€ç‰ˆæœ¬
                //var process = await SqlSugarHelper.Db.Queryable<Dt_EquipmentProcess>()
                //    .FirstAsync(x => x.EquipmentName == task.Roadway);
                //var info = JsonConvert.DeserializeObject<ResponseEqptRunDto>(process.ProcessValue);
                //if (!task.Roadway.Contains("FR") && stock.ProcessCode != "OCVB")  //非分容库区与当前工序是OCVB均上报MOM出入站
                //{
                //    var agingOutputDto = MapToAgingOutputDto(stock);
                //    content = await _agingInOrOutInputService.GetOCVOutputAsync(agingOutputDto);
                //    //ValidateResponse(content);
                //    var result = JsonConvert.DeserializeObject<BasicResult>(content.Data.ToString());
                //    if (!result.Success || !agingOutputDto.SerialNos[0].SerialNoResult)
                //    {
                //        if (result.MessageCode == "E10001")
                //        {
                //            var area = _areaInfoRepository.QueryFirst(x => x.AreaCode == stock.AreaCode);
                //            if (area == null)
                //            {
                //                throw new Exception("未找到对应的库区信息");
                //            }
                //            var trayCells = new TrayCellsStatusDto()
                //            {
                //                Software = area.Spare3,
                //                TrayBarcode = task.PalletCode,
                //                EquipmentCode = area.Spare2,
                //                SceneType = area.Spare4
                //            };
                //            content = await _cellStateService.GetTrayCellStatusAsync(trayCells);
                //            if (!content.Status) return content;
                //            var ResultTray = JsonConvert.DeserializeObject<ResultTrayCellsStatus>(content.Data.ToString());
                //            if (ResultTray.SerialNos.Count > 0)
                //            {
                //                var parameterInfo = JsonConvert.DeserializeObject<List<ParameterInfo>>(stock.ParameterInfos).FirstOrDefault(y => y.Description.Contains("时间"));
                //                if (parameterInfo == null) throw new Exception("");
                //                var outHours = (DateTime.Now - (stock.LinedProcessFeedbackTime == null ? stock.CreateDate : stock.LinedProcessFeedbackTime.ToDateTime())).TotalHours;
                //                var isNG = outHours > parameterInfo.LowerSpecificationsLimit.ToDouble() && outHours < parameterInfo.UpperSpecificationsLimit.ToDouble();
                //                var defectCode = string.Empty;
                //                if (!isNG) defectCode = "TQCK";
                //                var outputDto = new AgingOutputDto
                //                {
                //                    OpFlag = 1,
                //                    Software = area.Spare3,
                //                    EquipmentCode = area.Spare2,
                //                    TrayBarcode = stock.PalletCode,
                //                    SerialNos = ResultTray.SerialNos.Select(x => new SerialNoOutDto
                //                    {
                //                        SlotNo = x.PositionNo,
                //                        SerialNo = x.SerialNo,
                //                        SerialNoResult = true, //isNG,
                //                        ParameterInfo = new List<ParameterInfoOutput> {
                //                            new ParameterInfoOutput() {
                //                                Value = outHours.ToString(),
                //                                ParameterCode =parameterInfo.ParameterCode,
                //                                ParameterDesc = parameterInfo.Description,
                //                                ParameterResult  = "OK", //isNG.ToString(),
                //                                TargetValue = parameterInfo.TargetValue,
                //                                LowerLomit = parameterInfo.LowerSpecificationsLimit,
                //                                UpperLimit = parameterInfo.UpperSpecificationsLimit,
                //                                DefectCode = defectCode,
                //                                UOMCode = parameterInfo.UOMCode,
                //                            }
                //                        }
                //                    }).ToList()
                //                };
                //                content = await _agingInOrOutInputService.GetOCVOutputAsync(outputDto);
                //                result = JsonConvert.DeserializeObject<BasicResult>(content.Data.ToString());
                //                if (!result.Success)
                //                    task.Remark = "NG";
                //            }
                //        }
                //        else
                //            task.Remark = "NG";
                //    }
                //}
                #endregion è€ç‰ˆæœ¬
                if (task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
                {
                    if (!task.Roadway.Contains("FR") && stock.ProcessCode != "OCVB")
@@ -189,12 +112,12 @@
                ConsoleHelper.WriteErrorLine("MOM通报点芯NG");
                return content.Error("MOM通报点芯NG");
            }
            // æ›´æ–°åº“存状态和任务状态
            (var loc, var tas) = UpdateStockAndTaskStatus(stock, task);
            var taskHty = task.Adapt<Dt_Task_Hty>();
            taskHty.FinishTime = DateTime.Now;
            taskHty.OperateType = (int)OperateTypeEnum.自动完成;
            taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成;
            taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System";
            DtStockInfo_Hty stockInfo_Hty = stock.Adapt<DtStockInfo_Hty>();
            stockInfo_Hty.ModifyDate = DateTime.Now;
@@ -212,6 +135,20 @@
                await DeleteTaskAsync(task.TaskId);
                await AddTaskHtyAsync(taskHty);
            });
            try
            {
                //using (_simpleCacheService.AcquireLock(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, 2000))
                //{
                _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { stock.PalletCode });
                //}
            }
            catch (Exception ex)
            {
                LogFactory.GetLog("删除缓存失败").Error(true, $"{stock.PalletCode}_删除缓存失败,异常信息:{ex.Message}");
                //using (_simpleCacheService.AcquireLock(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, 2000))
                //{
                //}
            }
            return content.OK("任务完成成功", task.Remark);
        }
@@ -222,7 +159,7 @@
        }
    }
    private AgingOutputDto MapToAgingOutputDto(DtStockInfo stock, ResponseEqptRunDto info = null)
    private AgingOutputDto MapToAgingOutputDto(DtStockInfo stock, ResponseEqptRunDto? info = null)
    {
        // TODO Value值根据MOM下发的静置时间到当前时间的分钟数
        var area = _areaInfoRepository.QueryFirst(x => x.AreaCode == stock.AreaCode);
@@ -446,6 +383,20 @@
            if (isResult)
            {
                _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(locationInf, lastStatus, (int)StatusChangeTypeEnum.AutomaticStorage, task.TaskNum);
                stock.StockInfoDetails = new List<DtStockInfoDetail>() { { stock.StockInfoDetails[0] } };
                stock.LocationInfo = locationInf;
                //using(_simpleCacheService.AcquireLock(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, 2000))
                //{
                try
                {
                    _simpleCacheService.HashAdd(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, stock.PalletCode, stock);
                }
                catch (Exception ex)
                {
                    LogFactory.GetLog("添加缓存失败").Error(true, $"{stock.PalletCode}_添加缓存失败,异常信息:{ex.Message}");
                }
                content.OK("入库任务完成成功");
            }
            else
@@ -594,9 +545,9 @@
            {
                isFull = respone.SpecialParameterDuration.IsNullOrEmpty();
            }
            if (respone.ProductionLine == null || respone.ParameterInfos == null)
            if (respone.ProductionLine == null || respone.ParameterInfos == null || respone.ParameterInfos.IsNullOrEmpty())
            {
                throw new Exception("MOM数据返回错误");
                throw new Exception($"MOM数据返回错误,产线{respone.ProductionLine},ParameterInfos{respone.ParameterInfos}");
            }
            stock.LinedProcessFeedbackTime = respone.LinedProcessFeedbackTime;
            stock.SpecialParameterDuration = respone.SpecialParameterDuration;
@@ -678,244 +629,6 @@
    #endregion ä»»åŠ¡å®Œæˆ
    #region è¯·æ±‚任务入库
    #region
    /// <summary>
    /// è¯·æ±‚任务巷道
    /// </summary>
    /// <param name="input">请求模型</param>
    /// <returns>包含任务信息的响应内容</returns>
    public async Task<WebResponseContent> RequestTaskAsync2(RequestTaskDto input)
    {
        // åˆ›å»ºä¸€ä¸ªWebResponseContent对象
        WebResponseContent content = new WebResponseContent();
        try
        {
            // è°ƒç”¨BaseDal.QueryFirstAsync方法,查询任务
            var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == input.PalletCode);
            if (task != null)
            {
                //if (task.TaskState == (int)TaskInStatusEnum.InNew)
                {
                    // åˆ›å»ºWMS任务
                    WMSTaskDTO taskDTO = new WMSTaskDTO()
                    {
                        TaskNum = task.TaskNum.Value,
                        Grade = 1,
                        PalletCode = task.PalletCode,
                        RoadWay = task.Roadway,
                        SourceAddress = task.SourceAddress,
                        TargetAddress = task.Roadway,
                        TaskState = task.TaskState.Value,
                        Id = 0,
                        TaskType = task.TaskType,
                    };
                    return content.OK(data: taskDTO);
                }
            }
            var stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.PalletCode == input.PalletCode && x.IsFull);
            if (stock != null)
            {
                // TODO质检回库
            }
            var area = await _areaInfoRepository.QueryFirstAsync(x => x.Spare1.Contains(input.Position));
            if (area == null)
                return content.Error("改点位不在区域列表中存在");
            // åˆ›å»ºä¸€ä¸ªTrayCellsStatusDto对象,并赋值
            TrayCellsStatusDto trayCells = new TrayCellsStatusDto()
            {
                Software = area.Spare3,
                TrayBarcode = input.PalletCode,
                EquipmentCode = area.Spare2,
                SceneType = area.Spare4,
            };
            // è°ƒç”¨GetTrayCellStatusAsync方法,获取整盘电芯
            content = await GetTrayCellStatusAsync(trayCells);
            // å¦‚果状态为false,则返回content
            if (!content.Status) return content;
            // æ·»åŠ ç»„ç›˜ä¿¡æ¯
            // å°†content.Data转换为ResultTrayCellsStatus对象
            var result = JsonConvert.DeserializeObject<ResultTrayCellsStatus>(content.Data.ToString());
            if (!result.Success)
                return content.Error(result.MOMMessage);
            // èŽ·å–å¼‚å¸¸ç”µèŠ¯
            List<SerialNoDto>? serialNosError = result.SerialNos.Where(x => x.SerialNoStatus != 1 && x.SerialNoStatus != 4).ToList();
            if (serialNosError.Count > 0)
            {
                // TODO åˆ›å»ºä»»åŠ¡é€è‡³NG排出口
                var efg = _stationManagerRepository.QueryData(x => x.stationType == 1 && x.stationChildCode == input.Position && x.stationArea == area.AreaCode).ToList();
                //List<string> NGStation = input.Position == "1088" ? new List<string>() { "1020" } : new List<string>() { "JZSC01" };
                if (efg.Count <= 0)
                {
                    throw new Exception("未找到NG入库站台配置");
                }
                List<string> NGStation = efg.Select(x => x.stationNGLocation).ToList();
                if (NGStation.Count <= 0)
                {
                    NGStation = efg.Select(x => x.stationNGChildCode).ToList();
                }
                content = await CreateNewTask(input, result.ProductionLine, result.ProcessCode, NGStation, 2);
                return content.Error("存在异常电芯");
            }
            if (result.SerialNos.Count <= 0)
            {
                // Todo ç©ºæ‰˜ç›˜å…¥åº“逻辑
                content = await RequestTrayInTaskAsync(input);
                return content;
            }
            var boxing = CreateBoxingInfo(result, input.PalletCode);
            //Console.WriteLine(boxing.ToJsonString());
            if (boxing == null) return content.Error("组盘失败");
            if (result.ProcessCode == "OCVB")
            {
                //TODO åˆ¤æ–­éœ€ä¸éœ€è¦åŽ»åŒ…è£…ï¼Œä¸éœ€è¦å°±åŽ»å¸¸æ¸©ä¸‰
                var stationManagers = _stationManagerRepository.QueryData(x => x.stationPLC == "1018" && x.stationArea == "Cache");
                var station = stationManagers.Select(x => x.stationChildCode).ToList();
                // èŽ·å–WCSip地址
                var configz = _configService.GetConfigsByCategory(CateGoryConst.CONFIG_SYS_IPAddress);
                var wcsBasez = configz.Where(x => x.ConfigKey == SysConfigConst.WCSIPAddress).FirstOrDefault()?.ConfigValue;
                var address = configz.Where(x => x.ConfigKey == SysConfigConst.GetStation).FirstOrDefault()?.ConfigValue;
                if (wcsBasez == null || address == null)
                {
                    throw new InvalidOperationException("WCS IP æœªé…ç½®");
                }
                var wcsIpAddrss = wcsBasez + address;
                var abc = HttpHelper.PostAsync(wcsIpAddrss, station.ToJsonString()).Result;
                content = JsonConvert.DeserializeObject<WebResponseContent>(abc);
                if (content.Data.ObjToInt() > 0)
                {
                    // TODO é€è‡³åŒ…装
                    List<string> strings = stationManagers.Where(x => x.stationType == 0).Select(x => x.Roadway).ToList();
                    content = await CreateNewTask(input, result.ProductionLine, result.ProcessCode, strings, 3);
                    return content;
                }
                else
                {
                    var config = _configService.GetByConfigKey("SYS_InStacker", "CW3InStacker");
                    var strings = config.ConfigValue.Split(',').ToList();
                    // TODO å…¥åº“
                    content = await CreateNewTask(input, result.ProductionLine, result.ProcessCode, strings);
                    if (content.Status)
                        await _boxingInfoRepository.AddDataNavAsync(boxing);
                }
            }
            else
            {
                // TODO èŽ·å–æœ¬åœ°æ–™æ¡†å±žæ€§ä¸Žæ•´ç›˜ç”µèŠ¯å±žæ€§èŽ·å–çš„å€¼è¿›è¡Œå¯¹æ¯”ï¼Œå¦‚æžœä¸€è‡´åˆ™ç»§ç»­ï¼Œå¦åˆ™è¿”å›žé”™è¯¯ä¿¡æ¯
                //var productions = await _productionRepository.QueryDataAsync(x => result.TrayBarcodePropertys.Select(x => x.TrayBarcodeProperty).ToList().Contains(x.TrayBarcodeProperty));
                //if (productions.Count <= 0)
                //    return content.Error("料框属性不存在");
                // è°ƒç”¨CreateBoxingInfo方法,创建组盘信息
                //var boxing = CreateBoxingInfo(result, input.PalletCode);
                ////Console.WriteLine(boxing.ToJsonString());
                //if (boxing == null) return content.Error("组盘失败");
                // è°ƒç”¨GetProcessApplyAsync方法,获取工艺路线
                ProcessApplyDto process = await GetProcessApplyAsync(result);
                // å¦‚æžœprocess为null,则返回content
                if (process == null) return content;
                // å¹¶èµ‹å€¼ä¸Šä½è½¯ä»¶åç§°å’Œè®¾å¤‡ç¼–码
                process.Software = area.Spare3;
                process.EquipmentCode = area.Spare2;
                // è°ƒç”¨GetProcessApplyAsync方法,获取工艺申请
                // è°ƒç”¨_processApplyService.GetProcessApplyAsync方法,获取工艺申请
                content = await _processApplyService.GetProcessApplyAsync(process);
                // å¦‚果状态为false,则返回null
                if (!content.Status) return content.Error("工艺申请失败");
                var resultProcessApply = JsonConvert.DeserializeObject<ResultProcessApply>(content.Data.ToString());
                if (!resultProcessApply.Success) return content.Error("工艺申请失败");
                var number = resultProcessApply.ProcessInfo.Where(x => x.ProcessCode == boxing.ProcessCode).FirstOrDefault().Number.ToInt32();
                foreach (var item in resultProcessApply.ProcessInfo)
                {
                    if (item.Number.ToInt32() == number + 1)
                    {
                        boxing.NextProcessCode = item.ProcessCode;
                    }
                }
                Console.WriteLine();
                Console.WriteLine($"当前工序:{boxing.ProcessCode}");
                Console.WriteLine($"下一工序:{boxing.NextProcessCode}");
                Console.WriteLine(area.AreaCode + "-----------------------");
                Console.WriteLine(input.Position + "-----------------------");
                var areaIn = string.Empty;
                switch (boxing.NextProcessCode)
                {
                    case "CH01":
                        areaIn = "CH001";
                        break;
                    case "JZ01":
                        areaIn = "JZ001";
                        break;
                    case "GW01":
                        areaIn = "GWSC1";
                        break;
                    case "CW01":
                        areaIn = "CWSC1";
                        break;
                    case "CW02":
                        areaIn = "CWSC2";
                        break;
                    default:
                        break;
                }
                var stationManagers = _stationManagerRepository.QueryData(x => x.stationType == 1 && x.stationChildCode == input.Position && x.stationArea.Contains(areaIn)).FirstOrDefault();
                if (stationManagers == null)
                {
                    throw new Exception("未找到入库站台配置");
                }
                List<string> strings = stationManagers.Roadway.Split(',').ToList();
                Console.WriteLine(strings.ToJsonString() + "b-----------------------");
                //// è°ƒç”¨CreateNewTask方法,创建新任务
                content = await CreateNewTask(input, result.ProductionLine, result.ProcessCode, strings);
                if (content.Status)
                {
                    var isBox = await _boxingInfoRepository.AddDataNavAsync(boxing);
                }
                //}
            }
        }
        catch (Exception err)
        {
            // å¦‚果发生异常,则调用content.Error方法,记录错误信息,并输出错误信息
            content.Error(err.Message);
            Console.WriteLine(err.Message);
        }
        // è¿”回content
        return content;
    }
    #endregion è¯·æ±‚任务入库
    public async Task<WebResponseContent> RequestTaskAsync(RequestTaskDto input)
    {
@@ -1001,7 +714,6 @@
                    return content.Error(result.MOMMessage);
            }
            if (result.SerialNos.Count <= 0)
            {
                var config = _configService.GetByConfigKey(CateGoryConst.CONFIG_SYS_InStacker, SysConfigConst.InboundIsEmpty);
@@ -1079,18 +791,6 @@
            {
                // åˆ›å»ºWMS任务
                WMSTaskDTO taskDTO = CreateTaskDTO(task);
                //WMSTaskDTO taskDTO = new WMSTaskDTO()
                //{
                //    TaskNum = task.TaskNum.Value,
                //    Grade = 1,
                //    PalletCode = task.PalletCode,
                //    RoadWay = task.Roadway,
                //    SourceAddress = task.SourceAddress,
                //    TargetAddress = task.Roadway,
                //    TaskState = task.TaskState.Value,
                //    Id = 0,
                //    TaskType = task.TaskType,
                //};
                return content.OK(data: task);
            }
@@ -1117,7 +817,6 @@
                ConsoleHelper.WriteErrorLine($"当前托盘无产线,联系MOM添加产线");
                return content.Error("当前托盘无产线,联系MOM添加产线");
            }
            var stationManagers = _stationManagerRepository.QueryData(x => x.stationType == 6 && x.stationChildCode == input.Position).FirstOrDefault();
            if (stationManagers == null)
@@ -1177,7 +876,7 @@
        };
    }
    #endregion å¤–部接口方法
    #endregion è¯·æ±‚任务入库
    #region è¯·æ±‚出库(实盘&空盘)
@@ -1205,7 +904,6 @@
            }
            //ConsoleHelper.WriteColorLine(JsonConvert.SerializeObject(stockInfo), ConsoleColor.DarkMagenta);
            // æ–°å¢žé‡å¤ä»»åŠ¡æ ¡éªŒ
            var hasTask = BaseDal.QueryFirst(x => x.PalletCode == stockInfo.PalletCode);
@@ -1240,7 +938,7 @@
        {
            // è®°å½•异常信息并抛出
            LogFactory.GetLog("请求托盘任务").Error(true, ex);
            ConsoleHelper.WriteErrorLine("请求空/实托盘任务" + ex.Message);
            ConsoleHelper.WriteErrorLine("请求空/实托盘任务" + ex.Message + "\r\n" + ex.StackTrace);
            return content.Error(ex.Message);
        }
    }
@@ -1250,35 +948,52 @@
    /// </summary>
    private async Task<DtStockInfo> QueryStockInfoForRealTrayAsync(string areaCode, List<string> devices, string productionLine)
    {
        var area = await _areaInfoRepository.QueryFirstAsync(x => x.AreaCode == areaCode);
        if (area == null)
        try
        {
            ConsoleHelper.WriteErrorLine($"查询实盘库存信息时,未找到区域代码为{areaCode}的数据");
            var area = await _areaInfoRepository.QueryFirstAsync(x => x.AreaCode == areaCode);
            if (area == null)
            {
                ConsoleHelper.WriteErrorLine($"查询实盘库存信息时,未找到区域代码为{areaCode}的数据");
                return null;
            }
            var outBoundMateriel = AppSettings.app<OutBoundMateriel>("OutBoundMateriel");
            List<string>? materielCodes = outBoundMateriel.Count != 0
                ? outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == area.AreaCode)
                                  .Select(x => x.MaterielCode)
                                  .ToList()
                : null;
            IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
            List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
            var result = new DtStockInfo();
            //if (stockInfoList.IsNullOrEmpty())
            //{
            //    stockInfoList = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
            //        .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock).IncludesAllFirstLayer().ToListAsync();
            //}
            result = stockInfoList.Where(x => x.AreaCode == areaCode && x.OutboundTime < DateTime.Now && x.IsFull)
                              .WhereIF(!productionLine.IsNullOrEmpty(), x => x.ProductionLine == productionLine)
                              .Where(x => x.LocationInfo != null && x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable)
                              .WhereIF(!devices.IsNullOrEmpty(), x => devices.Contains(x.LocationInfo.RoadwayNo))
                              .WhereIF(!materielCodes.IsNullOrEmpty(), x => x.StockInfoDetails != null && x.StockInfoDetails.Any(y => materielCodes.Contains(y.MaterielCode)))
                              .OrderBy(x => x.OutboundTime)
            .FirstOrDefault();
            if (result != null)
                _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { result.PalletCode });
            else
                ConsoleHelper.WriteErrorLine("QueryStockInfoForRealTrayAsync查询实盘库存信息失败:未找到符合条件的数据");
            return result;
        }
        catch (Exception ex)
        {
            ConsoleHelper.WriteErrorLine("QueryStockInfoForRealTrayAsync查询实盘库存信息失败:" + ex.Message + "\r\n" + ex.StackTrace);
            return null;
        }
        var outBoundMateriel = AppSettings.app<OutBoundMateriel>("OutBoundMateriel");
        List<string> materielCodes = null;
        if (outBoundMateriel.Count != 0)
        {
            materielCodes = outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == area.AreaCode).Select(x => x.MaterielCode).ToList();
        }
        var result = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
            .Includes(x => x.LocationInfo) // é¢„加载LocationInfo
            .Includes(x => x.StockInfoDetails) // é¢„加载StockInfoDetails
            .Where(x => x.AreaCode == areaCode && x.OutboundTime < DateTime.Now && x.IsFull == true) // è¿‡æ»¤æ¡ä»¶
            .WhereIF(!productionLine.IsNullOrEmpty(), x => x.ProductionLine == productionLine)
            .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
            .WhereIF(!devices.IsNullOrEmpty(), x => devices.Contains(x.LocationInfo.RoadwayNo))
            .WhereIF(!materielCodes.IsNullOrEmpty(), x => x.StockInfoDetails.Any(y => materielCodes.Contains(y.MaterielCode)))
            .OrderBy(x => x.OutboundTime) // æŽ’序
            .FirstAsync(); // èŽ·å–ç¬¬ä¸€ä¸ªå…ƒç´ 
        //var firstOrDefault = result.FirstOrDefault(x => roadways.Contains(x.LocationInfo.RoadwayNo)); // æŸ¥æ‰¾ç¬¬ä¸€ä¸ªåŒ¹é…çš„元素
        //var firstOrDefault = result[0]; // æŸ¥æ‰¾ç¬¬ä¸€ä¸ªåŒ¹é…çš„元素
        //return firstOrDefault;
        return result;
    }
    /// <summary>
@@ -1286,42 +1001,62 @@
    /// </summary>
    private async Task<DtStockInfo> QueryStockInfoForRealTrayCWAsync(List<string> areaCodes, string productionLine)
    {
        var areaId = (await _areaInfoRepository.QueryDataAsync(x => areaCodes.Contains(x.AreaCode))).Select(x => x.AreaID).ToList();
        if (areaId.Count == 0)
        try
        {
            ConsoleHelper.WriteErrorLine($"查询常温实盘库存信息时,未找到区域代码为{JsonConvert.SerializeObject(areaCodes)}的数据");
            var areaId = (await _areaInfoRepository.QueryDataAsync(x => areaCodes.Contains(x.AreaCode))).Select(x => x.AreaID).ToList();
            if (areaId.Count == 0)
            {
                ConsoleHelper.WriteErrorLine($"查询常温实盘库存信息时,未找到区域代码为{JsonConvert.SerializeObject(areaCodes)}的数据");
                return null;
            }
            //var outBoundMateriel = AppSettings.app<OutBoundMateriel>("OutBoundMateriel");
            //List<string> materielCodes = null;
            //if (outBoundMateriel.Count != 0)
            //{
            //    materielCodes = outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == areaCodes[0]).Select(x => x.MaterielCode).ToList();
            //}
            var outBoundMateriel = AppSettings.app<OutBoundMateriel>("OutBoundMateriel");
            List<string>? materielCodes = outBoundMateriel.Count != 0
                ? outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == areaCodes[0])
                                  .Select(x => x.MaterielCode)
                                  .ToList()
                : null;
            var deviceCode = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
                .Where(x => x.DeviceStatus == "1")
                .Where(x => x.DeviceCode.Contains("CWSC"))
                .ToList().Select(x => x.DeviceCode).ToList();
            //var deviceCode = devices.Select(x => x.DeviceCode).ToList();
            IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
            List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
            var result = stockInfoList.Where(x => areaCodes.Contains(x.AreaCode) && x.OutboundTime < DateTime.Now && x.IsFull == true) // è¿‡æ»¤æ¡ä»¶
                .WhereIF(!productionLine.IsNullOrEmpty(), x => x.ProductionLine == productionLine)
                .Where(x => x.LocationInfo != null && x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && areaId.Contains(x.LocationInfo.AreaId) && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
                .WhereIF(!deviceCode.IsNullOrEmpty(), x => deviceCode.Contains(x.LocationInfo.RoadwayNo))
                .WhereIF(!materielCodes.IsNullOrEmpty(), x => x.StockInfoDetails != null && x.StockInfoDetails.Any(y => materielCodes.Contains(y.MaterielCode)))
                .OrderBy(x => x.OutboundTime) // æŽ’序
                .FirstOrDefault(); // èŽ·å–ç¬¬ä¸€ä¸ªå…ƒç´ 
            if (result != null)
            {
                _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { result.PalletCode });
            }
            else
            {
                ConsoleHelper.WriteErrorLine("QueryStockInfoForRealTrayCWAsync查询常温实盘库存信息失败:未找到符合条件的数据");
            }
            return result;
        }
        catch (Exception ex)
        {
            ConsoleHelper.WriteErrorLine("QueryStockInfoForRealTrayCWAsync查询实盘库存信息失败:" + ex.Message + "\r\n" + ex.StackTrace);
            return null;
        }
        var outBoundMateriel = AppSettings.app<OutBoundMateriel>("OutBoundMateriel");
        List<string> materielCodes = null;
        if (outBoundMateriel.Count != 0)
        {
            materielCodes = outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == areaCodes[0]).Select(x => x.MaterielCode).ToList();
        }
        var devices = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
            .Where(x => x.DeviceStatus == "1")
            .Where(x => x.DeviceCode.Contains("CWSC"))
            .ToList();
        var deviceCode = devices.Select(x => x.DeviceCode).ToList();
        var result = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
            .Includes(x => x.LocationInfo) // é¢„加载LocationInfo
            .Includes(x => x.StockInfoDetails) // é¢„加载StockInfoDetails
            .Where(x => areaCodes.Contains(x.AreaCode) && x.OutboundTime < DateTime.Now && x.IsFull == true) // è¿‡æ»¤æ¡ä»¶
            .WhereIF(!productionLine.IsNullOrEmpty(), x => x.ProductionLine == productionLine)
            .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && areaId.Contains(x.LocationInfo.AreaId) && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
            .WhereIF(!deviceCode.IsNullOrEmpty(), x => deviceCode.Contains(x.LocationInfo.RoadwayNo))
            .WhereIF(!materielCodes.IsNullOrEmpty(), x => x.StockInfoDetails.Any(y => materielCodes.Contains(y.MaterielCode)))
            .OrderBy(x => x.OutboundTime) // æŽ’序
            .FirstAsync(); // èŽ·å–ç¬¬ä¸€ä¸ªå…ƒç´ 
        //var firstOrDefault = result.FirstOrDefault(x => roadways.Contains(x.LocationInfo.RoadwayNo)); // æŸ¥æ‰¾ç¬¬ä¸€ä¸ªåŒ¹é…çš„元素
        //var firstOrDefault = result[0]; // æŸ¥æ‰¾ç¬¬ä¸€ä¸ªåŒ¹é…çš„元素
        //return firstOrDefault;
        return result;
    }
    /// <summary>
@@ -1329,36 +1064,44 @@
    /// </summary>
    private async Task<DtStockInfo> QueryStockInfoForEmptyTrayAsync(string areaCode, string position)
    {
        var area = await _areaInfoRepository.QueryFirstAsync(x => x.AreaCode == areaCode);
        try
        {
            var area = await _areaInfoRepository.QueryFirstAsync(x => x.AreaCode == areaCode);
        ConsoleHelper.WriteColorLine(position + "..." + areaCode, ConsoleColor.Magenta);
        var station = await _stationManagerRepository.QueryFirstAsync(x => x.stationChildCode == position && x.stationType == 17);
            ConsoleHelper.WriteColorLine(position + "..." + areaCode, ConsoleColor.Magenta);
            var station = await _stationManagerRepository.QueryFirstAsync(x => x.stationChildCode == position && x.stationType == 17);
        ConsoleHelper.WriteColorLine(station.Roadway, ConsoleColor.Magenta);
        var stackers = station.Roadway.Split(',').ToList();
            ConsoleHelper.WriteColorLine(station.Roadway, ConsoleColor.Magenta);
            var stackers = station.Roadway.Split(',').ToList();
            var deviceCode = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
                .Where(x => x.DeviceStatus == "1")
                .Where(x => stackers.Contains(x.DeviceCode))
                .ToList().Select(x => x.DeviceCode).ToList();
        var devices = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
            .Where(x => x.DeviceStatus == "1")
            .Where(x => stackers.Contains(x.DeviceCode))
            .ToList();
            IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
            List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
        var deviceCode = devices.Select(x => x.DeviceCode).ToList();
            var result = stockInfoList.Where(x => x.ProductionLine == station.productLine)
                .Where(x => x.AreaCode == areaCode && x.IsFull == false)
                .Where(x => x.StockInfoDetails != null && x.StockInfoDetails.Any(y => y.MaterielCode == "空托盘"))
                .Where(x => x.LocationInfo != null && x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
                .WhereIF(!deviceCode.IsNullOrEmpty(), x => deviceCode.Contains(x.LocationInfo.RoadwayNo))
                .OrderBy(x => x.CreateDate) // æŽ’序
                .FirstOrDefault(); // è½¬æ¢ä¸ºåˆ—表
        var result = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
            .Includes(x => x.LocationInfo) // é¢„加载LocationInfo
            .Includes(x => x.StockInfoDetails) // é¢„加载StockInfoDetails
            .Where(x => x.ProductionLine == station.productLine)
            .Where(x => x.AreaCode == areaCode && x.IsFull == false)
            .Where(x => x.StockInfoDetails.Any(y => y.MaterielCode == "空托盘"))
            .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
            .WhereIF(!deviceCode.IsNullOrEmpty(), x => deviceCode.Contains(x.LocationInfo.RoadwayNo))
            .OrderBy(x => x.CreateDate) // æŽ’序
            .FirstAsync(); // è½¬æ¢ä¸ºåˆ—表
            if (result != null)
                _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { result.PalletCode });
            else
                ConsoleHelper.WriteErrorLine("QueryStockInfoForEmptyTrayAsync查询空盘库存信息失败:未找到符合条件的数据");
        //var firstOrDefault = result[0]; // æŸ¥æ‰¾ç¬¬ä¸€ä¸ªåŒ¹é…çš„元素
        //return firstOrDefault;
        return result;
            return result;
        }
        catch (Exception ex)
        {
            ConsoleHelper.WriteErrorLine("QueryStockInfoForEmptyTrayAsync查询实盘库存信息失败:" + ex.Message + "\r\n" + ex.StackTrace);
            return null;
        }
    }
    /// <summary>
@@ -1684,7 +1427,7 @@
        //    content.Error(ex.Message);
        //}
        //return content;
        #endregion
        #endregion é™ç½®å¼‚常口入库
        WebResponseContent content = new WebResponseContent();
        try
        {
@@ -1754,7 +1497,7 @@
                        TaskState = (int)TaskInStatusEnum.Line_InFinish,
                        TaskType = (int)TaskInboundTypeEnum.Inbound,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "Systeam",
                        Creater = "System",
                        ProductionLine = result.ProductionLine,
                        ProcessCode = result.ProcessCode,
                    };
@@ -1792,7 +1535,7 @@
                        TaskState = (int)TaskInStatusEnum.Line_InFinish,
                        TaskType = (int)TaskInboundTypeEnum.InTray,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "Systeam",
                        Creater = "System",
                        ProductionLine = result.ProductionLine,
                        ProcessCode = result.ProcessCode,
                    };
@@ -1825,7 +1568,6 @@
        }
        return content;
    }
    private WMSTaskDTO CreateWMSTaskDTO(object source)
    {
@@ -1867,11 +1609,9 @@
        }
    }
    #endregion é™ç½®å¼‚常口入库
    #endregion å¤–部接口方法
    #endregion å¤–部接口方法
    #region å†…部调用方法
@@ -2063,7 +1803,7 @@
        var taskHty = _mapper.Map<Dt_Task_Hty>(task);
        taskHty.FinishTime = DateTime.Now;
        taskHty.TaskId = 0;
        taskHty.OperateType = isHand ? (int)OperateTypeEnum.人工删除 : (int)OperateTypeEnum.自动完成;
        taskHty.OperateType = isHand ? (int)OperateTypeEnum.人工删除 : App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成;
        taskHty.SourceId = task.TaskId;
        if (isHand)
        {
@@ -2125,33 +1865,34 @@
                }
            }
            if (stock.IsFull)
            {
                // æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„库存信息
                var stocks = _stockInfoRepository.QueryData(x => x.AreaCode == stock.AreaCode && x.ProductionLine == stock.ProductionLine && x.SpecialParameterDuration != stock.SpecialParameterDuration);
            #region æ›´æ–°åº“存信息(暂时不需要)
            //if (stock.IsFull)
            //{
            //    // æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„库存信息
            //    var stocks = _stockInfoRepository.QueryData(x => x.AreaCode == stock.AreaCode && x.ProductionLine == stock.ProductionLine && x.SpecialParameterDuration != stock.SpecialParameterDuration);
                // æŸ¥è¯¢ä»»åŠ¡ä¿¡æ¯
                var tasks = BaseDal.QueryData(x => x.PalletCode != stock.PalletCode && x.ProductionLine == stock.ProductionLine).Select(x => x.PalletCode).ToList();
            //    // æŸ¥è¯¢ä»»åŠ¡ä¿¡æ¯
            //    var tasks = BaseDal.QueryData(x => x.PalletCode != stock.PalletCode && x.ProductionLine == stock.ProductionLine).Select(x => x.PalletCode).ToList();
                if (stocks != null && stocks.Count > 0)
                {
                    // è¿‡æ»¤å‡ºéœ€è¦æ›´æ–°çš„库存信息
                    var stocksToUpdate = stocks.Where(item => !tasks.Contains(item.PalletCode)).ToList();
                    foreach (var item in stocksToUpdate)
                    {
                        // æ›´æ–°åº“存信息的特定参数
                        item.SpecialParameterDuration = stock.SpecialParameterDuration;
                        item.ParameterInfos = stock.ParameterInfos;
                        item.OutboundTime = Convert.ToDateTime(item.LinedProcessFeedbackTime == null ? item.CreateDate : item.LinedProcessFeedbackTime).AddHours(Convert.ToDouble(stock.SpecialParameterDuration));
                    }
                    if (stocksToUpdate.Count > 0)
                    {
                        // å¼‚步更新库存信息
                        var isUpdates = await _stockInfoRepository.UpdateDataAsync(stocksToUpdate);
                    }
                }
            }
            //    if (stocks != null && stocks.Count > 0)
            //    {
            //        // è¿‡æ»¤å‡ºéœ€è¦æ›´æ–°çš„库存信息
            //        var stocksToUpdate = stocks.Where(item => !tasks.Contains(item.PalletCode)).ToList();
            //        foreach (var item in stocksToUpdate)
            //        {
            //            // æ›´æ–°åº“存信息的特定参数
            //            item.SpecialParameterDuration = stock.SpecialParameterDuration;
            //            item.ParameterInfos = stock.ParameterInfos;
            //            item.OutboundTime = Convert.ToDateTime(item.LinedProcessFeedbackTime == null ? item.CreateDate : item.LinedProcessFeedbackTime).AddHours(Convert.ToDouble(stock.SpecialParameterDuration));
            //        }
            //        if (stocksToUpdate.Count > 0)
            //        {
            //            // å¼‚步更新库存信息
            //            var isUpdates = await _stockInfoRepository.UpdateDataAsync(stocksToUpdate);
            //        }
            //    }
            //}
            #endregion
            // æ·»åŠ åŽ†å²ä»»åŠ¡
            var isTaskHtyAdd = await _task_HtyRepository.AddDataAsync(taskHty) > 0;
@@ -2185,7 +1926,6 @@
    }
    #region ä»»åŠ¡è¯·æ±‚æ–¹æ³•
    private static readonly SemaphoreSlim _semaphoreUpdate = new SemaphoreSlim(1, 1);
    // æ›´æ–°ä»»åŠ¡è´§ä½
@@ -2273,7 +2013,6 @@
        }
        catch (Exception)
        {
            throw;
        }
        finally { _semaphoreUpdate.Release(); }
@@ -2344,7 +2083,7 @@
            TaskState = flag == 3 ? (int)TaskOutStatusEnum.OutNew : (int)TaskInStatusEnum.InNew,
            TaskType = flag == 0 ? (int)TaskInboundTypeEnum.Inbound : flag == 1 ? (int)TaskInboundTypeEnum.InTray : flag == 2 ? (int)TaskInboundTypeEnum.InNG : (int)TaskOutboundTypeEnum.Outbound,
            TaskNum = await BaseDal.GetTaskNo(),
            Creater = "Systeam",
            Creater = "System",
            ProductionLine = productionLine,
            ProcessCode = processCode
        };
@@ -2387,8 +2126,8 @@
        return content;
    }
    private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
    /// <summary>
    /// æŸ¥æ‰¾è´§ä½
    /// </summary>
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Partial/Dt_TaskService.cs
@@ -1,7 +1,6 @@
using Masuit.Tools;
using SqlSugar;
using WIDESEA_Common.CustomModels;
//using WIDESEA_Common.CustomModels;
using WIDESEA_Core.Const;
using WIDESEA_DTO.MOM;
using WIDESEA_DTO.WMS;
@@ -199,7 +198,7 @@
                    TaskState = (int)TaskInStatusEnum.Line_InFinish,
                    TaskType = (int)TaskOutboundTypeEnum.InToOut,
                    TaskNum = await BaseDal.GetTaskNo(),
                    Creater = "Systeam",
                    Creater = "System",
                    ProductionLine = result.ProductionLine,
                    ProcessCode = result.ProcessCode,
                };
@@ -226,7 +225,7 @@
                        TaskState = (int)TaskInStatusEnum.Line_InFinish,
                        TaskType = (int)TaskOutboundTypeEnum.InToOut,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "Systeam"
                        Creater = "System"
                    };
                    return taskNG;
                }
@@ -258,7 +257,7 @@
                        TaskState = (int)TaskInStatusEnum.Line_InFinish,
                        TaskType = (int)TaskOutboundTypeEnum.InToOut,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "Systeam",
                        Creater = "System",
                        ProductionLine = result.ProductionLine,
                        ProcessCode = result.ProcessCode,
                    };
@@ -292,7 +291,7 @@
                TaskState = (int)TaskInStatusEnum.Line_InFinish,
                TaskType = (int)TaskOutboundTypeEnum.InToOut,
                TaskNum = await BaseDal.GetTaskNo(),
                Creater = "Systeam",
                Creater = "System",
                ProductionLine = result.ProductionLine,
                ProcessCode = result.ProcessCode,
            };
@@ -370,7 +369,7 @@
                    TaskState = (int)TaskInStatusEnum.Line_InFinish,
                    TaskType = (int)TaskOutboundTypeEnum.InToOut,
                    TaskNum = await BaseDal.GetTaskNo(),
                    Creater = "Systeam",
                    Creater = "System",
                    ProductionLine = result.ProductionLine,
                    ProcessCode = result.ProcessCode,
                };
@@ -420,7 +419,7 @@
            TaskState = (int)TaskInStatusEnum.Line_InFinish,
            TaskType = stationManager.stationType == 1 ? (int)TaskInboundTypeEnum.Inbound : (int)TaskInboundTypeEnum.InTray,
            TaskNum = await BaseDal.GetTaskNo(),
            Creater = "Systeam",
            Creater = "System",
            ProductionLine = result.ProductionLine,
            ProcessCode = result.ProcessCode,
        };
@@ -541,12 +540,14 @@
        {
            if (stationManager.stationType != 7) throw new Exception("错误的调取");
            var stockinfo = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
                .Includes(x => x.LocationInfo)
                //.Includes(x=>x.StockInfoDetails)
                .Where(x => !x.IsFull && x.LocationInfo.RoadwayNo == stationManager.Roadway)
                .OrderBy(x => x.CreateDate)
                .FirstAsync();
            // ä»Žç¼“存中获取库存信息
            IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
            List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
            var stockinfo1 = stockInfoList.OrderBy(x => x.CreateDate)
                .ToList();
            var stockinfo = stockinfo1.Where(x => x.LocationInfo != null && !x.IsFull && x.LocationInfo.RoadwayNo == stationManager.Roadway)
                .FirstOrDefault();
            if (stockinfo == null) return null;
@@ -565,10 +566,10 @@
                TaskState = (int)TaskOutStatusEnum.OutNew,
                TaskType = (int)TaskOutboundTypeEnum.OutTray,
                TaskNum = await BaseDal.GetTaskNo(),
                Creater = "Systeam",
                Creater = "System",
                ProductionLine = stockinfo.ProductionLine,
            };
            _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { task.PalletCode });
            return task;
        }
        catch (Exception ex)
@@ -660,7 +661,7 @@
                    TaskState = (int)TaskInStatusEnum.Line_InFinish,
                    TaskType = (int)TaskInboundTypeEnum.InTray,
                    TaskNum = await BaseDal.GetTaskNo(),
                    Creater = "Systeam",
                    Creater = "System",
                    ProductionLine = result.ProductionLine,
                    ProcessCode = result.ProcessCode,
                };
@@ -722,7 +723,7 @@
                TaskState = (int)TaskInStatusEnum.Line_InFinish,
                TaskType = (int)TaskInboundTypeEnum.Inbound,
                TaskNum = await BaseDal.GetTaskNo(),
                Creater = "Systeam",
                Creater = "System",
                ProductionLine = result.ProductionLine,
                ProcessCode = result.ProcessCode,
            };
@@ -885,11 +886,34 @@
    #region å¸¸æ¸©è¡¥ç©ºæ‰˜ç›˜è‡³åˆ†å®¹
    private static readonly Dictionary<string, (int Count, DateTime LastRequestTime)> requestTrackerToCW = new();
    public async Task<WebResponseContent> GetFROutTrayToCW(RequestTaskDto taskDTO)
    {
        WebResponseContent content = new WebResponseContent();
        try
        {
            //string requestKey = JsonConvert.SerializeObject(taskDTO);
            //// æ£€æŸ¥è¯·æ±‚次数和时间限制
            //if (requestTrackerToCW.TryGetValue(requestKey, out var requestInfo))
            //{
            //    if (requestInfo.Count > 5 && DateTime.Now < requestInfo.LastRequestTime.AddMinutes(2))
            //    {
            //        // å¦‚果请求次数超过限制且未超过10分钟,抛出异常
            //        throw new InvalidOperationException("请求次数已达到限制,请稍后再试。");
            //    }
            //}
            //// æ›´æ–°è¯·æ±‚跟踪信息
            //if (requestTrackerToCW.ContainsKey(requestKey))
            //{
            //    requestTrackerToCW[requestKey] = (requestInfo.Count + 1, DateTime.Now);
            //}
            //else
            //{
            //    requestTrackerToCW[requestKey] = (1, DateTime.Now);
            //}
            var station = _stationManagerRepository.QueryFirst(x => x.stationChildCode == taskDTO.Position && x.stationStatus == "1");
            var locations = _locationRepository.QueryData(x => x.RoadwayNo == station.Roadway && x.LocationStatus == (int)LocationEnum.Free && x.LocationType == 1);
@@ -922,6 +946,8 @@
                    _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticDelivery, task.TaskNum);
                    // è¿”回成功响应
                    //requestTrackerToCW.Remove(requestKey);
                    return content.OK(data: wmsTask);
                }
                else
@@ -948,26 +974,30 @@
        ConsoleHelper.WriteColorLine(station.Roadway, ConsoleColor.Magenta);
        var stackers = station.Roadway.Split(',').ToList();
        var devices = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
        var deviceCode = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
            .Where(x => x.DeviceStatus == "1")
            .Where(x => stackers.Contains(x.DeviceCode))
            .ToList();
            .ToList().Select(x => x.DeviceCode).ToList();
        var deviceCode = devices.Select(x => x.DeviceCode).ToList();
        // ä»Žç¼“存中获取库存信息
        IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
        List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
        var result = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
            .Includes(x => x.LocationInfo) // é¢„加载LocationInfo
            .Includes(x => x.StockInfoDetails) // é¢„加载StockInfoDetails
            .Where(x => x.ProductionLine == productLine)
        var result1 = stockInfoList.Where(x => x.ProductionLine == productLine)
            .Where(x => x.AreaCode == areaCode && x.IsFull == false)
            .Where(x => x.StockInfoDetails.Any(y => y.MaterielCode == "空托盘"))
            .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
            .WhereIF(!deviceCode.IsNullOrEmpty(), x => deviceCode.Contains(x.LocationInfo.RoadwayNo))
            .WhereIF(!deviceCode.IsNullOrEmpty(), x => x.LocationInfo != null && deviceCode.Contains(x.LocationInfo.RoadwayNo))
            .OrderBy(x => x.CreateDate) // æŽ’序
            .FirstAsync(); // è½¬æ¢ä¸ºåˆ—表
            .ToList(); // è½¬æ¢ä¸ºåˆ—表
        //var firstOrDefault = result[0]; // æŸ¥æ‰¾ç¬¬ä¸€ä¸ªåŒ¹é…çš„元素
        //return firstOrDefault;
        var result = result1.Where(x => x.StockInfoDetails != null && x.StockInfoDetails.Any(y => y.MaterielCode == "空托盘"))
            .Where(x => x.LocationInfo != null && x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) // è¿‡æ»¤æ¡ä»¶
            .FirstOrDefault(); // èŽ·å–ç¬¬ä¸€ä¸ªå…ƒç´ 
        if (result != null)
            _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { result.PalletCode });
        else
            ConsoleHelper.WriteColorLine($"常温{productLine}空托盘库存不足", ConsoleColor.Red);
        return result;
    }
@@ -988,48 +1018,32 @@
        WebResponseContent content = new WebResponseContent();
        try
        {
            //string requestKey = JsonConvert.SerializeObject(json);
            //// æ£€æŸ¥è¯·æ±‚次数和时间限制
            //if (requestTracker.TryGetValue(requestKey, out var requestInfo))
            //{
            //    if (requestInfo.Count >= 9 && DateTime.Now < requestInfo.LastRequestTime.AddMinutes(5))
            //    {
            //        // å¦‚果请求次数超过限制且未超过10分钟,抛出异常
            //        throw new InvalidOperationException("请求次数已达到限制,请稍后再试。");
            //    }
            //}
            //// æ›´æ–°è¯·æ±‚跟踪信息
            //if (requestTracker.ContainsKey(requestKey))
            //{
            //    requestTracker[requestKey] = (requestInfo.Count + 1, DateTime.Now);
            //}
            //else
            //{
            //    requestTracker[requestKey] = (1, DateTime.Now);
            //}
            //LogFactory.GetLog("常温3出库至包装").Info(true, $"常温3出库至包装传入参数:" + JsonConvert.SerializeObject(json, Formatting.Indented));
            Dt_StationManager station = _stationManagerRepository.QueryFirst(x => x.stationChildCode == json.Position && x.stationType == 12 && x.stationArea == "Call");
            if (station == null) { throw new Exception($"未找到包装站台信息,请检查传入参数{json.Position}"); }
            var devices = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
            var deviceCode = SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
                .Where(x => x.DeviceStatus == "1")
                .Where(x => x.DeviceCode.Contains("CWSC")) // è¿‡æ»¤æ¡ä»¶
                .ToList().Select(x => x.DeviceCode).ToList();
            // ä»Žç¼“存中获取库存信息
            IDictionary<string, DtStockInfo>? stockInfos = _simpleCacheService.HashGetAll<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo);
            List<DtStockInfo> stockInfoList = stockInfos.Values.ToList();
            // ä¿®æ”¹åŽçš„æŸ¥è¯¢ä»£ç 
            var stockInfo1 = stockInfoList
                .Where(x => x.ProductionLine == station.productLine)
                .Where(x => x.AreaCode == "CWSC3" && x.IsFull == true)
                .OrderBy(x => x.OutboundTime)
                .ToList();
            var deviceCode = devices.Select(x => x.DeviceCode).ToList();
            //LogFactory.GetLog("常温3出库至包装").Info(true, $"常温3出库至包装传入参数:" + JsonConvert.SerializeObject(json, Formatting.Indented));
            var stockInfo = _stockInfoRepository.Db.Queryable<DtStockInfo>()
                    .Where(x => x.ProductionLine == station.productLine)
                    .Includes(x => x.LocationInfo) // é¢„加载LocationInfo
                    .Where(x => x.AreaCode == "CWSC3" && x.IsFull == true) // è¿‡æ»¤æ¡ä»¶
                    .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock) // è¿‡æ»¤æ¡ä»¶
                    .WhereIF(!deviceCode.IsNullOrEmpty(), x => deviceCode.Contains(x.LocationInfo.RoadwayNo))
                    .OrderBy(x => x.OutboundTime) // æŽ’序
                    .First(); // èŽ·å–ç¬¬ä¸€ä¸ªå…ƒç´ 
            var stockInfo = stockInfo1
                // å¢žåР坹 LocationInfo çš„空值检查
                .Where(x => x.LocationInfo != null && x.LocationInfo.LocationStatus == (int)LocationEnum.InStock)
                // å¢žåР坹 LocationInfo çš„空值检查
                .WhereIF(!deviceCode.IsNullOrEmpty(), x => x.LocationInfo != null && deviceCode.Contains(x.LocationInfo.RoadwayNo))
                .FirstOrDefault();
            //DtStockInfo stockInfo = _stockInfoRepository.QueryFirst(X => X.IsFull && X.AreaCode == "CWSC3" && X.ProductionLine == station.productLine);
            if (stockInfo == null) throw new Exception($"库内{station.productLine}无满足条件的库存可出库");
            DtLocationInfo locationInfo = _locationRepository.QueryFirst(x => x.AreaId == 5 && x.LocationCode == stockInfo.LocationCode);
@@ -1052,7 +1066,7 @@
                TaskState = (int)TaskOutStatusEnum.OutNew,
                TaskType = (int)TaskOutboundTypeEnum.Outbound,
                TaskNum = await BaseDal.GetTaskNo(),
                Creater = "Systeam",
                Creater = "System",
                ProductionLine = stockInfo.ProductionLine,
                ProcessCode = stockInfo.ProcessCode,
            };
@@ -1065,6 +1079,8 @@
            stockInfo.LocationInfo.LocationStatus = (int)LocationEnum.InStockDisable;
            _locationRepository.UpdateData(stockInfo.LocationInfo);
            _simpleCacheService.HashDel<DtStockInfo>(WIDESEA_Cache.CacheConst.Cache_DtStockInfo, new string[] { taskDTO.PalletCode });
            _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(stockInfo.LocationInfo, lastStatus, (int)StatusChangeTypeEnum.AutomaticDelivery, task.TaskNum);
            return content.OK(data: taskDTO);
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/WIDESEA_StorageTaskServices.csproj
@@ -16,6 +16,7 @@
  <ItemGroup>
    <ProjectReference Include="..\LogLibrary\LogLibrary.csproj" />
    <ProjectReference Include="..\WIDESEA_Cache\WIDESEA_Cache.csproj" />
    <ProjectReference Include="..\WIDESEA_IBusinessServices\WIDESEA_IBusinessServices.csproj" />
    <ProjectReference Include="..\WIDESEA_IStorageBasicService\WIDESEA_IStorageBasicServices.csproj" />
    <ProjectReference Include="..\WIDESEA_IStorageOutOrderService\WIDESEA_IStorageOutOrderServices.csproj" />
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer.sln
@@ -78,6 +78,8 @@
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WIDESEA_IStoragIntegrationServices", "WIDESEA_IStoragIntegrationServices\WIDESEA_IStoragIntegrationServices.csproj", "{94D572FA-810E-4897-B673-AF988FD4019E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WIDESEA_Cache", "WIDESEA_Cache\WIDESEA_Cache.csproj", "{461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
@@ -436,6 +438,18 @@
        {94D572FA-810E-4897-B673-AF988FD4019E}.Release|Any CPU.Build.0 = Release|Any CPU
        {94D572FA-810E-4897-B673-AF988FD4019E}.Release|x86.ActiveCfg = Release|Any CPU
        {94D572FA-810E-4897-B673-AF988FD4019E}.Release|x86.Build.0 = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Debug|x86.ActiveCfg = Debug|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Debug|x86.Build.0 = Debug|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Dev|Any CPU.ActiveCfg = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Dev|Any CPU.Build.0 = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Dev|x86.ActiveCfg = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Dev|x86.Build.0 = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Release|Any CPU.Build.0 = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Release|x86.ActiveCfg = Release|Any CPU
        {461A73BF-9FC7-4BFE-9BEB-2AE686CBFEEC}.Release|x86.Build.0 = Release|Any CPU
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs
@@ -1,5 +1,4 @@
using WIDESEA_DTO;
using static WIDESEA_DTO.RequestTaskDto;
namespace WIDESEA_WMSServer.Controllers;
@@ -29,21 +28,11 @@
    /// <param name="saveModel">任务号</param>
    /// <returns>成功或失败</returns>
    [HttpGet, Route("CompleteTaskAsync"), AllowAnonymous]
    //[TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> CompleteTaskAsync(int taskNum)
    {
        return await _taskService.CompleteAsync(taskNum);
    }
    /// <summary>
    /// ä»»åŠ¡å®Œæˆ
    /// </summary>
    /// <param name="saveModel">任务号</param>
    /// <returns>成功或失败</returns>
    //[HttpGet, Route("CompleteTaskByStation"), AllowAnonymous]
    //public async Task<WebResponseContent> CompleteTaskByStation(int taskNum)
    //{
    //    return await _taskService.CompleteTaskByStation(taskNum);
    //}
    /// <summary>
    /// æ£€æŸ¥æ˜¯å¦éœ€è¦è¿›è¡Œç§»åº“
@@ -51,6 +40,7 @@
    /// <param name="taskNum">任务号</param>
    /// <returns>任务</returns>
    [HttpGet, Route("TransferCheckAsync"), AllowAnonymous]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> TransferCheckAsync(int taskNum)
    {
        return new WebResponseContent().OK(data: await _locationService.TransferCheckAsync(taskNum));
@@ -62,6 +52,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestTaskAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> RequestTaskAsync([FromBody] RequestTaskDto input)
    {
        return await Service.RequestTaskAsync(input);
@@ -73,6 +64,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestInTask")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> RequestInTask([FromBody] RequestTaskDto input)
    {
        return await Service.RequestInTask(input);
@@ -84,6 +76,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestLocationTaskAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> UpdateExistingTask([FromBody] RequestTaskDto input)
    {
        return await Service.UpdateExistingTask(input);
@@ -95,17 +88,19 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestTrayInTaskAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> RequestTrayInTaskAsync([FromBody] RequestTaskDto input)
    {
        return await Service.RequestTrayInTaskAsync(input);
    }
    /// <summary>
    /// ç©ºæ‰˜ç›˜&满盘出库请求
    /// ç©ºæ‰˜ç›˜æ»¡ç›˜å‡ºåº“请求
    /// </summary>
    /// <param name="request">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestTrayOutTaskAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> RequestTrayOutTaskAsync([FromBody] RequestOutTaskDto request)
    {
        return await Service.RequestTrayOutTaskAsync(request.Position, request.Tag, request.AreaCdoe, request.AreaCdoes, request.ProductionLine);
@@ -117,6 +112,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("UpdateTaskStatus")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> UpdateTaskStatus([FromBody] UpdateStatusDto input)
    {
        return await Service.UpdateTaskStatus(input.TaskNum, input.TaskState);
@@ -128,6 +124,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpGet, AllowAnonymous, Route("StockCheckingAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public WebResponseContent StockCheckingAsync()
    {
        return Service.StockCheckingAsync();
@@ -140,6 +137,7 @@
    /// <param name="palletCode">托盘号</param>
    /// <returns></returns>
    [HttpGet, AllowAnonymous, Route("CreateAndSendOutboundTask")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> CreateAndSendOutboundTask(string locationCode, string palletCode)
    {
        return await Service.CreateAndSendOutboundTask(locationCode, palletCode);
@@ -152,6 +150,7 @@
    /// <param name="palletCode">托盘号</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestInBoundTaskNG")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> RequestInBoundTaskNG([FromBody] RequestTaskDto input)
    {
        return await Service.CreateAndSendInboundTask(input.PalletCode, input.Position);
@@ -163,6 +162,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("GetFROutTrayToCW")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 15 })] // 5秒节流
    public async Task<WebResponseContent> GetFROutTrayToCW([FromBody] RequestTaskDto input)
    {
        return await Service.GetFROutTrayToCW(input);
@@ -174,11 +174,11 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("EmergencyTask")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public WebResponseContent EmergencyTask([FromBody] object input)
    {
        return Service.EmergencyTask(input);
    }
    /// <summary>
    /// CW3 å‡ºåº“至包装
@@ -186,6 +186,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("RequestOutTaskToBZAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> RequestOutTaskToBZAsync([FromBody] RequestTaskDto input)
    {
        return await Service.RequestOutTaskToBZAsync(input);
@@ -197,6 +198,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("SetEmptyOutbyInToOutAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> SetEmptyOutbyInToOutAsync([FromBody] RequestTaskDto input)
    {
        return await Service.SetEmptyOutbyInToOutAsync(input);
@@ -208,6 +210,7 @@
    /// <param name="input">请求数据</param>
    /// <returns></returns>
    [HttpPost, AllowAnonymous, Route("SetEmptyOutbyInToOutOneAsync")]
    [TypeFilter(typeof(ThrottleFilter), Arguments = new object[] { 5 })] // 5秒节流
    public async Task<WebResponseContent> SetEmptyOutbyInToOutOneAsync([FromBody] RequestTaskDto input)
    {
        return await Service.SetEmptyOutbyInToOutOneAsync(input);
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Filter/CheckingStockOutMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@

using WIDESEA_Core.Middlewares;
using WIDESEA_IStorageTaskServices;
using WIDESEA_StorageOutTaskServices;
namespace WIDESEA_WMSServer.Filter
{
    public static class StockOutMiddleware
    {
        public static Task InvokeAsync()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    var _taskService = WIDESEA_Core.App.GetService<IDt_TaskService>();
                    if (_taskService != null)
                    {
                        _taskService.StockCheckingAsync();
                    }
                    Thread.Sleep(10000);
                }
            });
            return Task.CompletedTask;
        }
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Filter/ThrottleFilter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System.Collections.Concurrent;
using System.Text.Json;
public class ThrottleFilter : IAsyncActionFilter
{
    private static readonly ConcurrentDictionary<string, DateTime> _lastExecutionTimes = new ConcurrentDictionary<string, DateTime>();
    private readonly int _intervalInSeconds;
    public ThrottleFilter(int intervalInSeconds)
    {
        _intervalInSeconds = intervalInSeconds;
    }
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var actionName = context.ActionDescriptor.DisplayName;
        var parameterString = GenerateParameterString(context.ActionArguments);
        var key = $"{actionName}_{parameterString}";
        if (_lastExecutionTimes.TryGetValue(key, out var lastExecutionTime))
        {
            var elapsedTime = DateTime.Now - lastExecutionTime;
            if (elapsedTime.TotalSeconds < _intervalInSeconds)
            {
                context.Result = new OkObjectResult(new WebResponseContent().Error("请求过于频繁,请稍后再试"));
                return;
            }
        }
        _lastExecutionTimes[key] = DateTime.Now;
        await next();
    }
    private string GenerateParameterString(IDictionary<string, object> arguments)
    {
        if (arguments == null || arguments.Count == 0)
        {
            return "";
        }
        var paramStrings = new List<string>();
        foreach (var argument in arguments)
        {
            var key = argument.Key;
            var value = argument.Value;
            string valueString;
            if (value == null)
            {
                valueString = "null";
            }
            else if (IsSimpleType(value.GetType()))
            {
                valueString = value.ToString();
            }
            else
            {
                valueString = JsonSerializer.Serialize(value);
            }
            paramStrings.Add($"{key}={valueString}");
        }
        return string.Join("&", paramStrings);
    }
    // åˆ¤æ–­ç±»åž‹æ˜¯å¦ä¸ºç®€å•类型
    private bool IsSimpleType(Type type)
    {
        return type.IsPrimitive || type == typeof(string) || type == typeof(decimal);
    }
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Program.cs
@@ -20,6 +20,13 @@
using Swashbuckle.AspNetCore.SwaggerGen;
using Microsoft.OpenApi.Models;
using WIDESEA_StorageTaskServices;
using Autofac.Core;
using WIDESEA_Cache;
using SimpleRedis;
using WIDESEA_DTO.WMS;
using static NewLife.Remoting.ApiHttpClient;
using NewLife.Windows;
using WIDESEA_Core.Enums;
var builder = WebApplication.CreateBuilder(args);
@@ -112,8 +119,41 @@
builder.Services.AddHostedService<MyBackgroundService>();
//缓存设置配置转实体
builder.Services.AddConfigurableOptions<CacheSettingsOptions>();
//禁止在主机启动时通过 App.GetOptions<TOptions> èŽ·å–é€‰é¡¹ï¼Œå¦‚éœ€èŽ·å–é…ç½®é€‰é¡¹ç†åº”é€šè¿‡ App.GetConfig<TOptions>("配置节点", true)。
var cacheSettings = AppSettings.Configuration.GetSection("CacheSettings").Get<CacheSettingsOptions>();
//如果有redis连接字符串
if (cacheSettings.UseRedis)
{
    var connectionString =
        $"server={cacheSettings.RedisSettings.Address};db={cacheSettings.RedisSettings.Db}";
    //注入redis
    builder.Services.AddSimpleRedis(connectionString);
    builder.Services.AddScoped<ISimpleCacheService, RedisCacheService>();
}
else
{
    builder.Services.AddScoped<ISimpleCacheService, MemoryCacheService>();
}
var app = builder.Build();
// éªŒè¯ Redis æœåŠ¡æ˜¯å¦æˆåŠŸæ³¨å†Œ
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    var redisService = services.GetService<ISimpleCacheService>();
    if (redisService == null)
    {
        WIDESEA_Core.Helper.ConsoleHelper.WriteErrorLine("Redis æœåŠ¡æœªæˆåŠŸæ³¨å†Œ");
    }
    else
    {
        WIDESEA_Core.Helper.ConsoleHelper.WriteSuccessLine("Redis æœåŠ¡å·²æˆåŠŸæ³¨å†Œ");
    }
}
// 3、配置中间件
app.UseMiniProfiler();//性能分析器
@@ -151,5 +191,26 @@
app.MapControllers();
//通过 App.GetOptions<TOptions> èŽ·å–é€‰é¡¹
var cacheSettingsb = App.GetOptions<CacheSettingsOptions>();
//如果需要清除缓存
if (cacheSettingsb.UseRedis && cacheSettingsb.RedisSettings.ClearRedis)
{
    var redis = app.Services.CreateScope().ServiceProvider.GetService<ISimpleCacheService>(); //获取redis服务
    // åˆ é™¤redis的key
    redis.DelByPattern(CacheConst.Cache_Prefix);
    WIDESEA_Core.Helper.ConsoleHelper.WriteInfoLine("正在缓存库存信息");
    var stockInfoList = await SqlSugarHelper.DbWMS.Queryable<DtStockInfo>()
        .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock).IncludesAllFirstLayer().ToListAsync();
    // ç¼“存库存信息
    foreach (var item in stockInfoList)
    {
        item.StockInfoDetails = new List<DtStockInfoDetail>() { { item.StockInfoDetails[0] } };
        redis.HashAdd(CacheConst.Cache_DtStockInfo, item.PalletCode, item);
    }
    WIDESEA_Core.Helper.ConsoleHelper.WriteInfoLine("缓存库存信息完成");
}
app.Run();
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/WIDESEA_WMSServer.csproj
@@ -20,6 +20,7 @@
  </ItemGroup>
    <ItemGroup>
        <None Include="Controllers\Basic\MOMErrorMessageController.cs" />
        <None Include="wwwroot\WIDESEA_DB.DBSeed.Json\Sys_Tenant.tsv" />
        <None Include="wwwroot\WIDESEA_DB.DBSeed.Json\Sys_User.tsv" />
    </ItemGroup>
@@ -34,6 +35,7 @@
    
    <ItemGroup>
      <ProjectReference Include="..\WIDESEA_BusinessServices\WIDESEA_BusinessServices.csproj" />
      <ProjectReference Include="..\WIDESEA_Cache\WIDESEA_Cache.csproj" />
      <ProjectReference Include="..\WIDESEA_Services\WIDESEA_Services.csproj" />
      <ProjectReference Include="..\WIDESEA_IServices\WIDESEA_IServices.csproj" />
      <ProjectReference Include="..\WIDESEA_StorageBasicServices\WIDESEA_StorageBasicServices.csproj" />
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
@@ -11,11 +11,11 @@
  //连接字符串
  //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
  //"ConnectionString": "Data Source=192.168.5.251;Initial Catalog=WIDESEA_WMSDB_BBMain;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionString": "Data Source=127.0.0.1;Initial Catalog=WIDESEA_WMS2F08;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionString": "Data Source=127.0.0.1;Initial Catalog=WIDESEA_WMS2F08;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionString": "Data Source=.\\LIULEI;Initial Catalog=WIDESEA_WMSDB_BBMain;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionString": "Data Source=192.168.20.251;Initial Catalog=WIDESEA_WMSDB;User ID=sa;Password=123456@gy;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionString": "Data Source=192.168.20.251;Initial Catalog=WIDESEA_WMSDB;User ID=sa;Password=123456@gy;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionStringWCS": "Data Source=192.168.5.251;Initial Catalog=WIDESEAWCS_TEST;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionStringWCS": "Data Source=127.0.0.1;Initial Catalog=WIDESEA_WCSDB;User ID=sa;Password=sa123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionStringWCS": "Data Source=127.0.0.1;Initial Catalog=WIDESEA_WCS2F09;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //跨域
  "Cors": {
    "PolicyName": "CorsIpAccess", //策略名称
@@ -24,6 +24,18 @@
    // æ³¨æ„ï¼Œhttp://127.0.0.1:1818 å’Œ http://localhost:1818 æ˜¯ä¸ä¸€æ ·çš„
    "IPs": "http://127.0.0.1:8080,http://localhost:8080,http://127.0.0.1:8081,http://localhost:8081"
  },
  //缓存设置
  "CacheSettings": {
    "UseRedis": true, //启用redis
    "RedisSettings": {
      "Address": "127.0.0.1:6379", //地址
      "Password": "123456", //Redis服务密码
      "Db": 9, //默认库
      "ClearRedis": true //是否每次启动都清除Redis缓存
    }
  },
  "ApiName": "WIDESEA",
  "ExpMinutes": 120,
@@ -32,10 +44,10 @@
  // å…è®¸å‡ºåº“的编码
  "OutBoundMateriel": [
    {
      "MaterielCode": "CC01050001348",
      "ProductionLine": "ZJ-8",
      "ProcessCode": "CH001"
    }
    //{
    //  "MaterielCode": "CC01050001348",
    //  "ProductionLine": "ZJ-8",
    //  "ProcessCode": "CH001"
    //}
  ]
}
Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/obj/Debug/net6.0/WIDESEA_WMSServer.MvcApplicationPartsAssemblyInfo.cs
@@ -17,6 +17,7 @@
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("Swashbuckle.AspNetCore.SwaggerGen")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("WIDESEA_BusinessesRepository")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("WIDESEA_BusinessServices")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("WIDESEA_Cache")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("WIDESEA_Core")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("WIDESEA_DTO")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("WIDESEA_IBusinessesRepository")]