feat: 文件存储添加业务模块和业务记录id冗余
This commit is contained in:
parent
f65a4c0b99
commit
46a4132877
|
@ -10,6 +10,7 @@ const app: FastifyAdapter = new FastifyAdapter({
|
||||||
export { app as fastifyApp };
|
export { app as fastifyApp };
|
||||||
|
|
||||||
app.register(FastifyMultipart, {
|
app.register(FastifyMultipart, {
|
||||||
|
attachFieldsToBody:true,
|
||||||
limits: {
|
limits: {
|
||||||
fields: 10, // Max number of non-file fields
|
fields: 10, // Max number of non-file fields
|
||||||
fileSize: 1024 * 1024 * 6, // limit size 6M
|
fileSize: 1024 * 1024 * 6, // limit size 6M
|
||||||
|
|
|
@ -33,7 +33,6 @@ async function bootstrap() {
|
||||||
|
|
||||||
// class-validator 的 DTO 类中注入 nest 容器的依赖 (用于自定义验证器)
|
// class-validator 的 DTO 类中注入 nest 容器的依赖 (用于自定义验证器)
|
||||||
useContainer(app.select(AppModule), { fallbackOnErrors: true });
|
useContainer(app.select(AppModule), { fallbackOnErrors: true });
|
||||||
|
|
||||||
app.enableCors({ origin: '*', credentials: true });
|
app.enableCors({ origin: '*', credentials: true });
|
||||||
app.setGlobalPrefix(globalPrefix);
|
app.setGlobalPrefix(globalPrefix);
|
||||||
app.useStaticAssets({ root: path.join(__dirname, '..', 'public') });
|
app.useStaticAssets({ root: path.join(__dirname, '..', 'public') });
|
||||||
|
|
|
@ -62,11 +62,12 @@ export class ContractService {
|
||||||
{ fileIds, contractNumber, ...ext }: Partial<ContractUpdateDto>
|
{ fileIds, contractNumber, ...ext }: Partial<ContractUpdateDto>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.entityManager.transaction(async manager => {
|
await this.entityManager.transaction(async manager => {
|
||||||
if (await this.checkIsContractNumberExsit(contractNumber, id)) {
|
if (contractNumber && (await this.checkIsContractNumberExsit(contractNumber, id))) {
|
||||||
throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST);
|
throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST);
|
||||||
}
|
}
|
||||||
await manager.update(ContractEntity, id, {
|
await manager.update(ContractEntity, id, {
|
||||||
...ext
|
...ext,
|
||||||
|
contractNumber
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fileIds?.length) {
|
if (fileIds?.length) {
|
||||||
|
|
|
@ -129,9 +129,9 @@ export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutQueryDto> {
|
||||||
remark?: string;
|
remark?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsNumber()
|
||||||
@ApiProperty({ description: '项目' })
|
@ApiProperty({ description: '项目Id' })
|
||||||
project?: string;
|
projectId?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class MaterialsInOutService {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
product: productName,
|
product: productName,
|
||||||
project: projectName,
|
projectId,
|
||||||
isCreateOut,
|
isCreateOut,
|
||||||
...ext
|
...ext
|
||||||
}: MaterialsInOutQueryDto): Promise<Pagination<MaterialsInOutEntity>> {
|
}: MaterialsInOutQueryDto): Promise<Pagination<MaterialsInOutEntity>> {
|
||||||
|
@ -46,15 +46,24 @@ export class MaterialsInOutService {
|
||||||
.leftJoin('materialsInOut.product', 'product')
|
.leftJoin('materialsInOut.product', 'product')
|
||||||
.leftJoin('product.unit', 'unit')
|
.leftJoin('product.unit', 'unit')
|
||||||
.leftJoin('product.company', 'company')
|
.leftJoin('product.company', 'company')
|
||||||
.addSelect(['files.id','files.path', 'project.name', 'product.name', 'unit.label', 'company.name'])
|
.addSelect([
|
||||||
|
'files.id',
|
||||||
|
'files.path',
|
||||||
|
'project.name',
|
||||||
|
'product.name',
|
||||||
|
'unit.label',
|
||||||
|
'company.name'
|
||||||
|
])
|
||||||
.where(fieldSearch(ext))
|
.where(fieldSearch(ext))
|
||||||
.andWhere('materialsInOut.isDelete = 0')
|
.andWhere('materialsInOut.isDelete = 0')
|
||||||
.addOrderBy('materialsInOut.createdAt', 'DESC');
|
.addOrderBy('materialsInOut.createdAt', 'DESC');
|
||||||
|
|
||||||
if (productName) {
|
if (productName) {
|
||||||
sqb.andWhere('product.name like :productName', { productName: `%${productName}%` });
|
sqb.andWhere('product.name like :productName', { productName: `%${productName}%` });
|
||||||
}
|
}
|
||||||
if (projectName) {
|
|
||||||
sqb.andWhere('project.name like :projectName', { projectName: `%${projectName}%` });
|
if (projectId) {
|
||||||
|
sqb.andWhere('project.id = :projectId', { projectId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCreateOut) {
|
if (isCreateOut) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import { ArrayNotEmpty, IsArray, IsOptional, IsString } from 'class-validator';
|
import { ArrayNotEmpty, IsArray, IsNumber, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
import { PagerDto } from '~/common/dto/pager.dto';
|
import { PagerDto } from '~/common/dto/pager.dto';
|
||||||
|
|
||||||
|
@ -34,6 +34,16 @@ export class StoragePageDto extends PagerDto {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
username: string;
|
username: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '文件所属模块' })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
businessModule: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '文件上传的业务记录ID' })
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
bussinessRecordId: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '附件' })
|
@ApiProperty({ description: '附件' })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(
|
@Transform(
|
||||||
|
|
|
@ -45,6 +45,15 @@ export class Storage extends CommonEntity {
|
||||||
@ApiProperty({ description: '用户ID' })
|
@ApiProperty({ description: '用户ID' })
|
||||||
userId: number;
|
userId: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, name: 'bussiness_module' })
|
||||||
|
@ApiProperty({ description: '文件上传的业务模块' })
|
||||||
|
bussinessModule: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, name: 'bussiness_record_id' })
|
||||||
|
@ApiProperty({ description: '文件上传的业务记录ID' })
|
||||||
|
bussinessRecordId: number;
|
||||||
|
|
||||||
|
|
||||||
@ApiHideProperty()
|
@ApiHideProperty()
|
||||||
@ManyToMany(() => ContractEntity, contract => contract.files)
|
@ManyToMany(() => ContractEntity, contract => contract.files)
|
||||||
contracts: Relation<ContractEntity[]>;
|
contracts: Relation<ContractEntity[]>;
|
||||||
|
|
|
@ -93,7 +93,9 @@ export class StorageService {
|
||||||
type: e.storage_type,
|
type: e.storage_type,
|
||||||
size: e.storage_size,
|
size: e.storage_size,
|
||||||
createdAt: e.storage_created_at,
|
createdAt: e.storage_created_at,
|
||||||
username: e.user_username
|
username: e.user_username,
|
||||||
|
bussinessRecordId:e.storage_bussiness_record_id,
|
||||||
|
bussinessModule:e.storage_bussiness_module
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { BadRequestException, Controller, Post, Req } from '@nestjs/common';
|
import { BadRequestException, Body, Controller, Post, Req, UseInterceptors } from '@nestjs/common';
|
||||||
import { ApiBody, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiBody, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { FastifyRequest } from 'fastify';
|
import { FastifyRequest } from 'fastify';
|
||||||
|
|
||||||
|
@ -27,18 +27,18 @@ export class UploadController {
|
||||||
@ApiBody({
|
@ApiBody({
|
||||||
type: FileUploadDto
|
type: FileUploadDto
|
||||||
})
|
})
|
||||||
async upload(@Req() req: FastifyRequest, @AuthUser() user: IAuthUser) {
|
async upload(@Req() req: FastifyRequest, @AuthUser() user: IAuthUser, @Body() body: any) {
|
||||||
if (!req.isMultipart()) throw new BadRequestException('Request is not multipart');
|
if (!req.isMultipart()) throw new BadRequestException('Request is not multipart');
|
||||||
|
const { file } = body;
|
||||||
const file = await req.file();
|
const bussinessModule = body.bussinessModule?.value;
|
||||||
|
const bussinessRecordId = Number(body.bussinessRecordId?.value) || null;
|
||||||
// https://github.com/fastify/fastify-multipart
|
|
||||||
// const parts = req.files()
|
|
||||||
// for await (const part of parts)
|
|
||||||
// console.log(part.file)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const savedFile = await this.uploadService.saveFile(file, user.uid);
|
const savedFile = await this.uploadService.saveFile(
|
||||||
|
file,
|
||||||
|
user.uid,
|
||||||
|
bussinessModule,
|
||||||
|
bussinessRecordId
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filename: savedFile
|
filename: savedFile
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { MultipartFile } from '@fastify/multipart';
|
import { MultipartFile } from '@fastify/multipart';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
import { IsDefined } from 'class-validator';
|
import { IsDefined, IsNumber, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
import { IsFile } from './file.constraint';
|
import { IsFile } from './file.constraint';
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,12 @@ export class UploadService {
|
||||||
/**
|
/**
|
||||||
* 保存文件上传记录
|
* 保存文件上传记录
|
||||||
*/
|
*/
|
||||||
async saveFile(file: MultipartFile, userId: number): Promise<{ id: number; path: string }> {
|
async saveFile(
|
||||||
|
file: MultipartFile,
|
||||||
|
userId: number,
|
||||||
|
bussinessModule?: string,
|
||||||
|
bussinessRecordId?: number
|
||||||
|
): Promise<{ id: number; path: string }> {
|
||||||
if (isNil(file)) throw new NotFoundException('Have not any file to upload!');
|
if (isNil(file)) throw new NotFoundException('Have not any file to upload!');
|
||||||
|
|
||||||
const fileName = file.filename;
|
const fileName = file.filename;
|
||||||
|
@ -44,7 +49,9 @@ export class UploadService {
|
||||||
path,
|
path,
|
||||||
type,
|
type,
|
||||||
size,
|
size,
|
||||||
userId
|
userId,
|
||||||
|
bussinessModule,
|
||||||
|
bussinessRecordId
|
||||||
});
|
});
|
||||||
|
|
||||||
return { path, id: storage.id };
|
return { path, id: storage.id };
|
||||||
|
|
Loading…
Reference in New Issue