张诺
7 小时以前 ea324e1975ffec307758e00b5736b4399c36e6f6
绑定工艺路线调整
已添加2个文件
已修改2个文件
1101 ■■■■■ 文件已修改
src/api/productionManagement/productionOrder.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/ActionFileUpload.vue 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/BindRouteDialog.vue 793 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionOrder.js
@@ -130,3 +130,23 @@
    data: data,
  });
}
// ç”Ÿäº§è®¢å•绑定兹定于工艺路线
// /productionProductInput/save
export function saveProductionProductInput(data) {
    return request({
        url: "/productionProductInput/save",
        method: "post",
        data,
    })
}
// ç”Ÿè¾°è®¢å•查看工艺路线
// /productionProductInput/getByProductWordId/{productOrderId}
export function viewGetByProductWordId(data) {
    return request({
        url: "/productionProductInput/getByProductWordId/"+data,
        method: "post",
    })
}
src/components/Upload/ActionFileUpload.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,181 @@
<template>
  <el-upload
    v-model:file-list="innerFileList"
    :action="action"
    :name="name"
    :multiple="multiple"
    ref="fileUploadRef"
    :auto-upload="autoUpload"
    :headers="headers"
    :before-upload="handleBeforeUpload"
    :on-error="handleUploadError"
    :on-success="handleUploadSuccess"
    :on-remove="handleRemove"
    :on-preview="handlePreview"
    :show-file-list="showFileList"
  >
    <el-button type="primary">{{ buttonText }}</el-button>
    <template #file="{ file }">
      <div style="display:flex; align-items:center; gap: 10px; width: 100%;">
        <span style="flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
          {{ file.name }}
        </span>
        <div style="display:flex; align-items:center; gap: 6px;">
          <el-button link type="success" :icon="Download" @click="handleDownload(file)" />
          <el-button link type="primary" :icon="View" @click="handlePreview(file)" />
          <el-button link type="danger" :icon="Delete" @click="triggerRemoveFile(file)" />
        </div>
      </div>
    </template>
    <template #tip>
      <div class="el-upload__tip">
        {{ tipText }}
      </div>
    </template>
  </el-upload>
</template>
<script setup>
import { computed, ref } from "vue";
import { Delete, Download, View } from "@element-plus/icons-vue";
const props = defineProps({
  name: {
    type: String,
    default: "file",
  },
  fileList: {
    type: Array,
    default: () => [],
  },
  action: {
    type: String,
    required: true,
  },
  headers: {
    type: Object,
    default: () => ({}),
  },
  multiple: {
    type: Boolean,
    default: true,
  },
  autoUpload: {
    type: Boolean,
    default: true,
  },
  showFileList: {
    type: Boolean,
    default: true,
  },
  buttonText: {
    type: String,
    default: "上传",
  },
  tipText: {
    type: String,
    default: "支持文档和图片格式",
  },
  beforeUpload: {
    type: Function,
    default: null,
  },
  onError: {
    type: Function,
    default: null,
  },
  onSuccess: {
    type: Function,
    default: null,
  },
  onRemove: {
    type: Function,
    default: null,
  },
  onPreview: {
    type: Function,
    default: null,
  },
  onDownload: {
    type: Function,
    default: null,
  },
});
const emit = defineEmits([
  "update:fileList",
  "error",
  "success",
  "remove",
  "preview",
  "download",
]);
const fileUploadRef = ref(null);
const innerFileList = computed({
  get: () => props.fileList || [],
  set: (val) => emit("update:fileList", val),
});
const getFileUrl = (file) => {
  return file?.url || file?.response?.data?.tempPath || file?.response?.data?.url || "";
};
const triggerRemoveFile = (file) => {
  fileUploadRef.value?.handleRemove?.(file);
};
const handleBeforeUpload = (...args) => {
  if (props.beforeUpload) {
    return props.beforeUpload(...args);
  }
  return true;
};
const handleUploadError = (...args) => {
  props.onError?.(...args);
  emit("error", ...args);
};
const handleUploadSuccess = (...args) => {
  props.onSuccess?.(...args);
  emit("success", ...args);
};
const handleRemove = (...args) => {
  props.onRemove?.(...args);
  emit("remove", ...args);
};
const handlePreview = (file, ...rest) => {
  if (props.onPreview) {
    props.onPreview(file, ...rest);
    emit("preview", file, ...rest);
    return;
  }
  const url = getFileUrl(file);
  if (url) {
    window.open(url, "_blank");
  }
  emit("preview", file, ...rest);
};
const handleDownload = (file) => {
  if (props.onDownload) {
    props.onDownload(file);
    emit("download", file);
    return;
  }
  const url = getFileUrl(file);
  if (!url) return;
  const link = document.createElement("a");
  link.href = url;
  link.download = file?.name || "download";
  link.target = "_blank";
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  emit("download", file);
};
</script>
src/views/productionManagement/productionOrder/BindRouteDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,793 @@
<template>
  <FormDialog
    v-model="visible"
    :title="type === 'add' ? '绑定工艺路线' : '编辑工艺路线'"
    width="1400px"
    :operation-type="type"
    :column="8"
    @close="handleClose"
    @confirm="handleConfirm"
    @cancel="handleClose"
  >
    <!-- ================= åŸºæœ¬ä¿¡æ¯ ================= -->
    <el-descriptions :column="3">
      <el-descriptions-item label="编号" align="center" v-if="formData.productOrderList">
        {{ formData.productOrderList.salesContractNo || "暂无数据" }}
      </el-descriptions-item>
      <el-descriptions-item label="制单日期" align="center" v-if="formData.productOrderList">
        {{ formData.productOrderList.entryDate || "暂无数据" }}
      </el-descriptions-item>
      <el-descriptions-item label="交付日期" align="center" v-if="formData.productOrderList">
        {{ formData.productOrderList.deliveryDate || "暂无数据" }}
      </el-descriptions-item>
    </el-descriptions>
    <el-descriptions border :column="4">
      <el-descriptions-item label="委托单位" :span="2" align="center">
        {{formData.clientName || "--"}}
      </el-descriptions-item>
      <el-descriptions-item label="数量" :span="1" align="center">
        {{formData.orderQty || "--"}}
      </el-descriptions-item>
      <el-descriptions-item label="成品尺寸" :span="1" align="center">
        {{formData.specificationModel || "--"}}
      </el-descriptions-item>
      <el-descriptions-item label="产品名称" :span="2" align="center">
        {{formData.productName || "--"}}
      </el-descriptions-item>
      <el-descriptions-item label="单据类型" :span="2" align="center">
        <el-checkbox-group v-model="introductionLetterList">
          <el-checkbox label="介绍信" value="介绍信" />
          <el-checkbox label="商标注册书" value="商标注册书" />
          <el-checkbox label="委印单" value="委印单" />
        </el-checkbox-group>
      </el-descriptions-item>
    </el-descriptions>
    <!-- ================= ææ–™è¡¨ ================= -->
    <div class="process-table-header">
     <div class="section-title">材料信息</div>
      <el-button type="primary" size="small" @click="addMaterialRow">新增一行</el-button>
    </div>
    <el-table border :data="formData.materialInfo" style="width: 100%">
      <el-table-column label="材料名称">
        <template #default="{ row }">
          <el-tree-select
            v-model="row.productId"
            placeholder="请选择"
            clearable
            check-strictly
            @change="(val) => getModels(val, row)"
            :data="productOptions"
            :render-after-expand="false"
            style="width: 100%"
          />
        </template>
      </el-table-column>
      <el-table-column label="规格">
        <template #default="{ row }">
          <el-select
            v-model="row.productModelId"
            placeholder="请选择规格"
            filterable
            clearable
            @change="(val) => handleMaterialModelChange(val, row)"
          >
            <el-option
              v-for="item in row.modelOptions || []"
              :key="item.id"
              :label="item.model"
              :value="item.id"
            />
          </el-select>
        </template>
      </el-table-column>
      <el-table-column label="数量">
        <template #default="{ row }">
          <el-input v-model="row.num" placeholder="数量">
            <template #append>{{ row.numSuffix }}</template>
          </el-input>
        </template>
      </el-table-column>
      <el-table-column label="计量单位">
        <template #default="{ row }">
          <el-input v-model="row.unit" placeholder="计量单位" />
        </template>
      </el-table-column>
      <el-table-column label="单价">
        <template #default="{ row }">
          <el-input v-model="row.price" placeholder="单价">
            <template #append>{{ row.unitSuffix }}</template>
          </el-input>
        </template>
      </el-table-column>
      <el-table-column label="金额">
        <template #default="{ row }">
          <el-input v-model="row.totalAmount" placeholder="金额" />
        </template>
      </el-table-column>
      <el-table-column label="操作" width="80">
        <template #default="{ $index }">
          <el-button type="danger" size="small" @click="removeMaterialRow($index)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-descriptions border :column="2" :span="2">
      <el-descriptions-item
          label="注意事项"
          :span="2"
          align="center"
          style="white-space: pre-line; word-break: break-all; min-height: 60px;"
      >
        <el-input
            v-model="formData.productDescription"
            :autosize="{ minRows: 2, maxRows: 4 }"
            type="textarea"
            placeholder="请输入注意事项"
        />
      </el-descriptions-item>
    </el-descriptions>
    <hr>
    <!-- ================= åˆ‡æ–™å›¾ç¤º ================= -->
    <div class="section-title">切料图示</div>
    <ActionFileUpload
        style="width: 50%;"
        v-model:file-list="fileList"
        :action="upload.url"
        :headers="upload.headers"
        :multiple="false"
        :name="'files'"
        :onSuccess="uploadSuccess"
    tip-text="支持图片(jpg, jpeg, png)格式"
    />
    <!-- ================= åˆ‡æ–™ä¿¡æ¯ ================= -->
    <el-descriptions
      border
      :column="6"
      direction="vertical"
      style="width: 100%"
      class="fixed-desc"
    >
      <el-descriptions-item label="切料尺寸" align="center">
        <el-input v-model="formData.cutNum" placeholder="切料尺寸" />
      </el-descriptions-item>
      <el-descriptions-item label="切料数量" align="center">
        <el-input v-model="formData.cutSize" placeholder="切料尺寸" />
      </el-descriptions-item>
      <el-descriptions-item label="中盒数量" align="center">
        <el-input v-model="formData.mediumBoxQty" placeholder="中盒数量" />
      </el-descriptions-item>
      <el-descriptions-item label="小盒数量" align="center">
        <el-input v-model="formData.smallBoxQty" placeholder="小盒数量" />
      </el-descriptions-item>
      <el-descriptions-item label="正数" align="center">
        <el-input v-model="formData.positiveQty" placeholder="正数" />
      </el-descriptions-item>
      <el-descriptions-item label="加放数" align="center">
        <el-input v-model="formData.allowanceQty" placeholder="加放数" />
      </el-descriptions-item>
    </el-descriptions>
    <div class="middle-sheet-table">
      <table class="middle-sheet-table__inner">
        <tbody>
          <tr>
            <th>软片版:</th>
            <th colspan="2">开张色</th>
            <th>晒板</th>
            <th colspan="2">开拼</th>
            <th>别刀版</th>
            <th>联色块</th>
          </tr>
          <tr>
            <th rowspan="2">制版</th>
            <th>设计制作费</th>
            <th>拼版费</th>
            <th>出片费</th>
            <th>打样费</th>
            <th>别刀版费</th>
            <th>烫/凸版费</th>
            <th>小计</th>
          </tr>
          <tr v-for="(plate, index) in formData.plateMaking" :key="index">
            <td>
              <el-input v-model="plate.designProductionFee" placeholder="请输入设计制作费" />
            </td>
            <td>
              <el-input v-model="plate.impositionFee" placeholder="请输入拼版费" />
            </td>
            <td>
              <el-input v-model="plate.filmOutputFee" placeholder="请输入出片费" />
            </td>
            <td>
              <el-input v-model="plate.proofingFee" placeholder="请输入打样费" />
            </td>
            <td>
              <el-input v-model="plate.doctorBladePlateFee" placeholder="请输入别刀版费" />
            </td>
            <td>
              <el-input v-model="plate.hotEmbossingPlateFee" placeholder="请输入烫/凸版费" />
            </td>
            <td>
              <el-input v-model="plate.subtotalFee" placeholder="请输入小计" />
            </td>
          </tr>
        </tbody>
      </table>
    </div>
<!--  class="section-title" -->
    <!-- ================= å·¥è‰ºåŠ å·¥ ================= -->
    <div class="process-table-header">
     <div class="section-title">工艺加工</div>
      <el-button type="primary" size="small" @click="addProcessRow">新增一行</el-button>
    </div>
    <el-table border :data="formData.processContent" style="width: 100%" :span-method="objectSpanMethod">
      <el-table-column label="工序" width="140">
        <template #default="{ row }">
          <el-table-column label="工序" width="140">
            <template #default="{ row }">
              <el-select
                  v-model="row.processId"
                  placeholder="请选择工序"
                  @change="(val) => onProcessChange(val, row)"
              >
                <el-option
                    v-for="item in processOptions"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id"
                />
              </el-select>
            </template>
          </el-table-column>
        </template>
      </el-table-column>
      <el-table-column label="开数">
        <template #default="{ row }">
          <el-input v-model="row.openCount" placeholder="请输入开数" />
        </template>
      </el-table-column>
      <el-table-column label="工艺正数">
        <template #default="{ row }">
          <el-input v-model="row.processPositive" placeholder="请输入工艺正数" />
        </template>
      </el-table-column>
      <el-table-column label="加放数">
        <template #default="{ row }">
          <el-input v-model="row.allowanceQty" placeholder="请输入加放数" />
        </template>
      </el-table-column>
      <el-table-column label="机台" width="180">
        <template #default="{ row }">
          <el-select
            v-model="row.deviceId"
            placeholder="请选择机台"
            filterable
            clearable
            @change="(val) => handleDeviceChange(val, row)"
          >
            <el-option
              v-for="item in deviceOptions"
              :key="item.id"
              :label="item.deviceName"
              :value="item.id"
            />
          </el-select>
        </template>
      </el-table-column>
      <el-table-column label="报工人" width="220">
        <template #default="{ row }">
          <el-select
            v-model="row.reportUserIds"
            placeholder="请选择报工人"
            filterable
            clearable
            multiple
            collapse-tags
            collapse-tags-tooltip
            @change="(val) => handleReportUsersChange(val, row)"
          >
            <el-option
              v-for="item in userOptions"
              :key="item.userId"
              :label="item.nickName"
              :value="item.userId"
            />
          </el-select>
        </template>
      </el-table-column>
      <el-table-column label="工艺要求">
        <template #default="{ rowIndex }">
          <el-input
            v-model="formData.processRequirement"
            type="textarea"
            :rows="6"
            placeholder="请输入工艺要求"
          />
        </template>
      </el-table-column>
      <el-table-column label="操作" width="80">
        <template #default="{ $index }">
          <el-button type="danger" size="small" @click="removeProcessRow($index)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- ================= åŒ…装信息 ================= -->
    <el-descriptions border :column="3" class="mt">
      <el-descriptions-item label="送货地点" align="center">
        <el-input v-model="formData.deliveryAddress" placeholder="送货地点" />
      </el-descriptions-item>
      <el-descriptions-item label="联系人" align="center">
        <el-input v-model="formData.contactName" placeholder="联系人" />
      </el-descriptions-item>
      <el-descriptions-item label="包装要求" align="center">
        <el-input v-model="formData.packagingRequirement" placeholder="包装要求" />
      </el-descriptions-item>
      <el-descriptions-item label="尺寸" align="center">
        <el-input v-model="formData.postProcessSize" placeholder="尺寸" />
      </el-descriptions-item>
      <el-descriptions-item label="定货数量" align="center">
        {{formData.orderQty || "--"}}
      </el-descriptions-item>
      <el-descriptions-item label="实交数量" :span="3" align="center">
        <el-input v-model="formData.actualDeliveryQty" placeholder="实交数量" />
      </el-descriptions-item>
    </el-descriptions>
  </FormDialog>
</template>
<script setup>
import { ref, reactive, computed, onMounted, watch } from 'vue'
import dayjs from 'dayjs'
import FormDialog from '@/components/Dialog/FormDialog.vue'
import ActionFileUpload from "@/components/Upload/ActionFileUpload.vue";
import { list } from "@/api/productionManagement/productionProcess.js"
import { modelList, productTreeList } from "@/api/basicData/product.js"
import {getSalesLedgerWithProducts} from "@/api/salesManagement/salesLedger.js"
import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js"
import { userListNoPageByTenantId } from "@/api/system/user.js"
import { getToken } from "@/utils/auth";
const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false
  },
  type: {
    type: String,
    default: 'add'
  },
  orderData: {
    type: Object,
    default: () => ({})
  },
  rowData: {
    type: Object,
    default: null
  }
})
const emit = defineEmits(['update:modelValue', 'confirm'])
const visible = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val)
})
const processOptions = ref([])
const deviceOptions = ref([])
const userOptions = ref([])
const reportWorkerList = ref([])
const productOptions = ref([])
const introductionLetterList = ref([])
const fileList = ref([])
const upload = reactive({
  url: import.meta.env.VITE_APP_BASE_API + '/basic/customer-follow/upload',
  headers: { Authorization: 'Bearer ' + getToken() }
})
const formData = reactive({
  productOrderList:null,
  salesLedgerId: null,
  productOrderId: null,
  printOrderTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
  fileList:[],
  finishTime: "",
  no: "",
  productName: "",
  productDescription: "",
  clientName: "",
  finishedSize: "",
  cutNum: "",
  cutSize:"",
  mediumBoxQty: "",
  smallBoxQty: "",
  positiveQty: "",
  allowanceQty: "",
  introductionLetter: "",
  plateMaking: [
    {
      designProductionFee: "",
      impositionFee: "",
      filmOutputFee: "",
      proofingFee: "",
      doctorBladePlateFee: "",
      hotEmbossingPlateFee: "",
      subtotalFee: ""
    }
  ],
  processContent: [
    {
      id: "1",
      processId: "",
      processName: "",
      mediumBoxQty: "",
      smallBoxQty: "",
      openCount: "",
      processPositive: "",
      allowanceQty: "",
      deviceId: "",
      deviceName: "",
      reportUserIds: [],
      reportWorkerList: []
    }
  ],
  materialInfo: [
    {
      id: "1",
      productId: "",
      name: "",
      productModelId: "",
      model: "",
      modelOptions: [],
      num: "",
      numSuffix: "å¼ ",
      unitSuffix: "元/kg",
      unit: "",
      price: "",
      totalAmount: ""
    }
  ],
  processRequirement: "",
  deliveryAddress: "",
  contactName: "",
  packagingRequirement: "",
  postProcessSize: "",
  orderQty: "",
  actualDeliveryQty: "",
  productionDept: "",
  technicalDept: "",
  warehouseDept: "",
  productModelId: "",
  specificationModel:"",
})
// ç›‘听 checkbox group å˜åŒ–并同步到 introductionLetter å­—符串
watch(introductionLetterList, (val) => {
  formData.introductionLetter = val.join(',')
})
const onProcessChange = (processId, row) => {
  const selected = processOptions.find(item => item.id === processId)
  row.processName = selected?.name || ''
}
const cloneDeep = (val) => JSON.parse(JSON.stringify(val))
const uploadSuccess = (...args) => {
  console.log(...args)
}
const mergeRowDataToForm = (source) => {
  if (!source || typeof source !== 'object') {
    return
  }
  Object.keys(formData).forEach((key) => {
    if (source[key] !== undefined) {
      formData[key] = Array.isArray(source[key]) ? cloneDeep(source[key]) : source[key]
    }
  })
  // å…¼å®¹ index.vue é‡Œå¸¸ç”¨å­—段名与弹窗字段名不一致的情况
  if (source.productName === undefined && source.productCategory !== undefined) {
    formData.productName = source.productCategory
  }
  if (source.orderQty === undefined && source.quantity !== undefined) {
    formData.orderQty = source.quantity
  }
  if (source.no === undefined && source.salesContractNo !== undefined) {
    formData.no = source.salesContractNo
  }
  if (source.clientName === undefined && source.customerName !== undefined) {
    formData.clientName = source.customerName
  }
  if (source.productOrderId === undefined && source.id !== undefined) {
    formData.productOrderId = source.id
  }
}
// èŽ·å–é”€å”®è®¢å•
const getProductOrder = () => {
  if(!formData.salesLedgerId) return
  getSalesLedgerWithProducts({
    type: "1",
    id: formData.salesLedgerId
  }).then(res => {
    if(res){
      formData.productOrderList = res
    }
    console.log(formData)
  })
}
watch(() => props.orderData, (val) => {
  mergeRowDataToForm(val)
}, { immediate: true, deep: true })
watch(
  () => props.rowData,
  (val) => {
    mergeRowDataToForm(val)
    getProductOrder()
  },
  { immediate: true, deep: true }
)
const getProcessList = () => {
  list().then(res => {
    processOptions.value = res.data
  })
}
const getDeviceList = () => {
  getDeviceLedger().then(res => {
    deviceOptions.value = Array.isArray(res?.data) ? res.data : []
  })
}
const getUserList = () => {
  userListNoPageByTenantId().then(res => {
    userOptions.value = Array.isArray(res?.data) ? res.data : []
  })
}
const convertProductOptions = (data) => {
  return data.map(item => ({
    label: item.label || item.productName || item.name || "",
    value: item.id,
    children: item.children?.length ? convertProductOptions(item.children) : undefined
  }))
}
const findProductLabelById = (options, productId) => {
  for (const item of options) {
    if (item.value === productId) {
      return item.label
    }
    if (item.children?.length) {
      const label = findProductLabelById(item.children, productId)
      if (label) {
        return label
      }
    }
  }
  return ""
}
const getMaterialProductOptions = () => {
  productTreeList().then(res => {
    const rawData = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
    productOptions.value = convertProductOptions(rawData)
  })
}
const handleProcessChange = (val, row) => {
  console.log(row)
  const process = processOptions.value.find(item => item.id === val)
  if (process) {
    row.processName = process.name
    console.log(process)
    if (process.deviceId) {
      row.deviceId = process.deviceId || ""
      row.deviceName = process.deviceName || ""
    }
  }
}
const handleDeviceChange = (val, row) => {
  const device = deviceOptions.value.find(item => item.id === val)
  row.deviceName = device?.deviceName || ""
  row.deviceId = val || ""
}
const handleReportUsersChange = (val, row) => {
  const userMap = new Map(
      userOptions.value.map(item => [item.userId, item.nickName])
  )
  row.reportWorkerList = (val || []).map(userId => ({
    userId,
    userName: userMap.get(userId) || ''
  }))
}
const getModels = (val, row) => {
  row.productId = val || ""
  row.name = val ? findProductLabelById(productOptions.value, val) : ""
  row.productModelId = ""
  row.model = ""
  row.unit = ""
  row.modelOptions = []
  if (!val) {
    return
  }
  modelList({ id: val }).then(res => {
    row.modelOptions = Array.isArray(res) ? res : Array.isArray(res?.data) ? res.data : []
  })
}
const handleMaterialModelChange = (val, row) => {
  const currentModel = (row.modelOptions || []).find(item => item.id === val)
  row.productModelId = val || ""
  row.model = currentModel?.model || ""
  row.unit = currentModel?.unit || ""
}
// ææ–™ä¿¡æ¯
const addMaterialRow = () => {
  formData.materialInfo.push({
    id: Date.now().toString(),
    productId: "",
    name: "",
    productModelId: "",
    model: "",
    modelOptions: [],
    num: "",
    numSuffix: "å¼ ",
    unitSuffix: "元/kg",
    unit: "",
    price: "",
    totalAmount: ""
  })
}
const removeMaterialRow = (index) => {
  formData.materialInfo.splice(index, 1)
}
const addProcessRow = () => {
  formData.processContent.push({
    id: Date.now().toString(),
    processId: "",
    processName: "",
    openCount: "",
    processPositive: "",
    allowanceQty: "",
    deviceId: "",
    deviceName: "",
    reportUserIds: [],
    reportWorkerList: []
  })
}
const removeProcessRow = (index) => {
  formData.processContent.splice(index, 1)
}
const objectSpanMethod = ({ column, rowIndex }) => {
  if (column.label === "工艺要求") {
    if (rowIndex === 0) {
      return {
        rowspan: Math.max(formData.processContent.length, 1),
        colspan: 1,
      }
    }
    return {
      rowspan: 0,
      colspan: 0,
    }
  }
}
const handleClose = () => {
  visible.value = false
}
const handleConfirm = () => {
  emit('confirm', JSON.parse(JSON.stringify(formData)))
}
onMounted(() => {
  getProcessList()
  getDeviceList()
  getUserList()
  getMaterialProductOptions()
})
defineExpose({
  getProductOrder
})
</script>
<style scoped lang="scss">
.section-title {
  font-size: 16px;
  font-weight: bold;
  margin: 20px 0 10px;
  padding-left: 10px;
  border-left: 4px solid #409eff;
}
.fixed-desc {
  margin-top: 20px;
  :deep(.el-descriptions__table) {
    table-layout: fixed;
    width: 100%;
  }
  :deep(.el-descriptions__cell) {
    width: 25%;
    word-break: break-word;
  }
}
.middle-sheet-table {
  margin-top: 20px;
  width: 100%;
  border: 1px solid #ebeef5;
}
.middle-sheet-table__inner {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  th, td {
    border: 1px solid #ebeef5;
    padding: 8px;
    text-align: center;
    font-size: 14px;
  }
  th {
    background-color: #f5f7fa;
    color: #606266;
    font-weight: bold;
  }
  :deep(.el-input__wrapper) {
    box-shadow: none !important;
    background-color: transparent;
  }
}
.process-table-header {
  margin-top: 20px;
  margin-bottom: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  span {
    font-size: 16px;
    font-weight: bold;
  }
}
.mt {
  margin-top: 20px;
}
:deep(.el-textarea__inner){
  box-shadow: none;
}
</style>
src/views/productionManagement/productionOrder/index.vue
@@ -11,7 +11,7 @@
                    style="width: 160px;"
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="合同号:">
        <el-form-item label="订单编号:">
          <el-input v-model="searchForm.salesContractNo"
                    placeholder="请输入"
                    clearable
@@ -41,7 +41,7 @@
        </el-form-item>
      </el-form>
      <div>
        <el-button type="primary" @click="isShowNewModal = true">新增</el-button>
<!--        <el-button type="primary" @click="isShowNewModal = true">新增</el-button>-->
        <el-button type="danger" @click="handleDelete">删除</el-button>
        <el-button @click="handleOut">导出</el-button>
      </div>
@@ -65,32 +65,14 @@
        </template>
      </PIMTable>
    </div>
    <el-dialog v-model="bindRouteDialogVisible"
               title="绑定工艺路线"
               width="500px">
      <el-form label-width="90px">
        <el-form-item label="工艺路线">
          <el-select v-model="bindForm.routeId"
                     placeholder="请选择工艺路线"
                     style="width: 100%;"
                     :loading="bindRouteLoading">
            <el-option v-for="item in routeOptions"
                       :key="item.id"
                       :label="`${item.processRouteCode || ''}`"
                       :value="item.id" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     :loading="bindRouteSaving"
                     @click="handleBindRouteConfirm">ç¡® è®¤</el-button>
          <el-button @click="bindRouteDialogVisible = false">取 æ¶ˆ</el-button>
        </span>
      </template>
    </el-dialog>
    <BindRouteDialog
        ref="BindRouteDialogRef"
        v-model="bindRouteDialogVisible"
        :type="bindDialogType"
        :rowData="rowData"
        @confirm="handleBindRouteSubmit"
    />
    <new-product-order v-if="isShowNewModal"
                         v-model:visible="isShowNewModal"
                         @completed="handleQuery" />
@@ -98,25 +80,39 @@
</template>
<script setup>
  import { onMounted, ref } from "vue";
  import { defineAsyncComponent, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  import { useRouter } from "vue-router";
  import {
    productOrderListPage,
    listProcessRoute,
    bindingRoute,
    listProcessBom, delProductOrder,
    delProductOrder,
    saveProductionProductInput,
    viewGetByProductWordId
  } from "@/api/productionManagement/productionOrder.js";
  import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
  import {fileDel} from "@/api/financialManagement/revenueManagement.js";
  import PIMTable from "@/components/PIMTable/PIMTable.vue";
  import BindRouteDialog from "./BindRouteDialog.vue";
  import {getDeviceLedger} from "@/api/equipmentManagement/ledger.js";
  const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
  const { proxy } = getCurrentInstance();
  const router = useRouter();
  const isShowNewModal = ref(false);
  const MOCK_MODE = true;
  const loading = ref(false)
  const dialogVisible = ref(false)
  const bindDialogType = ref('add')
  const BindRouteDialogRef = ref(null)
  const handleBindRouteSubmit =async (data)=>{
    const res = await saveProductionProductInput(data)
    console.log(res)
  }
  const tableColumn = ref([
    {
@@ -187,21 +183,22 @@
      label: "操作",
      align: "center",
      fixed: "right",
      width: 200,
      width: 300,
      operation: [
        {
          name: "工艺路线",
          type: "text",
          clickFun: row => {
            showRouteItemModal(row);
          },
        },
        {
          name: "绑定工艺路线",
          type: "text",
          showHide: row => !row.processRouteCode,
          clickFun: row => {
            openBindRouteDialog(row);
          },
        },
        {
          name: "查看工艺路线",
          type: "text",
          showHide: row => row.processRouteCode,
          clickFun: row => {
            openBindRouteDialog(row,"view");
          },
        },
        {
@@ -273,25 +270,27 @@
  const bindRouteLoading = ref(false);
  const bindRouteSaving = ref(false);
  const routeOptions = ref([]);
  const rowData = ref(null)
  const bindForm = reactive({
    orderId: null,
    routeId: null,
  });
  const openBindRouteDialog = async row => {
  const openBindRouteDialog = async (row,type) => {
    bindForm.orderId = row.id;
    bindForm.routeId = null;
    bindRouteDialogVisible.value = true;
    routeOptions.value = [];
    if (!row.productModelId) {
      proxy.$modal.msgWarning("当前订单缺少产品型号,无法查询工艺路线");
      bindRouteDialogVisible.value = false;
      return;
    }
    bindRouteLoading.value = true;
    if(type === "view") {
      bindDialogType.value = "view"
      let res = await viewGetByProductWordId(row.id)
      console.log(res)
    }
    BindRouteDialogRef.value?.getProductOrder()
    try {
      const res = await listProcessRoute({ productModelId: row.productModelId });
      routeOptions.value = res.data || [];
      rowData.value = row;
    } catch (e) {
      console.error("获取工艺路线列表失败:", e);
      proxy.$modal.msgError("获取工艺路线列表失败");
@@ -443,8 +442,6 @@
      });
  };
  const handleConfirmRoute = () => {};
  onMounted(() => {
    getList();
  });
@@ -464,10 +461,20 @@
}
::v-deep .red {
  background-color: #f80202;
  background-color: #ffe5e5;
}
::v-deep .purple{
  background-color: #F4DEFA;
}
:deep(.fixed-desc .el-descriptions__table) {
  table-layout: fixed;
  width: 100%;
}
:deep(.fixed-desc .el-descriptions__cell) {
  width: 25%;
  word-break: break-word;
}
</style>