gaoluyang
2 天以前 3a07f2ca675bbd3c55893f7731b8f49d854b0e07
src/views/productionManagement/productionOrder/New.vue
@@ -3,66 +3,95 @@
    <el-dialog
        v-model="isShow"
        title="新增生产订单"
        width="800"
        width="1500"
        :close-on-click-modal="false"
        @close="closeModal"
        class="production-order-dialog"
    >
      <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
        <el-form-item
            label="产品名称"
            prop="productModelId"
            :rules="[
                {
                required: true,
                message: '请选择产品',
                trigger: 'change',
              }
            ]"
        >
          <el-button type="primary" @click="showProductSelectDialog = true">
            {{ formState.productName ? formState.productName : '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item
            label="图纸编号"
            prop="drawingNumber"
        >
          <el-input v-model="formState.drawingNumber"  disabled />
        </el-form-item>
        <el-form-item
            label="规格"
            prop="productModelName"
        >
          <el-input v-model="formState.productModelName"  disabled />
        </el-form-item>
        <el-form-item
            label="单位"
            prop="unit"
        >
          <el-input v-model="formState.unit"  disabled />
        </el-form-item>
        <el-form-item label="工艺路线">
          <el-select v-model="formState.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-item
            label="需求数量"
            prop="quantity"
        >
          <el-input-number v-model="formState.quantity" :step="1" :min="1" style="width: 100%" />
        </el-form-item>
      </el-form>
      <!-- 基本信息 -->
      <div class="section-card">
        <div class="section-header">
          <span class="section-icon">📋</span>
          <span class="section-title-text">基本信息</span>
        </div>
        <el-form label-width="100px" :model="formState" label-position="right" ref="formRef" class="compact-form">
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item
                  label="产品名称"
                  prop="productModelId"
                  :rules="[{ required: true, message: '请选择产品', trigger: 'change' }]"
              >
                <el-button type="primary" @click="showProductSelectDialog = true" class="select-btn">
                  {{ formState.productName ? formState.productName : '选择产品' }}
                </el-button>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="图纸编号" prop="productModelName">
                <el-input v-model="formState.productModelName" disabled />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="单位" prop="unit">
                <el-input v-model="formState.unit" disabled />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="销售合同号" prop="salesContractNo">
                <el-input v-model="formState.salesContractNo" placeholder="请输入销售合同号" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="客户名称" prop="customerName">
                <el-input v-model="formState.customerName" placeholder="请输入客户名称" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="需求数量" prop="quantity">
                <el-input-number v-model="formState.quantity" :step="1" :min="1" style="width: 100%" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="交付日期" prop="deliveryDate">
                <el-date-picker
                    v-model="formState.deliveryDate"
                    type="date"
                    placeholder="选择交付日期"
                    style="width: 100%"
                    format="YYYY-MM-DD"
                    value-format="YYYY-MM-DD"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="图纸上传">
                <el-upload
                    action="#"
                    :auto-upload="false"
                    :on-change="handleFileChange"
                    :file-list="fileList"
                    :limit="5"
                    class="upload-inline"
                >
                  <el-button type="primary" plain size="small">
                    <el-icon><Upload /></el-icon> 选择文件
                  </el-button>
                  <template #tip>
                    <div class="el-upload__tip">支持jpg/png/pdf,单个不超过10MB</div>
                  </template>
                </el-upload>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </div>
      <!-- 产品选择弹窗 -->
      <ProductSelectDialog
@@ -70,6 +99,136 @@
          @confirm="handleProductSelect"
          single
      />
      <!-- 用料产品选择弹窗 -->
      <ProductSelectDialog
          v-model="showMaterialProductDialog"
          @confirm="handleMaterialProductSelect"
      />
      <!-- 生产任务 -->
      <div class="section-card">
        <div class="section-header">
          <span class="section-icon">🔧</span>
          <span class="section-title-text">生产任务</span>
          <el-button type="primary" size="small" @click="addProductionTask" class="add-btn">
            <el-icon><Plus /></el-icon> 添加任务
          </el-button>
        </div>
        <div class="table-container">
          <el-table :data="productionTaskList" border size="small" class="compact-table">
        <el-table-column type="index" label="序号" width="60" />
        <el-table-column label="工序名称" min-width="150">
          <template #default="{ row }">
            <el-select
              v-model="row.processId"
              placeholder="请选择工序"
              style="width: 100%"
              @change="(val) => handleProcessChange(val, row)"
            >
              <el-option
                v-for="item in processOptions"
                :key="item.id"
                :label="item.name"
                :value="item.id"
              />
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="计划数" min-width="120">
          <template #default="{ row }">
            <el-input-number v-model="row.planQuantity" :min="0" style="width: 100%" />
          </template>
        </el-table-column>
        <el-table-column label="报工权限" min-width="150">
          <template #default="{ row }">
            <el-input v-model="row.reportPermission" placeholder="请输入报工权限" />
          </template>
        </el-table-column>
        <el-table-column label="计划开始时间" min-width="180">
          <template #default="{ row }">
            <el-date-picker
                v-model="row.planStartTime"
                type="datetime"
                placeholder="选择开始时间"
                style="width: 100%"
                format="YYYY-MM-DD HH:mm"
                value-format="YYYY-MM-DD HH:mm:ss"
            />
          </template>
        </el-table-column>
        <el-table-column label="计划结束时间" min-width="180">
          <template #default="{ row }">
            <el-date-picker
                v-model="row.planEndTime"
                type="datetime"
                placeholder="选择结束时间"
                style="width: 100%"
                format="YYYY-MM-DD HH:mm"
                value-format="YYYY-MM-DD HH:mm:ss"
            />
          </template>
        </el-table-column>
        <el-table-column label="操作" width="80" fixed="right" align="center">
          <template #default="{ $index }">
            <el-button type="danger" link size="small" @click="removeProductionTask($index)">
              <el-icon><Delete /></el-icon>
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <div v-if="productionTaskList.length === 0" class="empty-tip">
        <el-empty description="暂无生产任务,点击上方按钮添加" :image-size="60" />
      </div>
        </div>
      </div>
      <!-- 用料清单 -->
      <div class="section-card">
        <div class="section-header">
          <span class="section-icon">📦</span>
          <span class="section-title-text">用料清单</span>
          <el-button type="primary" size="small" @click="addMaterialItem" class="add-btn">
            <el-icon><Plus /></el-icon> 添加用料
          </el-button>
        </div>
        <div class="table-container">
          <el-table :data="materialList" border size="small" class="compact-table">
            <el-table-column type="index" label="序号" width="50" align="center" />
            <el-table-column label="图纸编号" min-width="140">
              <template #default="{ row }">
                <el-input v-model="row.drawingNumber" placeholder="请输入图纸编号" size="small" />
              </template>
            </el-table-column>
            <el-table-column label="产品名称" min-width="140">
              <template #default="{ row }">
                <el-input v-model="row.productName" placeholder="请输入产品名称" size="small" />
              </template>
            </el-table-column>
            <el-table-column label="单位用量" min-width="100">
              <template #default="{ row }">
                <el-input-number v-model="row.unitQuantity" :min="0" :precision="2" size="small" style="width: 100%" />
              </template>
            </el-table-column>
            <el-table-column label="库存数量" min-width="100">
              <template #default="{ row }">
                <el-input-number v-model="row.inventoryQuantity" :min="0" size="small" style="width: 100%" />
              </template>
            </el-table-column>
            <el-table-column label="操作" width="80" fixed="right" align="center">
              <template #default="{ $index }">
                <el-button type="danger" link size="small" @click="removeMaterialItem($index)">
                  <el-icon><Delete /></el-icon>
                </el-button>
              </template>
            </el-table-column>
          </el-table>
          <div v-if="materialList.length === 0" class="empty-tip">
            <el-empty description="暂无用料清单,点击上方按钮添加" :image-size="60" />
          </div>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
@@ -82,8 +241,10 @@
<script setup>
import {ref, computed, getCurrentInstance} from "vue";
import { Plus, Delete, Upload } from '@element-plus/icons-vue';
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import {addProductOrder, listProcessRoute} from "@/api/productionManagement/productionOrder.js";
import {list as listProcess} from "@/api/productionManagement/productionProcess.js";
const props = defineProps({
  visible: {
@@ -110,7 +271,22 @@
  unit: "",
  drawingNumber: "",
  quantity: 0,
  salesContractNo: "",
  customerName: "",
  deliveryDate: "",
});
// 生产任务列表
const productionTaskList = ref([]);
// 用料清单列表
const materialList = ref([]);
// 工序列表
const processOptions = ref([]);
// 文件列表
const fileList = ref([]);
const isShow = computed({
  get() {
@@ -122,6 +298,17 @@
});
const showProductSelectDialog = ref(false);
const showMaterialProductDialog = ref(false);
// 获取工序列表
const fetchProcessOptions = () => {
  listProcess().then(res => {
    processOptions.value = res.data || [];
  });
};
// 组件挂载时获取工序列表
fetchProcessOptions();
let { proxy } = getCurrentInstance()
@@ -134,8 +321,16 @@
    productName: "",
    drawingNumber: "",
    productModelName: "",
    quantity: '',
    unit: "",
    quantity: 0,
    salesContractNo: "",
    customerName: "",
    deliveryDate: "",
  };
  // 重置生产任务和用料清单
  productionTaskList.value = [];
  materialList.value = [];
  fileList.value = [];
  isShow.value = false;
};
@@ -169,6 +364,65 @@
  })
}
// 工序选择变化处理
const handleProcessChange = (processId, row) => {
  const selectedProcess = processOptions.value.find(item => item.id === processId);
  if (selectedProcess) {
    row.processName = selectedProcess.name;
    row.processNo = selectedProcess.no;
  }
};
// 添加生产任务
const addProductionTask = () => {
  productionTaskList.value.push({
    processId: undefined,
    processName: "",
    processNo: "",
    planQuantity: 1,
    reportPermission: "",
    planStartTime: "",
    planEndTime: "",
  });
};
// 删除生产任务
const removeProductionTask = (index) => {
  productionTaskList.value.splice(index, 1);
};
// 添加用料 - 弹出产品选择框
const addMaterialItem = () => {
  showMaterialProductDialog.value = true;
};
// 处理用料产品选择
const handleMaterialProductSelect = (products) => {
  if (products && products.length > 0) {
    products.forEach(product => {
      materialList.value.push({
        productModelId: product.id,
        drawingNumber: product.model,
        productName: product.productName,
        unit: product.unit,
        unitQuantity: 1,
        inventoryQuantity: 0,
      });
    });
  }
  showMaterialProductDialog.value = false;
};
// 删除用料
const removeMaterialItem = (index) => {
  materialList.value.splice(index, 1);
};
// 文件上传变更
const handleFileChange = (file, files) => {
  fileList.value = files;
};
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
@@ -182,7 +436,15 @@
        return;
      }
      addProductOrder(formState.value).then(res => {
      // 组装提交数据
      const submitData = {
        ...formState.value,
        productionTasks: productionTaskList.value,
        materials: materialList.value,
        files: fileList.value,
      };
      addProductOrder(submitData).then(res => {
        // 关闭模态框
        isShow.value = false;
        // 告知父组件已完成
@@ -200,3 +462,90 @@
  isShow,
});
</script>
<style scoped>
.production-order-dialog :deep(.el-dialog__body) {
  padding: 15px 20px;
  max-height: 70vh;
  overflow-y: auto;
}
.section-card {
  background: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
  margin-bottom: 15px;
}
.section-header {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #e4e7ed;
}
.section-icon {
  font-size: 18px;
  margin-right: 8px;
}
.section-title-text {
  font-size: 15px;
  font-weight: 600;
  color: #303133;
  flex: 1;
}
.add-btn {
  margin-left: auto;
}
.compact-form :deep(.el-form-item) {
  margin-bottom: 12px;
}
.compact-form :deep(.el-form-item__label) {
  font-size: 13px;
  color: #606266;
}
.select-btn {
  width: 100%;
  justify-content: flex-start;
}
.table-container {
  background: #fff;
  border-radius: 4px;
  padding: 10px;
}
.compact-table :deep(.el-table__cell) {
  padding: 4px 0;
}
.compact-table :deep(.el-input__wrapper),
.compact-table :deep(.el-input-number) {
  width: 100%;
}
.empty-tip {
  padding: 20px 0;
}
.upload-inline :deep(.el-upload) {
  display: inline-flex;
}
.upload-inline :deep(.el-upload__tip) {
  margin-top: 4px;
  font-size: 12px;
}
.dialog-footer {
  display: flex;
  justify-content: center;
  gap: 10px;
}
</style>