From 8d660404dcb6fe552c9f13c16d7d0b76e0606508 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Thu, 31 Jul 2025 13:43:47 +0800
Subject: [PATCH 1/8] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-stock=20?=
=?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=A7=E5=93=81=E5=BA=93=E5=AD=98=E7=AE=A1?=
=?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增产品库存管理页面,包括库存列表和搜索功能
- 添加导出库存数据功能
- 集成 API 接口和数据处理逻辑
- 优化页面布局和组件使用
---
.../web-antd/src/api/erp/stock/stock/index.ts | 2 +-
.../src/views/erp/stock/stock/data.ts | 76 +++++++++++++++
.../src/views/erp/stock/stock/index.vue | 94 ++++++++++++++-----
3 files changed, 147 insertions(+), 25 deletions(-)
create mode 100644 apps/web-antd/src/views/erp/stock/stock/data.ts
diff --git a/apps/web-antd/src/api/erp/stock/stock/index.ts b/apps/web-antd/src/api/erp/stock/stock/index.ts
index 57d4ec229..fa4cfaddb 100644
--- a/apps/web-antd/src/api/erp/stock/stock/index.ts
+++ b/apps/web-antd/src/api/erp/stock/stock/index.ts
@@ -2,7 +2,7 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
-namespace ErpStockApi {
+export namespace ErpStockApi {
/** 产品库存信息 */
export interface Stock {
id?: number; // 编号
diff --git a/apps/web-antd/src/views/erp/stock/stock/data.ts b/apps/web-antd/src/views/erp/stock/stock/data.ts
new file mode 100644
index 000000000..4d0e52b7e
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/stock/data.ts
@@ -0,0 +1,76 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { getProductSimpleList } from '#/api/erp/product/product';
+import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
+
+/** 搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'productId',
+ label: '产品',
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择产品',
+ allowClear: true,
+ showSearch: true,
+ api: getProductSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ filterOption: false,
+ },
+ },
+ {
+ fieldName: 'warehouseId',
+ label: '仓库',
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择仓库',
+ allowClear: true,
+ showSearch: true,
+ api: getWarehouseSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ filterOption: false,
+ },
+ },
+ ];
+}
+
+/** 列表的字段 */
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ field: 'productName',
+ title: '产品名称',
+ minWidth: 150,
+ },
+ {
+ field: 'unitName',
+ title: '产品单位',
+ minWidth: 100,
+ },
+ {
+ field: 'categoryName',
+ title: '产品分类',
+ minWidth: 120,
+ },
+ {
+ field: 'count',
+ title: '库存量',
+ minWidth: 100,
+ cellRender: {
+ name: 'CellAmount',
+ props: {
+ digits: 2,
+ },
+ },
+ },
+ {
+ field: 'warehouseName',
+ title: '仓库',
+ minWidth: 120,
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/erp/stock/stock/index.vue b/apps/web-antd/src/views/erp/stock/stock/index.vue
index 04305f885..8cd51e59c 100644
--- a/apps/web-antd/src/views/erp/stock/stock/index.vue
+++ b/apps/web-antd/src/views/erp/stock/stock/index.vue
@@ -1,32 +1,78 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
--
Gitee
From 2e6575f368a0ed536e2a2553aee3ce7d7686563e Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Thu, 31 Jul 2025 14:33:16 +0800
Subject: [PATCH 2/8] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-record=20?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=A7=E5=93=81=E5=BA=93=E5=AD=98=E6=98=8E?=
=?UTF-8?q?=E7=BB=86=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 实现了产品库存明细的查询、导出功能
- 添加了搜索表单和列表展示
- 集成了仓库和产品选择器
- 使用了 VxeTable 组件
---
.../src/views/erp/stock/record/data.ts | 146 ++++++++++++++++++
.../src/views/erp/stock/record/index.vue | 94 ++++++++---
2 files changed, 216 insertions(+), 24 deletions(-)
create mode 100644 apps/web-antd/src/views/erp/stock/record/data.ts
diff --git a/apps/web-antd/src/views/erp/stock/record/data.ts b/apps/web-antd/src/views/erp/stock/record/data.ts
new file mode 100644
index 000000000..3f8054921
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/record/data.ts
@@ -0,0 +1,146 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { getProductSimpleList } from '#/api/erp/product/product';
+import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
+import { DICT_TYPE, getDictOptions } from '#/utils';
+
+/** 搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'productId',
+ label: '产品',
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择产品',
+ allowClear: true,
+ showSearch: true,
+ api: getProductSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ filterOption: false,
+ },
+ },
+ {
+ fieldName: 'warehouseId',
+ label: '仓库',
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择仓库',
+ allowClear: true,
+ showSearch: true,
+ api: getWarehouseSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ filterOption: false,
+ },
+ },
+ {
+ fieldName: 'bizType',
+ label: '类型',
+ component: 'Select',
+ componentProps: {
+ placeholder: '请选择类型',
+ allowClear: true,
+ options: getDictOptions(DICT_TYPE.ERP_STOCK_RECORD_BIZ_TYPE, 'number'),
+ },
+ },
+ {
+ fieldName: 'bizNo',
+ label: '业务单号',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入业务单号',
+ allowClear: true,
+ },
+ },
+ {
+ fieldName: 'createTime',
+ label: '创建时间',
+ component: 'RangePicker',
+ componentProps: {
+ placeholder: ['开始日期', '结束日期'],
+ showTime: true,
+ format: 'YYYY-MM-DD HH:mm:ss',
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ },
+ },
+ ];
+}
+
+/** 列表的字段 */
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ field: 'productName',
+ title: '产品名称',
+ minWidth: 150,
+ },
+ {
+ field: 'categoryName',
+ title: '产品分类',
+ width: 120,
+ },
+ {
+ field: 'unitName',
+ title: '产品单位',
+ width: 100,
+ },
+ {
+ field: 'warehouseName',
+ title: '仓库',
+ width: 120,
+ },
+ {
+ field: 'bizType',
+ title: '类型',
+ width: 100,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.ERP_STOCK_RECORD_BIZ_TYPE },
+ },
+ },
+ {
+ field: 'bizNo',
+ title: '出入库单号',
+ width: 200,
+ showOverflow: 'tooltip',
+ },
+ {
+ field: 'createTime',
+ title: '出入库日期',
+ width: 180,
+ cellRender: {
+ name: 'CellDateTime',
+ },
+ },
+ {
+ field: 'count',
+ title: '出入库数量',
+ width: 120,
+ cellRender: {
+ name: 'CellAmount',
+ props: {
+ digits: 2,
+ },
+ },
+ },
+ {
+ field: 'totalCount',
+ title: '库存量',
+ width: 100,
+ cellRender: {
+ name: 'CellAmount',
+ props: {
+ digits: 2,
+ },
+ },
+ },
+ {
+ field: 'creatorName',
+ title: '操作人',
+ width: 100,
+ },
+ ];
+}
\ No newline at end of file
diff --git a/apps/web-antd/src/views/erp/stock/record/index.vue b/apps/web-antd/src/views/erp/stock/record/index.vue
index 33dddb833..a05f403eb 100644
--- a/apps/web-antd/src/views/erp/stock/record/index.vue
+++ b/apps/web-antd/src/views/erp/stock/record/index.vue
@@ -1,32 +1,78 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
--
Gitee
From 510ec125824c3949821648718deced0ba4f6c0fd Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Thu, 31 Jul 2025 17:20:09 +0800
Subject: [PATCH 3/8] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-in=20?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=B6=E5=AE=83=E5=85=A5=E5=BA=93=E5=8D=95?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增其它入库单列表页面
- 实现其它入库单的创建、编辑和删除功能
- 添加产品清单管理功能
- 集成供应商、产品和仓库的选择接口
- 优化表格展示和搜索功能
---
apps/web-antd/src/api/erp/stock/in/index.ts | 23 +-
.../web-antd/src/api/erp/stock/stock/index.ts | 8 +-
apps/web-antd/src/views/erp/stock/in/data.ts | 338 ++++++++++++++++
.../web-antd/src/views/erp/stock/in/index.vue | 201 +++++++++-
.../erp/stock/in/modules/StockInItemForm.vue | 368 ++++++++++++++++++
.../src/views/erp/stock/in/modules/form.vue | 252 ++++++++++++
6 files changed, 1167 insertions(+), 23 deletions(-)
create mode 100644 apps/web-antd/src/views/erp/stock/in/data.ts
create mode 100644 apps/web-antd/src/views/erp/stock/in/modules/StockInItemForm.vue
create mode 100644 apps/web-antd/src/views/erp/stock/in/modules/form.vue
diff --git a/apps/web-antd/src/api/erp/stock/in/index.ts b/apps/web-antd/src/api/erp/stock/in/index.ts
index 119398bc3..8fe9bafd4 100644
--- a/apps/web-antd/src/api/erp/stock/in/index.ts
+++ b/apps/web-antd/src/api/erp/stock/in/index.ts
@@ -2,17 +2,38 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
-namespace ErpStockInApi {
+export namespace ErpStockInApi {
/** 其它入库单信息 */
export interface StockIn {
id?: number; // 入库编号
no: string; // 入库单号
supplierId: number; // 供应商编号
+ supplierName?: string; // 供应商名称
inTime: Date; // 入库时间
totalCount: number; // 合计数量
totalPrice: number; // 合计金额,单位:元
status: number; // 状态
remark: string; // 备注
+ fileUrl?: string; // 附件
+ productNames?: string; // 产品信息
+ creatorName?: string; // 创建人
+ items?: StockInItem[]; // 入库产品清单
+ }
+
+ /** 其它入库单产品信息 */
+ export interface StockInItem {
+ id?: number; // 编号
+ warehouseId: number; // 仓库编号
+ productId: number; // 产品编号
+ productName?: string; // 产品名称
+ productUnitId?: number; // 产品单位编号
+ productUnitName?: string; // 产品单位名称
+ productBarCode?: string; // 产品条码
+ count: number; // 数量
+ productPrice: number; // 产品单价
+ totalPrice: number; // 总价
+ stockCount?: number; // 库存数量
+ remark?: string; // 备注
}
/** 其它入库单分页查询参数 */
diff --git a/apps/web-antd/src/api/erp/stock/stock/index.ts b/apps/web-antd/src/api/erp/stock/stock/index.ts
index fa4cfaddb..3ef12dff6 100644
--- a/apps/web-antd/src/api/erp/stock/stock/index.ts
+++ b/apps/web-antd/src/api/erp/stock/stock/index.ts
@@ -54,9 +54,13 @@ export function getStockByProductAndWarehouse(
/**
* 获得产品库存数量
*/
-export function getStockCount(productId: number) {
+export function getStockCount(productId: number, warehouseId?: number) {
+ const params: any = { productId };
+ if (warehouseId !== undefined) {
+ params.warehouseId = warehouseId;
+ }
return requestClient.get('/erp/stock/get-count', {
- params: { productId },
+ params,
});
}
diff --git a/apps/web-antd/src/views/erp/stock/in/data.ts b/apps/web-antd/src/views/erp/stock/in/data.ts
new file mode 100644
index 000000000..2086066ff
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/in/data.ts
@@ -0,0 +1,338 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { erpPriceInputFormatter } from '@vben/utils';
+
+import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
+import { getSimpleUserList } from '#/api/system/user';
+import { DICT_TYPE, getDictOptions } from '#/utils';
+
+/** 表单的配置项 */
+export function useFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ component: 'Input',
+ componentProps: {
+ style: { display: 'none' },
+ },
+ fieldName: 'id',
+ label: 'ID',
+ hideLabel: true,
+ formItemClass: 'hidden',
+ },
+ {
+ component: 'Input',
+ componentProps: {
+ placeholder: '系统自动生成',
+ disabled: true,
+ },
+ fieldName: 'no',
+ label: '入库单号',
+ },
+ {
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择供应商',
+ allowClear: true,
+ showSearch: true,
+ api: getSupplierSimpleList,
+ fieldNames: {
+ label: 'name',
+ value: 'id',
+ },
+ },
+ fieldName: 'supplierId',
+ label: '供应商',
+ },
+ {
+ component: 'DatePicker',
+ componentProps: {
+ placeholder: '选择入库时间',
+ showTime: true,
+ format: 'YYYY-MM-DD HH:mm:ss',
+ valueFormat: 'x',
+ style: { width: '100%' },
+ },
+ fieldName: 'inTime',
+ label: '入库时间',
+ rules: 'required',
+ },
+ {
+ component: 'Textarea',
+ componentProps: {
+ placeholder: '请输入备注',
+ autoSize: { minRows: 2, maxRows: 4 },
+ class: 'w-full',
+ },
+ fieldName: 'remark',
+ label: '备注',
+ formItemClass: 'col-span-3',
+ },
+ {
+ component: 'FileUpload',
+ componentProps: {
+ maxNumber: 1,
+ maxSize: 10,
+ accept: [
+ 'pdf',
+ 'doc',
+ 'docx',
+ 'xls',
+ 'xlsx',
+ 'txt',
+ 'jpg',
+ 'jpeg',
+ 'png',
+ ],
+ showDescription: true,
+ },
+ fieldName: 'fileUrl',
+ label: '附件',
+ formItemClass: 'col-span-3',
+ },
+ {
+ fieldName: 'product',
+ label: '产品清单',
+ component: 'Input',
+ formItemClass: 'col-span-3',
+ },
+ {
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '合计数量',
+ precision: 2,
+ disabled: true,
+ style: { width: '100%' },
+ },
+ fieldName: 'totalCount',
+ label: '合计数量',
+ },
+ {
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '合计金额',
+ precision: 2,
+ formatter: erpPriceInputFormatter,
+ disabled: true,
+ style: { width: '100%' },
+ },
+ fieldName: 'totalPrice',
+ label: '合计金额',
+ },
+ ];
+}
+
+/** 入库产品清单表格列定义 */
+export function useStockInItemTableColumns(): VxeTableGridOptions['columns'] {
+ return [
+ { type: 'seq', title: '序号', minWidth: 50, fixed: 'left' },
+ {
+ field: 'warehouseId',
+ title: '仓库名称',
+ minWidth: 150,
+ slots: { default: 'warehouseId' },
+ },
+ {
+ field: 'productId',
+ title: '产品名称',
+ minWidth: 200,
+ slots: { default: 'productId' },
+ },
+ {
+ field: 'stockCount',
+ title: '库存',
+ minWidth: 100,
+ },
+ {
+ field: 'productBarCode',
+ title: '条码',
+ minWidth: 120,
+ },
+ {
+ field: 'productUnitName',
+ title: '单位',
+ minWidth: 80,
+ },
+ {
+ field: 'count',
+ title: '数量',
+ minWidth: 120,
+ slots: { default: 'count' },
+ },
+ {
+ field: 'productPrice',
+ title: '产品单价',
+ minWidth: 120,
+ slots: { default: 'productPrice' },
+ },
+ {
+ field: 'totalPrice',
+ title: '金额',
+ minWidth: 120,
+ formatter: 'formatAmount2',
+ },
+ {
+ field: 'remark',
+ title: '备注',
+ minWidth: 150,
+ slots: { default: 'remark' },
+ },
+ {
+ title: '操作',
+ width: 50,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
+
+/** 列表的搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'no',
+ label: '入库单号',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入入库单号',
+ allowClear: true,
+ },
+ },
+ {
+ fieldName: 'supplierId',
+ label: '供应商',
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择供应商',
+ allowClear: true,
+ showSearch: true,
+ api: getSupplierSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ filterOption: false,
+ },
+ },
+ {
+ fieldName: 'inTime',
+ label: '入库时间',
+ component: 'RangePicker',
+ componentProps: {
+ placeholder: ['开始日期', '结束日期'],
+ showTime: true,
+ format: 'YYYY-MM-DD HH:mm:ss',
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ },
+ },
+ {
+ fieldName: 'status',
+ label: '状态',
+ component: 'Select',
+ componentProps: {
+ placeholder: '请选择状态',
+ allowClear: true,
+ options: getDictOptions(DICT_TYPE.ERP_AUDIT_STATUS, 'number'),
+ },
+ },
+ {
+ fieldName: 'remark',
+ label: '备注',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入备注',
+ allowClear: true,
+ },
+ },
+ {
+ fieldName: 'creator',
+ label: '创建人',
+ component: 'ApiSelect',
+ componentProps: {
+ placeholder: '请选择创建人',
+ allowClear: true,
+ showSearch: true,
+ api: getSimpleUserList,
+ labelField: 'nickname',
+ valueField: 'id',
+ filterOption: false,
+ },
+ },
+ ];
+}
+
+/** 列表的字段 */
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ type: 'checkbox',
+ width: 50,
+ fixed: 'left',
+ },
+ {
+ field: 'no',
+ title: '入库单号',
+ minWidth: 180,
+ },
+ {
+ field: 'productNames',
+ title: '产品信息',
+ minWidth: 200,
+ showOverflow: 'tooltip',
+ },
+ {
+ field: 'supplierName',
+ title: '供应商',
+ width: 120,
+ },
+ {
+ field: 'inTime',
+ title: '入库时间',
+ width: 180,
+ cellRender: {
+ name: 'CellDateTime',
+ },
+ },
+ {
+ field: 'creatorName',
+ title: '创建人',
+ width: 100,
+ },
+ {
+ field: 'totalCount',
+ title: '数量',
+ width: 100,
+ cellRender: {
+ name: 'CellAmount',
+ props: {
+ digits: 2,
+ },
+ },
+ },
+ {
+ field: 'totalPrice',
+ title: '金额',
+ width: 120,
+ cellRender: {
+ name: 'CellAmount',
+ props: {
+ digits: 2,
+ },
+ },
+ },
+ {
+ field: 'status',
+ title: '状态',
+ width: 90,
+ fixed: 'right',
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.ERP_AUDIT_STATUS },
+ },
+ },
+ {
+ title: '操作',
+ width: 220,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/erp/stock/in/index.vue b/apps/web-antd/src/views/erp/stock/in/index.vue
index ae06852cb..641c4347d 100644
--- a/apps/web-antd/src/views/erp/stock/in/index.vue
+++ b/apps/web-antd/src/views/erp/stock/in/index.vue
@@ -1,34 +1,195 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..d2ba3f195
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/in/modules/StockInItemForm.vue
@@ -0,0 +1,368 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ handlePriceChange(row)"
+ class="w-full"
+ />
+
+
+
+ handlePriceChange(row)"
+ class="w-full"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/erp/stock/in/modules/form.vue b/apps/web-antd/src/views/erp/stock/in/modules/form.vue
new file mode 100644
index 000000000..108ef2600
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/in/modules/form.vue
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+
+
+
+
+
+
--
Gitee
From 3afd9577137f3df0e0059bbe7521dce357b32819 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Fri, 1 Aug 2025 16:11:05 +0800
Subject: [PATCH 4/8] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-in=20?=
=?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BA=93=E5=AD=98=E5=85=A5=E5=BA=93=E6=A8=A1?=
=?UTF-8?q?=E5=9D=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 为表格列设置 minWidth 以优化布局
- 使用 Popconfirm组件替代 Modal 确认框
- 通过 message 组件展示操作结果
- 优化删除和审核操作的处理流程
- 引入 useVbenModal 优化表单弹窗
---
apps/web-antd/src/views/erp/stock/in/data.ts | 14 +--
.../web-antd/src/views/erp/stock/in/index.vue | 95 ++++++++++++-------
.../erp/stock/in/modules/StockInItemForm.vue | 5 +-
3 files changed, 71 insertions(+), 43 deletions(-)
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 2086066ff..bd54761d7 100644
--- a/apps/web-antd/src/views/erp/stock/in/data.ts
+++ b/apps/web-antd/src/views/erp/stock/in/data.ts
@@ -281,12 +281,12 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'supplierName',
title: '供应商',
- width: 120,
+ minWidth: 120,
},
{
field: 'inTime',
title: '入库时间',
- width: 180,
+ minWidth: 180,
cellRender: {
name: 'CellDateTime',
},
@@ -294,12 +294,12 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'creatorName',
title: '创建人',
- width: 100,
+ minWidth: 100,
},
{
field: 'totalCount',
title: '数量',
- width: 100,
+ minWidth: 100,
cellRender: {
name: 'CellAmount',
props: {
@@ -310,7 +310,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'totalPrice',
title: '金额',
- width: 120,
+ minWidth: 120,
cellRender: {
name: 'CellAmount',
props: {
@@ -321,7 +321,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'status',
title: '状态',
- width: 90,
+ minWidth: 90,
fixed: 'right',
cellRender: {
name: 'CellDict',
@@ -330,7 +330,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
},
{
title: '操作',
- width: 220,
+ width: 300,
fixed: 'right',
slots: { default: 'actions' },
},
diff --git a/apps/web-antd/src/views/erp/stock/in/index.vue b/apps/web-antd/src/views/erp/stock/in/index.vue
index 641c4347d..8bb4c15d8 100644
--- a/apps/web-antd/src/views/erp/stock/in/index.vue
+++ b/apps/web-antd/src/views/erp/stock/in/index.vue
@@ -2,12 +2,10 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ErpStockInApi } from '#/api/erp/stock/in';
-import { ref } from 'vue';
-
-import { DocAlert, Page } from '@vben/common-ui';
+import { DocAlert, Page, useVbenModal } from '@vben/common-ui';
import { downloadFileFromBlobPart } from '@vben/utils';
-import { message, Modal } from 'ant-design-vue';
+import { message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
@@ -24,7 +22,10 @@ import StockInForm from './modules/form.vue';
/** 其它入库单管理 */
defineOptions({ name: 'ErpStockIn' });
-const formRef = ref();
+const [FormModal, formModalApi] = useVbenModal({
+ connectedComponent: StockInForm,
+ destroyOnClose: true,
+});
/** 刷新表格 */
function onRefresh() {
@@ -39,34 +40,46 @@ async function handleExport() {
/** 新增/编辑/详情 */
function openForm(type: string, id?: number) {
- formRef.value?.modalApi.open({ type, id });
+ formModalApi.setData({ type, id }).open();
}
/** 删除 */
-function handleDelete(ids: any[]) {
- Modal.confirm({
- title: '系统提示',
- content: `是否确认删除编号为 ${ids.join(',')} 的其它入库单?`,
- onOk: async () => {
- await deleteStockIn(ids);
- message.success('删除成功');
- onRefresh();
- },
+async function handleDelete(ids: any[]) {
+ const hideLoading = message.loading({
+ content: '删除中...',
+ duration: 0,
+ key: 'action_process_msg',
});
+ try {
+ await deleteStockIn(ids);
+ message.success({
+ content: '删除成功',
+ key: 'action_process_msg',
+ });
+ onRefresh();
+ } finally {
+ hideLoading();
+ }
}
/** 审核/反审核 */
-function handleUpdateStatus(id: any, status: number) {
+async function handleUpdateStatus(id: any, status: number) {
const statusText = status === 20 ? '审核' : '反审核';
- Modal.confirm({
- title: '系统提示',
- content: `确认要${statusText}该入库单吗?`,
- onOk: async () => {
- await updateStockInStatus({ id, status });
- message.success(`${statusText}成功`);
- onRefresh();
- },
+ const hideLoading = message.loading({
+ content: `${statusText}中...`,
+ duration: 0,
+ key: 'action_process_msg',
});
+ try {
+ await updateStockInStatus({ id, status });
+ message.success({
+ content: `${statusText}成功`,
+ key: 'action_process_msg',
+ });
+ onRefresh();
+ } finally {
+ hideLoading();
+ }
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -135,13 +148,16 @@ const [Grid, gridApi] = useVbenVxeGrid({
danger: true,
icon: ACTION_ICON.DELETE,
auth: ['erp:stock-in:delete'],
- onClick: () => {
- const checkboxRecords = gridApi.grid.getCheckboxRecords();
- if (checkboxRecords.length === 0) {
- message.warning('请选择要删除的数据');
- return;
- }
- handleDelete(checkboxRecords.map((item) => item.id));
+ popConfirm: {
+ title: '是否删除所选中数据?',
+ confirm: () => {
+ const checkboxRecords = gridApi.grid.getCheckboxRecords();
+ if (checkboxRecords.length === 0) {
+ message.warning('请选择要删除的数据');
+ return;
+ }
+ handleDelete(checkboxRecords.map((item) => item.id));
+ },
},
},
]"
@@ -168,21 +184,30 @@ const [Grid, gridApi] = useVbenVxeGrid({
type: 'primary',
auth: ['erp:stock-in:update'],
ifShow: row.status === 10,
- onClick: () => handleUpdateStatus(row.id, 20),
+ popConfirm: {
+ title: '确认要审核该入库单吗?',
+ confirm: () => handleUpdateStatus(row.id, 20),
+ },
},
{
label: '反审核',
danger: true,
auth: ['erp:stock-in:update'],
ifShow: row.status === 20,
- onClick: () => handleUpdateStatus(row.id, 10),
+ popConfirm: {
+ title: '确认要反审核该入库单吗?',
+ confirm: () => handleUpdateStatus(row.id, 10),
+ },
},
{
label: '删除',
danger: true,
auth: ['erp:stock-in:delete'],
ifShow: row.status === 10,
- onClick: () => handleDelete([row.id]),
+ popConfirm: {
+ title: '确认要删除该入库单吗?',
+ confirm: () => handleDelete([row.id]),
+ },
},
]"
/>
@@ -190,6 +215,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
-
+
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 d2ba3f195..159e4e4a5 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
@@ -358,7 +358,10 @@ defineExpose({
label: '删除',
type: 'link',
danger: true,
- onClick: () => handleDelete(row),
+ popConfirm: {
+ title: '确认删除该产品吗?',
+ confirm: handleDelete.bind(null, row),
+ },
},
]"
/>
--
Gitee
From 1433a0980d99daf6b1d9cc751ea94a224d095cfd Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Fri, 1 Aug 2025 17:35:56 +0800
Subject: [PATCH 5/8] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-in=20?=
=?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=A5=E5=BA=93=E5=8D=95=E4=BA=A7=E5=93=81?=
=?UTF-8?q?=E6=B8=85=E5=8D=95=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了 totalCount 和 totalPrice 的计算逻辑
- 调整了添加产品的按钮位置
- 为表格底部的单元格添加了自定义样式
- 简化了组件的 props 接口
---
apps/web-antd/src/views/erp/stock/in/data.ts | 47 --------------
.../erp/stock/in/modules/StockInItemForm.vue | 65 +++++++------------
.../src/views/erp/stock/in/modules/form.vue | 24 ++-----
3 files changed, 28 insertions(+), 108 deletions(-)
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 bd54761d7..7111cae9c 100644
--- a/apps/web-antd/src/views/erp/stock/in/data.ts
+++ b/apps/web-antd/src/views/erp/stock/in/data.ts
@@ -1,8 +1,6 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
-import { erpPriceInputFormatter } from '@vben/utils';
-
import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
@@ -96,29 +94,6 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'Input',
formItemClass: 'col-span-3',
},
- {
- component: 'InputNumber',
- componentProps: {
- placeholder: '合计数量',
- precision: 2,
- disabled: true,
- style: { width: '100%' },
- },
- fieldName: 'totalCount',
- label: '合计数量',
- },
- {
- component: 'InputNumber',
- componentProps: {
- placeholder: '合计金额',
- precision: 2,
- formatter: erpPriceInputFormatter,
- disabled: true,
- style: { width: '100%' },
- },
- fieldName: 'totalPrice',
- label: '合计金额',
- },
];
}
@@ -296,28 +271,6 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
title: '创建人',
minWidth: 100,
},
- {
- field: 'totalCount',
- title: '数量',
- minWidth: 100,
- cellRender: {
- name: 'CellAmount',
- props: {
- digits: 2,
- },
- },
- },
- {
- field: 'totalPrice',
- title: '金额',
- minWidth: 120,
- cellRender: {
- name: 'CellAmount',
- props: {
- digits: 2,
- },
- },
- },
{
field: 'status',
title: '状态',
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 159e4e4a5..fd5f10a44 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
@@ -19,11 +19,7 @@ const props = withDefaults(defineProps(), {
disabled: false,
});
-const emit = defineEmits([
- 'update:items',
- 'update:total-count',
- 'update:total-price',
-]);
+const emit = defineEmits(['update:items']);
interface Props {
items?: ErpStockInApi.StockInItem[];
@@ -58,6 +54,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
enabled: false,
},
showFooter: true,
+ footerCellClassName: 'stock-in-footer-cell',
footerMethod: ({ columns }) => {
const footers: any[][] = [];
const sums = getSummaries();
@@ -96,31 +93,6 @@ watch(
},
);
-/** 计算 totalCount、totalPrice */
-watch(
- () => tableData.value,
- () => {
- if (!tableData.value || tableData.value.length === 0) {
- emit('update:total-count', 0);
- emit('update:total-price', 0);
- return;
- }
- const totalCount = tableData.value.reduce(
- (prev, curr) => prev + (curr.count || 0),
- 0,
- );
- const totalPrice = tableData.value.reduce(
- (prev, curr) => prev + (curr.totalPrice || 0),
- 0,
- );
-
- // 发送计算结果给父组件
- emit('update:total-count', totalCount);
- emit('update:total-price', totalPrice);
- },
- { deep: true },
-);
-
/** 初始化 */
onMounted(async () => {
productOptions.value = await getProductSimpleList();
@@ -260,23 +232,14 @@ function init(items: ErpStockInApi.StockInItem[]) {
defineExpose({
validate,
init,
+ handleAdd,
});
@@ -366,6 +329,26 @@ defineExpose({
]"
/>
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/erp/stock/in/modules/form.vue b/apps/web-antd/src/views/erp/stock/in/modules/form.vue
index 108ef2600..2f09d5215 100644
--- a/apps/web-antd/src/views/erp/stock/in/modules/form.vue
+++ b/apps/web-antd/src/views/erp/stock/in/modules/form.vue
@@ -49,24 +49,6 @@ const handleUpdateItems = (items: ErpStockInApi.StockInItem[]) => {
}
};
-const handleUpdateTotalCount = (totalCount: number) => {
- if (formData.value) {
- formData.value.totalCount = totalCount;
- formApi.setValues({
- totalCount: formData.value.totalCount,
- });
- }
-};
-
-const handleUpdateTotalPrice = (totalPrice: number) => {
- if (formData.value) {
- formData.value.totalPrice = totalPrice;
- formApi.setValues({
- totalPrice: formData.value.totalPrice,
- });
- }
-};
-
/**
* 创建或更新其它入库单
*/
@@ -145,6 +127,10 @@ const [Modal, modalApi] = useVbenModal({
if (itemFormInstance && typeof itemFormInstance.init === 'function') {
itemFormInstance.init([]);
}
+ // 如果是新增,自动添加一行
+ if (formType.value === 'create' && itemFormInstance) {
+ itemFormInstance.handleAdd();
+ }
return;
}
@@ -209,8 +195,6 @@ defineExpose({ modalApi, handleUpdateStatus });
:items="formData?.items ?? []"
:disabled="formType === 'detail'"
@update:items="handleUpdateItems"
- @update:total-count="handleUpdateTotalCount"
- @update:total-price="handleUpdateTotalPrice"
/>
--
Gitee
From 9d80b9fc7147a16483775925e27d778554010395 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Fri, 1 Aug 2025 18:22:51 +0800
Subject: [PATCH 6/8] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-in=20?=
=?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=A5=E5=BA=93=E5=8D=95=E4=BA=A7=E5=93=81?=
=?UTF-8?q?=E6=B8=85=E5=8D=95=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../web-antd/src/views/erp/stock/in/index.vue | 8 ++---
.../erp/stock/in/modules/StockInItemForm.vue | 26 ++++----------
.../src/views/erp/stock/in/modules/form.vue | 34 -------------------
3 files changed, 10 insertions(+), 58 deletions(-)
diff --git a/apps/web-antd/src/views/erp/stock/in/index.vue b/apps/web-antd/src/views/erp/stock/in/index.vue
index 8bb4c15d8..55891fa95 100644
--- a/apps/web-antd/src/views/erp/stock/in/index.vue
+++ b/apps/web-antd/src/views/erp/stock/in/index.vue
@@ -169,19 +169,19 @@ const [Grid, gridApi] = useVbenVxeGrid({
:actions="[
{
label: '详情',
+ icon: ACTION_ICON.VIEW,
auth: ['erp:stock-in:query'],
onClick: () => openForm('detail', row.id),
},
{
label: '编辑',
- type: 'primary',
auth: ['erp:stock-in:update'],
- ifShow: row.status === 10,
+ icon: ACTION_ICON.EDIT,
+ disabled: row.status !== 10,
onClick: () => openForm('update', row.id),
},
{
label: '审核',
- type: 'primary',
auth: ['erp:stock-in:update'],
ifShow: row.status === 10,
popConfirm: {
@@ -203,7 +203,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
label: '删除',
danger: true,
auth: ['erp:stock-in:delete'],
- ifShow: row.status === 10,
+ disabled: row.status !== 10,
popConfirm: {
title: '确认要删除该入库单吗?',
confirm: () => handleDelete([row.id]),
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 fd5f10a44..b35ff3146 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
@@ -246,41 +246,27 @@ defineExpose({
+ />
+ />
diff --git a/apps/web-antd/src/views/erp/stock/in/modules/form.vue b/apps/web-antd/src/views/erp/stock/in/modules/form.vue
index 2f09d5215..fffca0978 100644
--- a/apps/web-antd/src/views/erp/stock/in/modules/form.vue
+++ b/apps/web-antd/src/views/erp/stock/in/modules/form.vue
@@ -198,39 +198,5 @@ defineExpose({ modalApi, handleUpdateStatus });
/>
-
-
-
-
-
--
Gitee
From 5f56b1473357597d1ec8bcc669cb7a33df5843de Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Sat, 2 Aug 2025 21:21:51 +0800
Subject: [PATCH 7/8] =?UTF-8?q?feat(@vben/web-antd):=20=E9=AA=8C=E8=AF=81?=
=?UTF-8?q?=E6=A0=B7=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加 isValidating 状态管理,用于控制验证过程
- 在表格列定义中增加验证错误样式
- 实现必填字段错误提示功能
- 优化表格渲染逻辑,确保验证错误及时显示
- 新增相关 CSS 样式,定义验证错误的视觉效果
---
apps/web-antd/src/views/erp/stock/in/data.ts | 19 +++++++++++++-
.../erp/stock/in/modules/StockInItemForm.vue | 24 ++++++++++++++++-
.../effects/plugins/src/vxe-table/style.css | 26 +++++++++++++++++++
3 files changed, 67 insertions(+), 2 deletions(-)
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;
+}
--
Gitee
From c64be886b4e6b964a86f826b255963ede6e5e163 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Sat, 2 Aug 2025 23:28:59 +0800
Subject: [PATCH 8/8] =?UTF-8?q?feat(@vben/web-antd):=20vxe-table)=E6=96=B0?=
=?UTF-8?q?=E5=A2=9E=E8=A1=A8=E5=8D=95=E9=AA=8C=E8=AF=81=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 vxe-table.ts 中添加 createRequiredValidation函数
- 在 data.ts 中使用 createRequiredValidation 替代原有的 className 函数
- 在 vxe-table 插件中添加 validation 相关的工具函数
- 优化表格列的验证逻辑,提高代码复用性和可维护性
---
apps/web-antd/src/adapter/vxe-table.ts | 3 +-
apps/web-antd/src/views/erp/stock/in/data.ts | 19 ++----
.../effects/plugins/src/vxe-table/index.ts | 3 +-
.../plugins/src/vxe-table/validation.ts | 61 +++++++++++++++++++
4 files changed, 69 insertions(+), 17 deletions(-)
create mode 100644 packages/effects/plugins/src/vxe-table/validation.ts
diff --git a/apps/web-antd/src/adapter/vxe-table.ts b/apps/web-antd/src/adapter/vxe-table.ts
index 69f855503..e28a6ae1d 100644
--- a/apps/web-antd/src/adapter/vxe-table.ts
+++ b/apps/web-antd/src/adapter/vxe-table.ts
@@ -7,6 +7,7 @@ import { IconifyIcon } from '@vben/icons';
import { $te } from '@vben/locales';
import {
AsyncComponents,
+ createRequiredValidation,
setupVbenVxeTable,
useVbenVxeGrid,
} from '@vben/plugins/vxe-table';
@@ -354,7 +355,7 @@ setupVbenVxeTable({
useVbenForm,
});
-export { useVbenVxeGrid };
+export { createRequiredValidation, useVbenVxeGrid };
const [VxeTable, VxeColumn, VxeToolbar] = AsyncComponents;
export { VxeColumn, VxeTable, VxeToolbar };
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 ad981befd..68b667fc9 100644
--- a/apps/web-antd/src/views/erp/stock/in/data.ts
+++ b/apps/web-antd/src/views/erp/stock/in/data.ts
@@ -1,6 +1,7 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import { createRequiredValidation } from '#/adapter/vxe-table';
import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
@@ -108,22 +109,14 @@ export function useStockInItemTableColumns(
title: '仓库名称',
minWidth: 150,
slots: { default: 'warehouseId' },
- className: ({ row }: { row: any }) => {
- return isValidating?.value && !row.warehouseId
- ? 'required-field-error'
- : '';
- },
+ className: createRequiredValidation(isValidating, 'warehouseId'),
},
{
field: 'productId',
title: '产品名称',
minWidth: 200,
slots: { default: 'productId' },
- className: ({ row }: { row: any }) => {
- return isValidating?.value && !row.productId
- ? 'required-field-error'
- : '';
- },
+ className: createRequiredValidation(isValidating, 'productId'),
},
{
field: 'stockCount',
@@ -145,11 +138,7 @@ export function useStockInItemTableColumns(
title: '数量',
minWidth: 120,
slots: { default: 'count' },
- className: ({ row }: { row: any }) => {
- return isValidating?.value && (!row.count || row.count <= 0)
- ? 'required-field-error'
- : '';
- },
+ className: createRequiredValidation(isValidating, 'count'),
},
{
field: 'productPrice',
diff --git a/packages/effects/plugins/src/vxe-table/index.ts b/packages/effects/plugins/src/vxe-table/index.ts
index 70f4cfa5c..8cc12bef7 100644
--- a/packages/effects/plugins/src/vxe-table/index.ts
+++ b/packages/effects/plugins/src/vxe-table/index.ts
@@ -1,8 +1,9 @@
export { AsyncComponents, setupVbenVxeTable } from './init';
export type { VxeTableGridOptions } from './types';
export * from './use-vxe-grid';
-
export { default as VbenVxeGrid } from './use-vxe-grid.vue';
+
+export * from './validation';
export type {
VxeGridListeners,
VxeGridProps,
diff --git a/packages/effects/plugins/src/vxe-table/validation.ts b/packages/effects/plugins/src/vxe-table/validation.ts
new file mode 100644
index 000000000..487f24107
--- /dev/null
+++ b/packages/effects/plugins/src/vxe-table/validation.ts
@@ -0,0 +1,61 @@
+/**
+ * 创建验证类名的工具函数
+ * @param isValidating 验证状态
+ * @param fieldName 字段名
+ * @param validationRules 验证规则,可以是字符串或自定义函数
+ * @returns 返回 className 函数
+ */
+function createValidationClassName(
+ isValidating: any,
+ fieldName: string,
+ validationRules: ((row: any) => boolean) | string,
+) {
+ return ({ row }: { row: any }) => {
+ if (!isValidating?.value) return '';
+
+ let isValid = true;
+ if (typeof validationRules === 'string') {
+ // 处理简单的验证规则
+ if (validationRules === 'required') {
+ isValid =
+ fieldName === 'count'
+ ? row[fieldName] && row[fieldName] > 0
+ : !!row[fieldName];
+ }
+ } else if (typeof validationRules === 'function') {
+ // 处理自定义验证函数
+ isValid = validationRules(row);
+ }
+
+ return isValid ? '' : 'required-field-error';
+ };
+}
+
+/**
+ * 创建必填字段验证
+ * @param isValidating 验证状态
+ * @param fieldName 字段名
+ * @returns 返回 className 函数
+ */
+function createRequiredValidation(isValidating: any, fieldName: string) {
+ return createValidationClassName(isValidating, fieldName, 'required');
+}
+
+/**
+ * 创建自定义验证
+ * @param isValidating 验证状态
+ * @param validationFn 自定义验证函数
+ * @returns 返回 className 函数
+ */
+function createCustomValidation(
+ isValidating: any,
+ validationFn: (row: any) => boolean,
+) {
+ return createValidationClassName(isValidating, '', validationFn);
+}
+
+export {
+ createCustomValidation,
+ createRequiredValidation,
+ createValidationClassName,
+};
--
Gitee