feat: 产品根据项目进行库存数量维护

This commit is contained in:
louis 2024-03-11 13:41:59 +08:00
parent 568d77d178
commit 9764ead573
9 changed files with 135 additions and 187 deletions

View File

@ -1387,50 +1387,18 @@ declare namespace API {
};
type MaterialsInventoryEntity = {
/** 公司名称 */
companyName: string;
/** 产品名称(字典) */
product: number;
/** 单位(字典) */
unit: number;
/** 之前的库存数量 */
previousInventoryQuantity: number;
/** 之前的单价 */
previousUnitPrice: number;
/** 之前的金额 */
previousAmount: number;
/** 入库时间 */
inventoryTime: Date;
/** 入库数量 */
inventoryQuantity: number;
/** 入库单价*/
inventoryUnitPrice: number;
/** 入库金额 */
inventoryAmount: number;
/** 出库时间 */
outime: Date;
/** 出库数量 */
outQuantity: number;
/** 出库单价 */
outUnitPrice: number;
/** 出库金额 */
outAmount: number;
/** 现在的结存数量 */
currentInventoryQuantity: number;
/** 现在的单价 */
currentUnitPrice: number;
/** 现在的金额 */
currentAmount: number;
/** 项目 */
project?: ProjectEntity;
/** 产品 */
product: ProductEntity;
/** 单价 */
unitPrice: number;
/** 数量 */
quantity: number;
/** 经办人 */
agent: string;
/** 领料单号 */
issuanceNumber?: number;
/** 项目 */
project: ProjectEntity;
/** 备注 */
remark: string;
/** 附件 */
files: StorageInfo[];
id: number;
createdAt: string;
updatedAt: string;
@ -1616,6 +1584,8 @@ declare namespace API {
name: string;
/** 所属公司 */
company: CompanyEntity;
/** 产品备注 */
remark: string;
/** 单位 */
unit: DictItemEntity;
/** 是否删除 */
@ -1631,6 +1601,8 @@ declare namespace API {
name: string;
/** 所属公司 */
companyId?: number;
/** 产品备注 */
remark: string;
/** 单位 */
unitId?: number;
fileIds?: number[];
@ -1785,7 +1757,8 @@ declare namespace API {
};
type MaterialsInOutInfoParams = {
id: number;
id?: number;
inventoryNumber?: string;
};
type MaterialsInOutListParams = {

View File

@ -180,7 +180,6 @@ export function exportJson2Excel({
const wsName = 'SheetJS';
const wb = new Workbook(),
ws = sheetFromArrayOfArrays(data);
if (merges.length > 0) {
if (!ws['!merges']) ws['!merges'] = [];
merges.forEach((item) => {

View File

@ -1,7 +1,7 @@
import type { FormSchema } from '@/components/core/schema-form/';
import Api from '@/api';
import { debounce } from 'lodash-es';
import { debounce, isEmpty } from 'lodash-es';
import { MaterialsInOutEnum } from '@/enums/materialsInventoryEnum';
export const formSchemas = (isEdit?: boolean): FormSchema<API.MaterialsInOutEntity>[] => [
{
@ -28,7 +28,7 @@ export const formSchemas = (isEdit?: boolean): FormSchema<API.MaterialsInOutEnti
label: '库存编号',
vIf: ({ formModel }) => formModel.inOrOut === MaterialsInOutEnum.Out,
colProps: {
span: 16,
span: 24,
},
helpMessage: '出库必须选择入库时的编号',
componentProps: ({ formInstance, schema, formModel }) => ({
@ -66,6 +66,16 @@ export const formSchemas = (isEdit?: boolean): FormSchema<API.MaterialsInOutEnti
}
},
},
onSelect: async (inventoryNumber: string) => {
const { items = [] } = await Api.materialsInOut.materialsInOutList({
inventoryNumber,
isCreateOut: true,
});
if (!isEmpty(items)) {
const { inOrOut, id, ...ext } = items[0] as API.MaterialsInOutEntity;
formInstance?.setFieldsValue(ext);
}
},
onSearch: debounce(async (keyword) => {
schema.loading = true;
const newSchema = {
@ -141,8 +151,12 @@ export const formSchemas = (isEdit?: boolean): FormSchema<API.MaterialsInOutEnti
colProps: {
span: 12,
},
vIf: ({ formModel }) =>
formModel.inOrOut === MaterialsInOutEnum.In || isEdit || formModel.inventoryNumber,
rules: [{ required: true, type: 'number' }],
helpMessage: '如未找到对应项目,请先去项目管理添加项目。',
componentProps: ({ formInstance, schema, formModel }) => ({
disabled: Object.is(formModel.inOrOut, MaterialsInOutEnum.Out) || isEdit,
showSearch: true,
filterOption: false,
fieldNames: {
@ -165,6 +179,17 @@ export const formSchemas = (isEdit?: boolean): FormSchema<API.MaterialsInOutEnti
request: () => {
return getProjectOptions();
},
// request: {
// watchFields: ['framework'],
// options: {
// immediate: true,
// },
// callback: async ({ formModel }) => {
// console.log('values', formModel);
// formModel['lib'] = undefined;
// return fetchLibData(formModel['framework']);
// },
// },
onSearch: debounce(async (keyword) => {
schema.loading = true;
const newSchema = {
@ -224,7 +249,7 @@ export const formSchemas = (isEdit?: boolean): FormSchema<API.MaterialsInOutEnti
label: '领料单号',
field: 'issuanceNumber',
component: 'Input',
vIf:isEdit,
vIf: ({ formModel }) => formModel.inOrOut === MaterialsInOutEnum.Out,
colProps: {
span: 12,
},
@ -265,7 +290,7 @@ const getInventoryNumberOptions = async (inventoryNumber?: string): Promise<Labe
});
return (
result?.map((item) => ({
label: item.inventoryNumber,
label: `${item.inventoryNumber} (${item.project?.name || '-'}) (${item.product?.company?.name || '-'}) (${item.product?.name || '-'})`,
value: item.inventoryNumber,
})) || []
);

View File

@ -18,13 +18,7 @@
>
新增
</a-button>
<a-button
type="primary"
:disabled="!$auth('app:materials_inventory:export')"
@click="exportMI()"
>
导出原材料盘点表
</a-button>
</template>
</DynamicTable>
</div>
@ -43,7 +37,7 @@
import { useFormModal, useModal } from '@/hooks/useModal';
import { Button } from 'ant-design-vue';
import { formSchemas } from './formSchemas';
import { exportSchemas } from './exportSchema';
import AttachmentManage from '@/components/business/attachment-manage/index.vue';
import AttachmentUpload from '@/components/business/attachment-upload/index.vue';
import fileDownload from 'js-file-download';
@ -53,7 +47,7 @@
});
const [DynamicTable, dynamicTableInstance] = useTable({ formProps: { autoSubmitOnEnter: true } });
const [showModal] = useFormModal();
const [showExportModal] = useFormModal();
const [fnModal] = useModal();
const isUploadPopupVisiable = ref(false);
@ -107,35 +101,7 @@
},
];
});
const exportMI = async () => {
const { time } = unref<TableQueryItem>(
dynamicTableInstance?.queryFormRef?.formModel as TableQueryItem,
);
const [formRef] = await showExportModal({
modalProps: {
title: `导出条件选择`,
width: '50%',
okText: '导出',
onFinish: async (values) => {
const response = await Api.materialsInventory.materialsInventoryExport(values);
const { time } = values;
fileDownload(response, `${dayjs(time).format('YYYY年MM月')}.xls`);
},
},
formProps: {
labelWidth: 100,
schemas: exportSchemas,
},
});
// auto fill export time fields
if (time) {
formRef?.setFieldsValue({
time,
});
}
};
const openAttachmentUploadModal = async (record: TableListItem) => {
isUploadPopupVisiable.value = true;
fnModal.show({

View File

@ -9,10 +9,29 @@ export type TableListItem = API.MaterialsInventoryEntity;
export type TableColumnItem = TableColumn<TableListItem>;
const dictStore = useDictStore();
export const baseColumns: TableColumnItem[] = [
{
title: '所属项目',
width: 180,
dataIndex: 'project',
customRender: ({ record }) => {
return record?.project?.name || '';
},
},
{
title: '所属公司',
width: 180,
dataIndex: 'product',
customRender: ({ record }) => {
return record?.product?.company?.name || '';
},
},
{
title: '产品名称',
width: 180,
dataIndex: 'product',
customRender: ({ record }) => {
return record?.product?.name || '';
},
},
{
title: '单位',
@ -28,10 +47,7 @@ export const baseColumns: TableColumnItem[] = [
},
},
customRender: ({ record }) => {
return dictStore.getDictItemsByCode(DictEnum.Unit)?.length
? dictStore.getDictItemsByCode(DictEnum.Unit).find((item) => item.id === record.unit)
?.label || ''
: '';
return record?.product?.unit?.label || '';
},
},
{
@ -45,11 +61,9 @@ export const baseColumns: TableColumnItem[] = [
hideInSearch: true,
width: 80,
dataIndex: 'unitPrice',
},
{
title: '备注',
width: 80,
dataIndex: 'remark',
customRender: ({ record }) => {
return parseFloat(record.unitPrice) || 0;
},
},
];

View File

@ -2,7 +2,7 @@
<div v-if="columns?.length">
<DynamicTable
row-key="id"
header-title="原材料盘点"
header-title="原材料库存"
title-tooltip=""
:data-request="Api.materialsInventory.materialsInventoryList"
:columns="columns"
@ -12,12 +12,12 @@
<template #toolbar>
<a-button
type="primary"
:disabled="!$auth('system:role:create')"
@click="openEditModal({})"
:disabled="!$auth('app:materials_inventory:export')"
@click="exportMI()"
>
新增
</a-button>
</template>
导出原材料盘点表
</a-button></template
>
</DynamicTable>
</div>
</template>
@ -27,35 +27,29 @@
import { baseColumns, type TableColumnItem, type TableListItem } from './columns';
import Api from '@/api/';
import { useDictStore } from '@/store/modules/dict';
import { onMounted, ref, type FunctionalComponent } from 'vue';
import { onMounted, ref, type FunctionalComponent, unref } from 'vue';
import { DictEnum } from '@/enums/dictEnum';
import { useFormModal, useModal } from '@/hooks/useModal';
import { Button } from 'ant-design-vue';
import { exportSchemas } from './exportSchema';
import dayjs from 'dayjs';
import fileDownload from 'js-file-download';
defineOptions({
name: 'MaterialsInventory',
});
const [DynamicTable, dynamicTableInstance] = useTable();
const [fnModal] = useModal();
const isUploadPopupVisiable = ref(false);
const [showExportModal] = useFormModal();
let columns = ref<TableColumnItem[]>();
onMounted(() => {
columns.value = [
...baseColumns,
{
title: '附件',
width: 50,
maxWidth: 50,
hideInSearch: true,
dataIndex: 'files',
customRender: ({ record }) => <FilesRender {...record} />,
},
{
title: '操作',
maxWidth: 80,
width: 80,
minWidth: 80,
maxWidth: 60,
width: 60,
minWidth: 60,
dataIndex: 'ACTION',
hideInSearch: true,
actions: ({ record }) => [
@ -79,46 +73,38 @@
onConfirm: () => delRowConfirm(record.id),
},
},
{
icon: 'ant-design:cloud-upload-outlined',
tooltip: '上传附件',
onClick: () => openAttachmentUploadModal(record),
},
],
},
];
});
const exportMI = async () => {
const { time } = unref<{ time: string; projectId: number }>(
dynamicTableInstance?.queryFormRef?.formModel as { time: string; projectId: number },
);
const openAttachmentUploadModal = async (record: TableListItem) => {
// isUploadPopupVisiable.value = true;
// fnModal.show({
// width: 800,
// title: `: ${record.contractNumber}`,
// content: () => {
// return (
// <AttachmentUpload
// onClose={handleUploadClose}
// afterUploadCallback={(files) => {
// afterUploadCallback(files, record.id);
// }}
// ></AttachmentUpload>
// );
// },
// destroyOnClose: true,
// open: isUploadPopupVisiable.value,
// footer: null,
// });
};
const handleUploadClose = (hasSuccess: boolean) => {
fnModal.hide();
isUploadPopupVisiable.value = false;
};
const afterUploadCallback = async (
files: { filename: { path: string; id: number } }[],
id: number,
) => {
await Api.contract.contractUpdate({ id }, { fileIds: files.map((item) => item.filename.id) });
dynamicTableInstance?.reload();
const [formRef] = await showExportModal({
modalProps: {
title: `导出条件选择`,
width: '50%',
okText: '导出',
onFinish: async (values) => {
const response = await Api.materialsInventory.materialsInventoryExport(values);
const { time } = values;
fileDownload(response, `${dayjs(time).format('YYYY.MM.盘点表')}.xls`);
},
},
formProps: {
labelWidth: 100,
schemas: exportSchemas,
},
});
// auto fill export time fields
if (time) {
formRef?.setFieldsValue({
time,
});
}
};
/**
@ -160,42 +146,14 @@
await Api.contract.contractDelete({ id: record });
dynamicTableInstance?.reload();
};
const FilesRender: FunctionalComponent<TableListItem> = (contract: TableListItem) => {
const [fnModal] = useModal();
return (
<Button
type="link"
onClick={() => {
openFilesManageModal(fnModal, contract);
}}
>
{contract.files?.length || 0}
</Button>
);
};
const openFilesManageModal = (fnModal, contract: TableListItem) => {
// const fileIds = contract.files?.map((item) => item.id) || [];
// fnModal.show({
// width: 1200,
// title: ``,
// content: () => {
// return (
// <AttachmentManage
// fileIds={fileIds}
// onDelete={(unlinkIds) => unlinkAttachments(contract.id, unlinkIds)}
// ></AttachmentManage>
// );
// },
// destroyOnClose: true,
// footer: null,
// });
};
const unlinkAttachments = async (id: number, unlinkIds: number[]) => {
await Api.contract.unlinkAttachments({ id }, { fileIds: unlinkIds });
dynamicTableInstance?.reload();
};
</script>
<style lang="less" scoped></style>
import dayjs from 'dayjs'; import fileDownload from 'js-file-download'; import type { TableQueryItem
} from '../in-out/columns'; import { exportSchemas } from '../in-out/exportSchema'; import dayjs
from 'dayjs'; import fileDownload from 'js-file-download'; import type { TableQueryItem } from
'../in-out/columns'; import { exportSchemas } from './exportSchema'; import dayjs from 'dayjs';
import fileDownload from 'js-file-download'; import type { TableQueryItem } from
'../in-out/columns'; import { exportSchemas } from './exportSchema'; import dayjs from 'dayjs';
import fileDownload from 'js-file-download'; import type { TableQueryItem } from
'../in-out/columns';

View File

@ -18,8 +18,13 @@ export const baseColumns: TableColumnItem[] = [
{
title: '单位',
dataIndex: 'unit',
width:80,
customRender: ({ record }) => {
return record?.unit?.label || '';
},
},
{
title: '备注',
dataIndex: 'remark',
},
];

View File

@ -86,6 +86,14 @@ export const formSchemas: FormSchema<API.ProductDto>[] = [
}, 500),
}),
},
{
field: 'remark',
component: 'InputTextArea',
label: '备注',
colProps: {
span: 24,
},
},
];
const getCompanyOptions = async (keyword?: string): Promise<LabelValueOptions> => {