Ben Lin
2025-03-08 21a4e09672b1177d40c2bb5b937a8780c5eaa7fb
src/views/tigerprojects/mes/prod/biz_mes_wo/index.vue
@@ -1,8 +1,16 @@
<!--
 * @Description: 工单管理页面
 * @Author: Ben Lin
 * @version:
 * @Date: 2024-05-25 00:27:00
 * @LastEditors: Ben Lin
 * @LastEditTime: 2024-07-21 18:07:27
-->
<template>
  <div>
    <BasicTable @register="registerTable">
      <template #toolbar>
        <a-button color="primary" @click="addWo" preIcon="add_02|svg"> 新增 </a-button>
        <a-button type="primary" @click="addWo" preIcon="add_02|svg"> 新增 </a-button>
        <a-button ghost color="success" @click="ExcelToDb" preIcon="excel-import|svg">
          导入
        </a-button>
@@ -15,7 +23,7 @@
          @click="handleSelectItem"
          preIcon="search|svg"
        />
        <NormalModal @register="registerItemAdd" @success="handleItemSuccess" />
        <GeneralModal @register="registerItemAdd" @success="handleItemSuccess" />
      </template>
      <template #action="{ record }">
        <TableAction
@@ -24,6 +32,7 @@
              icon: 'clarity:note-edit-line',
              tooltip: '修改',
              onClick: handleEdit.bind(null, record),
              name: undefined
            },
            {
              icon: 'ant-design:delete-outlined',
@@ -34,27 +43,30 @@
                placement: 'left',
                confirm: handleDelete.bind(null, record),
              },
              name: undefined
            },
            {
              icon: 'config|svg',
              tooltip: '配置工艺',
              onClick: handleConfig.bind(null, record),
              name: undefined
            },
            {
              icon: 'release|svg',
              tooltip: '下发',
              onClick: handleRelease.bind(null, record),
              name: undefined
            },
            {
              icon: 'unrelease|svg',
              tooltip: '取消下发',
              onClick: handleUnRelease.bind(null, record),
            },
            {
              icon: 'suspend-blue|svg',
              tooltip: '暂停',
              onClick: handlePause.bind(null, record),
            },
            // {
            //   icon: 'unrelease|svg',
            //   tooltip: '取消下发',
            //   onClick: handleUnRelease.bind(null, record),
            // },
            // {
            //   icon: 'suspend-blue|svg',
            //   tooltip: '暂停',
            //   onClick: handlePause.bind(null, record),
            // },
          ]"
        />
      </template>
@@ -62,34 +74,41 @@
    <Loading :loading="compState.loading" :tip="compState.tip" />
    <WoDrawer @register="registerDrawer" @success="handleSuccess" />
    <WoModal @register="registerWo" @success="handleSuccess" :title="title" :mtitle="mtitle" />
    <!-- 自定义模态框,可以自定义多表单 -->
    <CustModal
      @register="registerCust"
      @success="custSuccess"
      :type="cType"
      :detailSlots="dtlSlots"
    >
      <!-- 用插槽自定义多表单 -->
      <template #[item.name] v-for="item in dtlSlots" :key="item.name">
        <BasicForm @register="useFormData[item.name][0]" v-if="useFormData[item.name]">
          <!-- 用插槽自定义弹出选择框 -->
          <template #[name]="{ field }" v-for="name in item.slots" :key="name">
            <a-button
              class="mt-1 ml-1"
              size="small"
              @click="handleCustClick(field)"
              :preIcon="item.preIcons[name]"
            />
            <NormalModal
              @register="useModalData[name][0]"
              @success="(d, u) => handleEntSuccess(d, u, item.name)"
            />
          </template>
        </BasicForm>
        <!-- 自定义内容 -->
        <div style="height: 200px" id="lfContainer" v-if="isCustEl[item.name]"></div>
      </template>
    </CustModal>
    <Suspense>
      <!-- 自定义模态框,可以自定义多表单 -->
      <CustModal
        @register="registerCust"
        @success="custSuccess"
        :type="cType"
        :detailSlots="dtlSlots"
        :entityName="entityName"
      >
        <!-- 用插槽自定义多表单 -->
        <template #[item.name] v-for="item in dtlSlots" :key="item.name">
          <BasicForm @register="useFormData[item.name][0]" v-if="useFormData[item.name]">
            <!-- 用插槽自定义弹出选择框 -->
            <template #[name]="{ field }" v-for="name in item.slots" :key="name">
              <a-button
                class="mt-1 ml-1"
                size="small"
                @click="handleCustClick(field)"
                :preIcon="item.preIcons[name]"
              />
              <GeneralModal
                @register="useModalData[name][0]"
                @success="(d, u) => handleEntSuccess(d, u, item.name)"
              />
            </template>
          </BasicForm>
          <!-- 自定义内容 -->
          <!-- <div style="height: 200px" id="lfContainer" v-if="isCustEl[item.name]"></div> -->
          <div class="h-full" style="height: 380px" v-if="isCustEl[item.name]">
            <FlowChartView :data="routeData" @init="init" />
          </div>
        </template>
      </CustModal>
      <!-- <template #fallback> Loading... </template> -->
    </Suspense>
    <RouteViewModal @register="registerRv" @success="RvItemSuccess" />
  </div>
</template>
@@ -100,8 +119,9 @@
  import { BasicForm, FormSchema, FormActionType, useForm } from '/@/components/Form/index';
  import WoDrawer from './WoDrawer.vue';
  import WoModal from './WoModal.vue';
  import NormalModal from '/@/views/components/NormalModal.vue';
  import GeneralModal from '/@/views/components/GeneralModal.vue';
  import RouteViewModal from '/@/views/components/RouteViewModal.vue';
  import { FlowChartView } from '/@/components/FlowChart';
  import CustModal from '/@/views/components/CustModal.vue';
  import { useDrawer } from '/@/components/Drawer';
  import { columns, searchFormSchema } from './biz_mes_wo.data';
@@ -110,18 +130,12 @@
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { useModal } from '/@/components/Modal';
  import { getListByPage } from '/@/api/tigerapi/system';
  import { SaveEntity, getListByPage } from '/@/api/tigerapi/system';
  import { GetSelectSuccess, OpenSelectItem, getFormSchema } from '/@/views/components/data';
  import LogicFlow from '@logicflow/core';
  import { getRouteData } from '/@/api/tigerapi/mes/router';
  import actionRect from '/@/components/FlowChart/src/actionRect';
  import TestNode from '/@/components/FlowChart/src/TestNode';
  import CollectNode from '/@/components/FlowChart/src/CollectNode';
  import AssemblyNode from '/@/components/FlowChart/src/AssemblyNode';
  import PackingNode from '/@/components/FlowChart/src/PackingNode';
  import RepairNode from '/@/components/FlowChart/src/RepairNode';
  import customEdge from '/@/components/FlowChart/src/customEdge';
  import { Snapshot, BpmnElement, Menu, DndPanel, SelectionSelect } from '@logicflow/extension';
  import { initRoute } from '../../../system/lowcode/data';
  import BIZ_MES_WO from '../../../system/lowcode/entityts/BIZ_MES_WO';
  import { useUserStore } from '/@/store/modules/user';
  const { t } = useI18n();
  const ASteps = Steps;
@@ -131,7 +145,7 @@
  const mtitle = ref('工单列表');
  const dtlSlots = ref([] as any[]);
  const selectVals = ref({});
  const { createMessage } = useMessage();
  const { createMessage, createErrorModal } = useMessage();
  const [registerDrawer, { openDrawer }] = useDrawer();
  const compState = reactive({
    absolute: false,
@@ -139,13 +153,22 @@
    tip: '加载中...',
  });
  const lfInstance = ref(null) as Ref<LogicFlow | null>;
  const [registerRv, { openModal: openRvModal }] = useModal();
  const [registerRv, { openModal: openRvModal, closeModal }] = useModal();
  const [registerWo, { openModal: openWoModal }] = useModal();
  const [registerItemAdd, { openModal: openItemModal }] = useModal();
  const [registerCust, { openModal: openCustModal, closeModal }] = useModal();
  const [registerCust, { openModal: openCustModal }] = useModal();
  const [registerTable, { getForm, reload }] = useTable({
    title: '工单信息',
    api: getListByPage,
    searchInfo: {
      TABLE_NAME: 'BIZ_MES_WO',
      option: {
        //根据据点查询,必需带这个参数
        UserId: useUserStore().getUserInfo.userId,
        ByOrg: true,
        CurOrg: useUserStore().getUserInfo.orgCode,
      },
    },
    columns,
    formConfig: {
      labelWidth: 120,
@@ -168,10 +191,10 @@
    nodes: [],
    edges: [],
  });
  const entityName = ref('BIZ_MES_WO');
  const formSchema = ref([] as FormSchema[]);
  const woSchema = ref([] as FormSchema[]);
  const prodSchema = ref([] as FormSchema[]);
  const rotSchema = ref([] as FormSchema[]);
  const woSchema = ref<FormSchema[]>(getFormSchema('woinfo'));
  const prodSchema = ref<FormSchema[]>(getFormSchema('prodinfo'));
  const isCustEl = ref({
    forminfo: false,
    woinfo: false,
@@ -185,43 +208,22 @@
    addRot: useModal(),
    setRot: useModal(),
  });
  //自定义多表单实例
  const useFormData = ref({
    forminfo: useForm({
      labelWidth: 120,
      schemas: formSchema,
      actionColOptions: {
        span: 24,
      },
      showActionButtonGroup: false,
    }),
    woinfo: useForm({
      labelWidth: 120,
      schemas: woSchema,
      actionColOptions: {
        span: 24,
      },
      showActionButtonGroup: false,
    }),
    prodinfo: useForm({
      labelWidth: 120,
      schemas: prodSchema,
      actionColOptions: {
        span: 24,
      },
      showActionButtonGroup: false,
    }),
    // rotinfo: useForm({
    //   labelWidth: 120,
    //   schemas: rotSchema,
    //   actionColOptions: {
    //     span: 24,
    //   },
    //   showActionButtonGroup: false,
    // }),
  });
  /* 获取多表单实例 */
  const [{ GetUseForm }] = BIZ_MES_WO();
  const useFormData = ref<any>(GetUseForm());
  onMounted(async () => {});
  const currlf = ref(null) as Ref<LogicFlow | null>;
  /**
   * @description: 工艺路线初始化
   * @param {*} lf
   * @return {*}
   */
  async function init(lf, rotId) {
    initRoute(lf, rotId, routeData, currlf);
  }
  //新增
  function addWo() {
@@ -259,33 +261,43 @@
      },
      { name: 'rotinfo', slots: ['add'], preIcons: { add: 'search|svg' }, title: '工艺信息' },
    ];
    woSchema.value = getFormSchema('woinfo');
    prodSchema.value = getFormSchema('prodinfo');
    // rotSchema.value = getFormSchema('rotinfo');
    if (lfInstance.value != null) {
      routeData.value = {
        nodes: [],
        edges: [],
      };
      const lf = unref(lfInstance)!;
      lf.render({});
    }
    routeData.value = {
      nodes: [],
      edges: [],
    };
    initRoute(currlf, record.ROUTE_CODE, routeData, currlf);
    selectVals.value['ROUTE_CODE'] = record.ROUTE_CODE;
    openCustModal(true, {
      isUpdate: true,
      ctype: cType,
      title: '工艺配置',
      width: '1000px',
      width: '1200px',
      formEl: useFormData.value, //如果是多个表单,增加多个插槽
      formElName: ['woinfo', 'prodinfo', 'rotinfo'], //表单插槽名称,支持多个表单
      RowKey: '',
      fnName: { BIZ_MES_WO_Config: 'SaveCofig' }, //保存方法名
      initFnName: {}, //初始化方法名
      isCustEl: isCustEl.value,
      ...record,
      fnName: 'SaveCofig', //保存方法名
      // initFnName: { BIZ_MES_WO_Config: 'initRoute' }, //初始化方法名
      // isCustEl: isCustEl.value,
      others: routeData.value,
      values: record, //表单记录
    });
  }
  //下发
  /**
   * @description: 下发
   * @param {*} record
   * @return {*}
   */
  function handleRelease(record: Recordable) {
    // if (record.STATUS == 2) {
    //   createErrorModal({
    //     title: t('警告'),
    //     content: t('工单已经下发,不能再下发!'),
    //     getContainer: () => document.body,
    //   });
    //   return;
    // }
    cType.value = 'BIZ_MES_WO';
    dtlSlots.value = [
      {
@@ -295,7 +307,7 @@
        title: '下发配置',
      },
    ];
    formSchema.value = getFormSchema(cType.value);
    // formSchema.value = getFormSchema(cType.value);
    openCustModal(true, {
      isUpdate: true, //是否更新操作
      ctype: cType, //是哪个页面
@@ -304,23 +316,73 @@
      formEl: useFormData.value,
      formElName: ['forminfo'], //表单插槽名称
      RowKeys: { add: 'ROUTE_CODE', set: 'ROUTE_CODE' }, //插槽的弹出框选择的code
      fnName: { BIZ_MES_WO: 'SaveWoBatch' }, //保存方法名
      initFnName: {}, //初始化方法名
      fnName: 'SaveWoBatch', //保存方法名
      initFnName: {}, //初始化方法名,没有就留空{}
      isCustEl: isCustEl.value,
      ...record,
      values: record, //表单记录
    });
  }
  function custSuccess(d) {
    reload();
  /**
   * @description: 取消下发
   * @param {*} record
   * @return {*}
   */
  function handleUnRelease(record: Recordable) {
    if (record.STATUS == 0) {
      createErrorModal({
        title: t('警告'),
        content: t('工单是初始化状态,不能取消下发!'),
        getContainer: () => document.body,
      });
      return;
    }
    record.STATUS = 0;
    SaveEntity(record, true, 'BIZ_MES_WO').then((action) => {
      if (action.IsSuccessed) {
        createMessage.success(t('已取消下发'));
        reload();
      } else {
        createMessage.success(t('取消下发操作失败'));
      }
    });
  }
  //取消下发
  function handleUnRelease(record: Recordable) {}
  //暂停
  function handlePause(record: Recordable) {}
  //删除
  function handlePause(record: Recordable) {
    if (record.STATUS == 0) {
      createErrorModal({
        title: t('警告'),
        content: t('工单是初始化状态,不能暂停!'),
        getContainer: () => document.body,
      });
      return;
    }
    if (record.STATUS == 5) {
      createErrorModal({
        title: t('警告'),
        content: t('工单是完成状态,不能暂停!'),
        getContainer: () => document.body,
      });
      return;
    }
    record.STATUS = 4;
    SaveEntity(record, true, 'BIZ_MES_WO').then((action) => {
      if (action.IsSuccessed) {
        createMessage.success(t('已暂停'));
        reload();
      } else {
        createMessage.success(t('暂停操作失败'));
      }
    });
  }
  /**
   * @description: 删除
   * @param {*} record
   * @return {*}
   */
  function handleDelete(record: Recordable) {
    const apiAction = DeleteMesWo(record.ID);
    apiAction.then((action) => {
    DeleteMesWo(record.ID).then((action) => {
      if (action.IsSuccessed) {
        createMessage.success(t('已删除'));
        reload();
@@ -329,7 +391,20 @@
      }
    });
  }
  //点击打开物料列表框
  /**
   * @description: 弹出框确定返回
   * @param {*} d
   * @return {*}
   */
  function custSuccess(d) {
    reload();
  }
  /**
   * @description: 点击打开物料列表框
   * @return {*}
   */
  function handleSelectItem() {
    openItemModal(true, {
      title: '物料列表',
@@ -361,31 +436,54 @@
      ],
      tableName: 'BAS_ITEM',
      rowKey: 'ITEM_CODE',
      searchInfo: { TABLE_NAME: 'BAS_ITEM' },
    });
  }
  /**
   * @description: 弹出选择物料框返回成功方法
   * @param {*} d
   * @param {*} u
   * @return {*}
   */
  function handleItemSuccess(d, u) {
    getForm().setFieldsValue({
      ITEM_CODE: d.values['val'],
    });
  }
  /* 各表单内弹出选择框选择成功后事件 */
  /**
   * @description: 各表单内弹出选择框选择成功后方法
   * @param {*} d
   * @param {*} u
   * @param {*} item
   * @return {*}
   */
  function handleEntSuccess(d, u, item) {
    var values = GetSelectSuccess(d, u, cType.value);
    selectVals.value = values; //保存弹出框选择的结果
    let _val = {};
    _val[d.returnFieldName] = values[d.returnFieldName];
    d.returnFieldName.map((x) => {
          _val[x] = values[x];
        });
    useFormData.value[item][1].setFieldsValue(_val);
    if (d.returnFieldName == 'ROUTE_CODE') {
    if (d.returnFieldName == 'ROUTE_CODE' && cType.value == 'BIZ_MES_WO_Config') {
      routeData.value = {
        nodes: [],
        edges: [],
      };
      init(selectVals.value['ID']);
      init(currlf, selectVals.value['ROUTE_CODE']);
      const { transformModel, width, height } = unref(currlf).graphModel;
      transformModel.focusOn(300, 200, width, height);
    }
  }
  /* 弹出选择框 */
  /**
   * @description: 弹出选择框
   * @param {*} item
   * @return {*}
   */
  function handleCustClick(item) {
    //打开自定义模态框
    OpenSelectItem(
@@ -393,59 +491,11 @@
      cType.value,
      item,
      [openRvModal],
      selectVals.value['ID'],
      selectVals.value['ROUTE_CODE'],
    ); //[openRvModal], selectVals.value['ID']这是自定义参数,按实际需求
  }
  function RvItemSuccess(d, u) {}
  async function init(rotId) {
    LogicFlow.use(BpmnElement);
    lfInstance.value = new LogicFlow({
      container: document.querySelector('#lfContainer'),
      edgeGenerator: (sourceNode) => {
        // console.log('a');
        // 起始节点类型 rect 时使用 自定义的边 custom-edge
        if (sourceNode.properties.isReturn) return 'custom-edge';
        // if (sourceNode.type === 'rect') return 'custom-edge';
        // return 'custom-edge';
      },
    });
    const lf = unref(lfInstance)!;
    // lf?.setDefaultEdgeType('line');
    lf.register(customEdge);
    lf.register(actionRect);
    lf.register(TestNode);
    lf.register(CollectNode);
    lf.register(AssemblyNode);
    lf.register(PackingNode);
    lf.register(RepairNode);
    lf.render({});
    //通过工艺路线ID获取图形数据,并渲染
    var _data = await getRouteData(rotId);
    console.log('组件已挂载', _data);
    //工艺路线全信息,包括Node、Edge和Act
    // routeConfig.routeData = _data.Data;
    if (_data.Data != null) {
      //工艺路线主信息
      var currRoute = _data.Data.route;
      _data.Data.nodes.forEach((n) => {
        n.node.properties = JSON.parse(n.node.properties);
        routeData.value.nodes.push(n.node);
      });
      console.log('111', routeData.value);
      _data.Data.edges.forEach((e) => {
        e.edge.properties = JSON.parse(e.edge.properties);
        routeData.value.edges.push(e.edge);
      });
      _data.Data.acts.forEach((act) => {
        act.node.properties = JSON.parse(act.node.properties);
        routeData.value.nodes.push(act.node);
      });
      console.log('init', unref(lf).getGraphData(), JSON.parse(JSON.stringify(routeData.value)));
      lf.render(routeData.value);
      // lf.graphModel.resize(500, 400);
      lf.graphModel.fitView();
      lf.graphModel.translateCenter();
    }
  function RvItemSuccess(d, u) {
    closeModal();
  }
</script>