--
Gitee
From e319888240b618d3f6230cb5341020acfa95ebf9 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Thu, 24 Jul 2025 17:13:15 +0800
Subject: [PATCH 17/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E9=87=87=E8=B4=AD=E8=AE=A2=E5=8D=95=E8=A1=A8=E5=8D=95?=
=?UTF-8?q?=E5=B8=83=E5=B1=80=E5=92=8C=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加订单单号字段并设置为只读
- 将附件上传组件替换为 FileUpload
- 新增产品清单字段
- 调整表单项的布局和样式
- 优化订单产品清单的展示方式
---
.../src/views/erp/purchase/order/data.ts | 38 ++++++++++++++++---
.../order/modules/PurchaseOrderItemForm.vue | 1 +
.../views/erp/purchase/order/modules/form.vue | 34 ++++++++---------
3 files changed, 49 insertions(+), 24 deletions(-)
diff --git a/apps/web-antd/src/views/erp/purchase/order/data.ts b/apps/web-antd/src/views/erp/purchase/order/data.ts
index 60f9e2954..7a3ea19c6 100644
--- a/apps/web-antd/src/views/erp/purchase/order/data.ts
+++ b/apps/web-antd/src/views/erp/purchase/order/data.ts
@@ -12,6 +12,15 @@ import { DICT_TYPE, getDictOptions } from '#/utils';
/** 表单的配置项 */
export function useFormSchema(): VbenFormSchema[] {
return [
+ {
+ component: 'Input',
+ componentProps: {
+ placeholder: '系统自动生成',
+ disabled: true,
+ },
+ fieldName: 'no',
+ label: '订单单号',
+ },
{
component: 'ApiSelect',
componentProps: {
@@ -50,17 +59,35 @@ export function useFormSchema(): VbenFormSchema[] {
},
fieldName: 'remark',
label: '备注',
- formItemClass: 'col-span-2',
+ formItemClass: 'col-span-3',
},
{
- component: 'Input',
+ component: 'FileUpload',
componentProps: {
- placeholder: '请输入附件地址',
- class: 'w-full',
+ maxNumber: 5,
+ maxSize: 10,
+ accept: [
+ 'pdf',
+ 'doc',
+ 'docx',
+ 'xls',
+ 'xlsx',
+ 'txt',
+ 'jpg',
+ 'jpeg',
+ 'png',
+ ],
+ showDescription: true,
},
fieldName: 'fileUrl',
label: '附件',
- formItemClass: 'col-span-2',
+ formItemClass: 'col-span-3',
+ },
+ {
+ fieldName: 'product',
+ label: '产品清单',
+ component: 'Input',
+ formItemClass: 'col-span-3',
},
{
component: 'InputNumber',
@@ -214,6 +241,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
componentProps: {
placeholder: '请输入订单单号',
allowClear: true,
+ disabled: true,
},
},
{
diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue b/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
index 977d52a26..2849755bc 100644
--- a/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
@@ -40,6 +40,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
border: true,
showOverflow: true,
autoResize: true,
+ minHeight: 250,
keepSource: true,
rowConfig: {
keyField: 'id',
diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
index cc3fe0c01..621d0f383 100644
--- a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
@@ -34,9 +34,10 @@ const [Form, formApi] = useVbenForm({
componentProps: {
class: 'w-full',
},
+ labelWidth: 120,
},
- wrapperClass: 'grid-cols-2',
- layout: 'horizontal',
+ wrapperClass: 'grid-cols-3',
+ layout: 'vertical',
schema: useFormSchema(),
showDefaultActions: false,
});
@@ -133,22 +134,17 @@ defineExpose({ modalApi });
:closable="true"
:mask-closable="true"
>
-
-
-
-
+
--
Gitee
From 8a7239ce2435d25d6810b4e4c31552406c06dfbe Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Fri, 25 Jul 2025 19:20:39 +0800
Subject: [PATCH 18/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-=E9=87=87?=
=?UTF-8?q?=E8=B4=AD=E8=AE=A2=E5=8D=95=E8=A1=A8=E5=8D=95=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 使用 handleValuesChange
- 优化 discountPrice 和 totalPrice 的计算逻辑
- 改进子表单的验证和数据处理
- 统一数值格式化处理
- 优化表格数据的更新方式
---
.../crm/product/modules/product-table.vue | 2 +-
.../src/views/erp/purchase/order/data.ts | 6 +-
.../order/modules/PurchaseOrderItemForm.vue | 70 ++++++++++++++-----
.../views/erp/purchase/order/modules/form.vue | 65 +++++++++--------
4 files changed, 95 insertions(+), 48 deletions(-)
diff --git a/apps/web-antd/src/views/crm/product/modules/product-table.vue b/apps/web-antd/src/views/crm/product/modules/product-table.vue
index 4b01eacdc..9518396d7 100644
--- a/apps/web-antd/src/views/crm/product/modules/product-table.vue
+++ b/apps/web-antd/src/views/crm/product/modules/product-table.vue
@@ -66,7 +66,7 @@ function handleUpdateValue(row: any) {
} else {
tableData.value[index] = row;
}
- emit('update:products', tableData.value);
+ emit('update:products', [...tableData.value]);
}
/** 表格配置 */
diff --git a/apps/web-antd/src/views/erp/purchase/order/data.ts b/apps/web-antd/src/views/erp/purchase/order/data.ts
index 7a3ea19c6..9a037f94f 100644
--- a/apps/web-antd/src/views/erp/purchase/order/data.ts
+++ b/apps/web-antd/src/views/erp/purchase/order/data.ts
@@ -3,6 +3,7 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { erpCountInputFormatter, erpPriceInputFormatter } from '@vben/utils';
+import { z } from '#/adapter/form';
import { getAccountSimpleList } from '#/api/erp/finance/account';
import { getProductSimpleList } from '#/api/erp/product/product';
import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
@@ -96,11 +97,11 @@ export function useFormSchema(): VbenFormSchema[] {
min: 0,
max: 100,
precision: 2,
- formatter: erpPriceInputFormatter,
style: { width: '100%' },
},
fieldName: 'discountPercent',
label: '优惠率(%)',
+ rules: z.number().min(0).optional(),
},
{
component: 'InputNumber',
@@ -146,11 +147,12 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: {
placeholder: '请输入支付订金',
precision: 2,
- formatter: erpPriceInputFormatter,
style: { width: '100%' },
+ min: 0,
},
fieldName: 'depositPrice',
label: '支付订金',
+ rules: z.number().min(0).optional(),
},
];
}
diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue b/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
index 2849755bc..7bcede093 100644
--- a/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
@@ -16,13 +16,19 @@ import { usePurchaseOrderItemTableColumns } from '../data';
const props = withDefaults(defineProps
(), {
items: () => [],
disabled: false,
+ discountPercent: 0,
});
-const emit = defineEmits(['update:items']);
+const emit = defineEmits([
+ 'update:items',
+ 'update:discount-price',
+ 'update:total-price',
+]);
interface Props {
items?: ErpPurchaseOrderApi.PurchaseOrderItem[];
disabled?: boolean;
+ discountPercent?: number;
}
const tableData = ref([]);
@@ -62,7 +68,8 @@ watch(
return;
}
await nextTick();
- tableData.value = items;
+ tableData.value = [...items];
+ await nextTick();
gridApi.grid.reloadData(tableData.value);
},
{
@@ -70,6 +77,30 @@ watch(
},
);
+/** 计算 discountPrice、totalPrice 价格 */
+watch(
+ () => [tableData.value, props.discountPercent],
+ () => {
+ if (!tableData.value || tableData.value.length === 0) {
+ return;
+ }
+ const totalPrice = tableData.value.reduce(
+ (prev, curr) => prev + (curr.totalPrice || 0),
+ 0,
+ );
+ const discountPrice =
+ props.discountPercent === null
+ ? 0
+ : erpPriceMultiply(totalPrice, props.discountPercent / 100);
+ const finalTotalPrice = totalPrice - discountPrice;
+
+ // 发送计算结果给父组件
+ emit('update:discount-price', discountPrice);
+ emit('update:total-price', finalTotalPrice);
+ },
+ { deep: true },
+);
+
/** 初始化 */
onMounted(async () => {
productOptions.value = await getProductSimpleList();
@@ -81,6 +112,11 @@ function handleAdd() {
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
gridApi.grid.remove(row);
+ const index = tableData.value.findIndex((item) => item.id === row.id);
+ if (index !== -1) {
+ tableData.value.splice(index, 1);
+ }
+ emit('update:items', [...tableData.value]);
}
async function handleProductChange(productId: any, row: any) {
@@ -121,7 +157,7 @@ function handleUpdateValue(row: any) {
} else {
tableData.value[index] = row;
}
- emit('update:items', tableData.value);
+ emit('update:items', [...tableData.value]);
}
const getSummaries = (): {
@@ -131,7 +167,7 @@ const getSummaries = (): {
totalPrice: number;
totalProductPrice: number;
} => {
- const sums = {
+ return {
productName: '合计',
count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0),
totalProductPrice: tableData.value.reduce(
@@ -147,20 +183,21 @@ const getSummaries = (): {
0,
),
};
- return sums;
};
const validate = async (): Promise => {
for (let i = 0; i < tableData.value.length; i++) {
const item = tableData.value[i];
- 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} 行:产品单价不能为空`);
+ 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} 行:产品单价不能为空`);
+ }
}
}
};
@@ -169,8 +206,10 @@ const getData = (): ErpPurchaseOrderApi.PurchaseOrderItem[] => tableData.value;
const init = (
items: ErpPurchaseOrderApi.PurchaseOrderItem[] | undefined,
): void => {
- tableData.value = items || [];
- gridApi.grid.reloadData(tableData.value);
+ tableData.value = items ? [...items] : [];
+ nextTick(() => {
+ gridApi.grid.reloadData(tableData.value);
+ });
};
defineExpose({ validate, getData, init });
@@ -232,7 +271,6 @@ defineExpose({ validate, getData, init });
-
合计:
diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
index 621d0f383..876115215 100644
--- a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
@@ -1,10 +1,10 @@
-
+
-
+
-
+
-
+
-
+
+
diff --git a/packages/effects/hooks/src/use-app-config.ts b/packages/effects/hooks/src/use-app-config.ts
index 857ac7cb7..41f383cd2 100644
--- a/packages/effects/hooks/src/use-app-config.ts
+++ b/packages/effects/hooks/src/use-app-config.ts
@@ -15,9 +15,22 @@ export function useAppConfig(
? window._VBEN_ADMIN_PRO_APP_CONF_
: (env as VbenAdminProAppConfigRaw);
- const { VITE_GLOB_API_URL } = config;
+ const {
+ VITE_GLOB_API_URL,
+ VITE_GLOB_AUTH_DINGDING_CORP_ID,
+ VITE_GLOB_AUTH_DINGDING_CLIENT_ID,
+ } = config;
- return {
+ const applicationConfig: ApplicationConfig = {
apiURL: VITE_GLOB_API_URL,
+ auth: {},
};
+ if (VITE_GLOB_AUTH_DINGDING_CORP_ID && VITE_GLOB_AUTH_DINGDING_CLIENT_ID) {
+ applicationConfig.auth.dingding = {
+ clientId: VITE_GLOB_AUTH_DINGDING_CLIENT_ID,
+ corpId: VITE_GLOB_AUTH_DINGDING_CORP_ID,
+ };
+ }
+
+ return applicationConfig;
}
diff --git a/packages/icons/src/iconify/index.ts b/packages/icons/src/iconify/index.ts
index a0985ac15..bec4d5a50 100644
--- a/packages/icons/src/iconify/index.ts
+++ b/packages/icons/src/iconify/index.ts
@@ -11,3 +11,5 @@ export const MdiGithub = createIconifyIcon('mdi:github');
export const MdiGoogle = createIconifyIcon('mdi:google');
export const MdiQqchat = createIconifyIcon('mdi:qqchat');
+
+export const RiDingding = createIconifyIcon('ri:dingding-fill');
diff --git a/packages/locales/src/langs/en-US/authentication.json b/packages/locales/src/langs/en-US/authentication.json
index f294cdd82..ec9b8ca7f 100644
--- a/packages/locales/src/langs/en-US/authentication.json
+++ b/packages/locales/src/langs/en-US/authentication.json
@@ -36,6 +36,11 @@
"qrcodeSubtitle": "Scan the QR code with your phone to login",
"qrcodePrompt": "Click 'Confirm' after scanning to complete login",
"qrcodeLogin": "QR Code Login",
+ "wechatLogin": "Wechat Login",
+ "qqLogin": "QQ Login",
+ "githubLogin": "Github Login",
+ "googleLogin": "Google Login",
+ "dingdingLogin": "Dingding Login",
"codeSubtitle": "Enter your phone number to start managing your project",
"code": "Security code",
"codeTip": "Security code required {0} characters",
diff --git a/packages/locales/src/langs/zh-CN/authentication.json b/packages/locales/src/langs/zh-CN/authentication.json
index 147da6322..ee4a2ec85 100644
--- a/packages/locales/src/langs/zh-CN/authentication.json
+++ b/packages/locales/src/langs/zh-CN/authentication.json
@@ -36,6 +36,11 @@
"qrcodeSubtitle": "请用手机扫描二维码登录",
"qrcodePrompt": "扫码后点击 '确认',即可完成登录",
"qrcodeLogin": "扫码登录",
+ "wechatLogin": "微信登录",
+ "qqLogin": "QQ登录",
+ "githubLogin": "Github登录",
+ "googleLogin": "Google登录",
+ "dingdingLogin": "钉钉登录",
"codeSubtitle": "请输入您的手机号码以开始管理您的项目",
"code": "验证码",
"codeTip": "请输入{0}位验证码",
diff --git a/packages/types/global.d.ts b/packages/types/global.d.ts
index 0c8f01983..5b3b3e91a 100644
--- a/packages/types/global.d.ts
+++ b/packages/types/global.d.ts
@@ -9,10 +9,20 @@ declare module 'vue-router' {
export interface VbenAdminProAppConfigRaw {
VITE_GLOB_API_URL: string;
+ VITE_GLOB_AUTH_DINGDING_CLIENT_ID: string;
+ VITE_GLOB_AUTH_DINGDING_CORP_ID: string;
+}
+
+interface AuthConfig {
+ dingding?: {
+ clientId: string;
+ corpId: string;
+ };
}
export interface ApplicationConfig {
apiURL: string;
+ auth: AuthConfig;
}
declare global {
diff --git a/playground/.env.development b/playground/.env.development
index dcf361e73..0b1dc0571 100644
--- a/playground/.env.development
+++ b/playground/.env.development
@@ -14,3 +14,7 @@ VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
+
+# 钉钉登录配置
+VITE_GLOB_AUTH_DINGDING_CLIENT_ID=应用的clientId
+VITE_GLOB_AUTH_DINGDING_CORP_ID=应用的corpId
--
Gitee
From f242f1c37db3cc2108d6b793ded75b0310cfc707 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Sat, 26 Jul 2025 17:36:59 +0800
Subject: [PATCH 22/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E4=B8=8A=E4=BC=A0=E9=99=84=E4=BB=B6=E5=8F=8A=E9=AA=8C?=
=?UTF-8?q?=E8=AF=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修改订单时间格式为 timestamp
- 限制文件上传数量为 1
- 调整表格列宽和显示逻辑
- 优化子表单验证和提交逻辑
- 修复文件上传组件的兼容性问题
- 优化产品清单的初始化和验证
---
.../src/views/erp/purchase/order/data.ts | 19 +++--
.../order/modules/PurchaseOrderItemForm.vue | 66 +++++++++++----
.../views/erp/purchase/order/modules/form.vue | 84 ++++++++++++++++---
3 files changed, 138 insertions(+), 31 deletions(-)
diff --git a/apps/web-antd/src/views/erp/purchase/order/data.ts b/apps/web-antd/src/views/erp/purchase/order/data.ts
index 9a037f94f..a623680cf 100644
--- a/apps/web-antd/src/views/erp/purchase/order/data.ts
+++ b/apps/web-antd/src/views/erp/purchase/order/data.ts
@@ -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 },
diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue b/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
index 7bcede093..6ecde04c2 100644
--- a/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/modules/PurchaseOrderItemForm.vue
@@ -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 => {
- 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 => {
+ 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,
+});
diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
index 876115215..9b605f246 100644
--- a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue
@@ -1,10 +1,9 @@
@@ -12,23 +145,76 @@ import { Button } from 'ant-design-vue';
url="https://doc.iocoder.cn/erp/purchase/"
/>
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue b/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue
new file mode 100644
index 000000000..d99884912
--- /dev/null
+++ b/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
--
Gitee
From 33cec7caee71601e97ca511cbb8126e75f49d570 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Wed, 30 Jul 2025 14:32:32 +0800
Subject: [PATCH 28/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-purchase-supp?=
=?UTF-8?q?lier-=E4=BE=9B=E5=BA=94=E5=95=86=E7=AE=A1=E7=90=86=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除状态字段,增加联系电话字段
- 调整供应商列表的展示逻辑
- 优化搜索和导出功能
- 使用 useVbenVxeGrid 替代原有的表格实现
- 用 downloadFileFromBlobPart 处理文件下载
---
.../src/views/erp/purchase/supplier/data.ts | 9 +-
.../src/views/erp/purchase/supplier/index.vue | 110 ++++--------------
.../erp/purchase/supplier/modules/form.vue | 2 +-
3 files changed, 26 insertions(+), 95 deletions(-)
diff --git a/apps/web-antd/src/views/erp/purchase/supplier/data.ts b/apps/web-antd/src/views/erp/purchase/supplier/data.ts
index 846cebccc..eed9d72db 100644
--- a/apps/web-antd/src/views/erp/purchase/supplier/data.ts
+++ b/apps/web-antd/src/views/erp/purchase/supplier/data.ts
@@ -163,13 +163,12 @@ export function useGridFormSchema(): VbenFormSchema[] {
},
},
{
- fieldName: 'status',
- label: '状态',
- component: 'Select',
+ fieldName: 'telephone',
+ label: '联系电话',
+ component: 'Input',
componentProps: {
- placeholder: '请选择状态',
+ placeholder: '请输入联系电话',
allowClear: true,
- options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
},
},
];
diff --git a/apps/web-antd/src/views/erp/purchase/supplier/index.vue b/apps/web-antd/src/views/erp/purchase/supplier/index.vue
index 2ace8bbbd..b0d6d79ef 100644
--- a/apps/web-antd/src/views/erp/purchase/supplier/index.vue
+++ b/apps/web-antd/src/views/erp/purchase/supplier/index.vue
@@ -2,15 +2,17 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ErpSupplierApi } from '#/api/erp/purchase/supplier';
-import { ref } from 'vue';
-
import { DocAlert, Page, useVbenModal } from '@vben/common-ui';
+import { downloadFileFromBlobPart } from '@vben/utils';
import { message } from 'ant-design-vue';
-import { useVbenForm } from '#/adapter/form';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
-import { deleteSupplier, getSupplierPage } from '#/api/erp/purchase/supplier';
+import {
+ deleteSupplier,
+ exportSupplier,
+ getSupplierPage,
+} from '#/api/erp/purchase/supplier';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';
@@ -19,53 +21,11 @@ import SupplierForm from './modules/form.vue';
/** 供应商管理 */
defineOptions({ name: 'ErpSupplier' });
-const searchParams = ref({
- pageNo: 1,
- pageSize: 10,
- name: '',
- mobile: '',
- status: undefined,
-});
-
-/** 搜索表单 */
-const [SearchForm, searchFormApi] = useVbenForm({
- commonConfig: {
- componentProps: {
- class: 'w-full',
- },
- formItemClass: 'col-span-1',
- labelWidth: 80,
- },
- layout: 'inline',
- schema: useGridFormSchema(),
- showDefaultActions: false,
-});
-
/** 刷新表格 */
function onRefresh() {
gridApi.query();
}
-/** 搜索 */
-async function handleSearch() {
- const values = await searchFormApi.getValues();
- Object.assign(searchParams.value, values, { pageNo: 1 });
- onRefresh();
-}
-
-/** 重置搜索 */
-async function handleReset() {
- await searchFormApi.resetFields();
- Object.assign(searchParams.value, {
- pageNo: 1,
- pageSize: 10,
- name: '',
- mobile: '',
- status: undefined,
- });
- onRefresh();
-}
-
/** 添加供应商 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
@@ -96,13 +56,8 @@ async function handleDelete(row: ErpSupplierApi.Supplier) {
/** 导出供应商 */
async function handleExport() {
- try {
- // const data = await exportSupplier(searchParams.value);
- // 这里需要处理文件下载逻辑
- message.success('导出成功');
- } catch {
- message.error('导出失败');
- }
+ const data = await exportSupplier(await gridApi.formApi.getValues());
+ downloadFileFromBlobPart({ fileName: '供应商.xls', source: data });
}
const [FormModal, formModalApi] = useVbenModal({
@@ -111,17 +66,20 @@ const [FormModal, formModalApi] = useVbenModal({
});
const [Grid, gridApi] = useVbenVxeGrid({
+ formOptions: {
+ schema: useGridFormSchema(),
+ },
gridOptions: {
columns: useGridColumns(),
- height: 600,
+ height: 'auto',
keepSource: true,
proxyConfig: {
ajax: {
- query: async ({ page }) => {
+ query: async ({ page }, formValues) => {
return await getSupplierPage({
- ...searchParams.value,
pageNo: page.currentPage,
pageSize: page.pageSize,
+ ...formValues,
});
},
},
@@ -131,14 +89,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
},
toolbarConfig: {
refresh: true,
- custom: true,
+ search: true,
},
} as VxeTableGridOptions,
});
-
+
-
-
-
-
-
+
--
Gitee
From 423bfffbea0ffc5749cb039230cc26623fcbb961 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Wed, 30 Jul 2025 15:24:05 +0800
Subject: [PATCH 29/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-purchase-supp?=
=?UTF-8?q?lier-=E4=BC=98=E5=8C=96=E9=87=87=E8=B4=AD=E8=AE=A2=E5=8D=95?=
=?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD=E5=B9=B6=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E4=BE=9B=E5=BA=94=E5=95=86=E7=AE=A1=E7=90=86=E6=9D=83=E9=99=90?=
=?UTF-8?q?=E6=8E=A7=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在供应商管理页面添加权限控制:
- 创建供应商
- 导出供应商信息
- 编辑供应商
- 删除供应商
---
apps/web-antd/src/views/erp/purchase/order/index.vue | 9 ++-------
apps/web-antd/src/views/erp/purchase/supplier/index.vue | 4 ++++
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/apps/web-antd/src/views/erp/purchase/order/index.vue b/apps/web-antd/src/views/erp/purchase/order/index.vue
index bc9552c80..3cb0130a6 100644
--- a/apps/web-antd/src/views/erp/purchase/order/index.vue
+++ b/apps/web-antd/src/views/erp/purchase/order/index.vue
@@ -129,13 +129,8 @@ function handleUpdateStatus(
/** 导出 */
async function handleExport() {
- try {
- const formValues = gridApi.getFormData();
- const data = await exportPurchaseOrder(formValues);
- downloadFileFromBlobPart({ fileName: '采购订单.xls', source: data });
- } catch {
- // 处理错误
- }
+ const data = await exportPurchaseOrder(await gridApi.formApi.getValues());
+ downloadFileFromBlobPart({ fileName: '采购订单.xls', source: data });
}
const [Grid, gridApi] = useVbenVxeGrid({
diff --git a/apps/web-antd/src/views/erp/purchase/supplier/index.vue b/apps/web-antd/src/views/erp/purchase/supplier/index.vue
index b0d6d79ef..98288f4ab 100644
--- a/apps/web-antd/src/views/erp/purchase/supplier/index.vue
+++ b/apps/web-antd/src/views/erp/purchase/supplier/index.vue
@@ -113,12 +113,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
label: $t('ui.actionTitle.create', ['供应商']),
type: 'primary',
icon: ACTION_ICON.ADD,
+ auth: ['erp:supplier:create'],
onClick: handleCreate,
},
{
label: $t('ui.actionTitle.export'),
type: 'primary',
icon: ACTION_ICON.DOWNLOAD,
+ auth: ['erp:supplier:export'],
onClick: handleExport,
},
]"
@@ -132,6 +134,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
label: '编辑',
type: 'link',
icon: ACTION_ICON.EDIT,
+ auth: ['erp:supplier:update'],
onClick: handleEdit.bind(null, row),
},
{
@@ -139,6 +142,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
type: 'link',
danger: true,
icon: ACTION_ICON.DELETE,
+ auth: ['erp:supplier:delete'],
popConfirm: {
title: $t('ui.actionMessage.deleteConfirm', [row.name]),
confirm: handleDelete.bind(null, row),
--
Gitee
From 787f5168ad7cd1052333b8574a526eb2b18863c8 Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Wed, 30 Jul 2025 16:48:08 +0800
Subject: [PATCH 30/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-warehou?=
=?UTF-8?q?se=20=E6=96=B0=E5=A2=9E=E4=BB=93=E5=BA=93=E7=AE=A1=E7=90=86?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加仓库管理相关的数据结构和 API 接口
- 实现仓库列表展示、搜索、添加、编辑和删除功能
- 添加仓库默认状态切换和导出功能
- 优化表格展示效果,固定操作列
- 移除不必要的按钮和链接
---
.../src/views/erp/purchase/supplier/data.ts | 1 +
.../erp/purchase/supplier/modules/form.vue | 3 -
.../src/views/erp/stock/warehouse/data.ts | 201 ++++++++++++++++++
.../src/views/erp/stock/warehouse/index.vue | 199 ++++++++++++++---
.../erp/stock/warehouse/modules/form.vue | 95 +++++++++
5 files changed, 471 insertions(+), 28 deletions(-)
create mode 100644 apps/web-antd/src/views/erp/stock/warehouse/data.ts
create mode 100644 apps/web-antd/src/views/erp/stock/warehouse/modules/form.vue
diff --git a/apps/web-antd/src/views/erp/purchase/supplier/data.ts b/apps/web-antd/src/views/erp/purchase/supplier/data.ts
index eed9d72db..daa268c24 100644
--- a/apps/web-antd/src/views/erp/purchase/supplier/data.ts
+++ b/apps/web-antd/src/views/erp/purchase/supplier/data.ts
@@ -225,6 +225,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
{
field: 'actions',
title: '操作',
+ fixed: 'right',
width: 160,
slots: { default: 'actions' },
},
diff --git a/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue b/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue
index 38cc3ad31..91775665f 100644
--- a/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue
+++ b/apps/web-antd/src/views/erp/purchase/supplier/modules/form.vue
@@ -77,9 +77,6 @@ const [Modal, modalApi] = useVbenModal({
// 编辑模式,加载数据
const supplierData = await getSupplier(data.id);
await formApi.setValues(supplierData);
- } else {
- // 新增模式,重置表单
- await formApi.resetFields();
}
} finally {
modalApi.unlock();
diff --git a/apps/web-antd/src/views/erp/stock/warehouse/data.ts b/apps/web-antd/src/views/erp/stock/warehouse/data.ts
new file mode 100644
index 000000000..fbf01ddeb
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/warehouse/data.ts
@@ -0,0 +1,201 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { DICT_TYPE, getDictOptions } from '#/utils';
+
+/** 新增/修改的表单 */
+export function useFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ component: 'Input',
+ fieldName: 'id',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+ {
+ fieldName: 'name',
+ label: '仓库名称',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入仓库名称',
+ },
+ rules: 'required',
+ },
+ {
+ fieldName: 'address',
+ label: '仓库地址',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入仓库地址',
+ },
+ },
+ {
+ fieldName: 'status',
+ label: '开启状态',
+ component: 'RadioGroup',
+ componentProps: {
+ options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
+ },
+ rules: 'required',
+ defaultValue: 0,
+ },
+ {
+ fieldName: 'warehousePrice',
+ label: '仓储费(元)',
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '请输入仓储费,单位:元/天/KG',
+ min: 0,
+ precision: 2,
+ class: 'w-full',
+ },
+ },
+ {
+ fieldName: 'truckagePrice',
+ label: '搬运费(元)',
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '请输入搬运费,单位:元',
+ min: 0,
+ precision: 2,
+ class: 'w-full',
+ },
+ },
+ {
+ fieldName: 'principal',
+ label: '负责人',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入负责人',
+ },
+ },
+ {
+ fieldName: 'sort',
+ label: '排序',
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '请输入排序',
+ precision: 0,
+ class: 'w-full',
+ },
+ rules: 'required',
+ defaultValue: 0,
+ },
+ {
+ fieldName: 'remark',
+ label: '备注',
+ component: 'Textarea',
+ componentProps: {
+ placeholder: '请输入备注',
+ rows: 3,
+ },
+ formItemClass: 'col-span-2',
+ },
+ ];
+}
+
+/** 搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'name',
+ label: '仓库名称',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入仓库名称',
+ allowClear: true,
+ },
+ },
+ {
+ fieldName: 'status',
+ label: '仓库状态',
+ component: 'Select',
+ componentProps: {
+ placeholder: '请选择仓库状态',
+ allowClear: true,
+ options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
+ },
+ },
+ ];
+}
+
+/** 列表的字段 */
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ field: 'name',
+ title: '仓库名称',
+ minWidth: 150,
+ },
+ {
+ field: 'address',
+ title: '仓库地址',
+ minWidth: 200,
+ showOverflow: 'tooltip',
+ },
+ {
+ field: 'warehousePrice',
+ title: '仓储费(元)',
+ width: 120,
+ cellRender: {
+ name: 'CellMoney',
+ },
+ },
+ {
+ field: 'truckagePrice',
+ title: '搬运费(元)',
+ width: 120,
+ cellRender: {
+ name: 'CellMoney',
+ },
+ },
+ {
+ field: 'principal',
+ title: '负责人',
+ width: 100,
+ },
+ {
+ field: 'sort',
+ title: '排序',
+ width: 80,
+ },
+ {
+ field: 'status',
+ title: '状态',
+ width: 100,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.COMMON_STATUS },
+ },
+ },
+ {
+ field: 'defaultStatus',
+ title: '是否默认',
+ width: 100,
+ slots: { default: 'defaultStatus' },
+ },
+ {
+ field: 'remark',
+ title: '备注',
+ minWidth: 150,
+ showOverflow: 'tooltip',
+ },
+ {
+ field: 'createTime',
+ title: '创建时间',
+ width: 180,
+ cellRender: {
+ name: 'CellDateTime',
+ },
+ },
+ {
+ field: 'actions',
+ title: '操作',
+ width: 160,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/erp/stock/warehouse/index.vue b/apps/web-antd/src/views/erp/stock/warehouse/index.vue
index ec0151274..879a26597 100644
--- a/apps/web-antd/src/views/erp/stock/warehouse/index.vue
+++ b/apps/web-antd/src/views/erp/stock/warehouse/index.vue
@@ -1,32 +1,181 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/erp/stock/warehouse/modules/form.vue b/apps/web-antd/src/views/erp/stock/warehouse/modules/form.vue
new file mode 100644
index 000000000..cbcda5d62
--- /dev/null
+++ b/apps/web-antd/src/views/erp/stock/warehouse/modules/form.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
--
Gitee
From 8d17d8d915a36cc0903420efa75072f2572b2ffa Mon Sep 17 00:00:00 2001
From: nehc <934298133@qq.com>
Date: Wed, 30 Jul 2025 17:42:50 +0800
Subject: [PATCH 31/41] =?UTF-8?q?feat(@vben/web-antd):=20erp-stock-warehou?=
=?UTF-8?q?se=20=E4=BF=AE=E5=A4=8D=E4=BB=93=E5=BA=93=E5=88=97=E8=A1=A8?=
=?UTF-8?q?=E7=9A=84=E7=8A=B6=E6=80=81=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将默认状态切换逻辑从组件模板移到单独的函数中
- 使用 confirm 对话框替代 message.confirm
- 优化了默认状态切换的用户体验和错误处理
- 引入了 Promise 机制,允许异步操作
---
.../src/views/erp/stock/warehouse/data.ts | 17 ++++++-
.../src/views/erp/stock/warehouse/index.vue | 45 +++++++++----------
2 files changed, 37 insertions(+), 25 deletions(-)
diff --git a/apps/web-antd/src/views/erp/stock/warehouse/data.ts b/apps/web-antd/src/views/erp/stock/warehouse/data.ts
index fbf01ddeb..8adfd1daa 100644
--- a/apps/web-antd/src/views/erp/stock/warehouse/data.ts
+++ b/apps/web-antd/src/views/erp/stock/warehouse/data.ts
@@ -1,5 +1,6 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { ErpWarehouseApi } from '#/api/erp/stock/warehouse';
import { DICT_TYPE, getDictOptions } from '#/utils';
@@ -122,7 +123,12 @@ export function useGridFormSchema(): VbenFormSchema[] {
}
/** 列表的字段 */
-export function useGridColumns(): VxeTableGridOptions['columns'] {
+export function useGridColumns(
+ onDefaultStatusChange?: (
+ newStatus: boolean,
+ row: T,
+ ) => PromiseLike,
+): VxeTableGridOptions['columns'] {
return [
{
field: 'name',
@@ -174,7 +180,14 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
field: 'defaultStatus',
title: '是否默认',
width: 100,
- slots: { default: 'defaultStatus' },
+ cellRender: {
+ attrs: { beforeChange: onDefaultStatusChange },
+ name: 'CellSwitch',
+ props: {
+ checkedValue: true,
+ unCheckedValue: false,
+ },
+ },
},
{
field: 'remark',
diff --git a/apps/web-antd/src/views/erp/stock/warehouse/index.vue b/apps/web-antd/src/views/erp/stock/warehouse/index.vue
index 879a26597..57c51d07a 100644
--- a/apps/web-antd/src/views/erp/stock/warehouse/index.vue
+++ b/apps/web-antd/src/views/erp/stock/warehouse/index.vue
@@ -2,10 +2,10 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ErpWarehouseApi } from '#/api/erp/stock/warehouse';
-import { DocAlert, Page, useVbenModal } from '@vben/common-ui';
+import { confirm, DocAlert, Page, useVbenModal } from '@vben/common-ui';
import { downloadFileFromBlobPart } from '@vben/utils';
-import { message, Switch } from 'ant-design-vue';
+import { message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
@@ -56,20 +56,26 @@ async function handleDelete(row: ErpWarehouseApi.Warehouse) {
}
/** 修改默认状态 */
-async function handleDefaultStatusChange(row: ErpWarehouseApi.Warehouse) {
- try {
- const text = row.defaultStatus ? '设置' : '取消';
- await message.confirm({
- title: '确认',
+async function handleDefaultStatusChange(
+ newStatus: boolean,
+ row: ErpWarehouseApi.Warehouse,
+): Promise {
+ return new Promise((resolve, reject) => {
+ const text = newStatus ? '开启' : '取消';
+
+ confirm({
content: `确认要${text}"${row.name}"默认吗?`,
- });
- await updateWarehouseDefaultStatus(row.id!, row.defaultStatus);
- message.success(`${text}默认状态成功`);
- onRefresh();
- } catch {
- // 取消后,进行恢复按钮
- row.defaultStatus = !row.defaultStatus;
- }
+ })
+ .then(async () => {
+ // 更新默认状态
+ await updateWarehouseDefaultStatus(row.id!, newStatus);
+ message.success(`${text}默认状态成功`);
+ resolve(true);
+ })
+ .catch(() => {
+ reject(new Error('取消操作'));
+ });
+ });
}
/** 导出仓库 */
@@ -88,7 +94,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
schema: useGridFormSchema(),
},
gridOptions: {
- columns: useGridColumns(),
+ columns: useGridColumns(handleDefaultStatusChange),
height: 'auto',
keepSource: true,
proxyConfig: {
@@ -145,13 +151,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
/>
-
-
-
-
+
+
+ 允许审批人撤回任务
+
+
+
+ 审批人可撤回正在审批节点的前一节点
+
+
+
+
diff --git a/apps/web-antd/src/views/bpm/task/done/index.vue b/apps/web-antd/src/views/bpm/task/done/index.vue
index 2c568a43a..abd6fcbf6 100644
--- a/apps/web-antd/src/views/bpm/task/done/index.vue
+++ b/apps/web-antd/src/views/bpm/task/done/index.vue
@@ -4,8 +4,10 @@ import type { BpmTaskApi } from '#/api/bpm/task';
import { DocAlert, Page } from '@vben/common-ui';
+import { message } from 'ant-design-vue';
+
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
-import { getTaskDonePage } from '#/api/bpm/task';
+import { getTaskDonePage, withdrawTask } from '#/api/bpm/task';
import { router } from '#/router';
import { useGridColumns, useGridFormSchema } from './data';
@@ -23,7 +25,15 @@ function handleHistory(row: BpmTaskApi.TaskManager) {
});
}
-const [Grid] = useVbenVxeGrid({
+/** 撤回任务 */
+async function handleWithdraw(row: BpmTaskApi.TaskManager) {
+ await withdrawTask(row.id);
+ message.success('撤回成功');
+ // 刷新表格数据
+ await gridApi.query();
+}
+
+const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
},
@@ -52,7 +62,7 @@ const [Grid] = useVbenVxeGrid({
cellConfig: {
height: 64,
},
- } as VxeTableGridOptions,
+ } as VxeTableGridOptions,
});
@@ -75,6 +85,13 @@ const [Grid] = useVbenVxeGrid({
diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/modules/time-line.vue b/apps/web-antd/src/views/bpm/processInstance/detail/modules/time-line.vue
index faea73383..59feeaeb5 100644
--- a/apps/web-antd/src/views/bpm/processInstance/detail/modules/time-line.vue
+++ b/apps/web-antd/src/views/bpm/processInstance/detail/modules/time-line.vue
@@ -23,12 +23,12 @@ defineOptions({ name: 'BpmProcessInstanceTimeline' });
const props = withDefaults(
defineProps<{
activityNodes: BpmProcessInstanceApi.ApprovalNodeInfo[]; // 审批节点信息
+ enableApproveUserSelect?: boolean; // 是否开启审批人自选功能
showStatusIcon?: boolean; // 是否显示头像右下角状态图标
- useNextAssignees?: boolean; // 是否用于下一个节点审批人选择
}>(),
{
showStatusIcon: true, // 默认值为 true
- useNextAssignees: false, // 默认值为 false
+ enableApproveUserSelect: false, // 默认值为 false
},
);
@@ -198,12 +198,12 @@ function shouldShowCustomUserSelect(
) {
return (
isEmpty(activity.tasks) &&
- isEmpty(activity.candidateUsers) &&
- (BpmCandidateStrategyEnum.START_USER_SELECT ===
- activity.candidateStrategy ||
- (BpmCandidateStrategyEnum.APPROVE_USER_SELECT ===
- activity.candidateStrategy &&
- props.useNextAssignees))
+ ((BpmCandidateStrategyEnum.START_USER_SELECT ===
+ activity.candidateStrategy &&
+ isEmpty(activity.candidateUsers)) ||
+ (props.enableApproveUserSelect &&
+ BpmCandidateStrategyEnum.APPROVE_USER_SELECT ===
+ activity.candidateStrategy))
);
}
@@ -226,6 +226,21 @@ function handleUserSelectClosed() {
function handleUserSelectCancel() {
selectedUsers.value = [];
}
+
+/** 设置自定义审批人 */
+const setCustomApproveUsers = (activityId: string, users: any[]) => {
+ customApproveUsers.value[activityId] = users || [];
+};
+
+/** 批量设置多个节点的自定义审批人 */
+const batchSetCustomApproveUsers = (data: Record