完成了 BOM 管理和生产管理,完成部分发料单、采购计划和调拨单。
This commit is contained in:
535
src/views/production/production-plan/ProductionPlanView.vue
Normal file
535
src/views/production/production-plan/ProductionPlanView.vue
Normal file
@@ -0,0 +1,535 @@
|
||||
<script lang="ts" setup>
|
||||
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
|
||||
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
|
||||
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
|
||||
import { usePage } from "@/composables/use-page";
|
||||
import BaseForm from "@/components/base/base-form/BaseForm.vue";
|
||||
import { $t } from "@/common/languages";
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
|
||||
import { formatDate } from "@/common/utils/format-utils";
|
||||
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
|
||||
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
|
||||
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
|
||||
import { get, post } from "@/common/http/request";
|
||||
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
|
||||
import { DocumentType } from "@/common/enums/DocumentType";
|
||||
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
|
||||
|
||||
/**
|
||||
* 必须要的变量
|
||||
*/
|
||||
|
||||
const getPageUrl = "/production/productionPlan/getProductionPlanPage";
|
||||
const addUrl = "/production/productionPlan/addProductionPlan";
|
||||
const editUrl = "/production/productionPlan/updateProductionPlan";
|
||||
const removeUrl = "/production/productionPlan/deleteProductionPlan";
|
||||
const getProjectSelectList = "/production/bom/getBomSelectList";
|
||||
const getWarehouseSelectListUrl = "/warehouse/warehouse/getWarehouseSelectList";
|
||||
const getProductionPlanShortageListUrl = "/production/productionPlan/getMaterialShortageList";
|
||||
const generatePurchasePlanUrl = "/production/productionPlan/generatePurchasePlan";
|
||||
const generateTransferOrderUrl = "/production/productionPlan/generateTransferOrder";
|
||||
const generateProductionIssueUrl = "/production/productionPlan/generateProductionIssue";
|
||||
const searchers = [
|
||||
{ name: "projectName", type: "text" as const, placeholder: $t("_prop.production.production_plan.projectName") },
|
||||
];
|
||||
const rules = reactive<FormRules>({
|
||||
projectId: [{ required: true, message: $t("_message.production.production_plan.select_projectId"), trigger: "blur" }],
|
||||
productionNum: [
|
||||
{ required: true, message: $t("_message.production.production_plan.input_productionNum"), trigger: "blur" },
|
||||
],
|
||||
storeNo: [{ required: true, message: $t("_message.production.production_plan.select_storeNo"), trigger: "blur" }],
|
||||
productionCount: [
|
||||
{ required: true, message: $t("_message.production.production_plan.input_productionCount"), trigger: "blur" },
|
||||
],
|
||||
productionMark: [
|
||||
{ required: false, message: $t("_message.production.production_plan.input_productionMark"), trigger: "blur" },
|
||||
],
|
||||
productionNote: [
|
||||
{ required: false, message: $t("_message.production.production_plan.input_productionNote"), trigger: "blur" },
|
||||
],
|
||||
});
|
||||
/**
|
||||
* 基本不变通用变量
|
||||
*/
|
||||
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
|
||||
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
|
||||
const { title, visible, formType, form } = useGeneralPageRef();
|
||||
const { getProductionPlanStatusLabel } = useStatus();
|
||||
const bomSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||
const transferWarehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||
const dialogRef = ref<InstanceType<typeof BaseTableForm>>();
|
||||
const dialogVisible = ref(false);
|
||||
const shortageData = ref([]);
|
||||
const dialogTableData = ref([]);
|
||||
const dialogSelectable = ref(false);
|
||||
const transferWarehouse = ref();
|
||||
const issueDialogVisible = ref(false);
|
||||
/**
|
||||
* 可以自定义的变量
|
||||
*/
|
||||
|
||||
const add = () => {
|
||||
form.value = {};
|
||||
title.value = "_title.production.production_plan.add";
|
||||
form.value["productionNum"] = generateDucumentNo("SCJH");
|
||||
visible.value = true;
|
||||
formType.value = false;
|
||||
};
|
||||
const edit = (row: any) => {
|
||||
title.value = "_title.production.production_plan.edit";
|
||||
form.value = { ...row };
|
||||
visible.value = true;
|
||||
formType.value = true;
|
||||
};
|
||||
const remove = (row: any) => {
|
||||
useRemove(removeUrl, row.id, "_message.production.production_plan.delete_message");
|
||||
};
|
||||
const submit = (form: any, formRef: FormInstance | undefined) => {
|
||||
setName();
|
||||
if (formRef !== undefined) {
|
||||
formRef.validate(valid => {
|
||||
if (valid) {
|
||||
if (formType.value) useEdit(editUrl, form, visible);
|
||||
else useAdd(addUrl, form, visible);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validateSelection = (requireStatusZero = false) => {
|
||||
const rows = tableRef.value?.tableMainRef?.tableRef?.getSelectionRows();
|
||||
|
||||
if (!rows || rows.length === 0) {
|
||||
ElMessage.warning($t("_message.production.production_plan.select_production_plan"));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (requireStatusZero && !rows.every(row => row.productionStatus === 0)) {
|
||||
ElMessage.warning($t("_message.production.production_plan.error_production_status"));
|
||||
return null;
|
||||
}
|
||||
|
||||
const warehouseId = rows[0].storeNo;
|
||||
if (!rows.every(item => item.storeNo === warehouseId)) {
|
||||
ElMessage.warning($t("_message.production.production_plan.duplicate_store_no"));
|
||||
return null;
|
||||
}
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
const buildDocumentInfo = (rows: any[], type: DocumentType | string, markSuffixKey: string, nameSuffixKey: string) => {
|
||||
const code = generateDucumentNo(type);
|
||||
const productionNums = rows.map((item: any) => item.productionNum).join(",");
|
||||
const projectNames = rows.map((item: any) => item.projectName).join(",");
|
||||
|
||||
return {
|
||||
code,
|
||||
mark:
|
||||
$t("_message.common.generate_document_mark_prefix") +
|
||||
productionNums +
|
||||
$t(markSuffixKey) +
|
||||
code +
|
||||
$t("_message.common.generate_document_mark_suffix"),
|
||||
name: projectNames + $t(nameSuffixKey),
|
||||
};
|
||||
};
|
||||
|
||||
const viewMaterialShortage = async () => {
|
||||
const rows = validateSelection(true); // 需要校验状态为 0
|
||||
if (!rows) return;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
rows.forEach(({ id }) => params.append("ids", id));
|
||||
|
||||
shortageData.value = await get(getProductionPlanShortageListUrl, params).then(res => res.data);
|
||||
|
||||
calculateDiffQty();
|
||||
dialogRef.value?.clearSelection();
|
||||
dialogTableData.value = shortageData.value;
|
||||
dialogSelectable.value = false;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const generatePurchasePlan = (selectedShortageRows: any[]) => {
|
||||
ElMessageBox.confirm($t("_message.production.production_plan.generate_purchase_plan_confirm"), $t("_level.warning"), {
|
||||
confirmButtonText: $t("_button.confirm"),
|
||||
cancelButtonText: $t("_button.cancel"),
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
const rows = validateSelection();
|
||||
if (!rows) return;
|
||||
|
||||
const {
|
||||
code: planNo,
|
||||
mark: planMark,
|
||||
name: planName,
|
||||
} = buildDocumentInfo(
|
||||
rows,
|
||||
"PA",
|
||||
"_message.production.production_plan.generate_purchase_plan_mark_suffix",
|
||||
"_message.production.production_plan.generate_purchase_plan_name_suffix"
|
||||
);
|
||||
|
||||
const plan = {
|
||||
planNo,
|
||||
storeNo: rows[0].storeNo,
|
||||
storeName: rows[0].storeName,
|
||||
remask: planMark,
|
||||
planName,
|
||||
planItems: selectedShortageRows.map(({ partNumber, diffQty, id }) => ({
|
||||
partNumber,
|
||||
purchaseCount: -diffQty,
|
||||
partId: id,
|
||||
})),
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await post(generatePurchasePlanUrl, plan);
|
||||
ElMessage[res.code === 0 ? "success" : "error"](
|
||||
res.code === 0
|
||||
? $t("_message.production.production_plan.generate_purchase_plan_success")
|
||||
: $t("_message.production.production_plan.generate_purchase_plan_fail") + res.msg
|
||||
);
|
||||
} catch (err) {
|
||||
ElMessage.error($t("_message.production.production_plan.generate_purchase_plan_fail") + err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const generateTransferOrder = (selectedShortageRows: any[]) => {
|
||||
ElMessageBox.confirm(
|
||||
$t("_message.production.production_plan.generate_transfer_order_confirm"),
|
||||
$t("_level.warning"),
|
||||
{
|
||||
confirmButtonText: $t("_button.confirm"),
|
||||
cancelButtonText: $t("_button.cancel"),
|
||||
type: "warning",
|
||||
}
|
||||
).then(async () => {
|
||||
const rows = validateSelection();
|
||||
if (!rows) return;
|
||||
|
||||
const outWarehouseId = transferWarehouse.value;
|
||||
if (!outWarehouseId) {
|
||||
ElMessage.warning("仓库不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
const outWarehouseName = transferWarehouseSelectRef.value?.getLabel();
|
||||
if (rows[0].storeNo === outWarehouseId) {
|
||||
ElMessage.warning("仓库不能相同");
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
code: formCode,
|
||||
mark: formMark,
|
||||
name: formName,
|
||||
} = buildDocumentInfo(
|
||||
rows,
|
||||
DocumentType.StockTransferOrder,
|
||||
"_message.production.production_plan.generate_transfer_order_mark_suffix",
|
||||
"_message.production.production_plan.generate_transfer_order_name_suffix"
|
||||
);
|
||||
|
||||
const plan = {
|
||||
formCode,
|
||||
formName,
|
||||
formMark,
|
||||
storeNo: rows[0].storeNo,
|
||||
storeName: rows[0].storeName,
|
||||
outStoreNo: outWarehouseId,
|
||||
outStoreName: outWarehouseName,
|
||||
transferOrderItems: selectedShortageRows.map(({ partNumber, diffQty, productSpec, id }) => ({
|
||||
partNumber,
|
||||
productCount: -diffQty,
|
||||
productSpec,
|
||||
partId: id,
|
||||
})),
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await post(generateTransferOrderUrl, plan);
|
||||
ElMessage[res.code === 0 ? "success" : "error"](
|
||||
res.code === 0
|
||||
? $t("_message.production.production_plan.generate_transfer_order_success")
|
||||
: $t("_message.production.production_plan.generate_transfer_order_fail") + res.msg
|
||||
);
|
||||
} catch (err) {
|
||||
ElMessage.error($t("_message.production.production_plan.generate_transfer_order_fail") + err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const generateProductionIssue = async () => {
|
||||
const rows = validateSelection(true); // 需要校验状态为 0
|
||||
if (!rows) return;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
rows.forEach(({ id }) => params.append("ids", id));
|
||||
|
||||
dialogTableData.value = await get(getProductionPlanShortageListUrl, params).then(res => res.data);
|
||||
setActualQtyAndDiffQty();
|
||||
issueDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const _generateProductionIssue = async () => {
|
||||
ElMessageBox.confirm(
|
||||
$t("_message.production.production_plan.generate_production_issue_confirm"),
|
||||
$t("_level.warning"),
|
||||
{
|
||||
confirmButtonText: $t("_button.confirm"),
|
||||
cancelButtonText: $t("_button.cancel"),
|
||||
type: "warning",
|
||||
}
|
||||
).then(async () => {
|
||||
const rows = validateSelection();
|
||||
if (!rows) return;
|
||||
|
||||
const {
|
||||
code: formCode,
|
||||
mark: formMark,
|
||||
name: formName,
|
||||
} = buildDocumentInfo(
|
||||
rows,
|
||||
DocumentType.StockTransferOrder,
|
||||
"_message.production.production_plan.generate_production_issue_mark_suffix",
|
||||
"_message.production.production_plan.generate_production_issue_name_suffix"
|
||||
);
|
||||
|
||||
const issue = {
|
||||
formCode,
|
||||
formName,
|
||||
formMark,
|
||||
storeNo: rows[0].storeNo,
|
||||
storeName: rows[0].storeName,
|
||||
items: dialogTableData.value.map(({ partNumber, storeNo, actualQty, requiredQty }) => ({
|
||||
partNumber,
|
||||
storeNo,
|
||||
productCount: actualQty,
|
||||
demandCount: requiredQty,
|
||||
})),
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await post(generateProductionIssueUrl, { ids: rows.map(r => r.id), issue });
|
||||
if (res.code === 0) {
|
||||
issueDialogVisible.value = false;
|
||||
tableRef.value?.reload();
|
||||
ElMessage.success($t("_message.production.production_plan.generate_production_issue_success"));
|
||||
} else {
|
||||
ElMessage.error($t("_message.production.production_plan.generate_production_issue_fail") + res.msg);
|
||||
}
|
||||
} catch (err) {
|
||||
ElMessage.error($t("_message.production.production_plan.generate_production_issue_fail") + err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const calculateDiffQty = () => {
|
||||
shortageData.value.forEach((item: any) => {
|
||||
item.diffQty = computed(() => item.stockQty - item.requiredQty);
|
||||
});
|
||||
};
|
||||
|
||||
const setActualQtyAndDiffQty = () => {
|
||||
dialogTableData.value.forEach((item: any) => {
|
||||
item.actualQty = item.requiredQty;
|
||||
item.diffQty = computed(() => item.stockQty - item.requiredQty);
|
||||
});
|
||||
};
|
||||
|
||||
const handleShortageFilterSubmit = () => {
|
||||
dialogTableData.value = shortageData.value.filter(item => (item as any).diffQty < 0);
|
||||
dialogSelectable.value = true;
|
||||
};
|
||||
|
||||
const handleUnfilterSubmit = () => {
|
||||
dialogTableData.value = shortageData.value;
|
||||
dialogSelectable.value = false;
|
||||
};
|
||||
|
||||
const topButtonClick = (eventName: string) => {
|
||||
switch (eventName) {
|
||||
case "add":
|
||||
add();
|
||||
break;
|
||||
case "viewMaterialShortage":
|
||||
viewMaterialShortage();
|
||||
break;
|
||||
case "generateProductionIssue":
|
||||
generateProductionIssue();
|
||||
break;
|
||||
}
|
||||
};
|
||||
const operateButtonClick = (eventName: string, row: any) => {
|
||||
switch (eventName) {
|
||||
case "edit":
|
||||
edit(row);
|
||||
break;
|
||||
case "remove":
|
||||
remove(row);
|
||||
break;
|
||||
}
|
||||
};
|
||||
const dialogButtonClick = (eventName: string, btn: any, rows: any[]) => {
|
||||
switch (eventName) {
|
||||
case "generatePurchasePlan":
|
||||
generatePurchasePlan(rows);
|
||||
break;
|
||||
case "generateTransferOrder":
|
||||
generateTransferOrder(rows);
|
||||
break;
|
||||
}
|
||||
};
|
||||
const setName = () => {
|
||||
form.value["projectName"] = bomSelectRef.value?.getLabel();
|
||||
form.value["storeName"] = warehouseSelectRef.value?.getLabel();
|
||||
};
|
||||
const handleReset = () => {
|
||||
form.value["productionNum"] = generateDucumentNo("SCJH");
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
|
||||
<template #tool-button>
|
||||
<DefaultToolButton @top-button-click="topButtonClick" />
|
||||
</template>
|
||||
<template #columns>
|
||||
<el-table-column prop="id" type="selection" width="40" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.productionNum')" prop="productionNum" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.projectName')" prop="projectName" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.storeName')" prop="storeName" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.productionCount')" prop="productionCount" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.productionMark')" prop="productionMark" />
|
||||
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
|
||||
<DefaultStatusSwitchColumn
|
||||
status-param-name="productionStatus"
|
||||
:status-label-mapping="getProductionPlanStatusLabel"
|
||||
/>
|
||||
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
|
||||
</template>
|
||||
</BasePageableTable>
|
||||
<BaseForm
|
||||
v-model:visible="visible"
|
||||
@submit="submit"
|
||||
v-model:form="form"
|
||||
:title="$t(title)"
|
||||
:rules="rules"
|
||||
@reset="handleReset"
|
||||
>
|
||||
<template #form-items>
|
||||
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
|
||||
<el-form-item prop="projectName" v-if="false"><el-input v-model="form.projectName" /></el-form-item>
|
||||
<el-form-item prop="storeName" v-if="false"><el-input v-model="form.storeName" /></el-form-item>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('_prop.production.production_plan.projectId')" prop="projectId">
|
||||
<BaseSelect v-model="form.projectId" :url="getProjectSelectList" ref="bomSelectRef" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('_prop.production.production_plan.productionNum')" prop="productionNum">
|
||||
<el-input
|
||||
v-model="form.productionNum"
|
||||
:placeholder="$t('_message.production.production_plan.input_productionNum')"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('_prop.production.production_plan.storeNo')" prop="storeNo">
|
||||
<BaseSelect v-model="form.storeNo" :url="getWarehouseSelectListUrl" ref="warehouseSelectRef" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('_prop.production.production_plan.productionCount')" prop="productionCount">
|
||||
<el-input-number
|
||||
:min="1"
|
||||
v-model="form.productionCount"
|
||||
:placeholder="$t('_message.production.production_plan.input_productionCount')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item :label="$t('_prop.production.production_plan.productionMark')" prop="productionMark">
|
||||
<el-input
|
||||
v-model="form.productionMark"
|
||||
type="textarea"
|
||||
autosize
|
||||
:placeholder="$t('_message.production.production_plan.input_productionMark')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('_prop.production.production_plan.productionNote')" prop="productionNote">
|
||||
<el-input
|
||||
v-model="form.productionNote"
|
||||
type="textarea"
|
||||
autosize
|
||||
:placeholder="$t('_message.production.production_plan.input_productionNote')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</BaseForm>
|
||||
<BaseTableForm
|
||||
ref="dialogRef"
|
||||
v-model:visible="dialogVisible"
|
||||
:title="$t('_title.production.production_plan.dialog')"
|
||||
:tableData="dialogTableData"
|
||||
:selectable="dialogSelectable"
|
||||
row-key="partNumber"
|
||||
@dialog-button-click="dialogButtonClick"
|
||||
>
|
||||
<template #filter>
|
||||
<el-button type="danger" @click="handleShortageFilterSubmit">{{ $t("_button.shortageFilterButton") }}</el-button>
|
||||
<el-button type="primary" @click="handleUnfilterSubmit">{{ $t("_button.unfilterButton") }}</el-button>
|
||||
</template>
|
||||
<template #table-columns>
|
||||
<el-table-column :label="$t('_prop.production.bom_item.partNumber')" prop="partNumber" />
|
||||
<el-table-column :label="$t('_prop.production.bom_item.productSpecs')" prop="productSpecs" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.requiredQty')" prop="requiredQty">
|
||||
<template #default="{ row }">
|
||||
<el-input-number v-model="row.requiredQty" :min="0" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('_prop.production.production_plan.stockQty')" prop="stockQty" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.diffQty')" prop="diffQty" />
|
||||
</template>
|
||||
<template #attachment="{ checkPermission }">
|
||||
<div v-if="checkPermission('generateTransferOrder')" style="display: flex; align-items: center">
|
||||
<span style="width: 200px; padding-right: 20px">{{ $t("_prop.production.production_plan.outStoreNo") }}</span>
|
||||
<BaseSelect v-model="transferWarehouse" :url="getWarehouseSelectListUrl" ref="transferWarehouseSelectRef" />
|
||||
</div>
|
||||
</template>
|
||||
</BaseTableForm>
|
||||
<BaseTableForm
|
||||
ref="dialogRef"
|
||||
v-model:visible="issueDialogVisible"
|
||||
:title="$t('_title.production.production_plan.issueDialog')"
|
||||
:tableData="dialogTableData"
|
||||
:selectable="false"
|
||||
:useAuth="false"
|
||||
>
|
||||
<template #table-columns>
|
||||
<el-table-column :label="$t('_prop.production.bom_item.partNumber')" prop="partNumber" />
|
||||
<el-table-column :label="$t('_prop.production.bom_item.productSpecs')" prop="productSpecs" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.requiredQty')" prop="requiredQty" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.actualQty')" prop="actualQty">
|
||||
<template #default="{ row }">
|
||||
<el-input-number v-model="row.actualQty" :min="0" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('_prop.production.production_plan.stockQty')" prop="stockQty" />
|
||||
<el-table-column :label="$t('_prop.production.production_plan.diffQty')" prop="diffQty" />
|
||||
</template>
|
||||
<template #attachment>
|
||||
<el-button type="primary" @click="_generateProductionIssue">
|
||||
{{ $t("_button.submit") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</BaseTableForm>
|
||||
</template>
|
||||
Reference in New Issue
Block a user