feat:【antd】【erp 系统】sale/order 部分代码优化(form 中量)
This commit is contained in:
@@ -24,6 +24,7 @@ export namespace ErpSaleOrderApi {
|
|||||||
depositPrice?: number; // 定金金额,单位:元
|
depositPrice?: number; // 定金金额,单位:元
|
||||||
items?: SaleOrderItem[]; // 销售订单产品明细列表
|
items?: SaleOrderItem[]; // 销售订单产品明细列表
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SaleOrderItem {
|
export interface SaleOrderItem {
|
||||||
id?: number; // 订单项编号
|
id?: number; // 订单项编号
|
||||||
orderId?: number; // 采购订单编号
|
orderId?: number; // 采购订单编号
|
||||||
@@ -66,6 +67,13 @@ export function getSaleOrder(id: number) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 查询销售订单项列表 */
|
||||||
|
export function getSaleOrderItemListByOrderId(orderId: number) {
|
||||||
|
return requestClient.get<ErpSaleOrderApi.SaleOrderItem[]>(
|
||||||
|
`/erp/sale-order/item/list-by-order-id?orderId=${orderId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** 新增销售订单 */
|
/** 新增销售订单 */
|
||||||
export function createSaleOrder(data: ErpSaleOrderApi.SaleOrder) {
|
export function createSaleOrder(data: ErpSaleOrderApi.SaleOrder) {
|
||||||
return requestClient.post('/erp/sale-order/create', data);
|
return requestClient.post('/erp/sale-order/create', data);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
|
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
|
||||||
|
|
||||||
import { computed, nextTick, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
@@ -16,18 +16,18 @@ import {
|
|||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { useFormSchema } from '../data';
|
||||||
import SaleOrderItemForm from './sale-order-item-form.vue';
|
import ItemForm from './item-form.vue';
|
||||||
|
|
||||||
const emit = defineEmits(['success']);
|
const emit = defineEmits(['success']);
|
||||||
const formData = ref<ErpSaleOrderApi.SaleOrder>();
|
const formData = ref<ErpSaleOrderApi.SaleOrder>();
|
||||||
const formType = ref(''); // 表单类型:'create' | 'update' | 'detail'
|
const formType = ref(''); // 表单类型:'create' | 'edit' | 'detail'
|
||||||
const itemFormRef = ref<InstanceType<typeof SaleOrderItemForm>>();
|
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
|
||||||
|
|
||||||
/* eslint-disable unicorn/no-nested-ternary */
|
/* eslint-disable unicorn/no-nested-ternary */
|
||||||
const getTitle = computed(() =>
|
const getTitle = computed(() =>
|
||||||
formType.value === 'create'
|
formType.value === 'create'
|
||||||
? $t('ui.actionTitle.create', ['销售订单'])
|
? $t('ui.actionTitle.create', ['销售订单'])
|
||||||
: formType.value === 'update'
|
: formType.value === 'edit'
|
||||||
? $t('ui.actionTitle.edit', ['销售订单'])
|
? $t('ui.actionTitle.edit', ['销售订单'])
|
||||||
: '销售订单详情',
|
: '销售订单详情',
|
||||||
);
|
);
|
||||||
@@ -38,7 +38,7 @@ const [Form, formApi] = useVbenForm({
|
|||||||
class: 'w-full',
|
class: 'w-full',
|
||||||
},
|
},
|
||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
// disabled: !['create', 'update'].includes(formType.value), // TODO @芋艿:这里晚点处理下;
|
// disabled: !['create', 'edit'].includes(formType.value), // TODO @芋艿:这里晚点处理下;
|
||||||
},
|
},
|
||||||
wrapperClass: 'grid-cols-3',
|
wrapperClass: 'grid-cols-3',
|
||||||
layout: 'vertical',
|
layout: 'vertical',
|
||||||
@@ -51,6 +51,7 @@ const [Form, formApi] = useVbenForm({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 更新商品项 */
|
||||||
const handleUpdateItems = (items: ErpSaleOrderApi.SaleOrderItem[]) => {
|
const handleUpdateItems = (items: ErpSaleOrderApi.SaleOrderItem[]) => {
|
||||||
formData.value = modalApi.getData<ErpSaleOrderApi.SaleOrder>();
|
formData.value = modalApi.getData<ErpSaleOrderApi.SaleOrder>();
|
||||||
if (formData.value) {
|
if (formData.value) {
|
||||||
@@ -58,6 +59,7 @@ const handleUpdateItems = (items: ErpSaleOrderApi.SaleOrderItem[]) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 更新优惠金额 */
|
||||||
const handleUpdateDiscountPrice = (discountPrice: number) => {
|
const handleUpdateDiscountPrice = (discountPrice: number) => {
|
||||||
if (formData.value) {
|
if (formData.value) {
|
||||||
formData.value.discountPrice = discountPrice;
|
formData.value.discountPrice = discountPrice;
|
||||||
@@ -67,6 +69,7 @@ const handleUpdateDiscountPrice = (discountPrice: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 更新总金额 */
|
||||||
const handleUpdateTotalPrice = (totalPrice: number) => {
|
const handleUpdateTotalPrice = (totalPrice: number) => {
|
||||||
if (formData.value) {
|
if (formData.value) {
|
||||||
formData.value.totalPrice = totalPrice;
|
formData.value.totalPrice = totalPrice;
|
||||||
@@ -87,10 +90,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
? itemFormRef.value[0]
|
? itemFormRef.value[0]
|
||||||
: itemFormRef.value;
|
: itemFormRef.value;
|
||||||
try {
|
try {
|
||||||
const isValid = await itemFormInstance.validate();
|
itemFormInstance.validate();
|
||||||
if (!isValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.message || '子表单验证失败');
|
message.error(error.message || '子表单验证失败');
|
||||||
return;
|
return;
|
||||||
@@ -140,14 +140,14 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
<Modal
|
<Modal
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:title="getTitle"
|
:title="getTitle"
|
||||||
class="w-1/2"
|
class="w-3/4"
|
||||||
:closable="true"
|
:closable="true"
|
||||||
:mask-closable="true"
|
:mask-closable="true"
|
||||||
:show-confirm-button="formType !== 'detail'"
|
:show-confirm-button="formType !== 'detail'"
|
||||||
>
|
>
|
||||||
<Form class="mx-3">
|
<Form class="mx-3">
|
||||||
<template #product="slotProps">
|
<template #product="slotProps">
|
||||||
<SaleOrderItemForm
|
<ItemForm
|
||||||
v-bind="slotProps"
|
v-bind="slotProps"
|
||||||
ref="itemFormRef"
|
ref="itemFormRef"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { ErpProductApi } from '#/api/erp/product/product';
|
||||||
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
|
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
|
||||||
|
|
||||||
import { nextTick, onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { erpPriceMultiply } from '@vben/utils';
|
import { erpPriceMultiply } from '@vben/utils';
|
||||||
|
|
||||||
@@ -13,6 +14,12 @@ import { getStockCount } from '#/api/erp/stock/stock';
|
|||||||
|
|
||||||
import { useSaleOrderItemTableColumns } from '../data';
|
import { useSaleOrderItemTableColumns } from '../data';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
items?: ErpSaleOrderApi.SaleOrderItem[];
|
||||||
|
disabled?: boolean;
|
||||||
|
discountPercent?: number;
|
||||||
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
items: () => [],
|
items: () => [],
|
||||||
disabled: false,
|
disabled: false,
|
||||||
@@ -25,14 +32,8 @@ const emit = defineEmits([
|
|||||||
'update:total-price',
|
'update:total-price',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
interface Props {
|
const tableData = ref<ErpSaleOrderApi.SaleOrderItem[]>([]); // 表格数据
|
||||||
items?: ErpSaleOrderApi.SaleOrderItem[];
|
const productOptions = ref<ErpProductApi.Product[]>([]); // 产品下拉选项
|
||||||
disabled?: boolean;
|
|
||||||
discountPercent?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableData = ref<ErpSaleOrderApi.SaleOrderItem[]>([]);
|
|
||||||
const productOptions = ref<any[]>([]);
|
|
||||||
|
|
||||||
/** 表格配置 */
|
/** 表格配置 */
|
||||||
const [Grid, gridApi] = useVbenVxeGrid({
|
const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
@@ -50,6 +51,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
keepSource: true,
|
keepSource: true,
|
||||||
rowConfig: {
|
rowConfig: {
|
||||||
keyField: 'row_id',
|
keyField: 'row_id',
|
||||||
|
isHover: true,
|
||||||
},
|
},
|
||||||
pagerConfig: {
|
pagerConfig: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@@ -67,9 +69,7 @@ watch(
|
|||||||
if (!items) {
|
if (!items) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await nextTick();
|
|
||||||
tableData.value = [...items];
|
tableData.value = [...items];
|
||||||
await nextTick();
|
|
||||||
await gridApi.grid.reloadData(tableData.value);
|
await gridApi.grid.reloadData(tableData.value);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,8 +93,7 @@ watch(
|
|||||||
? 0
|
? 0
|
||||||
: erpPriceMultiply(totalPrice, props.discountPercent / 100);
|
: erpPriceMultiply(totalPrice, props.discountPercent / 100);
|
||||||
const finalTotalPrice = totalPrice - discountPrice!;
|
const finalTotalPrice = totalPrice - discountPrice!;
|
||||||
|
// 通知父组件更新
|
||||||
// 发送计算结果给父组件
|
|
||||||
emit('update:discount-price', discountPrice);
|
emit('update:discount-price', discountPrice);
|
||||||
emit('update:total-price', finalTotalPrice);
|
emit('update:total-price', finalTotalPrice);
|
||||||
},
|
},
|
||||||
@@ -106,6 +105,7 @@ onMounted(async () => {
|
|||||||
productOptions.value = await getProductSimpleList();
|
productOptions.value = await getProductSimpleList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 处理新增 */
|
||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
const newRow = {
|
const newRow = {
|
||||||
productId: undefined,
|
productId: undefined,
|
||||||
@@ -124,38 +124,39 @@ function handleAdd() {
|
|||||||
};
|
};
|
||||||
tableData.value.push(newRow);
|
tableData.value.push(newRow);
|
||||||
gridApi.grid.insertAt(newRow, -1);
|
gridApi.grid.insertAt(newRow, -1);
|
||||||
|
// 通知父组件更新
|
||||||
emit('update:items', [...tableData.value]);
|
emit('update:items', [...tableData.value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleOrderApi.SaleOrderItem) {
|
function handleDelete(row: ErpSaleOrderApi.SaleOrderItem) {
|
||||||
gridApi.grid.remove(row);
|
gridApi.grid.remove(row);
|
||||||
const index = tableData.value.findIndex((item) => item.id === row.id);
|
const index = tableData.value.findIndex((item) => item.id === row.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
// 通知父组件更新
|
||||||
emit('update:items', [...tableData.value]);
|
emit('update:items', [...tableData.value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 处理产品变更 */
|
||||||
async function handleProductChange(productId: any, row: any) {
|
async function handleProductChange(productId: any, row: any) {
|
||||||
const product = productOptions.value.find((p) => p.id === productId);
|
const product = productOptions.value.find((p) => p.id === productId);
|
||||||
if (!product) {
|
if (!product) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stockCount = await getStockCount(productId);
|
|
||||||
|
|
||||||
row.productId = productId;
|
row.productId = productId;
|
||||||
row.productUnitId = product.unitId;
|
row.productUnitId = product.unitId;
|
||||||
row.productBarCode = product.barCode;
|
row.productBarCode = product.barCode;
|
||||||
row.productUnitName = product.unitName;
|
row.productUnitName = product.unitName;
|
||||||
row.productName = product.name;
|
row.productName = product.name;
|
||||||
row.stockCount = stockCount || 0;
|
row.stockCount = (await getStockCount(productId)) || 0;
|
||||||
row.productPrice = product.salePrice || 0;
|
row.productPrice = product.salePrice || 0;
|
||||||
row.count = row.count || 1;
|
row.count = row.count || 1;
|
||||||
|
|
||||||
handlePriceChange(row);
|
handlePriceChange(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 处理价格变更 */
|
||||||
function handlePriceChange(row: any) {
|
function handlePriceChange(row: any) {
|
||||||
if (row.productPrice && row.count) {
|
if (row.productPrice && row.count) {
|
||||||
row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
|
row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
|
||||||
@@ -166,6 +167,7 @@ function handlePriceChange(row: any) {
|
|||||||
handleUpdateValue(row);
|
handleUpdateValue(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 更新行数据 */
|
||||||
function handleUpdateValue(row: any) {
|
function handleUpdateValue(row: any) {
|
||||||
const index = tableData.value.findIndex((item) => item.id === row.id);
|
const index = tableData.value.findIndex((item) => item.id === row.id);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
@@ -176,13 +178,14 @@ function handleUpdateValue(row: any) {
|
|||||||
emit('update:items', [...tableData.value]);
|
emit('update:items', [...tableData.value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSummaries = (): {
|
/** 获取表格合计数据 */
|
||||||
|
function getSummaries(): {
|
||||||
count: number;
|
count: number;
|
||||||
productName: string;
|
productName: string;
|
||||||
taxPrice: number;
|
taxPrice: number;
|
||||||
totalPrice: number;
|
totalPrice: number;
|
||||||
totalProductPrice: number;
|
totalProductPrice: number;
|
||||||
} => {
|
} {
|
||||||
return {
|
return {
|
||||||
productName: '合计',
|
productName: '合计',
|
||||||
count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0),
|
count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0),
|
||||||
@@ -199,30 +202,25 @@ const getSummaries = (): {
|
|||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
const validate = async (): Promise<boolean> => {
|
/** 表单校验 */
|
||||||
try {
|
function validate() {
|
||||||
for (let i = 0; i < tableData.value.length; i++) {
|
for (let i = 0; i < tableData.value.length; i++) {
|
||||||
const item = tableData.value[i];
|
const item = tableData.value[i];
|
||||||
if (item) {
|
if (item) {
|
||||||
if (!item.productId) {
|
if (!item.productId) {
|
||||||
throw new Error(`第 ${i + 1} 行:产品不能为空`);
|
throw new Error(`第 ${i + 1} 行:产品不能为空`);
|
||||||
}
|
}
|
||||||
if (!item.count || item.count <= 0) {
|
if (!item.count || item.count <= 0) {
|
||||||
throw new Error(`第 ${i + 1} 行:产品数量不能为空`);
|
throw new Error(`第 ${i + 1} 行:产品数量不能为空`);
|
||||||
}
|
}
|
||||||
if (!item.productPrice || item.productPrice <= 0) {
|
if (!item.productPrice || item.productPrice <= 0) {
|
||||||
throw new Error(`第 ${i + 1} 行:产品单价不能为空`);
|
throw new Error(`第 ${i + 1} 行:产品单价不能为空`);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('验证失败:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
validate,
|
validate,
|
||||||
@@ -244,7 +242,6 @@ defineExpose({
|
|||||||
/>
|
/>
|
||||||
<span v-else>{{ row.productName || '-' }}</span>
|
<span v-else>{{ row.productName || '-' }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #count="{ row }">
|
<template #count="{ row }">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-if="!disabled"
|
v-if="!disabled"
|
||||||
Reference in New Issue
Block a user