diff --git a/apps/web-antd/src/views/erp/stock/in/data.ts b/apps/web-antd/src/views/erp/stock/in/data.ts index 7111cae9c..ad981befd 100644 --- a/apps/web-antd/src/views/erp/stock/in/data.ts +++ b/apps/web-antd/src/views/erp/stock/in/data.ts @@ -98,7 +98,9 @@ export function useFormSchema(): VbenFormSchema[] { } /** 入库产品清单表格列定义 */ -export function useStockInItemTableColumns(): VxeTableGridOptions['columns'] { +export function useStockInItemTableColumns( + isValidating?: any, +): VxeTableGridOptions['columns'] { return [ { type: 'seq', title: '序号', minWidth: 50, fixed: 'left' }, { @@ -106,12 +108,22 @@ export function useStockInItemTableColumns(): VxeTableGridOptions['columns'] { title: '仓库名称', minWidth: 150, slots: { default: 'warehouseId' }, + className: ({ row }: { row: any }) => { + return isValidating?.value && !row.warehouseId + ? 'required-field-error' + : ''; + }, }, { field: 'productId', title: '产品名称', minWidth: 200, slots: { default: 'productId' }, + className: ({ row }: { row: any }) => { + return isValidating?.value && !row.productId + ? 'required-field-error' + : ''; + }, }, { field: 'stockCount', @@ -133,6 +145,11 @@ export function useStockInItemTableColumns(): VxeTableGridOptions['columns'] { title: '数量', minWidth: 120, slots: { default: 'count' }, + className: ({ row }: { row: any }) => { + return isValidating?.value && (!row.count || row.count <= 0) + ? 'required-field-error' + : ''; + }, }, { field: 'productPrice', diff --git a/apps/web-antd/src/views/erp/stock/in/modules/StockInItemForm.vue b/apps/web-antd/src/views/erp/stock/in/modules/StockInItemForm.vue index b35ff3146..c1275a33c 100644 --- a/apps/web-antd/src/views/erp/stock/in/modules/StockInItemForm.vue +++ b/apps/web-antd/src/views/erp/stock/in/modules/StockInItemForm.vue @@ -29,6 +29,7 @@ interface Props { const tableData = ref([]); const productOptions = ref([]); const warehouseOptions = ref([]); +const isValidating = ref(false); /** 表格配置 */ const [Grid, gridApi] = useVbenVxeGrid({ @@ -37,7 +38,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ trigger: 'click', mode: 'cell', }, - columns: useStockInItemTableColumns(), + columns: useStockInItemTableColumns(isValidating), data: tableData.value, border: true, showOverflow: true, @@ -116,6 +117,10 @@ function handleAdd() { tableData.value.push(newRow); gridApi.grid.insertAt(newRow, -1); emit('update:items', [...tableData.value]); + // 触发表格重新渲染以更新cellClassName + nextTick(() => { + gridApi.grid.refreshColumn(); + }); } function handleDelete(row: ErpStockInApi.StockInItem) { @@ -182,6 +187,10 @@ function handleUpdateValue(row: any) { tableData.value[index] = row; } emit('update:items', [...tableData.value]); + // 触发表格重新渲染以更新cellClassName + nextTick(() => { + gridApi.grid.refreshColumn(); + }); } const getSummaries = (): { @@ -200,6 +209,13 @@ const getSummaries = (): { /** 验证表单 */ function validate(): Promise { return new Promise((resolve) => { + isValidating.value = true; + + // 触发表格重新渲染以显示验证错误 + nextTick(() => { + gridApi.grid.refreshColumn(); + }); + // 验证是否有产品清单 if (!tableData.value || tableData.value.length === 0) { resolve(false); @@ -219,6 +235,12 @@ function validate(): Promise { } } + // 验证通过,清除验证状态 + isValidating.value = false; + nextTick(() => { + gridApi.grid.refreshColumn(); + }); + resolve(true); }); } diff --git a/packages/effects/plugins/src/vxe-table/style.css b/packages/effects/plugins/src/vxe-table/style.css index 5b47fa2cf..152fcf219 100644 --- a/packages/effects/plugins/src/vxe-table/style.css +++ b/packages/effects/plugins/src/vxe-table/style.css @@ -115,3 +115,29 @@ .vxe-grid--layout-body-content-wrapper { overflow: hidden; } + +/* 必填字段错误样式 */ +.vxe-table .required-field-error::after { + position: absolute; + top: -1px; + right: -1px; + z-index: 10; + padding: 1px 4px; + font-size: 10px; + line-height: 1; + color: white; + content: '必填'; + background-color: #ff4d4f; + border-radius: 0 0 0 4px; +} + +/* 必填字段内的输入框样式 */ +.vxe-table .required-field-error .ant-select, +.vxe-table .required-field-error .ant-input-number, +.vxe-table .required-field-error .ant-input { + border-color: #ff4d4f !important; +} + +.vxe-table .required-field-error .ant-select .ant-select-selector { + border-color: #ff4d4f !important; +}