feat(@vben/web-antd): erp-优化上传附件及验证

- 修改订单时间格式为 timestamp
- 限制文件上传数量为 1
- 调整表格列宽和显示逻辑
- 优化子表单验证和提交逻辑
- 修复文件上传组件的兼容性问题
- 优化产品清单的初始化和验证
pull/181/head
nehc 2025-07-26 17:36:59 +08:00
parent 8a7239ce24
commit f242f1c37d
3 changed files with 138 additions and 31 deletions

View File

@ -44,7 +44,7 @@ export function useFormSchema(): VbenFormSchema[] {
placeholder: '选择订单时间',
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
style: { width: '100%' },
},
fieldName: 'orderTime',
@ -65,7 +65,7 @@ export function useFormSchema(): VbenFormSchema[] {
{
component: 'FileUpload',
componentProps: {
maxNumber: 5,
maxNumber: 1,
maxSize: 10,
accept: [
'pdf',
@ -340,17 +340,19 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'no',
title: '订单单号',
width: 260,
width: 200,
fixed: 'left',
},
{
field: 'productNames',
title: '产品信息',
showOverflow: 'tooltip',
minWidth: 120,
},
{
field: 'supplierName',
title: '供应商',
minWidth: 120,
},
{
field: 'orderTime',
@ -361,40 +363,45 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'creatorName',
title: '创建人',
minWidth: 120,
},
{
field: 'totalCount',
title: '总数量',
formatter: 'formatNumber',
minWidth: 120,
},
{
field: 'inCount',
title: '入库数量',
formatter: 'formatNumber',
minWidth: 120,
},
{
field: 'returnCount',
title: '退货数量',
formatter: 'formatNumber',
minWidth: 120,
},
{
field: 'totalProductPrice',
title: '金额合计',
formatter: 'formatNumber',
minWidth: 120,
},
{
field: 'totalPrice',
title: '含税金额',
formatter: 'formatNumber',
minWidth: 120,
},
{
field: 'depositPrice',
title: '支付订金',
formatter: 'formatNumber',
minWidth: 120,
},
{
field: 'status',
title: '状态',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.ERP_AUDIT_STATUS },

View File

@ -58,6 +58,16 @@ const [Grid, gridApi] = useVbenVxeGrid({
enabled: false,
},
},
gridEvents: {
// editClosed: ({ row }) => {
// // tableData
// const index = tableData.value.findIndex((item) => item.id === row.id);
// if (index !== -1) {
// tableData.value[index] = { ...row };
// emit('update:items', [...tableData.value]);
// }
// },
},
});
/** 监听外部传入的列数据 */
@ -107,7 +117,25 @@ onMounted(async () => {
});
function handleAdd() {
gridApi.grid.insertAt(null, -1);
const newRow = {
id: tableData.value.length + 1,
productId: null,
productName: '',
productUnitId: null,
productUnitName: '',
productBarCode: '',
count: 1,
productPrice: 0,
totalProductPrice: 0,
taxPercent: 0,
taxPrice: 0,
totalPrice: 0,
stockCount: 0,
remark: '',
};
tableData.value.push(newRow);
gridApi.grid.insertAt(newRow, -1);
emit('update:items', [...tableData.value]);
}
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
@ -185,20 +213,26 @@ const getSummaries = (): {
};
};
const validate = async (): Promise<void> => {
for (let i = 0; i < tableData.value.length; i++) {
const item = tableData.value[i];
if (item) {
if (!item.productId) {
throw new Error(`${i + 1} 行:产品不能为空`);
}
if (!item.count || item.count <= 0) {
throw new Error(`${i + 1} 行:产品数量不能为空`);
}
if (!item.productPrice || item.productPrice <= 0) {
throw new Error(`${i + 1} 行:产品单价不能为空`);
const validate = async (): Promise<boolean> => {
try {
for (let i = 0; i < tableData.value.length; i++) {
const item = tableData.value[i];
if (item) {
if (!item.productId) {
throw new Error(`${i + 1} 行:产品不能为空`);
}
if (!item.count || item.count <= 0) {
throw new Error(`${i + 1} 行:产品数量不能为空`);
}
if (!item.productPrice || item.productPrice <= 0) {
throw new Error(`${i + 1} 行:产品单价不能为空`);
}
}
}
return true;
} catch (error) {
console.error('验证失败:', error);
throw error;
}
};
@ -212,7 +246,11 @@ const init = (
});
};
defineExpose({ validate, getData, init });
defineExpose({
validate,
getData,
init,
});
</script>
<template>

View File

@ -1,10 +1,9 @@
<script lang="ts" setup>
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
import { computed, ref } from 'vue';
import { computed, nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { formatDateTime } from '@vben/utils';
import { message } from 'ant-design-vue';
@ -72,6 +71,9 @@ const handleUpdateTotalPrice = (totalPrice: number) => {
}
};
/**
* 创建或更新采购订单
*/
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
@ -79,17 +81,49 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
if (itemFormRef.value && typeof itemFormRef.value.validate === 'function') {
await itemFormRef.value.validate();
await nextTick(); //
// - itemFormRef.value 访
const itemFormInstance = Array.isArray(itemFormRef.value)
? itemFormRef.value[0]
: itemFormRef.value;
if (itemFormInstance && typeof itemFormInstance.validate === 'function') {
try {
const isValid = await itemFormInstance.validate();
if (!isValid) {
message.error('子表单验证失败');
return;
}
} catch (error) {
message.error(error.message || '子表单验证失败');
return;
}
} else {
message.error('子表单验证方法不存在');
return;
}
//
if (!formData.value?.items || formData.value.items.length === 0) {
message.error('产品清单不能为空,请至少添加一个产品');
return;
}
modalApi.lock();
//
const data =
(await formApi.getValues()) as ErpPurchaseOrderApi.PurchaseOrder;
data.items =
itemFormRef.value && typeof itemFormRef.value.getData === 'function'
? itemFormRef.value.getData()
: [];
data.items = formData.value?.items;
if (data.items) {
data.items = data.items.map((item) => {
const { ...itemWithoutId } = item;
return itemWithoutId;
});
}
//
if (data.fileUrl && Array.isArray(data.fileUrl)) {
data.fileUrl = data.fileUrl.length > 0 ? data.fileUrl[0] : '';
}
try {
await (formType.value === 'create'
? createPurchaseOrder(data)
@ -109,18 +143,46 @@ const [Modal, modalApi] = useVbenModal({
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
if (!data || !data.id) {
if (!data) {
return;
}
formType.value = data.type;
if (!data.id) {
//
formData.value = { items: [] } as ErpPurchaseOrderApi.PurchaseOrder;
await nextTick();
const itemFormInstance = Array.isArray(itemFormRef.value)
? itemFormRef.value[0]
: itemFormRef.value;
if (itemFormInstance && typeof itemFormInstance.init === 'function') {
itemFormInstance.init([]);
}
return;
}
modalApi.lock();
try {
formData.value = await getPurchaseOrder(data.id);
formData.value.orderTime = formatDateTime(formData.value.orderTime);
// URLFileUpload
if (
formData.value.fileUrl &&
typeof formData.value.fileUrl === 'string'
) {
formData.value.fileUrl = formData.value.fileUrl
? [formData.value.fileUrl]
: [];
}
// values
await formApi.setValues(formData.value);
//
itemFormRef.value?.init(formData.value.items || []);
await nextTick();
const itemFormInstance = Array.isArray(itemFormRef.value)
? itemFormRef.value[0]
: itemFormRef.value;
if (itemFormInstance && typeof itemFormInstance.init === 'function') {
itemFormInstance.init(formData.value.items || []);
}
} finally {
modalApi.unlock();
}