669 lines
23 KiB
Vue
669 lines
23 KiB
Vue
<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 DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
|
||
import { usePage } from "@/composables/use-page";
|
||
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
||
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
|
||
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
|
||
import { $t } from "@/common/languages";
|
||
import type { FormInstance, FormRules } from "element-plus";
|
||
import { formatDate } from "@/common/utils/format-utils";
|
||
import { get, post } from "@/common/http/request";
|
||
import { ElMessage } from "element-plus";
|
||
import type { FieldMappingConfig } from "@/components/base/base-form-with-table/type";
|
||
import { ref } from "vue";
|
||
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
|
||
import Decimal from "decimal.js";
|
||
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
|
||
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
|
||
|
||
/**
|
||
* 必须要的变量
|
||
*/
|
||
|
||
const getPageUrl = "/purchase/purchaseplan/getPurchasePlanPage";
|
||
const addUrl = "/purchase/purchaseplan/addPurchasePlan";
|
||
const editUrl = "/purchase/purchaseplan/updatePurchasePlan";
|
||
const removeUrl = "/purchase/purchaseplan/deletePurchasePlan";
|
||
const getItemsUrl = "/purchase/purchaseplan/getPurchasePlanItemsWithVendorSuggestions";
|
||
const generateOrderUrl = "/purchase/purchaseplan/generatePurchaseOrder";
|
||
const getItemUrl = "/purchase/purchaseplan/getPurchasePlanItems";
|
||
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
|
||
const searchers = [
|
||
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.purchase.purchase_plan.searchCode") },
|
||
];
|
||
|
||
const { getPurchasePlanStatusLabel, getPurchasePlanItemStatusLabel } = useStatus();
|
||
const rules = reactive<FormRules>({
|
||
planName: [{ required: true, message: $t("_message.purchase.purchase_plan.input_planName"), trigger: "blur" }],
|
||
vendorId: [{ required: true, message: $t("_message.purchase.purchase_plan.select_vendor"), trigger: "blur" }],
|
||
storeNo: [{ required: true, message: $t("_message.purchase.purchase_plan.select_store"), trigger: "blur" }],
|
||
planItems: [
|
||
{
|
||
required: true,
|
||
validator: (rule, value, callback) => {
|
||
if (value === undefined || value.length === 0) {
|
||
callback($t("_message.purchase.purchase_plan.upload_planItems"));
|
||
}
|
||
callback();
|
||
},
|
||
trigger: "change",
|
||
},
|
||
],
|
||
});
|
||
const itemArrayName = "planItems";
|
||
|
||
/**
|
||
* 验证物料编号是否存在
|
||
*/
|
||
const validatePartNumber = (rule: any, value: string, callback: (error?: Error) => void) => {
|
||
if (!value) {
|
||
callback(new Error($t("_message.purchase.purchase_plan_item.input_partNumber")));
|
||
return;
|
||
}
|
||
get(partNumberExistsUrl, { partNumber: value })
|
||
.then(res => {
|
||
if (res.data === true) {
|
||
callback();
|
||
} else {
|
||
callback(new Error($t("_message.warehouse.warehouse_item.not_exist_partNumber")));
|
||
}
|
||
})
|
||
.catch(() => {
|
||
callback();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 基本不变通用变量
|
||
*/
|
||
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
|
||
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
|
||
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
|
||
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
|
||
const generateOrderVisible = ref(false);
|
||
const generateOrderForm = reactive({
|
||
planId: 0,
|
||
planStatus: 0,
|
||
planNo: "",
|
||
});
|
||
const planItems = ref([] as any[]);
|
||
const allVendors = ref([] as any[]);
|
||
const partVendorMappings = ref([] as any[]);
|
||
|
||
const NOT_PURCHASE_VENDOR_ID = -1;
|
||
|
||
const add = () => {
|
||
form.value = {
|
||
planItems: [],
|
||
};
|
||
title.value = "_title.purchase.purchase_plan.add";
|
||
visible.value = true;
|
||
formType.value = false;
|
||
};
|
||
const edit = (row: any) => {
|
||
title.value = "_title.purchase.purchase_plan.edit";
|
||
form.value = { ...row };
|
||
visible.value = true;
|
||
formType.value = true;
|
||
};
|
||
const remove = (row: any) => {
|
||
useRemove(removeUrl, row.id, "_message.purchase.purchase_plan.delete_message");
|
||
};
|
||
const showItem = (row: any) => {
|
||
itemParentId.value = row.id;
|
||
itemVisible.value = true;
|
||
};
|
||
const submit = (form: any, formRef: FormInstance | undefined) => {
|
||
if (formRef !== undefined) {
|
||
formRef.validate(valid => {
|
||
if (valid) {
|
||
if (formType.value) useEdit(editUrl, form, visible);
|
||
else useAdd(addUrl, form, visible);
|
||
}
|
||
});
|
||
}
|
||
};
|
||
const topButtonClick = (eventName: string) => {
|
||
switch (eventName) {
|
||
case "add":
|
||
add();
|
||
break;
|
||
}
|
||
};
|
||
|
||
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
|
||
if (row.planStatus === 2 && button.eventName === "generatePurchaseOrder") {
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
// 采购计划状态标签类型映射
|
||
const getPurchasePlanStatusTagType = (code: number | null): string => {
|
||
const tagTypeMap: Record<number, string> = {
|
||
0: "warning", // 待处理
|
||
1: "primary", // 进行中
|
||
2: "success", // 已完成
|
||
};
|
||
return tagTypeMap[code ?? -1] || "info";
|
||
};
|
||
|
||
const operateButtonClick = (eventName: string, row: any) => {
|
||
switch (eventName) {
|
||
case "edit":
|
||
edit(row);
|
||
break;
|
||
case "remove":
|
||
remove(row);
|
||
break;
|
||
case "generatePurchaseOrder":
|
||
showGenerateOrderDialog(row);
|
||
break;
|
||
case "showItem":
|
||
showItem(row);
|
||
break;
|
||
}
|
||
};
|
||
|
||
const buildVendorSuggestions = (item: any) => {
|
||
const suggestions: any[] = [];
|
||
const addedVendorIds = new Set<number>();
|
||
|
||
const vendorCode1 = item.vendorCode1;
|
||
const vendorCode2 = item.vendorCode2;
|
||
const vendorCode3 = item.vendorCode3;
|
||
|
||
const vendorCodes = [vendorCode1, vendorCode2, vendorCode3];
|
||
for (let i = 0; i < vendorCodes.length; i++) {
|
||
if (vendorCodes[i] != null && !addedVendorIds.has(vendorCodes[i])) {
|
||
const vendor = allVendors.value.find((v: any) => v.vendorId === vendorCodes[i]);
|
||
if (vendor) {
|
||
const mapping = partVendorMappings.value.find(
|
||
(m: any) => m.partNumber === item.partNumber && m.vendorId === vendor.vendorId
|
||
);
|
||
suggestions.push({
|
||
vendorId: vendor.vendorId,
|
||
vendorName: vendor.vendorName,
|
||
priority: i + 1,
|
||
price: mapping?.costPrice || 0,
|
||
});
|
||
addedVendorIds.add(vendor.vendorId);
|
||
}
|
||
}
|
||
}
|
||
|
||
const itemMappings = partVendorMappings.value.filter((m: any) => m.partNumber === item.partNumber);
|
||
for (const mapping of itemMappings) {
|
||
if (!addedVendorIds.has(mapping.vendorId)) {
|
||
const vendor = allVendors.value.find((v: any) => v.vendorId === mapping.vendorId);
|
||
if (vendor) {
|
||
suggestions.push({
|
||
vendorId: vendor.vendorId,
|
||
vendorName: vendor.vendorName,
|
||
priority: 2,
|
||
price: mapping.costPrice || 0,
|
||
});
|
||
addedVendorIds.add(vendor.vendorId);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (const vendor of allVendors.value) {
|
||
if (!addedVendorIds.has(vendor.vendorId)) {
|
||
suggestions.push({
|
||
vendorId: vendor.vendorId,
|
||
vendorName: vendor.vendorName,
|
||
priority: 3,
|
||
price: 0,
|
||
});
|
||
addedVendorIds.add(vendor.vendorId);
|
||
}
|
||
}
|
||
|
||
suggestions.push({
|
||
vendorId: NOT_PURCHASE_VENDOR_ID,
|
||
vendorName: "暂不采购",
|
||
priority: 99,
|
||
price: 0,
|
||
});
|
||
|
||
return suggestions;
|
||
};
|
||
|
||
const showGenerateOrderDialog = async (row: any) => {
|
||
generateOrderForm.planId = row.id;
|
||
generateOrderForm.planStatus = row.planStatus;
|
||
generateOrderForm.planNo = row.planNo;
|
||
|
||
try {
|
||
const response = await get(getItemsUrl, { planId: row.id });
|
||
const data = response.data;
|
||
|
||
allVendors.value = data.allVendors || [];
|
||
partVendorMappings.value = data.partVendorMappings || [];
|
||
planItems.value = (data.items || []).map((item: any) => {
|
||
const currentCount = item.currentCount || item.purchaseCount || 1;
|
||
const price = item.price || 0;
|
||
|
||
return {
|
||
...item,
|
||
currentCount,
|
||
price,
|
||
total: new Decimal(currentCount).mul(price).toNumber(),
|
||
vendorSuggestions: [],
|
||
calculateTotal: function () {
|
||
this.total = new Decimal(this.currentCount).mul(this.price).toNumber();
|
||
},
|
||
};
|
||
});
|
||
|
||
for (const item of planItems.value) {
|
||
item.vendorSuggestions = buildVendorSuggestions(item);
|
||
if (item.completeStatus === 0 && item.vendorSuggestions.length > 0) {
|
||
const firstSuggestion = item.vendorSuggestions[0];
|
||
if (firstSuggestion.vendorId !== NOT_PURCHASE_VENDOR_ID) {
|
||
item.vendorId = firstSuggestion.vendorId;
|
||
item.price = firstSuggestion.price || 0;
|
||
item.calculateTotal();
|
||
}
|
||
} else if (item.completeStatus !== 0 && item.vendorId) {
|
||
const vendor = allVendors.value.find((v: any) => v.vendorId === item.vendorId);
|
||
if (vendor) {
|
||
item.vendorName = vendor.vendorName;
|
||
}
|
||
}
|
||
}
|
||
|
||
planItems.value.sort((a, b) => a.completeStatus - b.completeStatus);
|
||
|
||
generateOrderVisible.value = true;
|
||
} catch (error) {
|
||
ElMessage.error($t("_message.purchase.purchase_plan.get_items_error") + error);
|
||
}
|
||
};
|
||
|
||
const onVendorChange = (item: any, vendorId: number) => {
|
||
if (item.vendorSuggestions && item.vendorSuggestions.length > 0) {
|
||
const selectedVendor = item.vendorSuggestions.find((v: any) => v.vendorId === vendorId);
|
||
if (selectedVendor) {
|
||
if (selectedVendor.vendorId !== NOT_PURCHASE_VENDOR_ID) {
|
||
item.price = selectedVendor.price || 0;
|
||
}
|
||
item.calculateTotal();
|
||
}
|
||
}
|
||
};
|
||
|
||
const generatePurchaseOrder = async () => {
|
||
const validItems = planItems.value.filter(
|
||
item => item.vendorId && item.vendorId !== NOT_PURCHASE_VENDOR_ID && item.completeStatus === 0
|
||
);
|
||
|
||
if (validItems.length === 0) {
|
||
ElMessage.warning($t("_message.purchase.purchase_plan.select_vendor"));
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const vendorGroups = new Map<number, any[]>();
|
||
validItems.forEach(item => {
|
||
if (!vendorGroups.has(item.vendorId)) {
|
||
vendorGroups.set(item.vendorId, []);
|
||
}
|
||
vendorGroups.get(item.vendorId)!.push(item);
|
||
});
|
||
|
||
const now = new Date();
|
||
const baseFormCode =
|
||
"PO" +
|
||
now.getFullYear() +
|
||
String(now.getMonth() + 1).padStart(2, "0") +
|
||
String(now.getDate()).padStart(2, "0") +
|
||
String(now.getHours()).padStart(2, "0") +
|
||
String(now.getMinutes()).padStart(2, "0") +
|
||
String(now.getSeconds()).padStart(2, "0");
|
||
|
||
const promises: Promise<any>[] = [];
|
||
let orderIndex = 1;
|
||
vendorGroups.forEach((items, vendorId) => {
|
||
const vendor = allVendors.value.find((v: any) => v.vendorId === vendorId);
|
||
const vendorName = vendor ? vendor.vendorName : "";
|
||
|
||
const formCode = baseFormCode + String(orderIndex).padStart(2, "0");
|
||
const formName = `采购订单-${vendorName}-${formCode}`;
|
||
const formMark = `采购计划【${generateOrderForm.planNo}】生成`;
|
||
|
||
const totalValue = items.reduce((sum, item) => {
|
||
return new Decimal(sum).add(new Decimal(item.currentCount).mul(item.price)).toNumber();
|
||
}, 0);
|
||
|
||
const data = {
|
||
planId: generateOrderForm.planId,
|
||
vendorId: vendorId,
|
||
vendorName: vendorName,
|
||
formCode: formCode,
|
||
formName: formName,
|
||
formMark: formMark,
|
||
totalValue: totalValue,
|
||
selectedItems: items,
|
||
};
|
||
|
||
promises.push(post(generateOrderUrl, data));
|
||
orderIndex++;
|
||
});
|
||
|
||
await Promise.all(promises);
|
||
ElMessage.success($t("_message.purchase.purchase_plan.generate_order_success"));
|
||
generateOrderVisible.value = false;
|
||
tableRef.value?.reload();
|
||
} catch (err: any) {
|
||
ElMessage.error(err.response?.data?.message || $t("_message.purchase.purchase_plan.generate_order_error"));
|
||
}
|
||
};
|
||
|
||
const mappingConfig: FieldMappingConfig = {
|
||
partNumber: {
|
||
sourceKey: "物料编号",
|
||
defaultValue: "",
|
||
},
|
||
|
||
purchaseCount: {
|
||
sourceKey: "计划数量",
|
||
defaultValue: 0,
|
||
transform: (val: any) => {
|
||
const num = Number(val);
|
||
return isNaN(num) ? 0 : num;
|
||
},
|
||
},
|
||
|
||
price: {
|
||
sourceKey: "单价",
|
||
defaultValue: 0,
|
||
transform: (val: any) => {
|
||
const num = Number(val);
|
||
return isNaN(num) ? 0 : num;
|
||
},
|
||
},
|
||
|
||
currentCount: {
|
||
sourceKey: "本次采购数量",
|
||
defaultValue: 0,
|
||
transform: (val: any) => {
|
||
const num = Number(val);
|
||
return isNaN(num) ? 0 : num;
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
<template>
|
||
<ExpandablePageableTable
|
||
:url="getPageUrl"
|
||
:searchers="searchers"
|
||
ref="tableRef"
|
||
:item-url="getItemUrl"
|
||
item-id-key="id"
|
||
item-id-name="planId"
|
||
item-field-name="planItems"
|
||
>
|
||
<template #tool-button>
|
||
<DefaultToolButton @top-button-click="topButtonClick" />
|
||
</template>
|
||
<template #columns>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.planNo')" prop="planNo" width="150" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.planName')" prop="planName" width="180" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeName" width="150" />
|
||
<DefaultStatusSwitchColumn
|
||
status-param-name="planStatus"
|
||
:status-label-mapping="getPurchasePlanStatusLabel"
|
||
:tag-type-mapping="getPurchasePlanStatusTagType"
|
||
/>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.remask')" prop="remask" width="200" />
|
||
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" width="150" />
|
||
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
|
||
</template>
|
||
<template #item-content="{ itemData }">
|
||
<el-table :data="itemData" size="small" border stripe>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" prop="partNumber" width="150" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.model')" prop="productSpecs" width="150" />
|
||
<el-table-column
|
||
:label="$t('_prop.purchase.purchase_plan_item.purchaseCount')"
|
||
prop="purchaseCount"
|
||
width="120"
|
||
/>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.price')" prop="price" width="120" />
|
||
<el-table-column
|
||
:label="$t('_prop.purchase.purchase_plan_item.currentCount')"
|
||
prop="currentCount"
|
||
width="120"
|
||
/>
|
||
</el-table>
|
||
</template>
|
||
</ExpandablePageableTable>
|
||
<BaseFormWithTable
|
||
ref="baseFormWithTableRef"
|
||
v-model:visible="visible"
|
||
@submit="submit"
|
||
v-model:form="form"
|
||
:title="$t(title)"
|
||
:rules="rules"
|
||
:base-title="$t('_title.purchase.purchase_plan.baseTitle')"
|
||
:table-title="$t('_title.purchase.purchase_plan.tableTitle')"
|
||
item-array-name="planItems"
|
||
:mapping-config="mappingConfig"
|
||
:template-file-name="$t('_title.purchase.purchase_plan.templateFileName')"
|
||
>
|
||
<template #form-items>
|
||
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<el-form-item :label="$t('_prop.purchase.purchase_plan.planName')" prop="planName">
|
||
<el-input v-model="form.planName" :placeholder="$t('_message.purchase.purchase_plan.input_planName')" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item :label="$t('_prop.purchase.purchase_plan.vendorName')" prop="vendorId">
|
||
<BaseSelect
|
||
v-model="form.vendorId"
|
||
:url="'/sys/vendor/getVendorList'"
|
||
:placeholder="$t('_message.purchase.purchase_plan.select_vendor')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeNo">
|
||
<BaseSelect
|
||
v-model="form.storeNo"
|
||
:url="'/warehouse/warehouse/getWarehouseSelectList'"
|
||
:placeholder="$t('_message.purchase.purchase_plan.select_store')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-form-item :label="$t('_prop.purchase.purchase_plan.remask')" prop="remask">
|
||
<el-input
|
||
v-model="form.remask"
|
||
:placeholder="$t('_message.purchase.purchase_plan.input_remask')"
|
||
type="textarea"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
</template>
|
||
<template #form-table-columns>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" width="150">
|
||
<template #default="{ row, $index }">
|
||
<el-form-item
|
||
:prop="`${itemArrayName}.${$index}.partNumber`"
|
||
:rules="[{ required: true, validator: validatePartNumber, trigger: 'blur' }]"
|
||
>
|
||
<el-input v-model="row.partNumber" size="small" />
|
||
</el-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.purchaseCount')" width="150">
|
||
<template #default="{ row, $index }">
|
||
<el-form-item
|
||
:prop="`${itemArrayName}.${$index}.purchaseCount`"
|
||
:rules="[
|
||
{
|
||
required: true,
|
||
message: $t('_message.purchase.purchase_plan_item.input_purchaseCount'),
|
||
trigger: 'blur',
|
||
},
|
||
]"
|
||
>
|
||
<el-input-number v-model="row.purchaseCount" size="small" :min="1" />
|
||
</el-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.price')" width="150">
|
||
<template #default="{ row, $index }">
|
||
<el-form-item
|
||
:prop="`${itemArrayName}.${$index}.price`"
|
||
:rules="[
|
||
{ required: true, message: $t('_message.purchase.purchase_plan_item.input_price'), trigger: 'blur' },
|
||
]"
|
||
>
|
||
<el-input-number v-model="row.price" size="small" :min="0" :step="0.01" />
|
||
</el-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.currentCount')" width="150">
|
||
<template #default="{ row, $index }">
|
||
<el-form-item
|
||
:prop="`${itemArrayName}.${$index}.currentCount`"
|
||
:rules="[
|
||
{
|
||
required: true,
|
||
message: $t('_message.purchase.purchase_plan_item.input_currentCount'),
|
||
trigger: 'blur',
|
||
},
|
||
]"
|
||
>
|
||
<el-input-number v-model="row.currentCount" size="small" :min="1" />
|
||
</el-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
</template>
|
||
</BaseFormWithTable>
|
||
|
||
<!-- 生成采购订单对话框 -->
|
||
<BaseTableForm
|
||
v-model:visible="generateOrderVisible"
|
||
:title="$t('_title.purchase.purchase_plan.generateOrder')"
|
||
:table-data="planItems"
|
||
:show-summary="false"
|
||
:selectable="false"
|
||
:use-auth="false"
|
||
>
|
||
<!-- 自定义表格列 -->
|
||
<template #table-columns>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" prop="partNumber" width="150" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.model')" prop="productSpecs" width="150" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.vendorName')" width="180">
|
||
<template #default="{ row }">
|
||
<template v-if="row.completeStatus === 0">
|
||
<el-select
|
||
v-model="row.vendorId"
|
||
:placeholder="$t('_message.purchase.purchase_plan.select_vendor')"
|
||
style="width: 100%"
|
||
@change="onVendorChange(row, row.vendorId)"
|
||
:disabled="row.completeStatus !== 0"
|
||
>
|
||
<el-option
|
||
v-for="vendor in row.vendorSuggestions"
|
||
:key="vendor.vendorId"
|
||
:label="vendor.vendorName"
|
||
:value="vendor.vendorId"
|
||
>
|
||
<span>{{ vendor.vendorName }}</span>
|
||
<span v-if="vendor.priority === 1" style="margin-left: 8px; color: #67c23a">(优先)</span>
|
||
<span v-if="vendor.priority === 99" style="margin-left: 8px; color: #909399">(跳过)</span>
|
||
<span
|
||
v-if="vendor.price && vendor.price > 0 && vendor.priority !== 99"
|
||
style="margin-left: 8px; color: #909399"
|
||
>
|
||
¥{{ vendor.price }}
|
||
</span>
|
||
</el-option>
|
||
</el-select>
|
||
</template>
|
||
<template v-else>
|
||
<span>{{ row.vendorName }}</span>
|
||
</template>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.demandQuantity')" prop="purchaseCount" width="120" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.packQuantity')" prop="productPacking" width="120" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.purchaseQuantity')" width="150">
|
||
<template #default="{ row }">
|
||
<el-input-number
|
||
v-model="row.currentCount"
|
||
:min="1"
|
||
@change="row.calculateTotal()"
|
||
style="width: 100%"
|
||
:disabled="row.completeStatus !== 0"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.unitPrice')" width="130">
|
||
<template #default="{ row }">
|
||
<el-input-number
|
||
v-model="row.price"
|
||
:min="0"
|
||
:step="0.01"
|
||
@change="row.calculateTotal()"
|
||
style="width: 100%"
|
||
:disabled="row.completeStatus !== 0"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.totalPrice')" prop="total" width="120" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.purchaseStatus')" width="120">
|
||
<template #default="{ row }">
|
||
<span>{{ getPurchasePlanItemStatusLabel(row.completeStatus) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
</template>
|
||
|
||
<!-- 底部附加内容:自定义按钮 -->
|
||
<template #attachment>
|
||
<el-button
|
||
type="primary"
|
||
:disabled="
|
||
!planItems.some(
|
||
item => item.vendorId && item.vendorId !== NOT_PURCHASE_VENDOR_ID && item.completeStatus === 0
|
||
)
|
||
"
|
||
@click="generatePurchaseOrder"
|
||
>
|
||
{{ $t("_button.confirm") }}
|
||
</el-button>
|
||
</template>
|
||
</BaseTableForm>
|
||
<BaseItemDialog
|
||
:title="$t('_title.purchase.purchase_plan.showItem')"
|
||
v-model:visible="itemVisible"
|
||
:url="getItemUrl"
|
||
parent-param-name="planId"
|
||
v-model:parent-param-value="itemParentId"
|
||
>
|
||
<template #columns>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" prop="partNumber" width="150" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan.model')" prop="productSpecs" width="150" />
|
||
<el-table-column
|
||
:label="$t('_prop.purchase.purchase_plan_item.purchaseCount')"
|
||
prop="purchaseCount"
|
||
width="120"
|
||
/>
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.price')" prop="price" width="120" />
|
||
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.currentCount')" prop="currentCount" width="120" />
|
||
</template>
|
||
</BaseItemDialog>
|
||
</template>
|