feat(@vben/web-antd): erp-stock-in 添加其它入库单功能

- 新增其它入库单列表页面
- 实现其它入库单的创建、编辑和删除功能
- 添加产品清单管理功能
- 集成供应商、产品和仓库的选择接口
- 优化表格展示和搜索功能
pull/188/head
nehc 2025-07-31 17:20:09 +08:00
parent 2e6575f368
commit 510ec12582
6 changed files with 1168 additions and 24 deletions

View File

@ -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; // 备注
}
/** 其它入库单分页查询参数 */

View File

@ -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<number>('/erp/stock/get-count', {
params: { productId },
params,
});
}

View File

@ -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' },
},
];
}

View File

@ -1,34 +1,195 @@
<script lang="ts" setup>
import { DocAlert, Page } from '@vben/common-ui';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ErpStockInApi } from '#/api/erp/stock/in';
import { Button } from 'ant-design-vue';
import { ref } from 'vue';
import { DocAlert, Page } from '@vben/common-ui';
import { downloadFileFromBlobPart } from '@vben/utils';
import { message, Modal } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
deleteStockIn,
exportStockIn,
getStockInPage,
updateStockInStatus,
} from '#/api/erp/stock/in';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';
import StockInForm from './modules/form.vue';
/** 其它入库单管理 */
defineOptions({ name: 'ErpStockIn' });
const formRef = ref();
/** 刷新表格 */
function onRefresh() {
gridApi.query();
}
/** 导出入库单 */
async function handleExport() {
const data = await exportStockIn(await gridApi.formApi.getValues());
downloadFileFromBlobPart({ fileName: '其它入库单.xls', source: data });
}
/** 新增/编辑/详情 */
function openForm(type: string, id?: number) {
formRef.value?.modalApi.open({ type, id });
}
/** 删除 */
function handleDelete(ids: any[]) {
Modal.confirm({
title: '系统提示',
content: `是否确认删除编号为 ${ids.join(',')} 的其它入库单?`,
onOk: async () => {
await deleteStockIn(ids);
message.success('删除成功');
onRefresh();
},
});
}
/** 审核/反审核 */
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 [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
},
gridOptions: {
columns: useGridColumns(),
height: 'auto',
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getStockInPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
},
toolbarConfig: {
refresh: true,
search: true,
},
checkboxConfig: {
reserve: true,
},
} as VxeTableGridOptions<ErpStockInApi.StockIn>,
});
</script>
<template>
<Page>
<Page auto-content-height>
<template #doc>
<DocAlert
title="【库存】其它入库、其它出库"
url="https://doc.iocoder.cn/erp/stock-in-out/"
/>
</template>
<Button
danger
type="link"
target="_blank"
href="https://github.com/yudaocode/yudao-ui-admin-vue3"
>
该功能支持 Vue3 + element-plus 版本
</Button>
<br />
<Button
type="link"
target="_blank"
href="https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/erp/stock/in/index"
>
可参考
https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/erp/stock/in/index
代码pull request 贡献给我们
</Button>
<Grid table-title="">
<template #toolbar-tools>
<TableAction
:actions="[
{
label: $t('ui.actionTitle.create', ['其它入库']),
type: 'primary',
icon: ACTION_ICON.ADD,
auth: ['erp:stock-in:create'],
onClick: () => openForm('create'),
},
{
label: $t('ui.actionTitle.export'),
type: 'default',
icon: ACTION_ICON.DOWNLOAD,
auth: ['erp:stock-in:export'],
onClick: handleExport,
},
{
label: '批量删除',
type: 'default',
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));
},
},
]"
/>
</template>
<template #actions="{ row }">
<TableAction
:actions="[
{
label: '详情',
auth: ['erp:stock-in:query'],
onClick: () => openForm('detail', row.id),
},
{
label: '编辑',
type: 'primary',
auth: ['erp:stock-in:update'],
ifShow: row.status === 10,
onClick: () => openForm('update', row.id),
},
{
label: '审核',
type: 'primary',
auth: ['erp:stock-in:update'],
ifShow: row.status === 10,
onClick: () => handleUpdateStatus(row.id, 20),
},
{
label: '反审核',
danger: true,
auth: ['erp:stock-in:update'],
ifShow: row.status === 20,
onClick: () => handleUpdateStatus(row.id, 10),
},
{
label: '删除',
danger: true,
auth: ['erp:stock-in:delete'],
ifShow: row.status === 10,
onClick: () => handleDelete([row.id]),
},
]"
/>
</template>
</Grid>
<!-- 表单弹窗 -->
<StockInForm ref="formRef" @success="onRefresh" />
</Page>
</template>

View File

@ -0,0 +1,368 @@
<script lang="ts" setup>
import type { ErpStockInApi } from '#/api/erp/stock/in';
import { nextTick, onMounted, ref, watch } from 'vue';
import { erpPriceMultiply } from '@vben/utils';
import { Input, InputNumber, Select } from 'ant-design-vue';
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getProductSimpleList } from '#/api/erp/product/product';
import { getStockCount } from '#/api/erp/stock/stock';
import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { useStockInItemTableColumns } from '../data';
const props = withDefaults(defineProps<Props>(), {
items: () => [],
disabled: false,
});
const emit = defineEmits([
'update:items',
'update:total-count',
'update:total-price',
]);
interface Props {
items?: ErpStockInApi.StockInItem[];
disabled?: boolean;
}
const tableData = ref<ErpStockInApi.StockInItem[]>([]);
const productOptions = ref<any[]>([]);
const warehouseOptions = ref<any[]>([]);
/** 表格配置 */
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
editConfig: {
trigger: 'click',
mode: 'cell',
},
columns: useStockInItemTableColumns(),
data: tableData.value,
border: true,
showOverflow: true,
autoResize: true,
minHeight: 250,
keepSource: true,
rowConfig: {
keyField: 'id',
},
pagerConfig: {
enabled: false,
},
toolbarConfig: {
enabled: false,
},
showFooter: true,
footerMethod: ({ columns }) => {
const footers: any[][] = [];
const sums = getSummaries();
const footerData: any[] = [];
columns.forEach((column, columnIndex) => {
if (columnIndex === 0) {
footerData.push('合计');
} else if (column.field === 'count') {
footerData.push(sums.count);
} else if (column.field === 'totalPrice') {
footerData.push(sums.totalPrice);
} else {
footerData.push('');
}
});
footers.push(footerData);
return footers;
},
},
});
/** 监听外部传入的列数据 */
watch(
() => props.items,
async (items) => {
if (!items) {
return;
}
await nextTick();
tableData.value = [...items];
await nextTick();
gridApi.grid.reloadData(tableData.value);
},
{
immediate: true,
},
);
/** 计算 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();
warehouseOptions.value = await getWarehouseSimpleList();
});
function handleAdd() {
const newRow = {
warehouseId: null,
productId: null,
productName: '',
productUnitId: null,
productUnitName: '',
productBarCode: '',
count: 1,
productPrice: 0,
totalPrice: 0,
stockCount: 0,
remark: '',
};
tableData.value.push(newRow);
gridApi.grid.insertAt(newRow, -1);
emit('update:items', [...tableData.value]);
}
function handleDelete(row: ErpStockInApi.StockInItem) {
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 handleWarehouseChange(warehouseId: any, row: any) {
const warehouse = warehouseOptions.value.find((w) => w.id === warehouseId);
if (!warehouse) {
return;
}
row.warehouseId = warehouseId;
//
if (row.productId) {
const stockCount = await getStockCount(row.productId, warehouseId);
row.stockCount = stockCount || 0;
}
handleUpdateValue(row);
}
async function handleProductChange(productId: any, row: any) {
const product = productOptions.value.find((p) => p.id === productId);
if (!product) {
return;
}
//
const stockCount = row.warehouseId
? await getStockCount(productId, row.warehouseId)
: await getStockCount(productId);
row.productId = productId;
row.productUnitId = product.unitId;
row.productBarCode = product.barCode;
row.productUnitName = product.unitName;
row.productName = product.name;
row.stockCount = stockCount || 0;
row.productPrice = product.purchasePrice || 0;
row.count = row.count || 1;
handlePriceChange(row);
}
function handlePriceChange(row: any) {
if (row.productPrice && row.count) {
row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
}
handleUpdateValue(row);
}
function handleUpdateValue(row: any) {
const index = tableData.value.findIndex((item) => item.id === row.id);
if (index === -1) {
tableData.value.push(row);
} else {
tableData.value[index] = row;
}
emit('update:items', [...tableData.value]);
}
const getSummaries = (): {
count: number;
totalPrice: number;
} => {
return {
count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0),
totalPrice: tableData.value.reduce(
(sum, item) => sum + (item.totalPrice || 0),
0,
),
};
};
/** 验证表单 */
function validate(): Promise<boolean> {
return new Promise((resolve) => {
//
if (!tableData.value || tableData.value.length === 0) {
resolve(false);
return;
}
//
for (const item of tableData.value) {
if (
!item.warehouseId ||
!item.productId ||
!item.count ||
item.count <= 0
) {
resolve(false);
return;
}
}
resolve(true);
});
}
/** 初始化表格数据 */
function init(items: ErpStockInApi.StockInItem[]) {
tableData.value = items || [];
gridApi.grid.reloadData(tableData.value);
}
defineExpose({
validate,
init,
});
</script>
<template>
<div class="w-full">
<div class="mb-4 flex justify-between">
<span class="text-lg font-medium">入库产品清单</span>
<TableAction
v-if="!disabled"
:actions="[
{
label: '添加产品',
type: 'primary',
onClick: handleAdd,
},
]"
/>
</div>
<Grid>
<template #warehouseId="{ row }">
<Select
v-model:value="row.warehouseId"
placeholder="请选择仓库"
:disabled="disabled"
show-search
:filter-option="false"
@change="(value) => handleWarehouseChange(value, row)"
class="w-full"
>
<Select.Option
v-for="warehouse in warehouseOptions"
:key="warehouse.id"
:value="warehouse.id"
>
{{ warehouse.name }}
</Select.Option>
</Select>
</template>
<template #productId="{ row }">
<Select
v-model:value="row.productId"
placeholder="请选择产品"
:disabled="disabled"
show-search
:filter-option="false"
@change="(value) => handleProductChange(value, row)"
class="w-full"
>
<Select.Option
v-for="product in productOptions"
:key="product.id"
:value="product.id"
>
{{ product.name }}
</Select.Option>
</Select>
</template>
<template #count="{ row }">
<InputNumber
v-model:value="row.count"
:disabled="disabled"
:min="0.001"
:precision="3"
@change="() => handlePriceChange(row)"
class="w-full"
/>
</template>
<template #productPrice="{ row }">
<InputNumber
v-model:value="row.productPrice"
:disabled="disabled"
:min="0.01"
:precision="2"
@change="() => handlePriceChange(row)"
class="w-full"
/>
</template>
<template #remark="{ row }">
<Input
v-model:value="row.remark"
:disabled="disabled"
placeholder="请输入备注"
/>
</template>
<template #actions="{ row }">
<TableAction
v-if="!disabled"
:actions="[
{
label: '删除',
type: 'link',
danger: true,
onClick: () => handleDelete(row),
},
]"
/>
</template>
</Grid>
</div>
</template>

View File

@ -0,0 +1,252 @@
<script lang="ts" setup>
import type { ErpStockInApi } from '#/api/erp/stock/in';
import { computed, nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
createStockIn,
getStockIn,
updateStockIn,
updateStockInStatus,
} from '#/api/erp/stock/in';
import { useFormSchema } from '../data';
import StockInItemForm from './StockInItemForm.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpStockInApi.StockIn>();
const formType = ref('');
const itemFormRef = ref();
const getTitle = computed(() => {
if (formType.value === 'create') return '添加其它入库单';
if (formType.value === 'update') return '编辑其它入库单';
return '其它入库单详情';
});
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
labelWidth: 120,
},
wrapperClass: 'grid-cols-3',
layout: 'vertical',
schema: useFormSchema(),
showDefaultActions: false,
});
const handleUpdateItems = (items: ErpStockInApi.StockInItem[]) => {
formData.value = modalApi.getData<ErpStockInApi.StockIn>();
if (formData.value) {
formData.value.items = items;
}
};
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,
});
}
};
/**
* 创建或更新其它入库单
*/
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) {
return;
}
await nextTick();
const itemFormInstance = Array.isArray(itemFormRef.value)
? itemFormRef.value[0]
: itemFormRef.value;
if (itemFormInstance && typeof itemFormInstance.validate === 'function') {
try {
const isValid = await itemFormInstance.validate();
if (!isValid) {
message.error('产品清单验证失败,请检查必填项');
return;
}
} catch (error) {
message.error(error.message || '产品清单验证失败');
return;
}
} else {
message.error('产品清单验证方法不存在');
return;
}
//
if (!formData.value?.items || formData.value.items.length === 0) {
message.error('产品清单不能为空,请至少添加一个产品');
return;
}
modalApi.lock();
//
const data = (await formApi.getValues()) as ErpStockInApi.StockIn;
data.items = formData.value?.items;
//
if (data.fileUrl && Array.isArray(data.fileUrl)) {
data.fileUrl = data.fileUrl.length > 0 ? data.fileUrl[0] : '';
}
try {
await (formType.value === 'create'
? createStockIn(data)
: updateStockIn(data));
//
await modalApi.close();
emit('success');
message.success(formType.value === 'create' ? '新增成功' : '更新成功');
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
if (!data) {
return;
}
formType.value = data.type;
if (!data.id) {
//
formData.value = { items: [] } as ErpStockInApi.StockIn;
await nextTick();
const itemFormInstance = Array.isArray(itemFormRef.value)
? itemFormRef.value[0]
: itemFormRef.value;
if (itemFormInstance && typeof itemFormInstance.init === 'function') {
itemFormInstance.init([]);
}
return;
}
modalApi.lock();
try {
formData.value = await getStockIn(data.id);
// URLFileUpload
if (
formData.value.fileUrl &&
typeof formData.value.fileUrl === 'string'
) {
formData.value.fileUrl = formData.value.fileUrl
? [formData.value.fileUrl]
: [];
}
// values
await formApi.setValues(formData.value);
//
await nextTick();
const itemFormInstance = Array.isArray(itemFormRef.value)
? itemFormRef.value[0]
: itemFormRef.value;
if (itemFormInstance && typeof itemFormInstance.init === 'function') {
itemFormInstance.init(formData.value.items || []);
}
} finally {
modalApi.unlock();
}
},
});
/** 审核/反审核 */
async function handleUpdateStatus(id: number, status: number) {
try {
await updateStockInStatus({ id, status });
message.success(status === 20 ? '审核成功' : '反审核成功');
emit('success');
await modalApi.close();
} catch (error) {
message.error(error.message || '操作失败');
}
}
defineExpose({ modalApi, handleUpdateStatus });
</script>
<template>
<Modal
v-bind="$attrs"
:title="getTitle"
class="w-4/5"
:closable="true"
:mask-closable="true"
:show-confirm-button="formType !== 'detail'"
>
<Form class="mx-3">
<template #product="slotProps">
<StockInItemForm
v-bind="slotProps"
ref="itemFormRef"
class="w-full"
:items="formData?.items ?? []"
:disabled="formType === 'detail'"
@update:items="handleUpdateItems"
@update:total-count="handleUpdateTotalCount"
@update:total-price="handleUpdateTotalPrice"
/>
</template>
</Form>
<!-- 审核操作按钮 -->
<template #footer>
<div class="flex w-full justify-between">
<div>
<template v-if="formType === 'detail' && formData">
<a-button
v-if="formData.status === 10"
type="primary"
@click="handleUpdateStatus(formData.id!, 20)"
>
审核
</a-button>
<a-button
v-if="formData.status === 20"
danger
@click="handleUpdateStatus(formData.id!, 10)"
>
反审核
</a-button>
</template>
</div>
<div>
<a-button
v-if="formType !== 'detail'"
type="primary"
@click="modalApi.confirm()"
>
确定
</a-button>
<a-button @click="modalApi.close()"></a-button>
</div>
</div>
</template>
</Modal>
</template>