feat: 完成采购订单功能。
This commit is contained in:
@@ -246,12 +246,27 @@ export default {
|
|||||||
input_price: "请输入单价",
|
input_price: "请输入单价",
|
||||||
input_currentCount: "请输入本次采购数量",
|
input_currentCount: "请输入本次采购数量",
|
||||||
},
|
},
|
||||||
purchaseorder: {
|
purchase_order: {
|
||||||
totalValue: "订单总额",
|
totalValue: "订单总额",
|
||||||
formCode: "单据编号",
|
formCode: "单据编号",
|
||||||
formMark: "单据备注",
|
formMark: "单据备注",
|
||||||
formStatus: "入库状态",
|
formStatus: "入库状态",
|
||||||
vendorName: "供应商",
|
vendorName: "供应商",
|
||||||
|
storeName: "仓库",
|
||||||
|
searchCode: "单据编号/供应商",
|
||||||
|
inboundCode: "入库单号",
|
||||||
|
inboundCount: "本次入库",
|
||||||
|
orderCode: "采购订单编号",
|
||||||
|
},
|
||||||
|
purchase_order_item: {
|
||||||
|
partNumber: "物料编号",
|
||||||
|
productSpecs: "物料型号",
|
||||||
|
purchaseCount: "采购数量",
|
||||||
|
receiptCount: "已入库",
|
||||||
|
remainingCount: "剩余量",
|
||||||
|
price: "单价",
|
||||||
|
totalPrice: "总价",
|
||||||
|
purchaseMark: "备注",
|
||||||
},
|
},
|
||||||
finishedproductshipment: {
|
finishedproductshipment: {
|
||||||
formCode: "单据编号",
|
formCode: "单据编号",
|
||||||
@@ -390,6 +405,8 @@ export default {
|
|||||||
print: "打印",
|
print: "打印",
|
||||||
editVendors: "供应商列表",
|
editVendors: "供应商列表",
|
||||||
printQrCode: "打印二维码",
|
printQrCode: "打印二维码",
|
||||||
|
inbound: "入库",
|
||||||
|
delete: "删除",
|
||||||
},
|
},
|
||||||
_message: {
|
_message: {
|
||||||
common: {
|
common: {
|
||||||
@@ -656,8 +673,25 @@ export default {
|
|||||||
generate_order_error: "生成采购订单失败",
|
generate_order_error: "生成采购订单失败",
|
||||||
vendor_priority_tip: "优先",
|
vendor_priority_tip: "优先",
|
||||||
},
|
},
|
||||||
purchaseorder: {
|
purchase_order: {
|
||||||
delete_message: "删除采购订单",
|
delete_message: "删除采购订单",
|
||||||
|
input_vendorName: "请选择供应商",
|
||||||
|
select_vendor: "请选择供应商",
|
||||||
|
select_store: "请选择仓库",
|
||||||
|
input_formMark: "请输入备注",
|
||||||
|
upload_items: "请上传采购明细",
|
||||||
|
get_items_error: "获取订单明细失败",
|
||||||
|
delete_confirm: "确定要删除该采购订单吗?",
|
||||||
|
delete_success: "删除成功",
|
||||||
|
delete_fail: "删除失败",
|
||||||
|
inbound_confirm: "确定要进行入库操作吗?",
|
||||||
|
inbound_success: "入库成功",
|
||||||
|
inbound_fail: "入库失败",
|
||||||
|
select_inbound_items: "请选择要入库的物料",
|
||||||
|
get_qrcode_error: "获取二维码数据失败",
|
||||||
|
input_partNumber: "请输入物料编号",
|
||||||
|
input_purchaseCount: "请输入采购数量",
|
||||||
|
input_price: "请输入单价",
|
||||||
},
|
},
|
||||||
finishedproductshipment: {
|
finishedproductshipment: {
|
||||||
select_storeId: "请选择仓库",
|
select_storeId: "请选择仓库",
|
||||||
@@ -833,9 +867,13 @@ export default {
|
|||||||
totalPrice: "总价",
|
totalPrice: "总价",
|
||||||
purchaseStatus: "采购状态",
|
purchaseStatus: "采购状态",
|
||||||
},
|
},
|
||||||
purchaseorder: {
|
purchase_order: {
|
||||||
add: "新建采购订单",
|
add: "新建采购订单",
|
||||||
edit: "编辑采购订单",
|
edit: "编辑采购订单",
|
||||||
|
inbound: "采购入库",
|
||||||
|
qrcode: "二维码打印",
|
||||||
|
baseTitle: "采购订单基本信息",
|
||||||
|
tableTitle: "采购明细",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sale: {
|
sale: {
|
||||||
@@ -1118,4 +1156,8 @@ export default {
|
|||||||
returned: "已退料",
|
returned: "已退料",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
_status: {
|
||||||
|
in_progress: "入库中",
|
||||||
|
completed: "已完成",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
@@ -10,6 +11,10 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
qrCodeList: {
|
||||||
|
type: Array as () => Array<{ qrContent: string; label?: string }>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
qrCodeSize: {
|
qrCodeSize: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 200,
|
default: 200,
|
||||||
@@ -26,13 +31,19 @@ const props = defineProps({
|
|||||||
|
|
||||||
const visible = defineModel<boolean>("visible");
|
const visible = defineModel<boolean>("visible");
|
||||||
const qrCodeDataUrl = ref("");
|
const qrCodeDataUrl = ref("");
|
||||||
|
const qrCodeDataUrls = ref<Array<{ dataUrl: string; label?: string }>>([]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const currentIndex = ref(0);
|
||||||
|
|
||||||
const generateQrCode = async () => {
|
const generateQrCode = async () => {
|
||||||
if (!props.qrCodeContent) {
|
if (props.qrCodeList.length > 0) {
|
||||||
return;
|
await generateAllQrCodes();
|
||||||
|
} else if (props.qrCodeContent) {
|
||||||
|
await generateSingleQrCode();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateSingleQrCode = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
qrCodeDataUrl.value = await QRCode.toDataURL(props.qrCodeContent, {
|
qrCodeDataUrl.value = await QRCode.toDataURL(props.qrCodeContent, {
|
||||||
@@ -50,12 +61,55 @@ const generateQrCode = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateAllQrCodes = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const results = [];
|
||||||
|
for (const item of props.qrCodeList) {
|
||||||
|
const dataUrl = await QRCode.toDataURL(item.qrContent, {
|
||||||
|
width: props.qrCodeSize,
|
||||||
|
margin: 2,
|
||||||
|
color: {
|
||||||
|
dark: "#000000",
|
||||||
|
light: "#ffffff",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
results.push({ dataUrl, label: item.label || item.partNumber || "" });
|
||||||
|
}
|
||||||
|
qrCodeDataUrls.value = results;
|
||||||
|
currentIndex.value = 0;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Generate QR codes failed:", error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handlePrint = () => {
|
const handlePrint = () => {
|
||||||
const printWindow = window.open("", "_blank");
|
const printWindow = window.open("", "_blank");
|
||||||
if (!printWindow) {
|
if (!printWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let imagesHtml = "";
|
||||||
|
if (props.qrCodeList.length > 0) {
|
||||||
|
for (const item of qrCodeDataUrls.value) {
|
||||||
|
imagesHtml += `
|
||||||
|
<div class="qrcode-item">
|
||||||
|
<img src="${item.dataUrl}" alt="QR Code" />
|
||||||
|
${props.showLabel && item.label ? `<div class="label">${item.label}</div>` : ""}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
imagesHtml = `
|
||||||
|
<div class="qrcode-item">
|
||||||
|
<img src="${qrCodeDataUrl.value}" alt="QR Code" />
|
||||||
|
${props.showLabel ? `<div class="label">${props.label || props.qrCodeContent}</div>` : ""}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
const imgHtml = `
|
const imgHtml = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@@ -63,12 +117,13 @@ const handlePrint = () => {
|
|||||||
<title>${props.title || "QR Code"}</title>
|
<title>${props.title || "QR Code"}</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
.qrcode-item {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
@@ -82,12 +137,14 @@ const handlePrint = () => {
|
|||||||
body {
|
body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
.qrcode-item {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<img src="${qrCodeDataUrl.value}" alt="QR Code" />
|
${imagesHtml}
|
||||||
${props.showLabel ? `<div class="label">${props.label || props.qrCodeContent}</div>` : ""}
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
@@ -102,23 +159,53 @@ const handlePrint = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDownload = () => {
|
const handleDownload = () => {
|
||||||
const link = document.createElement("a");
|
if (props.qrCodeList.length > 0) {
|
||||||
link.download = `${props.label || props.qrCodeContent || "qrcode"}.png`;
|
const currentItem = qrCodeDataUrls.value[currentIndex.value];
|
||||||
link.href = qrCodeDataUrl.value;
|
const link = document.createElement("a");
|
||||||
link.click();
|
link.download = `${currentItem.label || "qrcode"}.png`;
|
||||||
|
link.href = currentItem.dataUrl;
|
||||||
|
link.click();
|
||||||
|
} else {
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.download = `${props.label || props.qrCodeContent || "qrcode"}.png`;
|
||||||
|
link.href = qrCodeDataUrl.value;
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const prevQrCode = () => {
|
||||||
|
if (currentIndex.value > 0) {
|
||||||
|
currentIndex.value--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextQrCode = () => {
|
||||||
|
if (currentIndex.value < qrCodeDataUrls.value.length - 1) {
|
||||||
|
currentIndex.value++;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.qrCodeContent,
|
() => props.qrCodeContent,
|
||||||
() => {
|
() => {
|
||||||
if (visible.value && props.qrCodeContent) {
|
if (visible.value && props.qrCodeContent && props.qrCodeList.length === 0) {
|
||||||
generateQrCode();
|
generateSingleQrCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.qrCodeList,
|
||||||
|
() => {
|
||||||
|
if (visible.value && props.qrCodeList.length > 0) {
|
||||||
|
generateAllQrCodes();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
watch(visible, newVal => {
|
watch(visible, newVal => {
|
||||||
if (newVal && props.qrCodeContent) {
|
if (newVal) {
|
||||||
generateQrCode();
|
generateQrCode();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -128,25 +215,47 @@ watch(visible, newVal => {
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
:title="title"
|
:title="title"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
width="400px"
|
width="450px"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
>
|
>
|
||||||
<div v-loading="loading" class="qrcode-container">
|
<div v-loading="loading" class="qrcode-container">
|
||||||
<div v-if="qrCodeDataUrl" class="qrcode-display">
|
<div v-if="props.qrCodeList.length > 0" class="qrcode-list-container">
|
||||||
<img :src="qrCodeDataUrl" alt="QR Code" />
|
<div v-if="qrCodeDataUrls.length > 0" class="qrcode-display">
|
||||||
<div v-if="showLabel" class="qrcode-label">{{ label || qrCodeContent }}</div>
|
<img :src="qrCodeDataUrls[currentIndex].dataUrl" alt="QR Code" />
|
||||||
|
<div v-if="showLabel && qrCodeDataUrls[currentIndex].label" class="qrcode-label">
|
||||||
|
{{ qrCodeDataUrls[currentIndex].label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="qrCodeDataUrls.length > 0 && qrCodeDataUrls.length > 1" class="qrcode-navigation">
|
||||||
|
<el-button :disabled="currentIndex === 0" @click="prevQrCode" circle>
|
||||||
|
<el-icon><ArrowLeft /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<span class="qrcode-pagination">{{ currentIndex + 1 }} / {{ qrCodeDataUrls.length }}</span>
|
||||||
|
<el-button :disabled="currentIndex === qrCodeDataUrls.length - 1" @click="nextQrCode" circle>
|
||||||
|
<el-icon><ArrowRight /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-if="qrCodeDataUrls.length === 0 && !loading" class="qrcode-placeholder">
|
||||||
|
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="qrcode-placeholder">
|
<div v-else>
|
||||||
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
|
<div v-if="qrCodeDataUrl" class="qrcode-display">
|
||||||
|
<img :src="qrCodeDataUrl" alt="QR Code" />
|
||||||
|
<div v-if="showLabel" class="qrcode-label">{{ label || qrCodeContent }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="!loading" class="qrcode-placeholder">
|
||||||
|
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="visible = false">{{ $t("_button.cancel") }}</el-button>
|
<el-button @click="visible = false">{{ $t("_button.cancel") }}</el-button>
|
||||||
<el-button type="primary" @click="handleDownload" :disabled="!qrCodeDataUrl">
|
<el-button type="primary" @click="handleDownload" :disabled="!qrCodeDataUrl && qrCodeDataUrls.length === 0">
|
||||||
{{ $t("_button.download") }}
|
{{ $t("_button.download") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" @click="handlePrint" :disabled="!qrCodeDataUrl">
|
<el-button type="success" @click="handlePrint" :disabled="!qrCodeDataUrl && qrCodeDataUrls.length === 0">
|
||||||
{{ $t("_button.print") }}
|
{{ $t("_button.print") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -162,6 +271,13 @@ watch(visible, newVal => {
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.qrcode-list-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.qrcode-display {
|
.qrcode-display {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -181,6 +297,20 @@ watch(visible, newVal => {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.qrcode-navigation {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-pagination {
|
||||||
|
min-width: 60px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.qrcode-placeholder {
|
.qrcode-placeholder {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
|
|||||||
@@ -1,58 +1,290 @@
|
|||||||
<script lang="ts" setup>
|
<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 DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
|
||||||
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.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 { usePage } from "@/composables/use-page";
|
||||||
import BaseForm from "@/components/base/base-form/BaseForm.vue";
|
|
||||||
import { $t } from "@/common/languages";
|
import { $t } from "@/common/languages";
|
||||||
import type { FormInstance, FormRules } from "element-plus";
|
import { ElMessage, ElMessageBox, type FormInstance, type FormItemRule, type FormRules } from "element-plus";
|
||||||
|
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
||||||
|
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
|
||||||
|
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
|
||||||
|
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
|
||||||
|
import QrCodeDialog from "@/components/base/base-qrcode/QrCodeDialog.vue";
|
||||||
|
import { get, post } from "@/common/http/request";
|
||||||
import { formatDate } from "@/common/utils/format-utils";
|
import { formatDate } from "@/common/utils/format-utils";
|
||||||
|
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
|
||||||
/**
|
import type { FieldMappingConfig } from "@/components/base/base-form-with-table/type";
|
||||||
* 必须要的变量
|
import Decimal from "decimal.js";
|
||||||
*/
|
|
||||||
|
|
||||||
const getPageUrl = "/purchase/purchaseorder/getPurchaseOrderPage";
|
const getPageUrl = "/purchase/purchaseorder/getPurchaseOrderPage";
|
||||||
const addUrl = "/purchase/purchaseorder/addPurchaseOrder";
|
const addUrl = "/purchase/purchaseorder/addPurchaseOrder";
|
||||||
const editUrl = "/purchase/purchaseorder/updatePurchaseOrder";
|
const editUrl = "/purchase/purchaseorder/updatePurchaseOrder";
|
||||||
const removeUrl = "/purchase/purchaseorder/deletePurchaseOrder";
|
const removeUrl = "/purchase/purchaseorder/deletePurchaseOrder";
|
||||||
const searchers = [];
|
const getItemsUrl = "/purchase/purchaseorder/getPurchaseOrderItems";
|
||||||
const rules = reactive<FormRules>({});
|
const inboundUrl = "/purchase/purchaseorder/inbound";
|
||||||
/**
|
const getQrCodeDataUrl = "/purchase/purchaseorder/getQrCodeData";
|
||||||
* 基本不变通用变量
|
const getWarehouseSelectListUrl = "/warehouse/warehouse/getWarehouseSelectList";
|
||||||
*/
|
const getVendorSelectListUrl = "/sys/vendor/getVendorList";
|
||||||
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
|
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
|
||||||
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
|
|
||||||
|
const searchers = [
|
||||||
|
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.purchase.purchase_order.searchCode") },
|
||||||
|
];
|
||||||
|
|
||||||
|
const getFormStatusLabel = (status: number) => {
|
||||||
|
const labels: Record<number, string> = {
|
||||||
|
0: $t("_status.in_progress"),
|
||||||
|
4: $t("_status.completed"),
|
||||||
|
};
|
||||||
|
return labels[status] ?? String(status);
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemArrayName = "items";
|
||||||
|
|
||||||
|
const validatePartNumber = (rule: any, value: string, callback: (error?: Error) => void) => {
|
||||||
|
if (!value) {
|
||||||
|
callback(new Error($t("_message.purchase.purchase_order.input_partNumber")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
get(partNumberExistsUrl, { partNumber: value })
|
||||||
|
.then(res => {
|
||||||
|
if (res.data === true) {
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
callback(new Error($t("_message.purchase.purchase_order.part_number_not_exists")));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
vendorName: [{ required: true, message: $t("_message.purchase.purchase_order.input_vendorName"), trigger: "blur" }],
|
||||||
|
partNumber: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator: validatePartNumber,
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (value === undefined || value.length === 0) {
|
||||||
|
callback(new Error($t("_message.purchase.purchase_order.upload_items")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
trigger: "change",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
|
||||||
|
const { useAdd, useEdit, useGeneralPageRef } = usePage(tableRef);
|
||||||
const { title, visible, formType, form } = useGeneralPageRef();
|
const { title, visible, formType, form } = useGeneralPageRef();
|
||||||
/**
|
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
|
||||||
* 可以自定义的变量
|
const vendorSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||||
*/
|
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||||
|
|
||||||
|
const inboundVisible = ref(false);
|
||||||
|
const inboundWarehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||||
|
const inboundForm = reactive({
|
||||||
|
orderId: 0,
|
||||||
|
orderCode: "",
|
||||||
|
vendorName: "",
|
||||||
|
formCode: "",
|
||||||
|
storeNo: null as number | null,
|
||||||
|
storeName: "",
|
||||||
|
formMark: "",
|
||||||
|
items: [] as any[],
|
||||||
|
});
|
||||||
|
|
||||||
|
const qrCodeVisible = ref(false);
|
||||||
|
const qrCodeData = ref<any[]>([]);
|
||||||
|
|
||||||
|
const mappingConfig: FieldMappingConfig = {
|
||||||
|
partNumber: {
|
||||||
|
sourceKey: "物料编号",
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
productSpecs: {
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
purchaseMark: {
|
||||||
|
sourceKey: "备注",
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const add = () => {
|
const add = () => {
|
||||||
form.value = {};
|
form.value = {
|
||||||
title.value = "_title.purchase.purchaseorder.add";
|
items: [],
|
||||||
|
};
|
||||||
|
title.value = "_title.purchase.purchase_order.add";
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
formType.value = false;
|
formType.value = false;
|
||||||
};
|
};
|
||||||
const edit = (row: any) => {
|
|
||||||
title.value = "_title.purchase.purchaseorder.edit";
|
const edit = async (row: any) => {
|
||||||
form.value = { ...row };
|
title.value = "_title.purchase.purchase_order.edit";
|
||||||
visible.value = true;
|
|
||||||
formType.value = true;
|
formType.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await get(getItemsUrl, { orderId: row.id });
|
||||||
|
form.value = {
|
||||||
|
id: row.id,
|
||||||
|
vendorName: row.vendorName,
|
||||||
|
vendorNo: row.vendorNo,
|
||||||
|
storeNo: row.storeNo,
|
||||||
|
storeName: row.storeName,
|
||||||
|
formMark: row.formMark,
|
||||||
|
items: response.data || [],
|
||||||
|
};
|
||||||
|
visible.value = true;
|
||||||
|
} catch {
|
||||||
|
ElMessage.error($t("_message.purchase.purchase_order.get_items_error"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const remove = (row: any) => {
|
const remove = (row: any) => {
|
||||||
useRemove(removeUrl, row.id, "_message.purchase.purchaseorder.delete_message");
|
ElMessageBox.confirm($t("_message.purchase.purchase_order.delete_confirm"), $t("_level.warning"), {
|
||||||
|
confirmButtonText: $t("_button.confirm"),
|
||||||
|
cancelButtonText: $t("_button.cancel"),
|
||||||
|
type: "warning",
|
||||||
|
}).then(async () => {
|
||||||
|
try {
|
||||||
|
const res = await post(removeUrl, { id: row.id });
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success($t("_message.purchase.purchase_order.delete_success"));
|
||||||
|
tableRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || $t("_message.purchase.purchase_order.delete_fail"));
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
ElMessage.error(err.response?.data?.message || $t("_message.purchase.purchase_order.delete_fail"));
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const submit = (form: any, formRef: FormInstance | undefined) => {
|
|
||||||
|
const showInbound = async (row: any) => {
|
||||||
|
try {
|
||||||
|
const response = await get(getItemsUrl, { orderId: row.id });
|
||||||
|
const items = (response.data || []).map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
inboundCount: item.remainingCount || 0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
inboundForm.orderId = row.id;
|
||||||
|
inboundForm.orderCode = row.formCode;
|
||||||
|
inboundForm.vendorName = row.vendorName;
|
||||||
|
inboundForm.formCode = generateDucumentNo("RK");
|
||||||
|
inboundForm.storeNo = row.storeNo ?? null;
|
||||||
|
inboundForm.storeName = row.storeName ?? "";
|
||||||
|
inboundForm.formMark = "";
|
||||||
|
inboundForm.items = items;
|
||||||
|
|
||||||
|
inboundVisible.value = true;
|
||||||
|
} catch {
|
||||||
|
ElMessage.error($t("_message.purchase.purchase_order.get_items_error"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitInbound = async () => {
|
||||||
|
const validItems = inboundForm.items.filter(item => item.inboundCount > 0);
|
||||||
|
|
||||||
|
if (validItems.length === 0) {
|
||||||
|
ElMessage.warning($t("_message.purchase.purchase_order.select_inbound_items"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inboundForm.storeNo) {
|
||||||
|
ElMessage.warning($t("_message.purchase.purchase_order.select_store"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessageBox.confirm($t("_message.purchase.purchase_order.inbound_confirm"), $t("_level.warning"), {
|
||||||
|
confirmButtonText: $t("_button.confirm"),
|
||||||
|
cancelButtonText: $t("_button.cancel"),
|
||||||
|
type: "warning",
|
||||||
|
}).then(async () => {
|
||||||
|
const data = {
|
||||||
|
orderId: inboundForm.orderId,
|
||||||
|
orderCode: inboundForm.orderCode,
|
||||||
|
vendorName: inboundForm.vendorName,
|
||||||
|
storeNo: inboundForm.storeNo,
|
||||||
|
storeName: inboundWarehouseSelectRef.value?.getLabel() ?? inboundForm.storeName,
|
||||||
|
formMark: inboundForm.formMark,
|
||||||
|
items: validItems.map(item => ({
|
||||||
|
itemId: item.id,
|
||||||
|
inboundCount: item.inboundCount,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await post(inboundUrl, data);
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success($t("_message.purchase.purchase_order.inbound_success"));
|
||||||
|
inboundVisible.value = false;
|
||||||
|
tableRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg ?? $t("_message.purchase.purchase_order.inbound_fail"));
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
ElMessage.error(err.response?.data?.message ?? $t("_message.purchase.purchase_order.inbound_fail"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showQrCode = async (row: any) => {
|
||||||
|
try {
|
||||||
|
const response = await get(getQrCodeDataUrl, { orderId: row.id });
|
||||||
|
qrCodeData.value = response.data ?? [];
|
||||||
|
qrCodeVisible.value = true;
|
||||||
|
} catch {
|
||||||
|
ElMessage.error($t("_message.purchase.purchase_order.get_qrcode_error"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = (formData: any, formRef: FormInstance | undefined) => {
|
||||||
if (formRef !== undefined) {
|
if (formRef !== undefined) {
|
||||||
formRef.validate(valid => {
|
formRef.validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (formType.value) useEdit(editUrl, form, visible);
|
const data = {
|
||||||
else useAdd(addUrl, form, visible);
|
...formData,
|
||||||
|
vendorName: vendorSelectRef.value?.getLabel(),
|
||||||
|
storeName: warehouseSelectRef.value?.getLabel(),
|
||||||
|
};
|
||||||
|
if (formType.value) {
|
||||||
|
useEdit(editUrl, data, visible);
|
||||||
|
} else {
|
||||||
|
useAdd(addUrl, data, visible);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const topButtonClick = (eventName: string) => {
|
const topButtonClick = (eventName: string) => {
|
||||||
switch (eventName) {
|
switch (eventName) {
|
||||||
case "add":
|
case "add":
|
||||||
@@ -60,6 +292,7 @@ const topButtonClick = (eventName: string) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const operateButtonClick = (eventName: string, row: any) => {
|
const operateButtonClick = (eventName: string, row: any) => {
|
||||||
switch (eventName) {
|
switch (eventName) {
|
||||||
case "edit":
|
case "edit":
|
||||||
@@ -68,28 +301,262 @@ const operateButtonClick = (eventName: string, row: any) => {
|
|||||||
case "remove":
|
case "remove":
|
||||||
remove(row);
|
remove(row);
|
||||||
break;
|
break;
|
||||||
|
case "inbound":
|
||||||
|
showInbound(row);
|
||||||
|
break;
|
||||||
|
case "printQrCode":
|
||||||
|
showQrCode(row);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPartNumberRules = (): FormItemRule[] => {
|
||||||
|
return rules.partNumber as FormItemRule[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPurchaseCountRules = (): FormItemRule[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: $t("_message.purchase.purchase_order.input_purchaseCount"),
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPriceRules = (): FormItemRule[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: $t("_message.purchase.purchase_order.input_price"),
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
|
||||||
|
if (
|
||||||
|
row.formStatus === 4 &&
|
||||||
|
(button.eventName === "edit" || button.eventName === "remove" || button.eventName === "inbound")
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
|
<ExpandablePageableTable
|
||||||
|
:url="getPageUrl"
|
||||||
|
:searchers="searchers"
|
||||||
|
ref="tableRef"
|
||||||
|
:item-url="getItemsUrl"
|
||||||
|
item-id-key="id"
|
||||||
|
item-id-name="orderId"
|
||||||
|
>
|
||||||
<template #tool-button>
|
<template #tool-button>
|
||||||
<DefaultToolButton @top-button-click="topButtonClick" />
|
<DefaultToolButton @top-button-click="topButtonClick" />
|
||||||
</template>
|
</template>
|
||||||
<template #columns>
|
<template #columns>
|
||||||
<el-table-column prop="id" type="hidden" width="40" />
|
<el-table-column :label="$t('_prop.purchase.purchase_order.formCode')" prop="formCode" width="180" />
|
||||||
<el-table-column :label="$t('_prop.purchase.purchaseorder.formCode')" prop="formCode" />
|
<el-table-column :label="$t('_prop.purchase.purchase_order.vendorName')" prop="vendorName" width="150" />
|
||||||
<el-table-column :label="$t('_prop.purchase.purchaseorder.vendorName')" prop="vendorName" />
|
<el-table-column :label="$t('_prop.purchase.purchase_order.totalValue')" prop="totalValue" width="120">
|
||||||
<el-table-column :label="$t('_prop.purchase.purchaseorder.totalValue')" prop="totalValue" />
|
<template #default="{ row }">
|
||||||
<el-table-column :label="$t('_prop.purchase.purchaseorder.formMark')" prop="formMark" />
|
{{ new Decimal(row.totalValue ?? 0).toFixed(2) }}
|
||||||
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
|
</template>
|
||||||
<el-table-column :label="$t('_prop.purchase.purchaseorder.formStatus')" prop="formStatus" />
|
</el-table-column>
|
||||||
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
|
<el-table-column :label="$t('_prop.purchase.purchase_order.formMark')" prop="formMark" />
|
||||||
|
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" width="180" :formatter="formatDate" />
|
||||||
|
<DefaultStatusSwitchColumn status-param-name="formStatus" :status-label-mapping="getFormStatusLabel" />
|
||||||
|
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
|
||||||
</template>
|
</template>
|
||||||
</BasePageableTable>
|
<template #item-content="{ itemData }">
|
||||||
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
|
<el-table :data="itemData" size="small" border stripe>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.partNumber')" prop="partNumber" width="150" />
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('_prop.purchase.purchase_order_item.productSpecs')"
|
||||||
|
prop="productSpecs"
|
||||||
|
width="150"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('_prop.purchase.purchase_order_item.purchaseCount')"
|
||||||
|
prop="purchaseCount"
|
||||||
|
width="100"
|
||||||
|
/>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.price')" prop="price" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ new Decimal(row.price ?? 0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.totalPrice')" prop="totalPrice" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ new Decimal(row.totalPrice ?? 0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</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_order.baseTitle')"
|
||||||
|
:table-title="$t('_title.purchase.purchase_order.tableTitle')"
|
||||||
|
item-array-name="items"
|
||||||
|
upload-desc="采购明细"
|
||||||
|
:mapping-config="mappingConfig"
|
||||||
|
>
|
||||||
<template #form-items>
|
<template #form-items>
|
||||||
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
|
<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_order.vendorName')" prop="vendorName">
|
||||||
|
<BaseSelect
|
||||||
|
v-model="form.vendorName"
|
||||||
|
:url="getVendorSelectListUrl"
|
||||||
|
ref="vendorSelectRef"
|
||||||
|
:placeholder="$t('_message.purchase.purchase_order.select_vendor')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.storeName')" prop="storeNo">
|
||||||
|
<BaseSelect
|
||||||
|
v-model="form.storeNo"
|
||||||
|
:url="getWarehouseSelectListUrl"
|
||||||
|
ref="warehouseSelectRef"
|
||||||
|
:placeholder="$t('_message.purchase.purchase_order.select_store')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.formMark')" prop="formMark">
|
||||||
|
<el-input
|
||||||
|
v-model="form.formMark"
|
||||||
|
type="textarea"
|
||||||
|
autosize
|
||||||
|
:placeholder="$t('_message.purchase.purchase_order.input_formMark')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</BaseForm>
|
<template #form-table-columns>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.partNumber')" width="150">
|
||||||
|
<template #default="{ row, $index }">
|
||||||
|
<el-form-item :prop="`${itemArrayName}.${$index}.partNumber`" :rules="getPartNumberRules()">
|
||||||
|
<el-input v-model="row.partNumber" size="small" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.productSpecs')" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.productSpecs ?? "-" }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.purchaseCount')" width="150">
|
||||||
|
<template #default="{ row, $index }">
|
||||||
|
<el-form-item :prop="`${itemArrayName}.${$index}.purchaseCount`" :rules="getPurchaseCountRules()">
|
||||||
|
<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_order_item.price')" width="150">
|
||||||
|
<template #default="{ row, $index }">
|
||||||
|
<el-form-item :prop="`${itemArrayName}.${$index}.price`" :rules="getPriceRules()">
|
||||||
|
<el-input-number v-model="row.price" size="small" :min="0" :step="0.01" :precision="2" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.totalPrice')" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ new Decimal(row.purchaseCount ?? 0).mul(row.price ?? 0).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
</BaseFormWithTable>
|
||||||
|
|
||||||
|
<BaseTableForm
|
||||||
|
v-model:visible="inboundVisible"
|
||||||
|
:title="$t('_title.purchase.purchase_order.inbound')"
|
||||||
|
:table-data="inboundForm.items"
|
||||||
|
:selectable="false"
|
||||||
|
:use-auth="false"
|
||||||
|
>
|
||||||
|
<template #filter>
|
||||||
|
<el-form :model="inboundForm" label-width="100px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.inboundCode')">
|
||||||
|
<el-input v-model="inboundForm.formCode" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.orderCode')">
|
||||||
|
<el-input v-model="inboundForm.orderCode" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.vendorName')">
|
||||||
|
<el-input v-model="inboundForm.vendorName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.storeName')" required>
|
||||||
|
<BaseSelect
|
||||||
|
v-model="inboundForm.storeNo"
|
||||||
|
:url="getWarehouseSelectListUrl"
|
||||||
|
ref="inboundWarehouseSelectRef"
|
||||||
|
:placeholder="$t('_message.purchase.purchase_order.select_store')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-form-item :label="$t('_prop.purchase.purchase_order.formMark')">
|
||||||
|
<el-input v-model="inboundForm.formMark" type="textarea" autosize />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<template #table-columns>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.partNumber')" prop="partNumber" width="150" />
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.productSpecs')" prop="productSpecs" width="150" />
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('_prop.purchase.purchase_order_item.purchaseCount')"
|
||||||
|
prop="purchaseCount"
|
||||||
|
width="100"
|
||||||
|
/>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order_item.receiptCount')" prop="receiptCount" width="100" />
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('_prop.purchase.purchase_order_item.remainingCount')"
|
||||||
|
prop="remainingCount"
|
||||||
|
width="100"
|
||||||
|
/>
|
||||||
|
<el-table-column :label="$t('_prop.purchase.purchase_order.inboundCount')" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number v-model="row.inboundCount" :min="0" :max="row.remainingCount" size="small" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<template #attachment>
|
||||||
|
<el-button type="primary" @click="submitInbound">
|
||||||
|
{{ $t("_button.inbound") }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</BaseTableForm>
|
||||||
|
|
||||||
|
<QrCodeDialog
|
||||||
|
v-model:visible="qrCodeVisible"
|
||||||
|
:title="$t('_title.purchase.purchase_order.qrcode')"
|
||||||
|
:qr-code-list="qrCodeData"
|
||||||
|
:qr-code-size="200"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const generateOrderVisible = ref(false);
|
|||||||
const generateOrderForm = reactive({
|
const generateOrderForm = reactive({
|
||||||
planId: 0,
|
planId: 0,
|
||||||
planStatus: 0,
|
planStatus: 0,
|
||||||
|
planNo: "",
|
||||||
});
|
});
|
||||||
const planItems = ref([] as any[]);
|
const planItems = ref([] as any[]);
|
||||||
const allVendors = ref([] as any[]);
|
const allVendors = ref([] as any[]);
|
||||||
@@ -192,6 +193,7 @@ const buildVendorSuggestions = (item: any) => {
|
|||||||
const showGenerateOrderDialog = async (row: any) => {
|
const showGenerateOrderDialog = async (row: any) => {
|
||||||
generateOrderForm.planId = row.id;
|
generateOrderForm.planId = row.id;
|
||||||
generateOrderForm.planStatus = row.planStatus;
|
generateOrderForm.planStatus = row.planStatus;
|
||||||
|
generateOrderForm.planNo = row.planNo;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await get(getItemsUrl, { planId: row.id });
|
const response = await get(getItemsUrl, { planId: row.id });
|
||||||
|
|||||||
Reference in New Issue
Block a user