leiqunqing
2026-01-19 ba8aa925e7901381ceb394adb53eca8723d1c4c5
完善工位界面
已添加17个文件
已重命名2个文件
已删除15个文件
已修改44个文件
3605 ■■■■ 文件已修改
.vs/VSWorkspaceState.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vs/slnx.sqlite 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/api/http.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/components/basic/VolForm.vue 395 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/components/basic/VolTable.vue 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/extension/basicinfo/boxing.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/extension/basicinfo/boxingDetail.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/extension/basicinfo/formula.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/extension/basicinfo/processInfoDetail.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/router/viewGird.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/views/Home.vue 1084 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/views/basicinfo/boxing.vue 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/views/basicinfo/formula.vue 236 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/views/basicinfo/formulaDetail.vue 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/views/basicinfo/processInfoDetail.vue 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Client/src/views/basicinfo/scanStation.vue 226 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/SemanticSymbols.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/SemanticSymbols.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/CodeChunks.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/CodeChunks.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/SemanticSymbols.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/SemanticSymbols.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.794.21998/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.794.21998/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/DesignTimeBuild/.dtbcache.v2 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/0f5d7584-9cfe-4074-aeb3-fa1f9e570949.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/37cbdcf3-408e-4196-9c7f-486ef5eef107.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/5d2c31e8-d7a5-4453-ab25-eb41469b50b2.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/6b8b6a38-d1b1-459e-b415-f709208d542a.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/6ed546f4-fadb-4993-bf10-0046de75bd74.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/7765cc9c-7efa-493e-8c24-c5cc86a879de.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/8803666d-3cb0-4d8e-9882-52f506e51b7a.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/a92150fa-07f2-4b35-842d-8af5d93da741.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/c99954ff-673f-45d7-b93b-30e6c1adfe58.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/db45f673-18a0-4069-a270-036150636661.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/.futdcache.v2 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/.suo 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/BoxingDetailService.cs 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/FormulaDetailService.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/FormulaService.cs 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ProcessInfoDetailService.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ProcessInfoService.cs 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ScanStationService.cs 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/WIDESEAWCS_BasicInfoService.csproj 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Common/PLCEnum/R_PLCDBName.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Common/PLCEnum/W_PLCDBName.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_DTO/BasicInfo/ToolingBoardSubmitDto.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_DTO/BasicInfo/UpdatePartScannedStatusRequest.cs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IBoxingDetailService.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IFormulaDetailService.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IFormulaService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IProcessInfoDetailService.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IProcessInfoService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IScanStationService.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_Formula.cs 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_FormulaDetail.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_ProcessInfo.cs 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_ProcessInfoDetail.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_ScanStation.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/WIDESEAWCS_Model.csproj 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/.config/dotnet-tools.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/BoxingDetailController.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/FormulaController.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/ProcessInfoController.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/ProcessInfoDetailController.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/ScanStationController.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Properties/PublishProfiles/FolderProfile.pubxml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/obj/Debug/net6.0/WIDESEAWCS_TaskInfoService.AssemblyInfo.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/obj/Debug/net6.0/WIDESEAWCS_TaskInfoService.AssemblyInfoInputs.cache 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/obj/Debug/net6.0/WIDESEAWCs_TaskInfoService.assets.cache 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/PLCJob.cs 211 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketClient.cs 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vs/VSWorkspaceState.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
{
  "ExpandedNodes": [
    ""
  ],
  "SelectedNode": "\\WIDESEAWCS_Server.sln",
  "PreviewInSolutionExplorer": false
}
.vs/slnx.sqlite
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/api/http.js
@@ -19,7 +19,7 @@
}
else if (process.env.NODE_ENV == 'production') {
    axios.defaults.baseURL = 'http://127.0.0.1:8098/';
    axios.defaults.baseURL = 'http://192.168.2.110:8098/';
}
if (!axios.defaults.baseURL.endsWith('/')) {
    axios.defaults.baseURL+="/";
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/components/basic/VolForm.vue
@@ -26,9 +26,7 @@
          ></form-expand>
          <!-- 2021.10.17增加表单实时方法计算 -->
          <span
            v-else-if="
              item.readonly && typeof formFields[item.field] == 'function'
            "
            v-else-if="item.readonly && typeof formFields[item.field] == 'function'"
            >{{ formFields[item.field]() }}</span
          >
          <!-- åªè¯»å›¾ç‰‡æˆ–文件  -->
@@ -90,9 +88,7 @@
                {{  data.label}}</template
              >
            </el-tree-select>
            <template
              v-else-if="['select', 'selectList'].indexOf(item.type) != -1"
            >
            <template v-else-if="['select', 'selectList'].indexOf(item.type) != -1">
              <el-select-v2
                :disabled="item.readonly || item.disabled"
                v-show="!item.hidden"
@@ -230,9 +226,7 @@
            <div
              class="v-date-range"
              style="display: flex"
              v-else-if="
                ['date', 'datetime'].indexOf(item.type) != -1 && item.range
              "
              v-else-if="['date', 'datetime'].indexOf(item.type) != -1 && item.range"
            >
              <el-date-picker
                :size="size"
@@ -250,9 +244,7 @@
                :value-format="getDateFormat(item)"
              >
              </el-date-picker>
              <span style="margin: 0px 5px; font-size: 13px; color: #6f6b6b"
                >至</span
              >
              <span style="margin: 0px 5px; font-size: 13px; color: #6f6b6b">至</span>
              <el-date-picker
                :size="size"
                :disabled="item.readonly || item.disabled"
@@ -284,9 +276,7 @@
                v-model="formFields[item.field]"
                @change="item.onChange"
                :type="item.type"
                :placeholder="
                  item.placeholder ? item.placeholder : '请选择' + item.title
                "
                :placeholder="item.placeholder ? item.placeholder : '请选择' + item.title"
                :disabledDate="(val) => getDateOptions(val, item)"
                :value-format="getDateFormat(item)"
              >
@@ -308,9 +298,7 @@
            <el-scrollbar
              style="border: 1px solid #c7d8db; border-radius: 5px"
              :height="item.height || 150"
              v-else-if="
                item.type == 'editor' && (item.readonly || item.disabled)
              "
              v-else-if="item.type == 'editor' && (item.readonly || item.disabled)"
            >
              <div ref="editor" v-html="formFields[item.field]"></div>
            </el-scrollbar>
@@ -358,7 +346,7 @@
              v-else-if="item.type == 'cascader'"
              :options="item.data"
              :props="{
                checkStrictly: item.changeOnSelect || item.checkStrictly
                checkStrictly: item.changeOnSelect || item.checkStrictly,
              }"
              @change="item.onChange"
            >
@@ -373,10 +361,7 @@
              :max="item.max"
              v-model="formFields[item.field]"
            />
            <div
              style="display: flex"
              v-else-if="item.type == 'range' || item.range"
            >
            <div style="display: flex" v-else-if="item.type == 'range' || item.range">
              <el-input
                :size="size"
                :disabled="item.readonly || item.disabled"
@@ -404,7 +389,7 @@
              type="textarea"
              :autosize="{
                minRows: item.minRows || 2,
                maxRows: item.maxRows || 10
                maxRows: item.maxRows || 10,
              }"
              :placeholder="item.placeholder ? item.placeholder : item.title"
            />
@@ -492,33 +477,25 @@
</template>
<script>
const rule = {
  change: [
    'checkbox',
    'select',
    'date',
    'datetime',
    'drop',
    'radio',
    'cascader'
  ], // 2020.05.31增加级联类型
  change: ["checkbox", "select", "date", "datetime", "drop", "radio", "cascader"], // 2020.05.31增加级联类型
  phone: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
  decimal: /(^[\-0-9][0-9]*(.[0-9]+)?)$/,
  number: /(^[\-0-9][0-9]*([0-9]+)?)$/
  number: /(^[\-0-9][0-9]*([0-9]+)?)$/,
};
const inputTypeArr = ['text', 'string', 'mail', 'textarea', 'password'];
const inputTypeArr = ["text", "string", "mail", "textarea", "password"];
const types = {
  int: 'number',
  byte: 'number',
  decimal: 'number', // "float",
  string: 'string',
  bool: 'boolean',
  date: 'datetime',
  date: 'date',
  mail: 'email'
  int: "number",
  byte: "number",
  decimal: "number", // "float",
  string: "string",
  bool: "boolean",
  date: "datetime",
  date: "date",
  mail: "email",
};
//表单验证注意:每次验证都必须执行callback,否则验证不执行回调方法
const colPow = Math.pow(10, 3);
import FormExpand from './VolForm/VolFormRender';
import FormExpand from "./VolForm/VolFormRender";
import {
  defineAsyncComponent,
  defineComponent,
@@ -527,61 +504,59 @@
  toRefs,
  getCurrentInstance,
  onMounted,
  watch
} from 'vue';
  watch,
} from "vue";
export default defineComponent({
  components: {
    FormExpand,
    'vol-upload': defineAsyncComponent(() =>
      import('@/components/basic/VolUpload.vue')
    "vol-upload": defineAsyncComponent(() => import("@/components/basic/VolUpload.vue")),
    "vol-wang-editor": defineAsyncComponent(() =>
      import("@/components/editor/VolWangEditor.vue")
    ),
    'vol-wang-editor': defineAsyncComponent(() =>
      import('@/components/editor/VolWangEditor.vue')
    )
  },
  props: {
    loadKey: {
      // æ˜¯å¦åŠ è½½formRules字段配置的数据源
      type: Boolean,
      default: true
      default: true,
    },
    width: {
      // è¡¨å•宽度
      type: Number,
      default: 0
      default: 0,
    },
    labelWidth: {
      // è¡¨å•左边label文字标签的宽度
      type: Number,
      default: 100
      default: 100,
    },
    formRules: {
      // è¡¨å•配置规则,如字段类型,是否必填
      type: Array,
      default: []
      default: [],
    },
    formFields: {
      type: Object,
      default: () => {
        return {};
      }
      },
    },
    editor: {
      // 2021.01.16编辑器信息 {uploadImgUrl:"",upload:null//上传方法}
      type: Object,
      default: () => {
        return {};
      }
      },
    },
    size: {
      type: String, //large / default / small
      default: 'large'
      default: "large",
    },
    select2Count: {
      //超出数量显示select2组件
      type: Number,
      default: 500
    }
      default: 500,
    },
  },
  computed: {
    rules() {
@@ -597,7 +572,7 @@
        }, 100);
      }
      return ruleResult;
    }
    },
  },
  setup(props, context) {
    const { appContext, proxy } = getCurrentInstance();
@@ -630,7 +605,7 @@
          });
        }
        row.forEach((item, yIndex) => {
          if (item.type == 'number') {
          if (item.type == "number") {
            numberFields.push(item.field);
          }
          // ç›®å‰åªæ”¯æŒselect单选远程搜索,remote远程从后台字典数据源进行搜索,url从指定的url搜索
@@ -644,18 +619,18 @@
          // åˆå§‹åŒ–数据源空对象
          if (item.dataKey) {
            // ä¸‹æ‹‰æ¡†éƒ½å¼ºåˆ¶è®¾ç½®ä¸ºå­—符串类型
            item.columnType = 'string';
            item.columnType = "string";
            if (!item.data) {
              item.data = [];
            }
          }
          if (item.range || item.type == 'range') {
          if (item.range || item.type == "range") {
            if (
              !(props.formFields[item.field] instanceof Array) ||
              props.formFields[item.field].length != 2
            ) {
              props.formFields[item.field] = ['', ''];
              props.formFields[item.field] = ["", ""];
            }
            rangeFields.push(item.field);
          }
@@ -681,10 +656,10 @@
      if (keys.length == 0) return;
      appContext.config.globalProperties.http
        .post('/api/Sys_Dictionary/GetVueDictionary', keys)
        .post("/api/Sys_Dictionary/GetVueDictionary", keys)
        .then((dic) => {
          bindOptions(dic, binds);
          proxy.$emit('dicInited', dic);
          proxy.$emit("dicInited", dic);
        });
    };
    const bindOptions = (dic, binds) => {
@@ -692,7 +667,7 @@
        if (d.data.length > props.select2Count) {
          if (
            !binds.some((x) => {
              return x.key == d.dicNo && x.type == 'cascader';
              return x.key == d.dicNo && x.type == "cascader";
            })
          ) {
            d.data.forEach((item) => {
@@ -706,7 +681,7 @@
          // å¦‚果有数据的则不查询
          if (x.data.length > 0) return true;
          //2022.03.13增加级联数据源自动转换
          if (x.type == 'cascader' || x.type == 'treeSelect') {
          if (x.type == "cascader" || x.type == "treeSelect") {
            let _data = JSON.parse(JSON.stringify(d.data));
            let cascaderArr = appContext.config.globalProperties.base.convertTree(
              _data,
@@ -726,13 +701,13 @@
                }
              });
            });
          } else if (d.data.length > 0 && !d.data[0].hasOwnProperty('key')) {
          } 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: source['key'] + '',
                value: source['value']
                key: source["key"] + "",
                value: source["value"],
              };
            }
            x.data.push(...newSource);
@@ -745,18 +720,15 @@
    const initUpload = (item, init) => {
      if (!init) return;
      if (
        ['img', 'excel', 'file'].indexOf(item.type != -1) ||
        item.columnType == 'img'
      ) {
      if (["img", "excel", "file"].indexOf(item.type != -1) || item.columnType == "img") {
        // åªæ˜¯æ²¡è®¾ç½®æ˜¯å¦è‡ªåŠ¨ä¸Šä¼ çš„ï¼Œé»˜è®¤éƒ½æ˜¯é€‰æ‹©æ–‡ä»¶åŽè‡ªåŠ¨ä¸Šä¼ 
        if (!item.hasOwnProperty('autoUpload')) {
        if (!item.hasOwnProperty("autoUpload")) {
          item.autoUpload = true;
        }
        if (!item.hasOwnProperty('fileList')) {
        if (!item.hasOwnProperty("fileList")) {
          item.fileList = true;
        }
        if (!item.hasOwnProperty('downLoad')) {
        if (!item.hasOwnProperty("downLoad")) {
          item.downLoad = true;
        }
        if (!item.removeBefore) {
@@ -790,9 +762,9 @@
      let result = true;
      volform.value.validate((valid) => {
        if (!valid) {
          appContext.config.globalProperties.$message.error('数据验证未通过!');
          appContext.config.globalProperties.$message.error("数据验证未通过!");
          result = false;
        } else if (typeof callback === 'function') {
        } else if (typeof callback === "function") {
          try {
            callback(valid);
          } catch (error) {
@@ -812,7 +784,7 @@
      rangeFields,
      numberFields,
      validate,
      volform
      volform,
      //  initFormRules,
      // initSource
    };
@@ -820,7 +792,7 @@
  created() {
    this.formRules.forEach((rules) => {
      rules.forEach((option) => {
        if (option.type == 'treeSelect' && option.multiple === undefined) {
        if (option.type == "treeSelect" && option.multiple === undefined) {
          option.multiple = true;
        }
      });
@@ -830,7 +802,7 @@
  data() {
    return {
      // remoteCall: true,
      errorImg: 'this.src="' + require('@/assets/imgs/error-img.png') + '"'
      errorImg: 'this.src="' + require("@/assets/imgs/error-img.png") + '"',
      // span: 1,
      // rangeFields: [],
    };
@@ -847,8 +819,7 @@
        if (rowLength > _span) _span = rowLength;
      });
      let rete =
        Math.round(((item.colSize || 12 / _span) / 0.12) * colPow, 10.0) /
        colPow;
        Math.round(((item.colSize || 12 / _span) / 0.12) * colPow, 10.0) / colPow;
      if (item.colSize) return rete.toFixed(3);
      return rete.toFixed(3);
      // return (100 - rete).toFixed(3);
@@ -858,7 +829,7 @@
    },
    getSrc(path) {
      if (!path) return;
      if (!this.base.isUrl(path) && path.indexOf('.') != -1) {
      if (!this.base.isUrl(path) && path.indexOf(".") != -1) {
        return this.http.ipAddress + path;
      }
      return path;
@@ -866,10 +837,10 @@
    // æ˜¯å¦ä¸ºå›¾ç‰‡æ–‡ä»¶ç­‰æ ¼å¼å¹¶å¯¹å­—段的转换成数组:[{name:'1.jpg',path:'127.0.0.1/ff/1.jpg'}]
    isFile(item, formFields) {
      if (
        item.type == 'img' ||
        item.columnType == 'img' ||
        item.type == 'excel' ||
        item.type == 'file'
        item.type == "img" ||
        item.columnType == "img" ||
        item.type == "excel" ||
        item.type == "file"
      ) {
        this.convertFileToArray(item, formFields);
        return true;
@@ -896,21 +867,21 @@
        return;
      }
      // å°†ä»¥é€—号隔开的文件分割成数组127.0.0.1/aa/1.jpg,将127.0.0.1/aa/2.jpg
      if (typeof fileInfo === 'string') {
        if (fileInfo.trim() === '') {
      if (typeof fileInfo === "string") {
        if (fileInfo.trim() === "") {
          formFields[item.field] = [];
          return;
        }
        // å¦‚果文件路径是字符串,则使用,拆分
        fileInfo = fileInfo.replace(/\\/g, '/');
        let files = fileInfo.split(',');
        fileInfo = fileInfo.replace(/\\/g, "/");
        let files = fileInfo.split(",");
        formFields[item.field] = [];
        for (let index = 0; index < files.length; index++) {
          let file = files[index];
          let splitFile = file.split('/');
          let splitFile = file.split("/");
          formFields[item.field].push({
            name: splitFile.length > 0 ? splitFile[splitFile.length - 1] : file,
            path: file // this.base.isUrl(file) ? file : this.http.ipAddress + file,
            path: file, // this.base.isUrl(file) ? file : this.http.ipAddress + file,
          });
        }
      }
@@ -920,26 +891,26 @@
        file.path,
        file.name,
        {
          Authorization: this.$store.getters.getToken()
          Authorization: this.$store.getters.getToken(),
        },
        this.http.ipAddress
      );
    },
    validatorPhone(ruleOption, value, callback) {
      if (!ruleOption.required && !value && value != '0') {
      if (!ruleOption.required && !value && value != "0") {
        return callback();
      }
      if (!rule.phone.test((value || '').trim())) {
        return callback(new Error('请输入正确的手机号'));
      if (!rule.phone.test((value || "").trim())) {
        return callback(new Error("请输入正确的手机号"));
      }
      callback();
    },
    validatorPwd(ruleOption, value, callback) {
      if (!ruleOption.required && !value && value != '0') {
      if (!ruleOption.required && !value && value != "0") {
        return callback();
      }
      if ((value + '').trim().length < 6) {
        return callback(new Error('密码长度不能小于6位'));
      if ((value + "").trim().length < 6) {
        return callback(new Error("密码长度不能小于6位"));
      }
      callback();
    },
@@ -951,33 +922,33 @@
        ? val.map((x) => {
            return x;
          })
        : val.split(',');
        : val.split(",");
      for (let index = 0; index < valArr.length; index++) {
        var _item = data.find((x) => {
          return x.key && x.key != '0' && x.key + '' == valArr[index] + '';
          return x.key && x.key != "0" && x.key + "" == valArr[index] + "";
        });
        if (_item) {
          valArr[index] = _item.value;
        }
      }
      return valArr.join(',');
      return valArr.join(",");
    },
    getText(formFields, item) {
      // 2019.10.24修复表单select组件为只读的属性时没有绑定数据源
      let text = formFields[item.field];
      if (typeof text === 'function') return text(formFields);
      if (text === 'null' || text === '' || text === null || text === undefined)
        return '--';
      if (typeof text === "function") return text(formFields);
      if (text === "null" || text === "" || text === null || text === undefined)
        return "--";
      //2021.03.02增加只读时日期处理
      if (item.type == 'date') {
        return text.replace('T', ' ').split(' ')[0];
      if (item.type == "date") {
        return text.replace("T", " ").split(" ")[0];
      }
      //2021.03.31修复表单switch只读时没有转换值的问题
      if (item.type == 'switch') {
        return text ? '是' : '否';
      if (item.type == "switch") {
        return text ? "是" : "否";
      }
      if (!item.data) return text;
      if (item.type == 'selectList' || item.type == 'checkbox') {
      if (item.type == "selectList" || item.type == "checkbox") {
        return this.convertArrayValue(item.data, text);
      }
      var _item = item.data.find((x) => {
@@ -991,7 +962,7 @@
      // console.log(2);
    },
    onChange(item, value) {
      if (item.onChange && typeof item.onChange === 'function') {
      if (item.onChange && typeof item.onChange === "function") {
        item.onChange(value, item);
      }
    },
@@ -1002,7 +973,7 @@
        //  console.log('undefined');
      }
      this.remoteCall = false;
      if (item.onChange && typeof item.onChange === 'function') {
      if (item.onChange && typeof item.onChange === "function") {
        item.onChange(value, item);
      }
    },
@@ -1016,23 +987,22 @@
        return;
      }
      if (
        val == '' ||
        (item.data.length == 1 &&
          (val == item.data[0].key || val == item.data[0].value))
        val == "" ||
        (item.data.length == 1 && (val == item.data[0].key || val == item.data[0].value))
      ) {
        return;
      }
      // å¼¹å‡ºæ¡†æˆ–初始化表单时给data设置数组默认值2
      // 2020.09.26修复远程搜索自定义url不起作用的问题
      let url;
      if (typeof item.url === 'function') {
      if (typeof item.url === "function") {
        url = item.url(val, item.dataKey, item);
      } else {
        url =
          (item.url || '/api/Sys_Dictionary/GetSearchDictionary') +
          '?dicNo=' +
          (item.url || "/api/Sys_Dictionary/GetSearchDictionary") +
          "?dicNo=" +
          item.dataKey +
          '&value=' +
          "&value=" +
          val;
      }
      this.http.post(url).then((dicData) => {
@@ -1043,14 +1013,14 @@
      });
    },
    getObject(date) {
      if (typeof date === 'object') {
      if (typeof date === "object") {
        return date;
      }
      return new Date(date);
    },
    reset(sourceObj) {
      // é‡ç½®è¡¨å•时,禁用远程查询
      this.$refs['volform'].resetFields();
      this.$refs["volform"].resetFields();
      if (this.rangeFields.length) {
        this.rangeFields.forEach((key) => {
          this.formFields[key].splice(0);
@@ -1085,145 +1055,139 @@
      if (
        // item.readonly ||
        // item.disabled ||
        item.type == 'switch' ||
        item.type == 'range'
        item.type == "switch" ||
        item.type == "range"
      )
        return { required: false };
      // ç”¨æˆ·è®¾ç½®çš„自定义方法
      if (item.validator && typeof item.validator === 'function') {
      if (item.validator && typeof item.validator === "function") {
        return {
          validator: (rule, val, callback) => {
            // ç”¨æˆ·è‡ªå®šä¹‰çš„æ–¹æ³•,如果返回了值,直接显示返回的值,验证不通过
            let message = item.validator(rule, val);
            if (message) return callback(new Error(message + ''));
            if (message) return callback(new Error(message + ""));
            return callback();
          },
          required: item.required,
          trigger: rule.change.indexOf(item.type) != -1 ? 'change' : 'blur'
          trigger: rule.change.indexOf(item.type) != -1 ? "change" : "blur",
        };
      }
      if (['img', 'excel', 'file'].indexOf(item.type) != -1) {
      if (["img", "excel", "file"].indexOf(item.type) != -1) {
        return {
          validator: (rule, val, callback) => {
            //2021.09.05移除文件上传默认必填
            if (
              item.required &&
              !this.isReadonly(item) &&
              (!val || !val.length)
            ) {
            if (item.required && !this.isReadonly(item) && (!val || !val.length)) {
              return callback(
                new Error(item.type == 'img' ? '请上传照片' : '请上传文件')
                new Error(item.type == "img" ? "请上传照片" : "请上传文件")
              );
            }
            return callback();
          },
          required: item.required,
          trigger: 'change'
          trigger: "change",
        };
      }
      // è®¾ç½®æ•°å­—的最大值民最小值
      if (
        item.type == 'number' ||
        item.columnType == 'number' ||
        item.columnType == 'int' ||
        item.type == 'decimal'
        item.type == "number" ||
        item.columnType == "number" ||
        item.columnType == "int" ||
        item.type == "decimal"
      ) {
        // å¦‚果是必填项的数字,设置一个默认最大与最值小
        if (item.required && typeof item.min !== 'number') {
        if (item.required && typeof item.min !== "number") {
          item.min = 0; //item.type == "decimal" ? 0.1 : 1;
        }
        return {
          required: item.required,
          message: item.title + '只能是数字',
          message: item.title + "只能是数字",
          title: item.title,
          trigger: 'blur',
          trigger: "blur",
          min: item.min,
          max: item.max,
          type: item.columnType || item.type,
          validator: (ruleObj, value, callback) => {
            if (!ruleObj.min && !ruleObj.max) {
              if (ruleObj.required) {
                if ((!value && value != '0') || !rule.decimal.test(value)) {
                  return callback(new Error('只能是数字'));
                if ((!value && value != "0") || !rule.decimal.test(value)) {
                  return callback(new Error("只能是数字"));
                }
              }
              return callback();
            }
            if (this.isReadonly(item)) return callback();
            if (ruleObj.type == 'number') {
            if (ruleObj.type == "number") {
              if (!rule.number.test(value)) {
                ruleObj.message = ruleObj.title + '只能是整数';
                ruleObj.message = ruleObj.title + "只能是整数";
                return callback(new Error(ruleObj.message));
              }
            } else {
              if (!rule.decimal.test(value)) {
                ruleObj.message = ruleObj.title + '只能是数字';
                ruleObj.message = ruleObj.title + "只能是数字";
                return callback(new Error(ruleObj.message));
              }
            }
            if (
              ruleObj.min !== undefined &&
              typeof ruleObj.min === 'number' &&
              typeof ruleObj.min === "number" &&
              value < ruleObj.min
            ) {
              ruleObj.message = ruleObj.title + '不能小于' + ruleObj.min;
              ruleObj.message = ruleObj.title + "不能小于" + ruleObj.min;
              return callback(new Error(ruleObj.message));
            }
            if (
              ruleObj.max !== undefined &&
              typeof ruleObj.max === 'number' &&
              typeof ruleObj.max === "number" &&
              value > ruleObj.max
            ) {
              ruleObj.message = ruleObj.title + '不能大于' + ruleObj.max;
              ruleObj.message = ruleObj.title + "不能大于" + ruleObj.max;
              return callback(new Error(ruleObj.message));
            }
            return callback();
          }
          },
        };
      }
      // æ‰‹æœºã€å¯†ç éªŒè¯
      if (item.type == 'password' || item.type == 'phone') {
      if (item.type == "password" || item.type == "phone") {
        return {
          validator:
            item.type == 'phone' ? this.validatorPhone : this.validatorPwd,
          validator: item.type == "phone" ? this.validatorPhone : this.validatorPwd,
          required: item.required,
          trigger: 'blur'
          trigger: "blur",
        };
      }
      if (!item.required && item.type != 'mail') return { required: false };
      if (!item.required && item.type != "mail") return { required: false };
      if (!item.hasOwnProperty('type')) item.type = 'text';
      if (!item.hasOwnProperty("type")) item.type = "text";
      if (inputTypeArr.indexOf(item.type) != -1) {
        let message =
          item.title +
          (item.type == 'mail' ? '必须是一个邮箱地址' : '不能为空');
        let type = item.type == 'mail' ? 'email' : types[item.columnType];
          item.title + (item.type == "mail" ? "必须是一个邮箱地址" : "不能为空");
        let type = item.type == "mail" ? "email" : types[item.columnType];
        let _rule = {
          required: true,
          message: message,
          trigger: 'blur',
          trigger: "blur",
          type: type,
          validator: (ruleObj, value, callback) => {
            if (
              !this.isReadonly(item) &&
              (value === '' || value === undefined || value === null)
              (value === "" || value === undefined || value === null)
            ) {
              return callback(new Error(ruleObj.message));
            }
            return callback();
          }
          },
        };
        if (item.type == 'mail') {
        if (item.type == "mail") {
          _rule.validator = undefined;
          return _rule;
        }
        if (item.min) {
          _rule.min = item.min;
          _rule.message = item.title + '至少' + item.min + '个字符!';
          _rule.message = item.title + "至少" + item.min + "个字符!";
        }
        if (item.max) {
          return [
@@ -1231,94 +1195,94 @@
            {
              max: item.max,
              required: true,
              message: item.title + '最多' + item.max + '个字符!',
              trigger: 'blur'
            }
              message: item.title + "最多" + item.max + "个字符!",
              trigger: "blur",
            },
          ];
        }
        return _rule;
      }
      if (item.type == 'radio') {
      if (item.type == "radio") {
        return {
          required: item.required,
          message: '请选择' + item.title,
          trigger: 'change',
          type: 'string'
          message: "请选择" + item.title,
          trigger: "change",
          type: "string",
        };
      }
      if (
        item.type == 'date' ||
        item.type == 'datetime' ||
        item.type == 'month' ||
        item.type == 'time'
        item.type == "date" ||
        item.type == "datetime" ||
        item.type == "month" ||
        item.type == "time"
      ) {
        return {
          required: true,
          message: '请选择' + item.title,
          trigger: 'change',
          type: item.range ? 'array' : 'string',
          message: "请选择" + item.title,
          trigger: "change",
          type: item.range ? "array" : "string",
          validator: (rule, val, callback) => {
            if (this.isReadonly(item)) return callback();
            // ç”¨æˆ·è‡ªå®šä¹‰çš„æ–¹æ³•,如果返回了值,直接显示返回的值,验证不通过
            if (!val || (item.range && !val.length)) {
              return callback(new Error('请选择日期'));
              return callback(new Error("请选择日期"));
            }
            return callback();
          }
          },
        };
      }
      if (item.type == 'cascader') {
      if (item.type == "cascader") {
        return {
          type: 'array',
          type: "array",
          required: true,
          min: item.min || 1,
          // message: "请选择" + item.title,
          trigger: 'change',
          trigger: "change",
          validator: (rule, val, callback) => {
            if (this.isReadonly(item)) return callback();
            // ç”¨æˆ·è‡ªå®šä¹‰çš„æ–¹æ³•,如果返回了值,直接显示返回的值,验证不通过
            let _arr = this.formFields[item.field];
            if (!_arr || !_arr.length) {
              return callback(new Error('请选择' + item.title));
              return callback(new Error("请选择" + item.title));
            }
            return callback();
          }
          },
        };
      }
      if (
        ['select', 'selectList', 'checkbox', 'cascader', 'treeSelect'].indexOf(
        ["select", "selectList", "checkbox", "cascader", "treeSelect"].indexOf(
          item.type
        ) != -1
      ) {
        let _rule = {
          type: item.type == 'select' ? 'string' : 'array',
          type: item.type == "select" ? "string" : "array",
          required: true,
          min: item.min || 1,
          message: '请选择' + item.title,
          trigger: 'change',
          message: "请选择" + item.title,
          trigger: "change",
          validator: (rule, value, callback) => {
            if (this.isReadonly(item)) return callback();
            //2021.11.27修复多选没有提示的问题
            if (value == undefined || value === '') {
            if (value == undefined || value === "") {
              return callback(new Error(rule.message));
            } else if (
              (item.type == 'checkbox' ||
                item.type == 'selectList' ||
                item.type == 'treeSelect') &&
              (item.type == "checkbox" ||
                item.type == "selectList" ||
                item.type == "treeSelect") &&
              (!(value instanceof Array) || !value.length)
            ) {
              return callback(new Error(rule.message));
            }
            return callback();
          }
          },
        };
        if (_rule.max) {
          _rule.nax = item.max;
          _rule.message = '最多只能选择' + item.max + '项';
          _rule.message = "最多只能选择" + item.max + "项";
        }
        return _rule;
      }
@@ -1329,8 +1293,7 @@
        return true;
      }
      return (
        date1.valueOf() <
        (typeof date2 == 'number' ? date2 : new Date(date2).valueOf())
        date1.valueOf() < (typeof date2 == "number" ? date2 : new Date(date2).valueOf())
      );
    },
    getDateOptions(date, item) {
@@ -1338,27 +1301,25 @@
      if ((!item.min && !item.max) || !date) {
        return false;
      }
      if (item.min && item.min.indexOf(' ') == -1) {
      if (item.min && item.min.indexOf(" ") == -1) {
        //不设置时分秒,后面会自动加上 08:00
        item.min = item.min + ' 00:00:000';
        item.min = item.min + " 00:00:000";
      }
      return (
        this.compareDate(date, item.min) || !this.compareDate(date, item.max)
      );
      return this.compareDate(date, item.min) || !this.compareDate(date, item.max);
    },
    getDateFormat(item) {
      if (item.type == 'month') {
        return 'YYYY-MM';
      if (item.type == "month") {
        return "YYYY-MM";
      }
      // if (item.type=='time') {
      //     return 'HH:mm:ss'
      // }
      //见https://day.js.org/docs/zh-CN/display/format
      return item.type == 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss';
      return item.type == "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss";
    },
    dateRangeChange(val, item) {
      if (!val) {
        this.$emit('update:formFields');
        this.$emit("update:formFields");
        return;
      }
      item.onChange && item.onChange(val);
@@ -1373,9 +1334,9 @@
      return data.label.includes(value);
    },
    getNode( label,node, data){
      console.log(label)
    }
  }
      console.log(label);
    },
  },
});
</script>
<style lang="less" scoped>
@@ -1455,8 +1416,8 @@
  padding-left: 5px;
}
.el-form-item ::v-deep(textarea) {
  font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
    'Microsoft YaHei', '微软雅黑', Arial, sans-serif !important;
  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei", "微软雅黑", Arial, sans-serif !important;
}
.el-form-item ::v-deep(.el-select .el-select__tags > span) {
  display: flex;
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/components/basic/VolTable.vue
@@ -642,6 +642,7 @@
      default: 500,
    },
    selectable: {
      type: Function,
      default: (row, index) => {
        return true;
@@ -884,18 +885,45 @@
    rowDbClick(row, column, event) {
      //2021.05.23增加双击行事件
      this.$emit("rowDbClick", { row, column, event });
    },
    rowClick(row, column, event) {
    },rowClick(row, column, event) {
      //2022.02.20增加点击时表格参数判断
      if (!column) {
        return;
      }
      //正在编辑时,禁止出发rowClick事件
  // ===== ä¼˜åŒ–:隔离复选框点击事件,避免冒泡干扰 å¼€å§‹ =====
  // åˆ¤æ–­ç‚¹å‡»ç›®æ ‡æ˜¯å¦æ˜¯å¤é€‰æ¡†ï¼ˆæˆ–复选框所在的单元格/图标)
  const targetEl = event.target;
  const isCheckbox = targetEl.classList.contains('el-checkbox__input') ||
                      targetEl.closest('.el-checkbox__input') ||
                      targetEl.closest('.el-table-column--selection');
  // å¦‚果点击的是复选框区域,直接返回,不执行行选中逻辑
  if (isCheckbox) {
    return;
  }
  // ===== ä¼˜åŒ–:隔离复选框点击事件 ç»“束 =====
  // ===== ä¼˜åŒ–:点击行选中/切换复选框 å¼€å§‹ =====
  // 1. åˆ¤æ–­æ˜¯å¦æ˜¾ç¤ºå¤é€‰æ¡†ï¼ˆck为true),不显示则无需处理
  // 2. ç¼–辑状态下不触发(避免干扰编辑功能)
  if (this.ck && this.edit.rowIndex === -1) {
    // 3. å•选场景(single为true):先清空所有选中项,再强制选中当前行(保持单选逻辑)
    if (this.single) {
      this.$refs.table.clearSelection(); // æ¸…空所有选中
      this.$refs.table.toggleRowSelection(row, true); // å•选场景强制选中当前行
    }
    // 4. å¤šé€‰åœºæ™¯ï¼ˆsingle为false):不传第二个参数,实现切换选中/取消状态
    else {
      this.$refs.table.toggleRowSelection(row); // åˆ‡æ¢çŠ¶æ€ï¼Œæ”¯æŒå–æ¶ˆé€‰ä¸­
    }
  }
  // ===== ä¼˜åŒ–:点击行选中/切换复选框 ç»“束 =====
  // æ­£åœ¨ç¼–辑时,禁止触发rowClick事件
      if (this.edit.rowIndex == -1) {
        this.$emit("rowClick", { row, column, event });
      }
      // ç‚¹å‡»è¡Œäº‹ä»¶(2020.11.07)
      if (!this.doubleEdit) {
        return;
      }
@@ -918,13 +946,49 @@
          this.edit.rowIndex = -1;
        }
        //当正在编辑,且点击到其他行时,在原编辑的行结束编辑后,触发新行的rowClick事件
        //正在编辑时,禁止出发rowClick事件
    //正在编辑时,禁止触发rowClick事件
        if (this.edit.rowIndex == -1) {
          this.$emit("rowClick", { row, column, event });
        }
      }
      this.rowBeginEdit(row, column);
    },
    //   //正在编辑时,禁止出发rowClick事件
    //   if (this.edit.rowIndex == -1) {
    //     this.$emit("rowClick", { row, column, event });
    //   }
    //   // ç‚¹å‡»è¡Œäº‹ä»¶(2020.11.07)
    //   if (!this.doubleEdit) {
    //     return;
    //   }
    //   // ç‚¹å‡»å…¶ä»–行时,如果点击的行与正在编辑的行相同,保持编辑状态
    //   if (this.clickEdit && this.edit.rowIndex != -1) {
    //     if (row.elementIndex == this.edit.rowIndex) {
    //       // ç‚¹å‡»çš„单元格如果不可以编辑,直接结束编辑
    //       // 2020.10.12修复结束编辑时,element table高版本属性获取不到的问题
    //       let _col = this.columns.find((x) => {
    //         return x.field == ((event && event.property) || column.property);
    //       });
    //       if (_col && (!_col.edit || _col.readonly)) {
    //         if (this.rowEndEdit(row, event)) {
    //           this.edit.rowIndex = -1;
    //         }
    //       }
    //       return;
    //     }
    //     if (this.rowEndEdit(row, event && event.property ? event : column)) {
    //       this.edit.rowIndex = -1;
    //     }
    //     //当正在编辑,且点击到其他行时,在原编辑的行结束编辑后,触发新行的rowClick事件
    //     //正在编辑时,禁止出发rowClick事件
    //     if (this.edit.rowIndex == -1) {
    //       this.$emit("rowClick", { row, column, event });
    //     }
    //   }
    //   this.rowBeginEdit(row, column);
    // },
    dowloadFile(file) {
      this.base.dowloadFile(
        file.path,
@@ -1654,6 +1718,7 @@
      return column.edit.type == "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss";
    },
    userSelect(selection, row) {
      console.log("userSelect", selection, row);
      this.selectRows = selection;
      if (!this.single) {
        this.$emit("rowChange", { row, selection });
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/extension/basicinfo/boxing.js
@@ -1,5 +1,3 @@
let extension = {
    components: {//动态扩充组件或组件路径
        //表单header、content、footer对应位置扩充的组件
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/extension/basicinfo/boxingDetail.js
@@ -1,5 +1,3 @@
let extension = {
    components: {//动态扩充组件或组件路径
        //表单header、content、footer对应位置扩充的组件
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/extension/basicinfo/formula.js
@@ -1,10 +1,9 @@
let extension = {
    components: {//动态扩充组件或组件路径
        //表单header、content、footer对应位置扩充的组件
        gridHeader:'',
        gridbody:'',
        gridBody: '',
        gridFooter: '',
        //弹出框(修改、编辑、查看)header、content、footer对应位置扩充的组件
        modelHeader: '',
@@ -14,6 +13,12 @@
    buttons: [],//扩展的按钮
    methods: {//事件扩展
        onInit() {
            var detailImport = this.detailOptions.buttons.find(item=>item.value == 'import');
      if(detailImport){
        detailImport.onClick = () => {
          this.$refs.gridBody.open();
        }
      }
        },
        onInited() {
        }
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/extension/basicinfo/processInfoDetail.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;
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/router/viewGird.js
@@ -78,6 +78,10 @@
    name: 'processInfo',
    component: () => import('@/views/basicinfo/processInfo.vue')
  }, {
    path: '/processInfoDetail',
    name: 'processInfoDetail',
    component: () => import('@/views/basicinfo/processInfoDetail.vue')
  }, {
    path: '/scanStation',
    name: 'scanStation',
    component: () => import('@/views/basicinfo/scanStation.vue')
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/views/Home.vue
@@ -1,24 +1,1094 @@
<template>
  <div class="title"></div>
  <div class="container">
    <!-- å·¦ä¾§åŒºåŸŸ - æ— ä»»ä½•标题标注 -->
    <div class="left-area">
      <div class="left-top">
        <!-- æŒ‰é’®+信号 æ¨ªå‘排列容器 -->
        <div class="btn-signal-group">
          <!-- æŒ‰é’®ç»„ - ä¿®æ”¹ä¸ºä¸Šä¸‹æŽ’列 -->
          <div class="btn-group">
            <button
              class="btn"
              :class="isPLCStarted ? 'stop-btn' : 'start-btn'"
              @click="handleToggle"
            >
              <i class="icon" :class="isPLCStarted ? 'icon-stop' : 'icon-start'"></i>
              {{ isPLCStarted ? "关闭" : "启动" }}
            </button>
            <button
              class="btn"
              :class="isPLCPaused ? 'resume-btn' : 'pause-btn'"
              @click="handlePauseToggle"
              :disabled="!isPLCStarted"
            >
              <i class="icon" :class="isPLCPaused ? 'icon-resume' : 'icon-pause'"></i>
              {{ isPLCPaused ? "恢复" : "暂停" }}
            </button>
          </div>
          <!-- ä¿¡å·ç¯ç»„ å ä¸¤ä¸ªæŒ‰é’®å®½åº¦ + æ•´ä½“放大 -->
          <div class="signal-status">
            <div class="signal-item" v-for="(signal, index) in signalStates" :key="index">
              <div
                class="signal-light"
                :class="signal ? 'signal-active' : 'signal-inactive'"
              >
                <div class="signal-light-inner"></div>
              </div>
              <span class="signal-label">{{ signalLabels[index] }}</span>
            </div>
          </div>
        </div>
      </div>
      <div class="left-bottom">
        <div class="form-row finished-product-row">
          <span class="label">成品编号:</span>
          <input type="text" class="input-box" v-model="finishedProduct" disabled />
        </div>
        <div class="parts-list">
          <div
            class="form-row part-item"
            v-for="(item, index) in leftPartCodes"
            :key="index"
          >
            <span class="label">零件{{ index + 1 }}:</span>
            <input
              type="text"
              class="input-box"
              v-model="leftPartCodes[index]"
              disabled
            />
            <label class="checkbox-container">
              <input
                type="checkbox"
                class="part-checkbox"
                v-model="leftPartChecked[index]"
                @change="handlePartCheck(index)"
              />
              <span class="checkmark"></span>
              <span class="checkbox-label">{{
                leftPartChecked[index] ? "扫码" : "不扫"
              }}</span>
            </label>
          </div>
        </div>
      </div>
    </div>
    <!-- å³ä¾§åŒºåŸŸ - æ— ä»»ä½•标题标注 ã€å·²åˆ é™¤æ¸…空+保存按钮】 -->
    <div class="right-area">
      <div class="right-top">
        <div class="form-row">
          <span class="label">录入框:</span>
          <!-- âœ… åªä¿ç•™çº¯å½•入框,清空/保存按钮已删除 -->
          <input type="text" class="input-box" v-model="rightTopInput" />
        </div>
      </div>
      <div class="right-bottom">
        <div class="form-row tooling-board-row">
          <span class="short-label">工装板编号:</span>
          <input
            type="text"
            class="input-box short-input"
            v-model="toolingBoardNo"
            placeholder="请输入工装板编号"
          />
          <button class="btn clear-btn" @click="clearToolingBoardNo">
            <i class="icon icon-clear"></i>清除
          </button>
          <button class="btn save-btn" @click="saveToolingBoardNo">
            <i class="icon icon-submit"></i>提交
          </button>
        </div>
        <div class="parts-list">
          <div class="form-row part-item finished-product-row">
            <span class="label">成品编号:</span>
            <input
              type="text"
              class="input-box"
              v-model="finishedProductCode"
              placeholder="请输入成品编号"
            />
            <button class="btn clear-btn" @click="clearFinishedProductCode">
              <i class="icon icon-clear"></i>清除
            </button>
          </div>
          <div
            class="form-row part-item"
            v-for="(item, index) in rightPartCodes"
            :key="index"
          >
            <span class="label">零件{{ index + 1 }}:</span>
            <input
              type="text"
              class="input-box"
              v-model="rightPartCodes[index]"
              placeholder="请输入零件编号"
            />
            <button class="btn clear-btn" @click="clearRightPart(index)">
              <i class="icon icon-clear"></i>清除
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { ref, reactive } from 'vue'
import { ref, onMounted, onUnmounted, watch, computed } from "vue";
import axios from "axios";
export default {
  setup() {
    return {
    // åŸºç¡€æ•°æ®å®šä¹‰ - 1:1精准对接后端 æˆå“ç¼–号+零件编号 æ— å†—余兼容
    const finishedProduct = ref(""); // å·¦ä¾§æˆå“ç¼–号(GetLeftInitialData接口返回)
    const finishedProductId = ref("");
    const rightTopInput = ref("");
    const leftPartCodes = ref(Array(10).fill("")); // å·¦ä¾§é›¶ä»¶ç¼–号数组
    const rightPartCodes = ref(Array(10).fill("")); // å³ä¾§é›¶ä»¶ç¼–号数组
    const leftPartChecked = ref(Array(10).fill(false));
    const toolingBoardNo = ref("");
    const fillIndex = ref(-1);
    const leftPartIds = ref(Array(10).fill(""));
    const finishedProductCode = ref(""); // å³ä¾§æˆå“ç¼–号(工装板接口返回)
    // PLC状态
    const isPLCStarted = ref(false);
    const isPLCPaused = ref(false);
    // ä¿¡å·ç›¸å…³
    const signalStates = ref([false, false, false, false, false]);
    const signalLabels = ref([
      "心跳信号",
      "急停信号",
      "自动运行信号",
      "在线模式信号",
      "故障信号",
    ]);
    // å®šæ—¶è½®è¯¢æ ¸å¿ƒé…ç½®
    let pollingTimer = null;
    const pollingInterval = 5000;
    let checkDebounceTimer = null;
    let destroyDelayTimer = null;
    const destroyDelayTime = 500; // âœ… æ ¸å¿ƒï¼šå¡«å……+清空 éƒ½å»¶è¿Ÿ500毫秒
    let boardCodeDebounceTimer = null;
    // âœ… æ–°å¢žï¼šè‡ªåŠ¨æäº¤é˜²æŠ–å®šæ—¶å™¨ï¼Œé˜²æ­¢é‡å¤æäº¤
    let autoSubmitDebounceTimer = null;
    // âœ… æ–°å¢žï¼šæäº¤é”ï¼Œé˜²æ­¢æ— å‹¾é€‰æ—¶é‡å¤è§¦å‘提交
    let submitLock = ref(false);
    // âœ… âœ… âœ… æ ¸å¿ƒæ–°å¢ž1:计算属性 - å®žæ—¶ç»Ÿè®¡å·¦ä¾§å‹¾é€‰çš„复选框数量 (自动更新)
    const checkedCount = computed(() => {
      // ç»Ÿè®¡leftPartChecked数组中为true的数量
      return leftPartChecked.value.filter((checked) => checked === true).length;
    });
    // âœ… âœ… âœ… æ ¸å¿ƒæ–°å¢ž2:计算属性 - å®žæ—¶ç»Ÿè®¡å³ä¾§å·²å¡«å……的零件数量 (自动更新)
    const filledPartCount = computed(() => {
      // ç»Ÿè®¡rightPartCodes数组中有值(非空)的零件数量
      return rightPartCodes.value.filter((code) => code.trim() !== "").length;
    });
    // âœ… èŽ·å–å·¦ä¾§åˆå§‹æ•°æ® - å¯¹æŽ¥ /api/scanStation/GetLeftInitialData
    const fetchLeftInitialData = async () => {
      try {
        console.log("正在获取左侧初始数据(成品编号+零件编号+勾选状态+零件ID)...");
        const response = await axios.get("/api/scanStation/GetLeftInitialData", {
          timeout: 5000,
        });
        const resData = response.data;
        const isSuccess = resData.Status === true || resData.status === true;
        if (isSuccess) {
          const data = resData.Data || resData.data || {};
          if (data.finishedProductId) finishedProductId.value = data.finishedProductId;
          if (data.finishedProduct) finishedProduct.value = data.finishedProduct;
          // èµ‹å€¼å·¦ä¾§é›¶ä»¶ç¼–号
          if (Array.isArray(data.leftPartCodes) && data.leftPartCodes.length >= 10) {
            for (let i = 0; i < 10; i++) {
              leftPartCodes.value[i] = data.leftPartCodes[i] || "";
              leftPartIds.value[i] = data.leftPartIds?.[i] || "";
            }
          }
          // èµ‹å€¼å‹¾é€‰çŠ¶æ€
          if (Array.isArray(data.leftPartChecked) && data.leftPartChecked.length >= 10) {
            for (let i = 0; i < 10; i++) {
              leftPartChecked.value[i] = !!data.leftPartChecked[i];
    }
  }
}
      } catch (error) {
        console.error("获取左侧初始数据失败:", error);
      }
    };
    // âœ… èŽ·å–ä¿¡å·+PLC状态
    const fetchSignalAndPLCStates = async () => {
      try {
        const response = await axios.get("/api/scanStation/GetSignalStates", {
          timeout: 5000,
        });
        const resData = response.data;
        const isSuccess = resData.Status === true || resData.status === true;
        if (isSuccess) {
          const data = resData.Data || resData.data || {};
          const newSignalStates = data.signalStates || [];
          for (let i = 0; i < 5; i++) signalStates.value[i] = newSignalStates[i] ?? false;
          const plcStatus = data.plcStatus || data.plc_status || {};
          isPLCStarted.value = plcStatus.isStarted ?? isPLCStarted.value;
          // âœ… ä¿®å¤BUG:原代码是 isPLCStarted.value å¯¼è‡´æš‚停状态赋值错误
          isPLCPaused.value = plcStatus.isPaused ?? isPLCPaused.value;
        }
      } catch (error) {
        console.error("获取信号和PLC状态失败:", error);
      }
    };
    // âœ… ã€æ ¸å¿ƒä¿®æ”¹ã€‘工装板查询接口 - æœ‰æ•°æ®å°±å¡«å……,无数据/失败 å®Œå…¨ä¿ç•™åŽŸæœ‰å†…å®¹ï¼Œä¸åšä»»ä½•æ¸…ç©ºæ“ä½œ
    const fetchProductAndPartsByBoardCode = async (boardCode) => {
      if (!boardCode.trim()) return;
      try {
        console.log(`工装板编号变更,请求数据:${boardCode}`);
        const response = await axios.get(
          "/api/boxingDetail/GetProductAndPartsByBoardNo",
          {
            params: { palletCode: boardCode.trim() },
            timeout: 5000,
          }
        );
        const resData = response.data;
        const isSuccess = resData.Status === true || resData.status === true;
        // âœ… åªæœ‰ã€æŽ¥å£æˆåŠŸ+有返回数据】的时候,才执行赋值覆盖
        if (isSuccess) {
          const data = resData.Data || resData.data || {};
          // æœ‰æˆå“ç¼–号就赋值,没有就不操作
          if (data.finishedProductCode) {
            finishedProductCode.value = data.finishedProductCode;
          }
          // æœ‰é›¶ä»¶åˆ—表就填充,没有就不操作
          const partsList = Array.isArray(data.partsList) ? data.partsList : [];
          if (partsList.length > 0) {
            for (let i = 0; i < 10; i++) {
              if (partsList[i]) {
                rightPartCodes.value[i] = partsList[i];
              }
            }
          }
          console.log("✅ å·¥è£…板查询成功,成品编号+零件编号填充完成");
        } else {
          // âœ… æ— å¯¹åº”数据:只弹提示,不清空任何内容
          alert(
            "获取数据失败:" + (resData.Message || resData.message || "无对应工装板数据")
          );
        }
      } catch (error) {
        // âœ… è¯·æ±‚失败:只弹提示,不清空任何内容
        alert("工装板数据请求失败,请检查网络或接口!");
        console.error("工装板接口请求失败:", error);
      } finally {
        boardCodeDebounceTimer = null;
      }
    };
    // å¯åЍ/停止定时轮询
    const startPolling = () => {
      if (pollingTimer) clearInterval(pollingTimer);
      fetchSignalAndPLCStates();
      pollingTimer = setInterval(fetchSignalAndPLCStates, pollingInterval);
    };
    const stopPolling = () => {
      if (pollingTimer) clearInterval(pollingTimer);
      pollingTimer = null;
    };
    // PLC启动/关闭逻辑
    const handleToggle = async () => {
      try {
        const response = await axios.get("/api/scanStation/StartPLC", {
          params: { isStop: isPLCStarted.value },
          timeout: 5000,
        });
        const resData = response.data;
        const isSuccess = resData.Status === true || resData.status === true;
        if (isSuccess) {
          isPLCStarted.value = !isPLCStarted.value;
          isPLCPaused.value = false;
          fetchSignalAndPLCStates();
        } else {
          alert(
            resData.Message ||
              resData.message ||
              (isPLCStarted.value ? "关闭失败" : "启动失败")
          );
        }
      } catch (error) {
        alert(isPLCStarted.value ? "关闭PLC失败" : "启动PLC失败");
        console.error("PLC启停失败:", error);
      }
    };
    // PLC暂停/恢复逻辑
    const handlePauseToggle = async () => {
      try {
        const response = await axios.get("/api/scanStation/PausePLC", {
          params: { isPause: !isPLCPaused.value },
          timeout: 5000,
        });
        const resData = response.data;
        const isSuccess = resData.Status === true || resData.status === true;
        if (isSuccess) {
          isPLCPaused.value = !isPLCPaused.value;
          fetchSignalAndPLCStates();
        } else {
          alert(
            resData.Message ||
              resData.message ||
              (isPLCPaused.value ? "恢复失败" : "暂停失败")
          );
        }
      } catch (error) {
        alert(isPLCPaused.value ? "恢复PLC失败" : "暂停PLC失败");
        console.error("PLC暂停恢复失败:", error);
      }
    };
    // é›¶ä»¶å‹¾é€‰çŠ¶æ€å˜æ›´å¤„ç†
    const handlePartCheck = async (index) => {
      const isChecked = leftPartChecked.value[index];
      const partCode = leftPartCodes.value[index];
      const partId = leftPartIds.value[index];
      if (!finishedProductId.value) {
        alert("成品ID不存在,无法更新零件扫码状态!");
        leftPartChecked.value[index] = !isChecked;
        return;
      }
      if (!partId) {
        alert(`零件${index + 1}数据库ID不存在,无法更新扫码状态!`);
        leftPartChecked.value[index] = !isChecked;
        return;
      }
      if (!partCode.trim()) {
        alert(`零件${index + 1}编号为空,无法更新扫码状态!`);
        leftPartChecked.value[index] = !isChecked;
        return;
      }
      if (checkDebounceTimer) clearTimeout(checkDebounceTimer);
      checkDebounceTimer = setTimeout(async () => {
        try {
          const response = await axios.post(
            "/api/scanStation/UpdatePartScannedStatus",
            { Id: partId, IsScanned: isChecked ? 1 : 0 },
            { timeout: 5000 }
          );
          const resData = response.data;
          const isSuccess = resData.Status === true || resData.status === true;
          if (isSuccess) {
            console.log(`零件${index + 1}扫码状态更新成功`);
            // âœ… å‹¾é€‰çŠ¶æ€å˜åŒ–æ—¶ï¼Œé‡ç½®æäº¤é”
            submitLock.value = false;
          } else {
            leftPartChecked.value[index] = !isChecked;
            alert(
              `零件${index + 1}状态更新失败:${
                resData.Message || resData.message || "未知错误"
              }`
            );
          }
        } catch (error) {
          leftPartChecked.value[index] = !isChecked;
          alert(`零件${index + 1}状态更新请求失败,请检查网络或接口!`);
          console.error(`更新零件${index + 1}扫码状态失败:`, error);
        } finally {
          checkDebounceTimer = null;
        }
      }, 500);
    };
    // âœ… æ ¸å¿ƒä¿®æ”¹ï¼šå»¶è¿Ÿ0.5秒填充 + å»¶è¿Ÿ0.5秒清空 åŒæ­¥æ‰§è¡Œ æ— éœ€æ‰‹åŠ¨æŒ‰é’®
    const fillContent = () => {
      if (!rightTopInput.value.trim()) return;
      const inputValue = rightTopInput.value.trim();
      // æ¸…除旧定时器,防止重复执行
      if (destroyDelayTimer) clearTimeout(destroyDelayTimer);
      // ç»Ÿä¸€å»¶è¿Ÿ500ms执行【填充+清空】
      destroyDelayTimer = setTimeout(() => {
        if (!toolingBoardNo.value.trim()) {
          toolingBoardNo.value = inputValue;
        } else if (!finishedProductCode.value.trim()) {
          finishedProductCode.value = inputValue;
        } else if (fillIndex.value < 10) {
          rightPartCodes.value[fillIndex.value] = inputValue;
          fillIndex.value++;
        } else {
          alert("工装板编号、成品编号和零件1-10已全部填充完成,无法继续录入!");
          rightTopInput.value = "";
          destroyDelayTimer = null;
          return;
        }
        // å¡«å……完成后 è‡ªåŠ¨æ¸…ç©ºå½•å…¥æ¡†
        rightTopInput.value = "";
        destroyDelayTimer = null;
      }, destroyDelayTime);
    };
    // âœ… ç›‘听录入框内容变化自动触发填充逻辑
    watch(
      rightTopInput,
      (newVal) => {
        if (newVal.trim()) fillContent();
      },
      { immediate: false }
    );
    // ç›‘听工装板编号变化查询数据
    watch(
      toolingBoardNo,
      (newVal) => {
        const boardCode = newVal.trim();
        if (boardCode) {
          if (boardCodeDebounceTimer) clearTimeout(boardCodeDebounceTimer);
          boardCodeDebounceTimer = setTimeout(
            () => fetchProductAndPartsByBoardCode(boardCode),
            300
          );
        } else {
          if (boardCodeDebounceTimer) clearTimeout(boardCodeDebounceTimer);
        }
      },
      { immediate: false }
    );
    // å³ä¾§é¡µé¢æ“ä½œæ–¹æ³• (已删除清空/保存录入框的方法,无冗余)
    const clearToolingBoardNo = () => (toolingBoardNo.value = "");
    const clearRightPart = (index) => (rightPartCodes.value[index] = "");
    const clearFinishedProductCode = () => (finishedProductCode.value = "");
    // æäº¤å·¥è£…板数据到后端
    const saveToolingBoardNo = async () => {
      if (!toolingBoardNo.value.trim()) {
        alert("工装板编号不能为空,请输入后再提交!");
        return;
      }
      if (!finishedProductCode.value.trim()) {
        alert("成品编号不能为空,请输入后再提交!");
        return;
      }
      try {
        const submitData = {
          toolingBoardNo: toolingBoardNo.value.trim(),
          finishedProductCode: finishedProductCode.value.trim(),
          partsList: rightPartCodes.value.map((item) => item.trim()),
        };
        console.log("✅ æäº¤å·¥è£…板数据:", submitData);
        const response = await axios.post(
          "/api/boxingDetail/SaveToolingBoardNo",
          submitData,
          { timeout: 5000 }
        );
        const resData = response.data;
        const isSuccess = resData.Status === true || resData.status === true;
        if (isSuccess) {
          alert("✅ æäº¤æˆåŠŸï¼");
          toolingBoardNo.value = "";
          finishedProductCode.value = "";
          rightPartCodes.value = Array(10).fill("");
          rightTopInput.value = "";
          fillIndex.value = -1;
          // âœ… æäº¤æˆåŠŸåŽï¼Œé‡ç½®æäº¤é”
          submitLock.value = false;
        } else {
          alert("提交失败:" + (resData.Message || resData.message || "未知错误"));
        }
      } catch (error) {
        alert("提交请求失败,请检查网络或接口!");
        console.error("提交接口失败:", error);
        // âœ… è¯·æ±‚失败也重置锁
        submitLock.value = false;
      }
    };
    // âœ… âœ… âœ… æ ¸å¿ƒå‡çº§ï¼šè‡ªåŠ¨æäº¤åˆ¤æ–­é€»è¾‘ - æ–°å¢žæ— å‹¾é€‰æ—¶æˆå“ç¼–号填充即提交
    const checkAutoSubmit = () => {
      // é˜²æŠ–:防止短时间内多次触发提交
      if (autoSubmitDebounceTimer) clearTimeout(autoSubmitDebounceTimer);
      autoSubmitDebounceTimer = setTimeout(() => {
        const needCheckNum = checkedCount.value; // å·¦ä¾§å‹¾é€‰çš„æ•°é‡
        const filledNum = filledPartCount.value; // å³ä¾§å¡«å……的零件数量
        const hasBoardNo = toolingBoardNo.value.trim() !== ""; // å·¥è£…板有值
        const hasProductCode = finishedProductCode.value.trim() !== ""; // æˆå“æœ‰å€¼
        console.log(`✅ è‡ªåŠ¨æäº¤æ ¡éªŒï¼šå·¦ä¾§å‹¾é€‰${needCheckNum}个,右侧填充${filledNum}个`);
        // åˆ†æ”¯1:左侧有勾选 â†’ åŽŸæœ‰é€»è¾‘ï¼šé›¶ä»¶å¡«å……æ•°â‰¥å‹¾é€‰æ•° æ‰æäº¤
        if (needCheckNum > 0) {
          if (hasBoardNo && hasProductCode && filledNum >= needCheckNum) {
            console.log("✅ æ»¡è¶³å‹¾é€‰æ•°é‡æ¡ä»¶ï¼Œæ‰§è¡Œè‡ªåŠ¨æäº¤ï¼");
            saveToolingBoardNo();
          }
        }
        // åˆ†æ”¯2:左侧无勾选 â†’ æ–°å¢žé€»è¾‘:工装板+成品都有值 å°±æäº¤ (加锁防重复)
        else {
          if (hasBoardNo && hasProductCode && !submitLock.value) {
            console.log("✅ å·¦ä¾§æ— å‹¾é€‰ï¼Œæˆå“ç¼–号填充完成,执行自动提交!");
            submitLock.value = true; // åŠ é”é˜²æ­¢é‡å¤æäº¤
            saveToolingBoardNo();
          }
        }
        autoSubmitDebounceTimer = null;
      }, 300);
    };
    // âœ… âœ… âœ… æ ¸å¿ƒæ–°å¢ž4:监听关键数据变化,触发自动提交校验
    watch(
      [checkedCount, filledPartCount, toolingBoardNo, finishedProductCode],
      () => {
        checkAutoSubmit();
      },
      { deep: true, immediate: false }
    );
    // è‡ªåŠ¨æ£€æµ‹å¡«å……ç´¢å¼•é€»è¾‘
    const detectFillIndex = () => {
      if (!toolingBoardNo.value.trim() || !finishedProductCode.value.trim()) {
        fillIndex.value = -1;
        return;
      }
      for (let i = 0; i < 10; i++) {
        if (!rightPartCodes.value[i].trim()) {
          fillIndex.value = i;
          return;
        }
      }
      fillIndex.value = 10;
    };
    watch(
      [toolingBoardNo, finishedProductCode, () => [...rightPartCodes.value]],
      detectFillIndex,
      {
        immediate: true,
        deep: true,
      }
    );
    // é¡µé¢æŒ‚è½½/卸载生命周期
    onMounted(async () => {
      await fetchLeftInitialData();
      startPolling();
      detectFillIndex();
    });
    onUnmounted(() => {
      stopPolling();
      if (checkDebounceTimer) clearTimeout(checkDebounceTimer);
      if (destroyDelayTimer) clearTimeout(destroyDelayTimer);
      if (boardCodeDebounceTimer) clearTimeout(boardCodeDebounceTimer);
      if (autoSubmitDebounceTimer) clearTimeout(autoSubmitDebounceTimer);
    });
    return {
      finishedProduct,
      finishedProductId,
      rightTopInput,
      leftPartCodes,
      rightPartCodes,
      leftPartChecked,
      leftPartIds,
      toolingBoardNo,
      isPLCStarted,
      isPLCPaused,
      signalStates,
      signalLabels,
      finishedProductCode,
      handleToggle,
      handlePauseToggle,
      handlePartCheck,
      clearToolingBoardNo,
      saveToolingBoardNo,
      clearRightPart,
      clearFinishedProductCode,
    };
  },
};
</script>
<style scoped>
.title {
  line-height: 70vh;
/* åŸºç¡€æ ·å¼é‡ç½®ä¸Žå…¨å±€æ ·å¼ */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Microsoft Yahei", "PingFang SC", "Inter", sans-serif;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
*::-webkit-scrollbar {
  display: none;
}
body {
  background: linear-gradient(135deg, #f0f4f8 0%, #e9ecef 100%);
  min-height: 100vh;
  overflow: hidden;
  font-size: 14px;
}
/* å®¹å™¨æ ·å¼ - æ”¾å¤§ é—´è·åР宽 */
.container {
  display: flex;
  width: 100%;
  height: 100vh;
  margin: 0;
  gap: 15px;
  padding: 15px;
  overflow: hidden;
}
/* é¢æ¿é€šç”¨æ ·å¼ - ç»Ÿä¸€å†…边距 ç¡®ä¿å·¦å³å¯¹é½ */
.left-area,
.right-area {
  flex: 1;
  width: 50%;
  display: flex;
  flex-direction: column;
  gap: 15px;
  padding: 18px;
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 15px;
  box-shadow: 0 6px 16px rgba(149, 157, 165, 0.15);
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
/* æŒ‰é’®+信号 æ¨ªå‘排列容器 - æ ¸å¿ƒå¸ƒå±€ */
.btn-signal-group {
  display: flex;
  align-items: center;
  gap: 20px;
  width: 100%;
}
.btn-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex-shrink: 0;
}
.signal-status {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 18px;
  flex-shrink: 0;
  padding: 0;
}
.left-top {
  background: #f8fafc;
  padding: 15px;
  border-radius: 12px;
  flex-shrink: 0;
  width: 100%;
}
.left-bottom,
.right-bottom {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
  overflow: hidden !important;
}
.right-top {
  padding: 15px;
  background: #f8fafc;
  border-radius: 12px;
  flex-shrink: 0;
}
/* è¡¨å•行样式 - ç»Ÿä¸€é«˜åº¦å’Œé—´è· ç¡®ä¿å·¦å³å¯¹é½ */
.form-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: nowrap;
  padding: 6px 10px;
  border-radius: 8px;
  transition: all 0.2s ease;
  height: 48px;
  line-height: 48px;
  flex-shrink: 0;
  width: 100%;
}
.form-row:hover {
  background: #f8fafc;
}
.finished-product-row {
  background: #eff6ff;
  border-left: 4px solid #3b82f6;
}
.tooling-board-row {
  background: #f0fdf4;
  border-left: 4px solid #22c55e;
}
.part-item {
  border-bottom: 1px solid #f1f5f9;
  margin-bottom: 3px;
}
.part-item:last-child {
  border-bottom: none;
}
/* æ ‡ç­¾æ ·å¼ - ç»Ÿä¸€å®½åº¦ ç¡®ä¿å·¦å³å¯¹é½ */
.label {
  width: 90px;
  text-align: right;
  color: #334155;
  font-size: 15px;
  font-weight: 600;
  flex-shrink: 0;
}
.short-label {
  width: 110px;
  text-align: right;
  color: #334155;
  font-size: 15px;
  font-weight: 600;
  flex-shrink: 0;
}
/* è¾“入框样式 - ç»Ÿä¸€å°ºå¯¸ ç¡®ä¿å·¦å³å¯¹é½ */
.input-box {
  flex: 1;
  min-width: 100px;
  height: 42px;
  padding: 0 15px;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  outline: none;
  font-size: 15px;
  transition: all 0.2s ease;
  background-color: #ffffff;
}
.short-input {
  width: 150px !important;
  flex: none !important;
}
.input-box:focus {
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.12);
}
.input-box:disabled {
  background-color: #f1f5f9;
  color: #64748b;
  cursor: not-allowed;
}
.input-box::placeholder {
  color: #94a3b8;
  font-size: 14px;
}
/* æŒ‰é’®æ ·å¼ - å›ºå®šå®½åº¦ ä¸å˜ */
.btn {
  width: 120px;
  height: 42px;
  padding: 0 16px;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  transition: all 0.2s ease;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  position: relative;
  overflow: hidden;
}
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}
.btn::after {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transition: all 0.5s ease;
}
.btn:hover::after {
  left: 100%;
}
/* å›¾æ ‡æ ·å¼ - å›¾æ ‡æ”¾å¤§ */
.icon {
  display: inline-block;
  width: 18px;
  height: 18px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.icon-start {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E");
}
.icon-stop {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M6 6h12v12H6z'/%3E%3C/svg%3E");
}
.icon-pause {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M6 19h4V5H6v14zm8-14v14h4V5h-4z'/%3E%3C/svg%3E");
}
.icon-resume {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M11 5L6 9H2v6h4l5 4V5zm7 0v14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2z'/%3E%3C/svg%3E");
}
.icon-clear {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E");
}
.icon-submit {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M2.01 21L15 13.4 23 21V5H2.01V21zM17 15l-5-5-5 5V7h10v8z'/%3E%3C/svg%3E");
}
/* æŒ‰é’®ç±»åž‹æ ·å¼ - ä¸å˜ */
.start-btn {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
  color: #fff;
}
.start-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(16, 185, 129, 0.2);
}
.stop-btn {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
  color: #fff;
}
.stop-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(239, 68, 68, 0.2);
}
.pause-btn {
  background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  color: #fff;
}
.pause-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(245, 158, 11, 0.2);
}
.resume-btn {
  background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
  color: #fff;
}
.resume-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(139, 92, 246, 0.2);
}
.clear-btn {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
  color: #fff;
  padding: 0 12px;
}
.clear-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(239, 68, 68, 0.15);
}
.save-btn {
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  color: #fff;
  padding: 0 12px;
}
.save-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(59, 130, 246, 0.15);
}
/* ä¿¡å·ç¯æ ·å¼ é†’目放大 */
.signal-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  min-width: 60px;
}
.signal-label {
  font-size: 14px;
  color: #334155;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
  text-align: center;
  font-size: 28px;
  color: orange;
  font-weight: 600;
}
.signal-light {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  transition: all 0.3s ease;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.signal-light-inner {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: white;
  opacity: 0.9;
  transition: all 0.3s ease;
}
.signal-active {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
  box-shadow: 0 0 18px rgba(16, 185, 129, 0.7);
  animation: pulse 2s infinite;
}
.signal-inactive {
  background: linear-gradient(135deg, #94a3b8 0%, #64748b 100%);
}
@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.8);
  }
  70% {
    box-shadow: 0 0 0 15px rgba(16, 185, 129, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
  }
}
/* è‡ªå®šä¹‰å¤é€‰æ¡†æ ·å¼ - æ”¾å¤§ ç‚¹å‡»åŒºåŸŸæ›´å¤§ */
.checkbox-container {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-size: 14px;
  color: #334155;
  flex-shrink: 0;
}
.part-checkbox {
  display: none;
}
.checkmark {
  width: 22px;
  height: 22px;
  background-color: #f1f5f9;
  border: 1px solid #cbd5e1;
  border-radius: 4px;
  transition: all 0.2s ease;
  position: relative;
}
.part-checkbox:checked ~ .checkmark {
  background-color: #3b82f6;
  border-color: #3b82f6;
}
.checkmark:after {
  content: "";
  position: absolute;
  display: none;
  left: 7px;
  top: 2px;
  width: 6px;
  height: 12px;
  border: solid white;
  border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}
.part-checkbox:checked ~ .checkmark:after {
  display: block;
}
.checkbox-label {
  font-size: 13px;
  color: #475569;
  width: 50px;
}
/* å“åº”式适配 */
@media (max-width: 1200px) {
  .container {
    flex-direction: column;
    height: auto;
  }
  .left-area,
  .right-area {
    width: 100%;
    flex: none;
  }
  .btn-signal-group {
    flex-direction: column;
    align-items: flex-start;
  }
  .signal-status {
    width: 100%;
    justify-content: flex-start;
  }
}
@media (max-width: 768px) {
  .form-row {
    flex-direction: column;
    align-items: flex-start;
    height: auto;
    line-height: normal;
  }
  .label,
  .short-label {
    width: 100%;
    text-align: left;
    margin-bottom: 6px;
  }
  .input-box {
    width: 100%;
  }
  .short-input {
    width: 100% !important;
  }
  .btn {
    width: 100%;
    margin-top: 6px;
  }
  .btn-group {
    flex-direction: column;
    gap: 10px;
    width: 100%;
  }
}
</style>
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/views/basicinfo/boxing.vue
@@ -41,22 +41,23 @@
          field: "palletCode",
          type: "input",
          width: 200,
          require: true
          link: true,
          require: true,
        },
        {
          title: "成品编号",
          field: "productCode",
          type: "input",
          width: 200,
          require: true
          require: true,
        },
        {
          title: "成品名称",
          field: "productName",
          type: "input",
          width: 200,
          require: true
        }
          require: true,
        },
      ],
      [
        {
@@ -65,9 +66,9 @@
          type: "input",
          width: 100,
          hidden: true,
          readonly: true
        }
      ]
          readonly: true,
        },
      ],
    ]);
    const searchFormFields = ref({
@@ -105,6 +106,7 @@
        field: "palletCode",
        title: "工装板编号",
        type: "string",
        link: true,
        width: 200,
        align: "left",
      },
@@ -161,11 +163,36 @@
    ]);
    const detail = ref({
      cnName: "",
      table: "",
      columns: [],
      sortName: "",
      key: "",
      cnName: "组盘详细信息",
      table: "boxingDetail",
      columns: [
        {
          field: "boxingId",
          title: "组盘ID",
          type: "int",
          width: 90,
          hidden: true,
          readonly: true,
          require: true,
          align: "left",
        },
        {
          field: "componentCode",
          title: "零件编号",
          type: "string",
          width: 200,
          align: "left",
        },
        {
          field: "componentName",
          title: "零件名称",
          type: "string",
          width: 200,
          align: "left",
        },
      ],
      sortName: "createDate",
      key: "id",
    });
    return {
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/views/basicinfo/formula.vue
@@ -53,106 +53,14 @@
          field: "productCode",
          type: "input",
          width: 200,
          require: true
          require: true,
        },
        {
          title: "成品名称",
          field: "productName",
          type: "input",
          width: 200,
          require: true
        },
        {
          title: "压装位产品长度",
          field: "productLength",
          type: "number",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "压装位产品宽度",
          field: "productWidth",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "压装位产品高度",
          field: "productHeight",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "压装位拧紧下降高度",
          field: "screwDownsetDistance",
          type: "number",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "压装位拧紧扭力",
          field: "screwTorqueOutput",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "压装位自动拧紧打开",
          field: "dintAutoScrewOn",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "检测位X偏移距离1",
          field: "xDirectionDistance1",
          type: "number",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "检测位Z高度1",
          field: "yDirectionHeight1",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "检测位X偏移距离2",
          field: "xDirectionDistance2",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "检测位Z高度2",
          field: "yDirectionHeight2",
          type: "number",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "检测位X偏移距离3",
          field: "xDirectionDistance3",
          type: "number",
          width: 200,
          require: false
        },
        {
          title: "检测位Z高度3",
          field: "yDirectionHeight3",
          type: "number",
          width: 200,
          require: false
          require: true,
        },
        {
          title: "主键ID",
@@ -160,9 +68,9 @@
          type: "input",
          width: 100,
          hidden: true,
          readonly: true
        }
      ]
          readonly: true,
        },
      ],
    ]);
    const searchFormFields = ref({
@@ -198,6 +106,7 @@
        field: "productCode",
        title: "成品编号",
        type: "string",
        link: true,
        width: 200,
        align: "left",
      },
@@ -205,90 +114,6 @@
        field: "productName",
        title: "成品名称",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "productLength",
        title: "压装位产品长度",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "productWidth",
        title: "压装位产品宽度",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "productHeight",
        title: "压装位产品高度",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "screwDownsetDistance",
        title: "压装位拧紧下降高度",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "screwTorqueOutput",
        title: "压装位拧紧扭力",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "dintAutoScrewOn",
        title: "压装位自动拧紧打开",
        type: "int",
        width: 200,
        align: "left",
      },
      {
        field: "xDirectionDistance1",
        title: "检测位X偏移距离1",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "yDirectionHeight1",
        title: "检测位Z高度1",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "xDirectionDistance2",
        title: "检测位X偏移距离2",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "yDirectionHeight2",
        title: "检测位Z高度2",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "xDirectionDistance3",
        title: "检测位X偏移距离3",
        type: "float",
        width: 200,
        align: "left",
      },
      {
        field: "yDirectionHeight3",
        title: "检测位Z高度3",
        type: "float",
        width: 200,
        align: "left",
      },
@@ -321,13 +146,50 @@
        align: "left",
      },
    ]);
    const detail = ref({
      cnName: "",
      table: "",
      columns: [],
      sortName: "",
      key: "",
      cnName: "零件详细信息",
      table: "componentDetail",
      columns: [
        {
          field: "formulaId",
          title: "ID",
          type: "int",
          width: 90,
          hidden: true,
          require: true,
          align: "left",
        },
        {
          field: "componentCode",
          title: "零件编号",
          type: "string",
          width: 120,
          require: true,
          align: "left",
        },
        {
          field: "componentName",
          title: "零件名称",
          type: "string",
          width: 150,
          require: true,
          align: "left",
        },
        {
          title: "是否扫码",
          field: "isScanned",
          type: "select",
          bind: {
            key: "value",
            data: [
              { key: "0", value: "否" },
              { key: "1", value: "是" },
            ],
          },
        },
      ],
      sortName: "createDate",
      key: "id",
    });
    return {
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/views/basicinfo/formulaDetail.vue
@@ -42,22 +42,31 @@
          field: "formulaId",
          type: "input",
          width: 200,
          require: true
          require: true,
        },
        {
          title: "零件编号",
          field: "componentCode",
          type: "input",
          width: 200,
          require: true
          require: true,
        },
        {
          title: "零件名称",
          field: "componentName",
          type: "input",
          width: 200,
          require: true
        }
          require: true,
        },
        {
          title: "是否扫码",
          field: "isScanned",
          type: "select",
          data: [
            { key: "0", value: "否" },
            { key: "1", value: "是" },
          ],
        },
      ],
      [
        {
@@ -66,9 +75,9 @@
          type: "input",
          width: 100,
          hidden: true,
          readonly: true
        }
      ]
          readonly: true,
        },
      ],
    ]);
    const searchFormFields = ref({
@@ -84,6 +93,15 @@
        { title: "配方信息主键", field: "formulaId", type: "int" },
        { title: "零件编号", field: "componentCode", type: "like" },
        { title: "零件名称", field: "componentName", type: "like" },
        {
          title: "是否扫码",
          field: "isScanned",
          type: "select",
          data: [
            { key: "0", value: "否" },
            { key: "1", value: "是" },
          ],
        },
      ],
      [
        { title: "创建人", field: "creater", type: "like" },
@@ -124,6 +142,18 @@
        align: "left",
      },
      {
        title: "是否扫码",
        field: "isScanned",
        type: "select",
        bind: {
          key: "value",
          data: [
            { key: "0", value: "否" },
            { key: "1", value: "是" },
          ],
        },
      },
      {
        field: "creater",
        title: "创建人",
        type: "string",
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/views/basicinfo/processInfoDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,176 @@
<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/basicinfo/processInfoDetail.js";
import { ref, defineComponent } from "vue";
export default defineComponent({
  setup() {
    const table = ref({
      key: "id",
      footer: "Foots",
      cnName: "加工信息详情",
      name: "processInfoDetail",
      url: "/processInfoDetail/",
      sortName: "createDate",
    });
    const editFormFields = ref({
      id: "",
      palletCode: "",
      productCode: "",
      productName: "",
    });
    const editFormOptions = ref([
      [
        {
          title: "工装板编号",
          field: "palletCode",
          type: "input",
          width: 200,
          require: true,
        },
        {
          title: "成品编号",
          field: "productCode",
          type: "input",
          width: 200,
          require: true,
        },
        {
          title: "成品名称",
          field: "productName",
          type: "input",
          width: 200,
          require: true,
        },
      ],
      [
        {
          title: "主键ID",
          field: "id",
          type: "input",
          width: 100,
          hidden: true,
          readonly: true,
        },
      ],
    ]);
    const searchFormFields = ref({
      palletCode: "",
      productCode: "",
      productName: "",
      creater: "",
      createDate: "",
    });
    const searchFormOptions = ref([
      [
        { title: "工装板编号", field: "palletCode", type: "like" },
        { title: "成品编号", field: "productCode", type: "like" },
        { title: "成品名称", field: "productName", type: "like" },
      ],
      [
        { title: "创建人", field: "creater", type: "like" },
        { title: "创建时间", field: "createDate", type: "datetime" },
      ],
    ]);
    const columns = ref([
      {
        field: "id",
        title: "序号",
        type: "int",
        width: 90,
        hidden: true,
        readonly: true,
        require: true,
        align: "left",
      },
      {
        field: "palletCode",
        title: "工装板编号",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "productCode",
        title: "成品编号",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "productName",
        title: "成品名称",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "creater",
        title: "创建人",
        type: "string",
        width: 90,
        align: "left",
      },
      {
        field: "createDate",
        title: "创建时间",
        type: "datetime",
        width: 150,
        align: "left",
      },
      {
        field: "modifier",
        title: "修改人",
        type: "string",
        width: 100,
        align: "left",
      },
      {
        field: "modifyDate",
        title: "修改时间",
        type: "datetime",
        width: 160,
        align: "left",
      },
    ]);
    const detail = ref({
      cnName: "",
      table: "",
      columns: [],
      sortName: "",
      key: "",
    });
    return {
      table,
      extend,
      editFormFields,
      editFormOptions,
      searchFormFields,
      searchFormOptions,
      columns,
      detail,
    };
  },
});
</script>
´úÂë¹ÜÀí/WIDESEAWCS_Client/src/views/basicinfo/scanStation.vue
@@ -15,10 +15,14 @@
<script>
import extend from "@/extension/basicinfo/scanStation.js";
import { ref, defineComponent } from "vue";
import { ref, defineComponent, onMounted } from "vue";
import axios from "axios";
export default defineComponent({
  setup() {
    // å…¨å±€ä¸‹æ‹‰æ•°æ®æºå˜é‡ - æ‰€æœ‰ä¸‹æ‹‰æ¡†å…±ç”¨ï¼Œä¸€å¤„赋值,三处复用
    const stationEndProductList = ref([]);
    const table = ref({
      key: "id",
      footer: "Foots",
@@ -33,17 +37,6 @@
      stationCode: "", 
      stationName: "",
      stationEndProduct: "",
      stationComponentQty: "",
      stationComponent1: "",
      stationComponent2: "",
      stationComponent3: "",
      stationComponent4: "",
      stationComponent5: "",
      stationComponent6: "",
      stationComponent7: "",
      stationComponent8: "",
      stationComponent9: "",
      stationComponent10: "",
    });
    
    const editFormOptions = ref([
@@ -53,116 +46,38 @@
          field: "stationCode",
          type: "input",
          width: 200,
          require: true
          require: true,
        },
      ],
      [
        {
          title: "站台名称",
          field: "stationName",
          type: "input",
          width: 200,
          require: true
          require: true,
        },
      ],
      [
        {
          title: "站台成品",
          field: "stationEndProduct",
          type: "input",
          type: "select",
          data: stationEndProductList, // ç»‘定全局接口数据
          width: 200,
          require: false
        }
          require: false,
        },
      ],
      [
        {
          title: "零件数量",
          field: "stationComponentQty",
          type: "input",
          width: 200,
          require: true
        },
        {
          title: "零件1",
          field: "stationComponent1",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "零件2",
          field: "stationComponent2",
          type: "input",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "零件3",
          field: "stationComponent3",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "零件4",
          field: "stationComponent4",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "零件5",
          field: "stationComponent5",
          type: "input",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "零件6",
          field: "stationComponent6",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "零件7",
          field: "stationComponent7",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "零件8",
          field: "stationComponent8",
          type: "input",
          width: 200,
          require: false
        }
      ],
      [
        {
          title: "零件9",
          field: "stationComponent9",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "零件10",
          field: "stationComponent10",
          type: "input",
          width: 200,
          require: false
        },
        {
          title: "主键ID",
          field: "id",
          type: "input",
          width: 100,
          hidden: true,
          readonly: true
        }
      ]
          readonly: true,
        },
      ],
    ]);
    const searchFormFields = ref({
@@ -177,7 +92,12 @@
      [
        { title: "站台编号", field: "stationCode", type: "like" },
        { title: "站台名称", field: "stationName", type: "like" },
        { title: "站台成品", field: "stationEndProduct", type: "like" },
        {
          title: "站台成品",
          field: "stationEndProduct",
          type: "select-search",
          data: stationEndProductList, // ç»‘定全局接口数据
        },
      ],
      [
        { title: "创建人", field: "creater", type: "like" },
@@ -213,84 +133,12 @@
      {
        field: "stationEndProduct",
        title: "站台成品",
        type: "string",
        width: 200,
        align: "left",
        type: "select",
        bind: {
          key: "value",
          data: stationEndProductList, // ç»‘定全局接口数据
      },
      {
        field: "stationComponentQty",
        title: "零件数量",
        type: "int",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent1",
        title: "零件1",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent2",
        title: "零件2",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent3",
        title: "零件3",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent4",
        title: "零件4",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent5",
        title: "零件5",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent6",
        title: "零件6",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent7",
        title: "零件7",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent8",
        title: "零件8",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent9",
        title: "零件9",
        type: "string",
        width: 200,
        align: "left",
      },
      {
        field: "stationComponent10",
        title: "零件10",
        type: "string",
        link: true,
        width: 200,
        align: "left",
      },
@@ -332,6 +180,22 @@
      key: "",
    });
    const getStationEndProductData = async () => {
      try {
        const res = await axios.get("/api/formula/getEndProductList");
        stationEndProductList.value = (res.data?.data || []).map(
          (item) => item || { key: "", value: "", disabled: false }
        );
      } catch (error) {
        stationEndProductList.value = [];
        console.error("获取站台成品数据失败:", error);
      }
    };
    onMounted(() => {
      getStationEndProductData();
    });
    return {
      table,
      extend,
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/CodeChunks.db
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/SemanticSymbols.db
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/SemanticSymbols.db-shm
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.12.53.23981/SemanticSymbols.db-wal
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/CodeChunks.db
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/CodeChunks.db-shm
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/CodeChunks.db-wal
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/SemanticSymbols.db
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/SemanticSymbols.db-shm
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.1518.61961/SemanticSymbols.db-wal
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.794.21998/CodeChunks.db
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.14.794.21998/SemanticSymbols.db
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/DesignTimeBuild/.dtbcache.v2
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/0f5d7584-9cfe-4074-aeb3-fa1f9e570949.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/37cbdcf3-408e-4196-9c7f-486ef5eef107.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/5d2c31e8-d7a5-4453-ab25-eb41469b50b2.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/6b8b6a38-d1b1-459e-b415-f709208d542a.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/6ed546f4-fadb-4993-bf10-0046de75bd74.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/7765cc9c-7efa-493e-8c24-c5cc86a879de.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/8803666d-3cb0-4d8e-9882-52f506e51b7a.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/a92150fa-07f2-4b35-842d-8af5d93da741.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/c99954ff-673f-45d7-b93b-30e6c1adfe58.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/db45f673-18a0-4069-a270-036150636661.vsidx
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/.futdcache.v2
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/.suo
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/BoxingDetailService.cs
@@ -1,22 +1,40 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
{
    public class BoxingDetailService : ServiceBase<Dt_BoxingDetail, IRepository<Dt_BoxingDetail>>, IBoxingDetailService
    {
        public BoxingDetailService(IRepository<Dt_BoxingDetail> BaseDal) : base(BaseDal)
        private readonly IBoxingService _boxingService;
        private readonly IFormulaService _formulaService;
        private readonly IFormulaDetailService _formulaDetailService;
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public BoxingDetailService(
            IRepository<Dt_BoxingDetail> BaseDal,
            IFormulaService formulaService,
            IBoxingService boxingService,
            IFormulaDetailService formulaDetailService,
            IUnitOfWorkManage unitOfWorkManage
            ) : base(BaseDal)
        {
            _formulaService = formulaService;
            _boxingService = boxingService;
            _formulaDetailService = formulaDetailService;
            _unitOfWorkManage = unitOfWorkManage;
        }
        public IRepository<Dt_BoxingDetail> Repository => BaseDal;
        /// <summary>
        /// æ¯”较零件是否齐全
@@ -30,26 +48,249 @@
            {
                return false;
            }
            List<string> BoxingIdList = new List<string>();
            List<string> FormulaIdList = new List<string>();
            for (int i = 0; i < boxingDetails.Count; i++)
            {
                BoxingIdList.Add(boxingDetails[i].ComponentCode);
                FormulaIdList.Add(formulaDetails[i].ComponentCode);
            List<string> BoxingIdList = boxingDetails.Select(x => x.ComponentCode).ToList();
            List<string> FormulaIdList = formulaDetails.Select(x => x.ComponentCode).ToList();
            return !BoxingIdList.Except(FormulaIdList).Any() && !FormulaIdList.Except(BoxingIdList).Any();
            }
            BoxingIdList.Sort();
            FormulaIdList.Sort();
            for (int i = 0; i < BoxingIdList.Count; i++)
        /// <summary>
        /// æ£€æŸ¥é›¶ä»¶
        /// </summary>
        /// <param name="boxingDetails"></param>
        /// <param name="formulaDetails"></param>
        /// <returns></returns>
        public string IsComponentCodesEqual(List<string> boxingDetails, List<string> formulaDetails)
            {
                if (BoxingIdList[i] != FormulaIdList[i])
            // å¤„理null集合,规避空指针异常
            var boxList = boxingDetails ?? new List<string>();
            var formulaList = formulaDetails ?? new List<string>();
            var validBoxCodes = boxList.Where(code => !string.IsNullOrEmpty(code)).ToList();
            var validFormulaCodes = formulaList.Where(code => !string.IsNullOrEmpty(code)).ToList();
            foreach (var group in validBoxCodes.GroupBy(code => code))
                {
                    return false;
                string componentCode = group.Key;
                int boxCount = group.Count();
                int formulaCount = validFormulaCodes.Count(code => code == componentCode);
                if (formulaCount == 0 || formulaCount < boxCount)
                {
                    return componentCode;
                }
            }
            return true;
            return null;
        }
        /// <summary>
        /// æ·»åŠ /修改组盘信息(一体化接口:传工装板编号存在则修改,不存在则新增)
        /// </summary>
        /// <param name="toolingBoardSubmitDto"></param>
        /// <returns></returns>
        public WebResponseContent SaveToolingBoardNo(ToolingBoardSubmitDto toolingBoardSubmitDto)
        {
            using (var uow = _unitOfWorkManage.CreateUnitOfWork())
            {
                try
                {
                    // 1. å‚数校验
                    if (toolingBoardSubmitDto == null)
                    {
                        return WebResponseContent.Instance.Error("提交参数不能为空");
                    }
                    string palletCode = toolingBoardSubmitDto.ToolingBoardNo?.Trim();
                    string productCode = toolingBoardSubmitDto.FinishedProductCode?.Trim();
                    if (string.IsNullOrWhiteSpace(palletCode))
                    {
                        return WebResponseContent.Instance.Error("工装板编号不能为空");
                    }
                    if (string.IsNullOrWhiteSpace(productCode))
                    {
                        return WebResponseContent.Instance.Error("成品编码不能为空");
                    }
                    // 2. æŸ¥è¯¢æˆå“é…æ–¹ä¿¡æ¯
                    Dt_Formula formulaModel = _formulaService.Repository.QueryFirst(x => x.ProductCode == productCode);
                    if (formulaModel == null)
                    {
                        return WebResponseContent.Instance.Error("无成品配方,请核对成品编码");
                    }
                    List<Dt_FormulaDetail> dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == formulaModel.Id && x.IsScanned == 1);
                    List<string> Codelist = dt_FormulaDetails.Select(x => x.ComponentCode).ToList();
                    string IsCode = IsComponentCodesEqual(toolingBoardSubmitDto.PartsList, Codelist);
                    if (IsCode != null)
                    {
                        return WebResponseContent.Instance.Error($"物料【{IsCode}】错误,请核对物料编号");
                    }
                    // 3. æ ¸å¿ƒåˆ¤æ–­ï¼šæ ¹æ®å·¥è£…板编号查询是否存在【新增/修改】的主表数据
                    Dt_Boxing existBoxinModel = _boxingService.Repository.QueryFirst(x => x.PalletCode == palletCode);
                    if (existBoxinModel == null)
                    {
                        #region æ–°å¢žé€»è¾‘ - åŽŸé€»è¾‘ä¼˜åŒ–ç‰ˆ
                        Dt_Boxing dt_boxin = new Dt_Boxing()
                        {
                            PalletCode = palletCode,
                            ProductCode = productCode,
                            ProductName = formulaModel.ProductName.Trim(),
                            Creater = "admin",
                            CreateDate = DateTime.Now
                        };
                        int newBoxingId = _boxingService.Repository.AddData(dt_boxin);
                        // æ‰¹é‡æ·»åŠ æ˜Žç»†è¡¨æ•°æ®
                        if (toolingBoardSubmitDto.PartsList != null && toolingBoardSubmitDto.PartsList.Count > 0)
                        {
                            List<Dt_BoxingDetail> detailList = new List<Dt_BoxingDetail>();
                            foreach (string ComponentCode in toolingBoardSubmitDto.PartsList)
                            {
                                if (string.IsNullOrWhiteSpace(ComponentCode)) continue;
                                string ComponentCodeTrim = ComponentCode.Trim();
                                Dt_FormulaDetail formulaDetail = _formulaDetailService.Repository.QueryFirst(x => x.FormulaId == formulaModel.Id && x.ComponentCode == ComponentCodeTrim);
                                if (formulaDetail == null)
                                {
                                    return WebResponseContent.Instance.Error($"配方中无此物料【{ComponentCodeTrim}】,请核对物料编号");
                                }
                                Dt_BoxingDetail detailModel = new Dt_BoxingDetail()
                                {
                                    BoxingId = newBoxingId,
                                    ComponentCode = ComponentCodeTrim,
                                    ComponentName = formulaDetail.ComponentName,
                                    Creater = "admin",
                                    CreateDate = DateTime.Now
                                };
                                detailList.Add(detailModel);
                            }
                            if (detailList.Count > 0)
                            {
                                BaseDal.AddData(detailList);
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        #region ä¿®æ”¹é€»è¾‘ - æ–°å¢žæ ¸å¿ƒé€»è¾‘
                        // 1. æ›´æ–°ä¸»è¡¨æ•°æ®
                        existBoxinModel.ProductCode = productCode;
                        existBoxinModel.ProductName = formulaModel.ProductName.Trim();
                         existBoxinModel.Modifier = "admin";
                        existBoxinModel.ModifyDate = DateTime.Now;
                        _boxingService.Repository.UpdateData(existBoxinModel);
                        int boxingId = existBoxinModel.Id;
                        // 2. åˆ é™¤è¯¥ç»„盘下的【原有全部明细表数据】
                        List<Dt_BoxingDetail> oldDetailList = BaseDal.QueryData(x => x.BoxingId == boxingId);
                        if (oldDetailList != null && oldDetailList.Count > 0)
                        {
                            BaseDal.DeleteData(oldDetailList);
                        }
                        // 3. é‡æ–°æ’入修改后的明细表数据
                        if (toolingBoardSubmitDto.PartsList != null && toolingBoardSubmitDto.PartsList.Count > 0)
                        {
                            List<Dt_BoxingDetail> detailList = new List<Dt_BoxingDetail>();
                            foreach (string ComponentCode in toolingBoardSubmitDto.PartsList)
                            {
                                if (string.IsNullOrWhiteSpace(ComponentCode)) continue;
                                string ComponentCodeTrim = ComponentCode.Trim();
                                Dt_FormulaDetail formulaDetail = _formulaDetailService.Repository.QueryFirst(x => x.FormulaId == formulaModel.Id && x.ComponentCode == ComponentCodeTrim);
                                if (formulaDetail == null)
                                {
                                    return WebResponseContent.Instance.Error($"配方中无此物料【{ComponentCodeTrim}】,请核对物料名称");
                                }
                                Dt_BoxingDetail detailModel = new Dt_BoxingDetail()
                                {
                                    BoxingId = boxingId,
                                    ComponentCode = ComponentCodeTrim,
                                    ComponentName = formulaDetail.ComponentName,
                                    Creater = "admin",
                                    CreateDate = DateTime.Now
                                };
                                detailList.Add(detailModel);
                            }
                            if (detailList.Count > 0)
                            {
                                BaseDal.AddData(detailList);
                            }
                        }
                        #endregion
                    }
                    uow.Commit();
                    string msg = existBoxinModel == null ? "组盘信息新增成功!" : "组盘信息修改成功!";
                    return WebResponseContent.Instance.OK(msg);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"保存工装板组盘信息异常:{ex.Message},堆栈:{ex.StackTrace}");
                    return WebResponseContent.Instance.Error($"提交失败:{ex.Message}");
                }
            }
        }
        /// <summary>
        /// èŽ·å–æˆå“ç¼–å·å’Œé›¶ä»¶ç¼–å·
        /// </summary>
        /// <param name="palletCode"></param>
        /// <returns></returns>
        public WebResponseContent GetProductAndPartsByBoardNo(string palletCode)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(palletCode))
                {
                    return WebResponseContent.Instance.OK("查询成功", new
                    {
                        finishedProductCode = "",
                        partsList = Enumerable.Repeat("", 10).ToList()
                    });
                }
                Dt_Boxing dt_Boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == palletCode);
                if (dt_Boxing == null)
                {
                    return WebResponseContent.Instance.OK("未查询到该工装板对应的成品信息", new
                    {
                        finishedProductCode = "",
                        partsList = Enumerable.Repeat("", 10).ToList()
                    });
                }
                List<Dt_BoxingDetail> dt_BoxingDetails = BaseDal.QueryData(x => x.BoxingId == dt_Boxing.Id)?.ToList() ?? new List<Dt_BoxingDetail>();
                // å–零件编号
                List<string> partsList = dt_BoxingDetails.Select(d => d.ComponentCode).ToList();
                List<string> resultPartsList = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                    if (i < partsList.Count)
                    {
                        resultPartsList.Add(partsList[i] ?? "");
                    }
                    else
                    {
                        resultPartsList.Add("");
                    }
                }
                return WebResponseContent.Instance.OK("零件编号列表查询成功", new
                {
                    finishedProductCode = dt_Boxing.ProductCode ?? "",
                    partsList = resultPartsList
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询零件编号列表异常:{ex.Message}");
            }
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/FormulaDetailService.cs
@@ -3,8 +3,10 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
@@ -16,5 +18,9 @@
        }
        public IRepository<Dt_FormulaDetail> Repository => BaseDal;
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/FormulaService.cs
@@ -31,18 +31,18 @@
                Id = saveModel.MainData["id"].ObjToInt(),
                ProductCode = saveModel.MainData["productCode"].ToString(),
                ProductName = saveModel.MainData["productName"].ToString(),
                ProductLength = float.Parse(saveModel.MainData["productLength"].ToString()),
                ProductWidth = float.Parse(saveModel.MainData["productWidth"].ToString()),
                ProductHeight = float.Parse(saveModel.MainData["productHeight"].ToString()),
                ScrewDownsetDistance = float.Parse(saveModel.MainData["screwDownsetDistance"].ToString()),
                ScrewTorqueOutput = float.Parse(saveModel.MainData["screwTorqueOutput"].ToString()),
                ProductLength = decimal.Parse(saveModel.MainData["productLength"].ToString()),
                ProductWidth = decimal.Parse(saveModel.MainData["productWidth"].ToString()),
                ProductHeight = decimal.Parse(saveModel.MainData["productHeight"].ToString()),
                ScrewDownsetDistance = decimal.Parse(saveModel.MainData["screwDownsetDistance"].ToString()),
                ScrewTorqueOutput = decimal.Parse(saveModel.MainData["screwTorqueOutput"].ToString()),
                DintAutoScrewOn = saveModel.MainData["dintAutoScrewOn"].ObjToInt(),
                XDirectionDistance1 = float.Parse(saveModel.MainData["xDirectionDistance1"].ToString()),
                YDirectionHeight1 = float.Parse(saveModel.MainData["yDirectionHeight1"].ToString()),
                XDirectionDistance2 = float.Parse(saveModel.MainData["xDirectionDistance2"].ToString()),
                YDirectionHeight2 = float.Parse(saveModel.MainData["yDirectionHeight2"].ToString()),
                XDirectionDistance3 = float.Parse(saveModel.MainData["xDirectionDistance3"].ToString()),
                YDirectionHeight3 = float.Parse(saveModel.MainData["yDirectionHeight3"].ToString())
                XDirectionDistance1 = decimal.Parse(saveModel.MainData["xDirectionDistance1"].ToString()),
                YDirectionHeight1 = decimal.Parse(saveModel.MainData["yDirectionHeight1"].ToString()),
                XDirectionDistance2 = decimal.Parse(saveModel.MainData["xDirectionDistance2"].ToString()),
                YDirectionHeight2 = decimal.Parse(saveModel.MainData["yDirectionHeight2"].ToString()),
                XDirectionDistance3 = decimal.Parse(saveModel.MainData["xDirectionDistance3"].ToString()),
                YDirectionHeight3 = decimal.Parse(saveModel.MainData["yDirectionHeight3"].ToString())
                //ScrewTorque = float.Parse(saveModel.MainData["ScrewTorque"].ToString()),
                //UpdateBy = saveModel.UpdateBy,
@@ -56,5 +56,28 @@
        {
            return base.UpdateData(entity);
        }
        /// <summary>
        /// èŽ·å–ç«™å°æˆå“
        /// </summary>
        /// <returns></returns>
        public WebResponseContent getEndProductList()
        {
            try
            {
                List<Dt_Formula> dt_Formulas = BaseDal.QueryData(x => 1 == 1);
                var resultList = dt_Formulas.Select(item => new
                {
                    key = item.ProductCode,
                    value = item.ProductCode
                }).ToList();
                return WebResponseContent.Instance.OK("查询站台成品成功", resultList);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询站台成品失败:{ex.Message}");
            }
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ProcessInfoDetailService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_IBasicInfoService;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
{
    public class ProcessInfoDetailService : ServiceBase<Dt_ProcessInfoDetail, IRepository<Dt_ProcessInfoDetail>>, IProcessInfoDetailService
    {
        public ProcessInfoDetailService(IRepository<Dt_ProcessInfoDetail> BaseDal) : base(BaseDal)
        {
        }
        public IRepository<Dt_ProcessInfoDetail> Repository => BaseDal;
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ProcessInfoService.cs
@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OfficeOpenXml;
using Spire.Xls;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
@@ -16,5 +15,41 @@
        }
        public IRepository<Dt_ProcessInfo> Repository => BaseDal;
        /// <summary>
        /// ä¸‹è½½æµç¨‹å¡
        /// </summary>
        /// <param name="dt_ProcessInfo"></param>
        /// <returns></returns>
        public WebResponseContent ExportData(Dt_ProcessInfo dt_ProcessInfo)
        {
                string fileName = $"{DateTime.Now.ToString("yyyyMMddHHssmm")}.xlsx";
                string templatePath = $"{AppDomain.CurrentDomain.BaseDirectory}ExprotTemplate\\发电机弹性支撑信息化流程卡.xlsx";//模板路径
                string savePath = $"{AppDomain.CurrentDomain.BaseDirectory}Download\\{fileName}";//保存文件路径
                using Stream templateStream = new FileStream(templatePath, FileMode.Open);
                using Stream saveStream = new FileStream(savePath, FileMode.Create);
                using ExcelPackage package = new ExcelPackage(saveStream, templateStream);
                ExcelWorksheet worksheet = package.Workbook.Worksheets["流程卡"];
                worksheet.Cells[3, 5].Value = dt_ProcessInfo.ProductCode;//成品编号
                package.Save();
                string pdfFileName = $"{DateTime.Now.ToString("yyyyMMddHHssmm")}.pdf";
                string pdfPath = $"{AppDomain.CurrentDomain.BaseDirectory}Download\\{pdfFileName}";
                Workbook workbook = new Workbook();
                workbook.LoadFromFile(savePath);
                // è½¬æ¢ç¬¬ä¸€ä¸ªå·¥ä½œè¡¨åˆ°PDF
                workbook.SaveToFile(pdfPath, FileFormat.PDF);
                return WebResponseContent.Instance.OK(data: new { path = pdfPath, fileName = pdfFileName });
            }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ScanStationService.cs
@@ -1,20 +1,224 @@
using System;
using Autofac.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Common.PLCEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_BasicInfoService
{
    public class ScanStationService : ServiceBase<Dt_ScanStation, IRepository<Dt_ScanStation>>, IScanStationService
    {
        public ScanStationService(IRepository<Dt_ScanStation> BaseDal) : base(BaseDal)
        private readonly IFormulaService _formulaService;
        private readonly IFormulaDetailService _formulaDetailService;
        public ScanStationService(IRepository<Dt_ScanStation> BaseDal,
            IFormulaService formulaService,
            IFormulaDetailService formulaDetailService
            ) : base(BaseDal)
        {
            _formulaService = formulaService;
            _formulaDetailService = formulaDetailService;
        }
        public IRepository<Dt_ScanStation> Repository => BaseDal;
        /// <summary>
        /// å¯åЍPLC
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        /// <summary>
        public WebResponseContent StartPLC(bool isStop)
        {
            try
            {
                OtherDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceName == "主控PLC") as OtherDevice;
                if (device == null) throw new Exception("未找到主控PLC设备信息");
                if (!device.IsConnected) throw new Exception($"主控PLC设备通讯异常");
                if (isStop)
                {
                    device.SetValue(W_PLCDBName.wboolAutoStart, false);
                    //暂停信号
                    device.SetValue(W_PLCDBName.wboolAutoPause, false);
                    return WebResponseContent.Instance.OK();
                }
                var Heart = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolHeart);
                var EMG = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolEMG);
                var OnlineExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolOnlineExecuting);
                var Error = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolError);
                if (Heart && !EMG && OnlineExecuting && !Error)
                {
                    device.SetValue(W_PLCDBName.wboolAutoStart, true);
                    //暂停信号
                    device.SetValue(W_PLCDBName.wboolAutoPause, false);
                    return WebResponseContent.Instance.OK();
                }
                return WebResponseContent.Instance.Error("设备不是在线状态");
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// æš‚停/恢复PLC(双向控制)
        /// </summary>
        /// <param name="isPause">是否为暂停操作:true=暂停,false=恢复</param>
        /// <returns>统一格式的响应结果</returns>
        public WebResponseContent PausePLC(bool isPause)
        {
            try
            {
                OtherDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceName == "主控PLC") as OtherDevice;
                if (device == null) throw new Exception("未找到主控PLC设备信息");
                if (!device.IsConnected) throw new Exception($"主控PLC设备通讯异常");
                var Heart = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolHeart);
                var EMG = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolEMG);
                var Error = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolError);
                if(!device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolAutoStart))
                {
                    return WebResponseContent.Instance.Error("设备未启动");
                }
                if (!Heart || EMG || Error)
                {
                    return WebResponseContent.Instance.Error("设备状态异常,无法执行暂停/恢复操作");
                }
                device.SetValue(W_PLCDBName.wboolAutoPause, isPause);
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// è¿”回信号
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public WebResponseContent GetSignalStates()
        {
            OtherDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceName == "主控PLC") as OtherDevice;
            if (device == null) throw new Exception("未找到主控PLC设备信息");
            if (!device.IsConnected) throw new Exception($"主控PLC设备通讯异常");
            //获取信号灯状态
            var Heart = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolHeart);
            var EMG = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolEMG);
            var AutoExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolAutoExecuting);
            var OnlineExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolOnlineExecuting);
            var Error = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolError);
            //获取启动暂停状态
            var IsStarted = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolAutoStart);
            var IsPaused = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolAutoPause);
            //返回对象
            var responseData = new
            {
                // ä¿¡å·ç¯çŠ¶æ€æ•°ç»„ï¼ˆä¿æŒåŽŸæœ‰é¡ºåºï¼‰
                signalStates = new bool[] { Heart, EMG, AutoExecuting, OnlineExecuting, Error },
                // PLC启动/暂停状态对象
                plcStatus = new
                {
                    isStarted = IsStarted,
                    isPaused = IsPaused
                }
            };
            return WebResponseContent.Instance.OK(data: responseData);
        }
        /// <summary>
        /// èŽ·å–æˆå“ä¿¡æ¯
        /// </summary>
        /// <returns></returns>
        public WebResponseContent GetLeftInitialData()
        {
            try
            {
                Dt_ScanStation dt_ScanStation = BaseDal.QueryFirst(x => x.StationCode == "001");
                if (dt_ScanStation == null)
                {
                    return WebResponseContent.Instance.Error("未找到工位编码为001的工位信息");
                }
                Dt_Formula dt_Formula = _formulaService.Repository.QueryFirst(x => x.ProductCode == dt_ScanStation.StationEndProduct);
                if (dt_Formula == null)
                {
                    return WebResponseContent.Instance.Error($"未找到成品编号【{dt_ScanStation.StationEndProduct}】对应的配方信息");
                }
                List<Dt_FormulaDetail> dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == dt_Formula.Id);
                var responseData = new
                {
                    finishedProductId = dt_Formula.Id,
                    finishedProduct = dt_Formula.ProductCode,
                    leftPartCodes = new List<string>(),
                    leftPartIds = new List<int>(),
                    leftPartChecked = new List<int>()
                };
                foreach (var detail in dt_FormulaDetails.Take(10))
                {
                    responseData.leftPartCodes.Add(detail.ComponentCode ?? "");
                    responseData.leftPartIds.Add(detail.Id);
                    responseData.leftPartChecked.Add(detail.IsScanned);
                }
                int needFillCount = 10 - responseData.leftPartCodes.Count;
                for (int i = 0; i < needFillCount; i++)
                {
                    responseData.leftPartCodes.Add("");
                    responseData.leftPartIds.Add(0);
                    responseData.leftPartChecked.Add(0);
                }
                return WebResponseContent.Instance.OK("获取左侧初始数据成功", responseData);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"获取左侧初始数据失败,请稍后重试【{ex.Message}】");
            }
        }
        /// <summary>
        /// æ›´æ–°æ˜¯å¦æ‰«ç 
        /// </summary>
        /// <param name="updatePartScannedStatusRequest"></param>
        /// <returns></returns>
        public WebResponseContent UpdatePartScannedStatus(UpdatePartScannedStatusRequest updatePartScannedStatusRequest)
        {
            try
            {
                Dt_FormulaDetail dt_FormulaDetail = _formulaDetailService.Repository.QueryFirst(x => x.Id == updatePartScannedStatusRequest.Id);
                dt_FormulaDetail.IsScanned = updatePartScannedStatusRequest.IsScanned;
                bool flag = _formulaDetailService.Repository.UpdateData(dt_FormulaDetail);
                if (flag)
                {
                    return WebResponseContent.Instance.OK();
                }
                return WebResponseContent.Instance.Error("更新错误");
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error("获取数据失败");
            }
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/WIDESEAWCS_BasicInfoService.csproj
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
@@ -7,11 +7,17 @@
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="WIDESEAWCS_QuartzJob" Version="1.0.0" />
    <PackageReference Include="WIDESEAWCS_QuartzJob" Version="3.0.11" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEAWCS_IBasicInfoService\WIDESEAWCS_IBasicInfoService.csproj" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="Spire.XLS">
      <HintPath>Spire.XLS.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Common/PLCEnum/R_PLCDBName.cs
ÎļþÃû´Ó ´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/R_PLCDBName.cs ÐÞ¸Ä
@@ -4,7 +4,7 @@
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Tasks
namespace WIDESEAWCS_Common.PLCEnum
{
    public enum R_PLCDBName
    {
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Common/PLCEnum/W_PLCDBName.cs
ÎļþÃû´Ó ´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/W_PLCDBName.cs ÐÞ¸Ä
@@ -4,7 +4,7 @@
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Tasks
namespace WIDESEAWCS_Common.PLCEnum
{
    public enum W_PLCDBName
    {
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_DTO/BasicInfo/ToolingBoardSubmitDto.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_DTO.BasicInfo
{
    public class ToolingBoardSubmitDto
    {
        /// <summary>
        /// å·¥è£…板编号 (必填)
        /// </summary>
        public string ToolingBoardNo { get; set; }
        /// <summary>
        /// æˆå“ç¼–号 (必填)
        /// </summary>
        public string FinishedProductCode { get; set; }
        /// <summary>
        /// é›¶ä»¶åˆ—表(固定10个,对应零件1~零件10,空则传空字符串)
        /// </summary>
        public List<string> PartsList { get; set; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_DTO/BasicInfo/UpdatePartScannedStatusRequest.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_DTO.BasicInfo
{
    public class UpdatePartScannedStatusRequest
    {
        /// <summary>
        /// é›¶ä»¶æ•°æ®åº“主键ID
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// æ˜¯å¦æ‰«ç 
        /// </summary>
        public int IsScanned { get; set; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IBoxingDetailService.cs
@@ -3,8 +3,10 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
@@ -15,5 +17,10 @@
        //比较零件是否齐全
        public bool IsComponentCodesEqual(List<Dt_BoxingDetail> boxingDetails, List<Dt_FormulaDetail> formulaDetails);
        //添加组盘信息
        public WebResponseContent SaveToolingBoardNo(ToolingBoardSubmitDto toolingBoardSubmitDto);
        //获取成品编号和零件
        public WebResponseContent GetProductAndPartsByBoardNo(string palletCode);
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IFormulaDetailService.cs
@@ -13,4 +13,11 @@
    {
        public IRepository<Dt_FormulaDetail> Repository { get; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IFormulaService.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Model.Models;
@@ -12,5 +13,8 @@
    public interface IFormulaService : IService<Dt_Formula>
    {
        public IRepository<Dt_Formula> Repository { get; }
        //获取站台成品
        public WebResponseContent getEndProductList();
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IProcessInfoDetailService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_IBasicInfoService
{
    public interface IProcessInfoDetailService : IService<Dt_ProcessInfoDetail>
    {
        public IRepository<Dt_ProcessInfoDetail> Repository { get; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IProcessInfoService.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Model.Models;
@@ -12,5 +13,8 @@
    public interface IProcessInfoService : IService<Dt_ProcessInfo>
    {
        public IRepository<Dt_ProcessInfo> Repository { get; }
        // ä¸‹è½½æµç¨‹å¡
        public WebResponseContent ExportData(Dt_ProcessInfo dt_ProcessInfo);
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IScanStationService.cs
@@ -3,8 +3,10 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
@@ -12,5 +14,19 @@
    public interface IScanStationService : IService<Dt_ScanStation>
    {
        public IRepository<Dt_ScanStation> Repository { get; }
        //启动PLC
        public WebResponseContent StartPLC(bool isStop);
        //暂停PLC
        public WebResponseContent PausePLC(bool isPause);
        //返回信号
        public WebResponseContent GetSignalStates();
        //获取成品信息
        public WebResponseContent GetLeftInitialData();
        //更新扫码状态
        public WebResponseContent UpdatePartScannedStatus(UpdatePartScannedStatusRequest updatePartScannedStatusRequest);
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_Formula.cs
@@ -33,74 +33,74 @@
        /// <summary>
        /// åŽ‹è£…ä½äº§å“é•¿åº¦
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "压装位产品长度")]
        public float ProductLength { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits =2, ColumnDescription = "压装位产品长度")]
        public decimal ProductLength { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½äº§å“å®½åº¦
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "压装位产品宽度")]
        public float ProductWidth { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位产品宽度")]
        public decimal ProductWidth { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½äº§å“é«˜åº¦
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "压装位产品高度")]
        public float ProductHeight { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位产品高度")]
        public decimal ProductHeight { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½æ‹§ç´§ä¸‹é™é«˜åº¦
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "压装位拧紧下降高度")]
        public float ScrewDownsetDistance { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位拧紧下降高度")]
        public decimal ScrewDownsetDistance { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½æ‹§ç´§æ‰­åŠ›
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "压装位拧紧扭力")]
        public float ScrewTorqueOutput { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位拧紧扭力")]
        public decimal ScrewTorqueOutput { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½è‡ªåŠ¨æ‹§ç´§æ‰“å¼€
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "压装位自动拧紧打开")]
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位自动拧紧打开")]
        public int DintAutoScrewOn { get; set; }
        /// <summary>
        /// æ£€æµ‹ä½X偏移距离1
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "检测位X偏移距离1")]
        public float XDirectionDistance1 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "检测位X偏移距离1")]
        public decimal XDirectionDistance1 { get; set; }
        /// <summary>
        /// æ£€æµ‹ä½Z高度1
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "检测位Z高度1")]
        public float YDirectionHeight1 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "检测位Z高度1")]
        public decimal YDirectionHeight1 { get; set; }
        /// <summary>
        /// æ£€æµ‹ä½X偏移距离2
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "检测位X偏移距离2")]
        public float XDirectionDistance2 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "检测位X偏移距离2")]
        public decimal XDirectionDistance2 { get; set; }
        /// <summary>
        /// æ£€æµ‹ä½Z高度2
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "检测位Z高度2")]
        public float YDirectionHeight2 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "检测位Z高度2")]
        public decimal YDirectionHeight2 { get; set; }
        /// <summary>
        /// æ£€æµ‹ä½X偏移距离3
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "检测位X偏移距离3")]
        public float XDirectionDistance3 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "检测位X偏移距离3")]
        public decimal XDirectionDistance3 { get; set; }
        /// <summary>
        /// æ£€æµ‹ä½Z高度3
        /// </summary>
        [SugarColumn(IsNullable = true,  ColumnDescription = "检测位Z高度3")]
        public float YDirectionHeight3 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "检测位Z高度3")]
        public decimal YDirectionHeight3 { get; set; }
        [SugarColumn(IsIgnore = true)]//不参与数据库映射,测试使用
        [Navigate(NavigateType.OneToMany, nameof(Dt_FormulaDetail.FormulaId), nameof(Id))]
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_FormulaDetail.cs
@@ -33,5 +33,13 @@
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "零件名称")]
        public string ComponentName { get; set; }
        /// <summary>
        /// æ˜¯å¦æ‰«ç 
        /// </summary>
         [SugarColumn(IsNullable = false, DefaultValue = "0", ColumnDescription = "是否扫码")]
        public int IsScanned { get; set; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_ProcessInfo.cs
@@ -44,67 +44,67 @@
        /// <summary>
        /// æ‰­åЛ值
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "扭力值")]
        public float TorsioValue { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "扭力值")]
        public decimal TorsioValue { get; set; }
        /// <summary>
        /// æ‰­åŠ›å€¼æ ‡å‡†
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "扭力值标准")]
        public float TorsioValueStandard { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "扭力值标准")]
        public decimal TorsioValueStandard { get; set; }
        /// <summary>
        /// åˆšåº¦å€¼
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "刚度值")]
        public float StiffnessValue { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "刚度值")]
        public decimal StiffnessValue { get; set; }
        /// <summary>
        /// åˆšåº¦å€¼æ ‡å‡†
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "刚度值标准")]
        public float StiffnessValueStandard { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "刚度值标准")]
        public decimal StiffnessValueStandard { get; set; }
        /// <summary>
        /// æµ‹è¯•结果
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "测试结果")]
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "测试结果")]
        public int TestResult { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½ä¸‹åŽ‹æ£€æµ‹é«˜åº¦
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "压装位下压检测高度")]
        public float PressHeight { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位下压检测高度")]
        public decimal PressHeight { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½æ‹§ç´§æ£€æµ‹æ‰­åŠ›
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "压装位拧紧检测扭力")]
        public float ScrewTorque { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位拧紧检测扭力")]
        public decimal ScrewTorque { get; set; }
        /// <summary>
        /// åŽ‹è£…ä½æ‹§ç´§æ£€æµ‹è§’åº¦
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "压装位拧紧检测角度")]
        public float ScrewAngle { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "压装位拧紧检测角度")]
        public decimal ScrewAngle { get; set; }
        /// <summary>
        /// æ‹§ç´§ä½æ£€æµ‹é«˜åº¦1
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "拧紧位检测高度1")]
        public float Height1 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "拧紧位检测高度1")]
        public decimal Height1 { get; set; }
        /// <summary>
        /// æ‹§ç´§ä½æ£€æµ‹é«˜åº¦2
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "拧紧位检测高度2")]
        public float Height2 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "拧紧位检测高度2")]
        public decimal Height2 { get; set; }
        /// <summary>
        /// æ‹§ç´§ä½æ£€æµ‹é«˜åº¦3
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "拧紧位检测高度3")]
        public float Height3 { get; set; }
        [SugarColumn(IsNullable = true, DecimalDigits = 2, ColumnDescription = "拧紧位检测高度3")]
        public decimal Height3 { get; set; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_ProcessInfoDetail.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
namespace WIDESEAWCS_Model.Models
{
    [SugarTable(nameof(Dt_ProcessInfoDetail), "加工信息详情表")]
    public class Dt_ProcessInfoDetail : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// å·¥è£…板编号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "工装板编号")]
        public string PalletCode { get; set; }
        /// <summary>
        /// æˆå“ç¼–号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "成品编号")]
        public string ProductCode { get; set; }
        /// <summary>
        /// æˆå“åç§°
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "成品名称")]
        public string ProductName { get; set; }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_ScanStation.cs
@@ -32,13 +32,13 @@
        /// <summary>
        /// ç«™å°æˆå“
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "站台成品")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "站台成品")]
        public string StationEndProduct { get; set; }
        /// <summary>
        /// é›¶ä»¶æ•°é‡
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "零件数量")]
        [SugarColumn(IsNullable = true, ColumnDescription = "零件数量")]
        public int StationComponentQty { get; set; }
        /// <summary>
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Model/WIDESEAWCS_Model.csproj
@@ -8,7 +8,7 @@
    <ItemGroup>
        <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
        <PackageReference Include="WIDESEAWCS_Core" Version="1.0.17" />
        <PackageReference Include="WIDESEAWCS_Core" Version="1.0.32" />
    </ItemGroup>
    <ItemGroup>
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/.config/dotnet-tools.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
{
  "version": 1,
  "isRoot": true,
  "tools": {}
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/BoxingDetailController.cs
@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseController;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Server.Controllers.BoxingInfo
@@ -17,5 +20,18 @@
        }
        [HttpPost, Route("SaveToolingBoardNo"), AllowAnonymous]
        public WebResponseContent SaveToolingBoardNo([FromBody] ToolingBoardSubmitDto toolingBoardSubmitDto)
        {
            return Service.SaveToolingBoardNo(toolingBoardSubmitDto);
        }
        [HttpGet, Route("GetProductAndPartsByBoardNo"), AllowAnonymous]
        public WebResponseContent GetProductAndPartsByBoardNo([FromQuery] string palletCode)
        {
            return Service.GetProductAndPartsByBoardNo(palletCode);
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/FormulaController.cs
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseController;
using WIDESEAWCS_Model.Models;
@@ -17,5 +19,16 @@
        }
        /// <summary>
        /// èŽ·å–ç«™å°æˆå“
        /// </summary>
        /// <returns></returns>
        [HttpGet, Route("getEndProductList"), AllowAnonymous]
        public WebResponseContent getEndProductList()
        {
            return Service.getEndProductList();
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/ProcessInfoController.cs
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseController;
using WIDESEAWCS_Model.Models;
@@ -17,5 +19,17 @@
        }
        /// <summary>
        /// ä¸‹è½½æµç¨‹å¡
        /// </summary>
        /// <param name="dt_ProcessInfo"></param>
        /// <returns></returns>
        [HttpPost, Route("ExportData"), AllowAnonymous]
        public WebResponseContent ExportData([FromBody]  Dt_ProcessInfo dt_ProcessInfo)
        {
            return Service.ExportData(dt_ProcessInfo);
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/ProcessInfoDetailController.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Mvc;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Core.BaseController;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_IBasicInfoService;
namespace WIDESEAWCS_Server.Controllers.BasicInfo
{
    /// <summary>
    /// åŠ å·¥ä¿¡æ¯
    /// </summary>
    [Route("api/processInfoDetail")]
    [ApiController]
    public class ProcessInfoDetailController : ApiBaseController<IProcessInfoDetailService, Dt_ProcessInfoDetail>
    {
        public ProcessInfoDetailController(IProcessInfoDetailService service) : base(service)
        {
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/ScanStationController.cs
@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseController;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Server.Controllers.BasicInfo
@@ -17,5 +20,62 @@
        }
        /// <summary>
        /// å¯åЍPLC
        /// </summary>
        /// <param name="isStop"></param>
        /// <returns></returns>
        [HttpGet, Route("StartPLC"), AllowAnonymous]
        public WebResponseContent StartPLC([FromQuery] bool isStop)
        {
            return Service.StartPLC(isStop);
        }
        /// <summary>
        /// æš‚停PLC
        /// </summary>
        /// <param name="isPause"></param>
        /// <returns></returns>
        [HttpGet, Route("PausePLC"), AllowAnonymous]
        public WebResponseContent PausePLC([FromQuery] bool isPause)
        {
            return Service.PausePLC(isPause);
        }
        /// <summary>
        /// èŽ·å–ä¿¡å·ç¯
        /// </summary>
        /// <returns></returns>
        [HttpGet, Route("GetSignalStates"), AllowAnonymous]
        public WebResponseContent GetSignalStates()
        {
            return Service.GetSignalStates();
        }
        /// <summary>
        /// èŽ·å–æˆå“ä¿¡æ¯
        /// </summary>
        /// <returns></returns>
        [HttpGet, Route("GetLeftInitialData"), AllowAnonymous]
        public WebResponseContent GetLeftInitialData()
        {
            return Service.GetLeftInitialData();
        }
        /// <summary>
        /// æ›´æ–°æ˜¯å¦æ‰«ç 
        /// </summary>
        /// <param name="updatePartScannedStatusRequest"></param>
        /// <returns></returns>
        [HttpPost, Route("UpdatePartScannedStatus"), AllowAnonymous]
        public WebResponseContent UpdatePartScannedStatus([FromBody] UpdatePartScannedStatusRequest updatePartScannedStatusRequest)
        {
            return Service.UpdatePartScannedStatus(updatePartScannedStatusRequest);
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/Properties/PublishProfiles/FolderProfile.pubxml
@@ -10,8 +10,12 @@
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <PublishProvider>FileSystem</PublishProvider>
    <PublishUrl>bin\Release\net6.0\publish\</PublishUrl>
    <PublishUrl>F:\IIS\思威博恒\WCS</PublishUrl>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <_TargetId>Folder</_TargetId>
    <SiteUrlToLaunchAfterPublish />
    <TargetFramework>net6.0</TargetFramework>
    <ProjectGuid>487fa45b-ea1a-4aca-bb5b-0f6708f462c0</ProjectGuid>
    <SelfContained>false</SelfContained>
  </PropertyGroup>
</Project>
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj
@@ -68,6 +68,7 @@
    </ItemGroup>
    <ItemGroup>
        <ProjectReference Include="..\WIDESEAWCS_IProductRecordServer\WIDESEAWCS_IProductRecordService.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_SystemServices\WIDESEAWCS_SystemServices.csproj" />
        <ProjectReference Include="..\WIDESEAWCs_TaskInfoService\WIDESEAWCs_TaskInfoService.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_Tasks\WIDESEAWCS_Tasks.csproj" />
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/obj/Debug/net6.0/WIDESEAWCS_TaskInfoService.AssemblyInfo.cs
@@ -14,7 +14,7 @@
[assembly: System.Reflection.AssemblyCompanyAttribute("WIDESEAWCS_TaskInfoService")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+86f5db51a5fd895dcae671d01b28cd0d4948af0e")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2eea48595c784d1d6d58d526f1da12427dfa0a25")]
[assembly: System.Reflection.AssemblyProductAttribute("WIDESEAWCS_TaskInfoService")]
[assembly: System.Reflection.AssemblyTitleAttribute("WIDESEAWCS_TaskInfoService")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/obj/Debug/net6.0/WIDESEAWCS_TaskInfoService.AssemblyInfoInputs.cache
@@ -1 +1 @@
d4cf05aa7aa7ae843c211aeed38667b4957a26b93e653654b3b863537f1c7404
c9c87e496556920f27ef09770ceb3d9cdc2a9b9b20ce0dfcd54bba65b5fd5b5e
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/obj/Debug/net6.0/WIDESEAWCs_TaskInfoService.assets.cache
Binary files differ
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/PLCJob.cs
@@ -1,27 +1,13 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Autofac.Core;
using HslCommunication;
using HslCommunication.Core;
using Microsoft.VisualBasic.FileIO;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
using System.Text;
using Quartz;
using SixLabors.ImageSharp.PixelFormats;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Common.PLCEnum;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_IBasicInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
namespace WIDESEAWCS_Tasks
{
@@ -33,19 +19,30 @@
        private readonly IFormulaService _formulaService;
        private readonly IFormulaDetailService _formulaDetailService;
        private readonly IProcessInfoService _processInfoService;
        private readonly IProcessInfoDetailService _processDetailInfoService;
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public PLCJob(IBoxingService boxingService, IBoxingDetailService boxingDetailService, IFormulaService formulaService, IFormulaDetailService formulaDetailService, IProcessInfoService processInfoService, IUnitOfWorkManage unitOfWorkManage)
        private readonly IScanStationService _scanStationService;
        //private readonly string PalletCode = "PL107";
        public PLCJob(IBoxingService boxingService,
            IBoxingDetailService boxingDetailService,
            IFormulaService formulaService,
            IFormulaDetailService formulaDetailService,
            IProcessInfoService processInfoService,
            IProcessInfoDetailService processDetailInfoService,
            IUnitOfWorkManage unitOfWorkManage,
            IScanStationService scanStationService
            )
        {
            _boxingService = boxingService;
            _boxingDetailService = boxingDetailService;
            _formulaService = formulaService;
            _formulaDetailService = formulaDetailService;
            _processInfoService = processInfoService;
            _processDetailInfoService = processDetailInfoService;
            _unitOfWorkManage = unitOfWorkManage;
            _scanStationService = scanStationService;
        }
        private readonly string set = "0x16,0x4D,0x0D,0x30,0x34,0x30,0x31,0x44,0x30,0x35,0x2E";//主机发送设置扫描模式为主机模式的命令,扫描器返回接收到的命令和<ACK>(0x06)后,将扫描模式更改为主机模式
        private readonly string Text = "开启扫码";//主机发送设置扫描模式为主机模式的命令,扫描器返回接收到的命令和<ACK>(0x06)后,将扫描模式更改为主机模式
        private readonly string command = "0x16,0x54,0x0D";//发送开始解码命令;"0x16,0x55,0x0D"发送停止解码命令
        public Task Execute(IJobExecutionContext context)
        {
@@ -63,6 +60,7 @@
                        var AutoExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolAutoExecuting);
                        var OnlineExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolOnlineExecuting);
                        var Error = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolError);
                        if (Heart && !EMG && AutoExecuting && OnlineExecuting && !Error)
                        {
                            #region ä¸Šçº¿æ‰«ç 
@@ -103,64 +101,35 @@
            var Location1ScanDone = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolLocation1ScanDone);
            if (Location1ScanStart && !Location1ScanDone)//控制扫码枪扫描托盘码,根据托盘码查询组盘数据,判断托盘绑定成品是否已绑定所有所需零件
            {
                #region ä¸²å£è¿žæŽ¥
                SerialPortCommunicator portCommunicator1 = new SerialPortCommunicator("COM1", 9600, "上线扫码枪");
                bool IsConnected1 = false;
                SerialPortCommunicator portCommunicator2 = new SerialPortCommunicator("COM2", 9600, "上线扫码枪");
                bool IsConnected2 = false;
                if (!IsConnected1) IsConnected1 = portCommunicator1.Connect();
                if (!IsConnected2) IsConnected2 = portCommunicator2.Connect();
                byte[] dataToSend1 = Encoding.ASCII.GetBytes(command);//转成字节数组
                portCommunicator1.Write(dataToSend1);
                string receiveData = portCommunicator2.ToString(Encoding.UTF8);
                //if (receiveData == "0x16,0x54,0x0D")
                //{
                //    Console.WriteLine(receiveData);
                byte[] dataToSend2 = Encoding.ASCII.GetBytes("PL106");//转成字节数组
                portCommunicator2.Write(dataToSend2);
                //}
                string PalletCode = portCommunicator1.ToString(Encoding.UTF8);
                using (var uow = _unitOfWorkManage.CreateUnitOfWork())
                {
                var PalletCode = TcpClientExample.Start("192.168.2.120", 2001);
                    try
                    {
                        if (PalletCode.IsNotEmptyOrNull())
                    if (!PalletCode.IsNotEmptyOrNull())
                        {
                        throw new InvalidOperationException("托盘为空");
                    }
                            var boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == PalletCode);
                            if (boxing == null)
                            {
                                WriteError(device.DeviceName, "空托盘");
                                return;
                        throw new InvalidOperationException("未添加组盘信息");
                            }
                            List<Dt_BoxingDetail> dt_BoxingDetails = _boxingDetailService.Repository.QueryData(x => x.BoxingId == boxing.Id);
                            Dt_Formula dt_Formula = _formulaService.Repository.QueryFirst(x => x.ProductCode == boxing.ProductCode);
                            if (dt_Formula == null)
                            {
                                WriteError(device.DeviceName, "无成品配方");
                                return;
                        throw new InvalidOperationException("无成品配方");
                            }
                            List<Dt_FormulaDetail> dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == dt_Formula.Id);
                    List<Dt_FormulaDetail> dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == dt_Formula.Id && x.IsScanned == 1);
                            //比较零件是否齐全
                            if (!_boxingDetailService.IsComponentCodesEqual(dt_BoxingDetails, dt_FormulaDetails))
                            {
                                WriteError(device.DeviceName, "零件有问题,请处理");
                                return;
                        throw new InvalidOperationException("零件有问题,请处理");
                            }
                        }
                        //提交事务
                        uow.Commit();
                        IsConnected1 = !portCommunicator1.Disconnect();
                        IsConnected2 = !portCommunicator2.Disconnect();
                        #endregion
                        device.SetValue(W_PLCDBName.wboolLocation1ScanDone, true);
                    }
                    catch (Exception ex)
                    {
                        WriteError(device.DeviceName, "上线扫码流程执行异常", ex);
                    }
                }
            }
            else if (!Location1ScanStart && Location1ScanDone)
@@ -179,27 +148,14 @@
            var Location2ScanDone = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolLocation2ScanDone);
            if (Location2ScanStart && !Location2ScanDone)//控制扫码枪扫描托盘码,根据托盘码查询托盘绑定成品加工所需数据,写入PLC
            {
                #region MyRegion
                #region ä¸²å£è¿žæŽ¥
                SerialPortCommunicator portCommunicator17 = new SerialPortCommunicator("COM17", 9600, "压装扫码枪");
                bool IsConnected17 = false;
                SerialPortCommunicator portCommunicator18 = new SerialPortCommunicator("COM18", 9600, "压装扫码枪");
                bool IsConnected18 = false;
                if (!IsConnected17) IsConnected17 = portCommunicator17.Connect();
                if (!IsConnected18) IsConnected18 = portCommunicator18.Connect();
                byte[] dataToSend1 = Encoding.ASCII.GetBytes(command);//转成字节数组
                portCommunicator17.Write(dataToSend1);
                string receiveData = portCommunicator18.ToString(Encoding.UTF8);
                byte[] dataToSend2 = Encoding.ASCII.GetBytes("PL106");//转成字节数组
                portCommunicator18.Write(dataToSend2);
                //}
                string PalletCode = portCommunicator17.ToString(Encoding.UTF8);
                using (var uow = _unitOfWorkManage.CreateUnitOfWork())
                {
                var PalletCode = TcpClientExample.Start("192.168.2.121", 2001);
                    try
                    {
                        if (PalletCode.IsNotEmptyOrNull())
                    if (!PalletCode.IsNotEmptyOrNull())
                        {
                        throw new InvalidOperationException("托盘为空");
                    }
                            Dt_Boxing dt_Boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == PalletCode);
                            Dt_Formula dt_Formula = _formulaService.Repository.QueryFirst(x => x.ProductCode == dt_Boxing.ProductCode);
                            //写入PLC
@@ -209,15 +165,12 @@
                            device.SetValue(W_PLCDBName.wrealScrewDownsetDistance, dt_Formula.ScrewDownsetDistance);
                            device.SetValue(W_PLCDBName.wrealScrewTorqueOutput, dt_Formula.ScrewTorqueOutput);
                            device.SetValue(W_PLCDBName.wDintAutoScrewOn, dt_Formula.DintAutoScrewOn);
                            //压装扫码完成
                            device.SetValue(W_PLCDBName.wboolLocation2ScanDone, true);
                            //接收数据
                            float PressHeight = device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectPressHeight);
                            float ScrewTorque = device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectScrewTorque);
                            float ScrewAngle = device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectScrewAngle);
                    decimal PressHeight = (decimal)device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectPressHeight);
                    decimal ScrewTorque = (decimal)device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectScrewTorque);
                    decimal ScrewAngle = (decimal)device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectScrewAngle);
                            //添加到数据库
                            Dt_ProcessInfo dt_ProcessInfo = new Dt_ProcessInfo()
                            {
@@ -227,23 +180,12 @@
                                PressHeight = PressHeight,
                                ScrewTorque = ScrewTorque,
                                ScrewAngle = ScrewAngle
                            };
                            _processInfoService.Repository.AddData(dt_ProcessInfo);
                        }
                        //提交事务
                        uow.Commit();
                        IsConnected17 = !portCommunicator17.Disconnect();
                        IsConnected18 = !portCommunicator18.Disconnect();
                        #endregion
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        WriteError(device.DeviceName, "压装扫码流程执行异常", ex);
                    }
                }
            }
            else if (!Location2ScanStart && Location2ScanDone)
@@ -262,28 +204,13 @@
            var Location3ScanDone = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolLocation3ScanDone);
            if (Location3ScanStart && !Location3ScanDone)
            {
                #region MyRegion
                #region ä¸²å£è¿žæŽ¥
                SerialPortCommunicator portCommunicator19 = new SerialPortCommunicator("COM19", 9600, "检测扫码枪");
                bool IsConnected19 = false;
                SerialPortCommunicator portCommunicator20 = new SerialPortCommunicator("COM20", 9600, "检测扫码枪");
                bool IsConnected20 = false;
                if (!IsConnected19) IsConnected19 = portCommunicator19.Connect();
                if (!IsConnected20) IsConnected20 = portCommunicator20.Connect();
                byte[] dataToSend1 = Encoding.ASCII.GetBytes(command);//转成字节数组
                portCommunicator19.Write(dataToSend1);
                string receiveData = portCommunicator20.ToString(Encoding.UTF8);
                byte[] dataToSend2 = Encoding.ASCII.GetBytes("PL106");//转成字节数组
                portCommunicator20.Write(dataToSend2);
                //}
                string PalletCode = portCommunicator19.ToString(Encoding.UTF8);
                using (var uow = _unitOfWorkManage.CreateUnitOfWork())
                {
                var PalletCode = TcpClientExample.Start("192.168.2.122", 2001);
                    try
                    {
                        if (PalletCode.IsNotEmptyOrNull())
                    if (!PalletCode.IsNotEmptyOrNull())
                        {
                        throw new InvalidOperationException("托盘为空");
                    }
                            Dt_Boxing dt_Boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == PalletCode);
                            Dt_Formula dt_Formula = _formulaService.Repository.QueryFirst(x => x.ProductCode == dt_Boxing.ProductCode);
                            //写入PLC
@@ -298,35 +225,23 @@
                            device.SetValue(W_PLCDBName.wboolLocation3ScanDone, true);
                            //接收数据
                            float Height1 = device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectHeight1);
                            float Height2 = device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectHeight2);
                            float Height3 = device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectHeight3);
                    decimal Height1 = (decimal)device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectHeight1);
                    decimal Height2 = (decimal)device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectHeight2);
                    decimal Height3 = (decimal)device.GetValue<R_PLCDBName, float>(R_PLCDBName.rrealDetectHeight3);
                            Dt_ProcessInfo dt_ProcessInfo = _processInfoService.Repository.QueryFirst(x => x.PalletCode == PalletCode);
                            if (dt_ProcessInfo == null)
                            {
                                WriteInfo(device.DeviceName, "成品未压装");
                                device.SetValue(W_PLCDBName.wboolLocation1ScanDone, true);
                                return;
                        throw new InvalidOperationException("成品未压装");
                            }
                            dt_ProcessInfo.Height1 = Height1;
                            dt_ProcessInfo.Height2 = Height2;
                            dt_ProcessInfo.Height3 = Height3;
                            _processInfoService.Repository.UpdateData(dt_ProcessInfo);
                        }
                        //提交事务
                        uow.Commit();
                        IsConnected19 = !portCommunicator19.Disconnect();
                        IsConnected20 = !portCommunicator20.Disconnect();
                        #endregion
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        WriteError(device.DeviceName, "检测扫码流程执行异常", ex);
                    }
                }
            }
            else if (!Location3ScanStart && Location3ScanDone)
@@ -346,38 +261,38 @@
            var Location4ScanDone = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolLocation4ScanDone);
            if (Location4ScanStart && !Location4ScanDone)//控制扫码枪扫描托盘码,根据托盘码查询组盘数据,判断托盘绑定成品是否已绑定所有所需零件
            {
                SerialPortCommunicator portCommunicator21 = new SerialPortCommunicator("COM21", 9600, "下线扫码枪");
                bool IsConnected21 = false;
                SerialPortCommunicator portCommunicator22 = new SerialPortCommunicator("COM22", 9600, "下线扫码枪");
                bool IsConnected22 = false;
                if (!IsConnected21) IsConnected21 = portCommunicator21.Connect();
                if (!IsConnected22) IsConnected22 = portCommunicator22.Connect();
                byte[] dataToSend1 = Encoding.ASCII.GetBytes(command);//转成字节数组
                portCommunicator21.Write(dataToSend1);
                string receiveData = portCommunicator22.ToString(Encoding.UTF8);
                byte[] dataToSend2 = Encoding.ASCII.GetBytes("PL106");//转成字节数组
                portCommunicator22.Write(dataToSend2);
                //}
                string PalletCode = portCommunicator21.ToString(Encoding.UTF8);
                var PalletCode = TcpClientExample.Start("192.168.2.123", 2001);
                using (var uow = _unitOfWorkManage.CreateUnitOfWork())
                {
                    try
                    {
                        if (PalletCode.IsNotEmptyOrNull())
                        if (!PalletCode.IsNotEmptyOrNull())
                        {
                            throw new InvalidOperationException("托盘为空");
                        }
                        Dt_ProcessInfo dt_ProcessInfo = _processInfoService.Repository.QueryFirst(x => x.PalletCode == PalletCode);
                        if (dt_ProcessInfo == null)
                        {
                            throw new InvalidOperationException("成品未压装和检测");
                        }
                            Dt_Boxing dt_Boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == PalletCode);
                            _boxingService.Repository.DeleteData(dt_Boxing);
                            List<Dt_BoxingDetail> dt_BoxingDetails = _boxingDetailService.Repository.QueryData(x => x.BoxingId == dt_Boxing.Id);
                            foreach (Dt_BoxingDetail dt_BoxingDetail in dt_BoxingDetails)
                        _boxingDetailService.Repository.DeleteData(dt_BoxingDetails);
                        Dt_ProcessInfoDetail dt_ProcessInfoDetail = new Dt_ProcessInfoDetail()
                            {
                                _boxingDetailService.Repository.DeleteDataById(dt_BoxingDetail.Id);
                            }
                            PalletCode = PalletCode,
                            ProductCode = dt_ProcessInfo.ProductCode,
                            ProductName = dt_ProcessInfo.ProductName,
                            Creater = "admin",
                            CreateDate = DateTime.Now
                        };
                        _processDetailInfoService.Repository.AddData(dt_ProcessInfoDetail);
                        _processInfoService.DeleteData(dt_ProcessInfo);
                            uow.Commit();
                            //下线扫码完成
                            device.SetValue(W_PLCDBName.wboolLocation4ScanDone, true);
                        }
                        IsConnected21 = !portCommunicator21.Disconnect();
                        IsConnected22 = !portCommunicator22.Disconnect();
                    }
                    catch (Exception ex)
                    {
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketClient.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_DTO.System;
namespace WIDESEAWCS_Tasks
{
    public class TcpClientExample
    {
        public static string Start(string Ip, int Prot)
        {
            try
            {
                // 1. åˆ›å»º Socket å¯¹è±¡
                Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 1.配置超时(核心:避免Receive无限阻塞)
                clientSocket.SendTimeout = 3000; // è¿žæŽ¥è¶…æ—¶3秒
                clientSocket.ReceiveTimeout = 3000; // è¿žæŽ¥è¶…æ—¶3秒
                // 2. è¿žæŽ¥æœåŠ¡å™¨ï¼ˆIP ä¸ºæœåŠ¡å™¨çš„ IP,端口与服务器一致)
                IPAddress serverIp = IPAddress.Parse(Ip); // æœ¬åœ°æµ‹è¯•用 127.0.0.1,实际替换为服务器 IP
                IPEndPoint serverEndPoint = new IPEndPoint(serverIp, Prot);
                clientSocket.Connect(serverEndPoint);
                //Console.WriteLine("已成功连接到服务器");
                // å°†å­—符串转换为字节数组并发送
                byte[] sendBuffer = Encoding.UTF8.GetBytes("start");
                clientSocket.Send(sendBuffer);
                // æŽ¥æ”¶æœåŠ¡å™¨å›žå¤
                byte[] recvBuffer = new byte[1024];
                int recvLen = clientSocket.Receive(recvBuffer);
                string recvMsg = Encoding.UTF8.GetString(recvBuffer, 0, recvLen);
                //Console.WriteLine($"收到服务器回复:{recvMsg}");
                // 4. å…³é—­è¿žæŽ¥
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
                //Console.WriteLine("已断开与服务器的连接");
                return recvMsg;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return "";
            }
        }
    }
}
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj
@@ -7,7 +7,7 @@
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="WIDESEAWCS_QuartzJob" Version="3.0.9" />
      <PackageReference Include="WIDESEAWCS_QuartzJob" Version="3.0.11" />
    </ItemGroup>
    <ItemGroup>