feat(@vben/web-antd): erp-优化上传附件及验证
- 修改订单时间格式为 timestamp - 限制文件上传数量为 1 - 调整表格列宽和显示逻辑 - 优化子表单验证和提交逻辑 - 修复文件上传组件的兼容性问题 - 优化产品清单的初始化和验证pull/181/head
parent
8a7239ce24
commit
f242f1c37d
|
@ -44,7 +44,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
placeholder: '选择订单时间',
|
placeholder: '选择订单时间',
|
||||||
showTime: true,
|
showTime: true,
|
||||||
format: 'YYYY-MM-DD HH:mm:ss',
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
valueFormat: 'x',
|
||||||
style: { width: '100%' },
|
style: { width: '100%' },
|
||||||
},
|
},
|
||||||
fieldName: 'orderTime',
|
fieldName: 'orderTime',
|
||||||
|
@ -65,7 +65,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
{
|
{
|
||||||
component: 'FileUpload',
|
component: 'FileUpload',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
maxNumber: 5,
|
maxNumber: 1,
|
||||||
maxSize: 10,
|
maxSize: 10,
|
||||||
accept: [
|
accept: [
|
||||||
'pdf',
|
'pdf',
|
||||||
|
@ -340,17 +340,19 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||||
{
|
{
|
||||||
field: 'no',
|
field: 'no',
|
||||||
title: '订单单号',
|
title: '订单单号',
|
||||||
width: 260,
|
width: 200,
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'productNames',
|
field: 'productNames',
|
||||||
title: '产品信息',
|
title: '产品信息',
|
||||||
showOverflow: 'tooltip',
|
showOverflow: 'tooltip',
|
||||||
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'supplierName',
|
field: 'supplierName',
|
||||||
title: '供应商',
|
title: '供应商',
|
||||||
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'orderTime',
|
field: 'orderTime',
|
||||||
|
@ -361,40 +363,45 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||||
{
|
{
|
||||||
field: 'creatorName',
|
field: 'creatorName',
|
||||||
title: '创建人',
|
title: '创建人',
|
||||||
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'totalCount',
|
field: 'totalCount',
|
||||||
title: '总数量',
|
title: '总数量',
|
||||||
formatter: 'formatNumber',
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'inCount',
|
field: 'inCount',
|
||||||
title: '入库数量',
|
title: '入库数量',
|
||||||
formatter: 'formatNumber',
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'returnCount',
|
field: 'returnCount',
|
||||||
title: '退货数量',
|
title: '退货数量',
|
||||||
formatter: 'formatNumber',
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'totalProductPrice',
|
field: 'totalProductPrice',
|
||||||
title: '金额合计',
|
title: '金额合计',
|
||||||
formatter: 'formatNumber',
|
formatter: 'formatNumber',
|
||||||
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'totalPrice',
|
field: 'totalPrice',
|
||||||
title: '含税金额',
|
title: '含税金额',
|
||||||
formatter: 'formatNumber',
|
formatter: 'formatNumber',
|
||||||
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'depositPrice',
|
field: 'depositPrice',
|
||||||
title: '支付订金',
|
title: '支付订金',
|
||||||
formatter: 'formatNumber',
|
formatter: 'formatNumber',
|
||||||
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'status',
|
field: 'status',
|
||||||
title: '状态',
|
title: '状态',
|
||||||
|
minWidth: 120,
|
||||||
cellRender: {
|
cellRender: {
|
||||||
name: 'CellDict',
|
name: 'CellDict',
|
||||||
props: { type: DICT_TYPE.ERP_AUDIT_STATUS },
|
props: { type: DICT_TYPE.ERP_AUDIT_STATUS },
|
||||||
|
|
|
@ -58,6 +58,16 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
enabled: false,
|
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() {
|
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) {
|
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
|
||||||
|
@ -185,20 +213,26 @@ const getSummaries = (): {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const validate = async (): Promise<void> => {
|
const validate = async (): Promise<boolean> => {
|
||||||
for (let i = 0; i < tableData.value.length; i++) {
|
try {
|
||||||
const item = tableData.value[i];
|
for (let i = 0; i < tableData.value.length; i++) {
|
||||||
if (item) {
|
const item = tableData.value[i];
|
||||||
if (!item.productId) {
|
if (item) {
|
||||||
throw new Error(`第 ${i + 1} 行:产品不能为空`);
|
if (!item.productId) {
|
||||||
}
|
throw new Error(`第 ${i + 1} 行:产品不能为空`);
|
||||||
if (!item.count || item.count <= 0) {
|
}
|
||||||
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} 行:产品单价不能为空`);
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
|
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 { useVbenModal } from '@vben/common-ui';
|
||||||
import { formatDateTime } from '@vben/utils';
|
|
||||||
|
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
@ -72,6 +71,9 @@ const handleUpdateTotalPrice = (totalPrice: number) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新采购订单
|
||||||
|
*/
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
|
@ -79,17 +81,49 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 验证子表单
|
// 验证子表单
|
||||||
if (itemFormRef.value && typeof itemFormRef.value.validate === 'function') {
|
await nextTick(); // 确保组件已经挂载
|
||||||
await itemFormRef.value.validate();
|
|
||||||
|
// 获取组件实例 - 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();
|
modalApi.lock();
|
||||||
// 提交表单
|
// 提交表单
|
||||||
const data =
|
const data =
|
||||||
(await formApi.getValues()) as ErpPurchaseOrderApi.PurchaseOrder;
|
(await formApi.getValues()) as ErpPurchaseOrderApi.PurchaseOrder;
|
||||||
data.items =
|
data.items = formData.value?.items;
|
||||||
itemFormRef.value && typeof itemFormRef.value.getData === 'function'
|
if (data.items) {
|
||||||
? itemFormRef.value.getData()
|
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 {
|
try {
|
||||||
await (formType.value === 'create'
|
await (formType.value === 'create'
|
||||||
? createPurchaseOrder(data)
|
? createPurchaseOrder(data)
|
||||||
|
@ -109,18 +143,46 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
}
|
}
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const data = modalApi.getData<{ id?: number; type: string }>();
|
const data = modalApi.getData<{ id?: number; type: string }>();
|
||||||
if (!data || !data.id) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
formType.value = data.type;
|
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();
|
modalApi.lock();
|
||||||
try {
|
try {
|
||||||
formData.value = await getPurchaseOrder(data.id);
|
formData.value = await getPurchaseOrder(data.id);
|
||||||
formData.value.orderTime = formatDateTime(formData.value.orderTime);
|
// 将字符串形式的文件URL转换为数组形式以适配FileUpload组件
|
||||||
|
if (
|
||||||
|
formData.value.fileUrl &&
|
||||||
|
typeof formData.value.fileUrl === 'string'
|
||||||
|
) {
|
||||||
|
formData.value.fileUrl = formData.value.fileUrl
|
||||||
|
? [formData.value.fileUrl]
|
||||||
|
: [];
|
||||||
|
}
|
||||||
// 设置到 values
|
// 设置到 values
|
||||||
await formApi.setValues(formData.value);
|
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 {
|
} finally {
|
||||||
modalApi.unlock();
|
modalApi.unlock();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue