fix: 所有上传文件bug,车辆使用模块完成

This commit is contained in:
louis 2024-03-08 10:38:28 +08:00
parent 10f6f1ff37
commit f65a4c0b99
14 changed files with 109 additions and 58 deletions

View File

@ -97,7 +97,7 @@ pnpm migration:revert
4.执行sql覆盖docker中的数据库 4.执行sql覆盖docker中的数据库
```bash ```bash
docker exec -i huaxin-admin-mysql mysql -h 127.0.0.1 -u root -phuaxin123 hxoa < hxoa_2024-03-05_222748.sql docker exec -i huaxin-admin-mysql mysql -h 127.0.0.1 -u root -phuaxin123 hxoa < hxoa_2024-03-07_171919.sql
``` ```
更多细节,请移步至[官方文档](https://typeorm.io/migrations) 更多细节,请移步至[官方文档](https://typeorm.io/migrations)

View File

@ -23,3 +23,10 @@ export enum MaterialsInOrOutEnum {
export enum ParamConfigEnum { export enum ParamConfigEnum {
MaterialsInOutPrefix = 'materials_in_out_prefix' MaterialsInOutPrefix = 'materials_in_out_prefix'
} }
// 合同审核状态
export enum ContractStatusEnum {
Pending = 0, // 待审核
Approved = 1, // 已通过
Rejected = 2 // 已拒绝
}

View File

@ -52,5 +52,8 @@ export enum ErrorEnum {
STORAGE_REFRENCE_EXISTS = '1405:文件存在关联,无法删除,请先找到该文件关联的业务解除关联。', STORAGE_REFRENCE_EXISTS = '1405:文件存在关联,无法删除,请先找到该文件关联的业务解除关联。',
// Product // Product
PRODUCT_EXIST = '1406:产品已存在' PRODUCT_EXIST = '1406:产品已存在',
// Contract
CONTRACT_NUMBER_EXIST = '1407:存在相同的合同编号'
} }

View File

@ -69,12 +69,12 @@ export class CompanyService {
if (count !== fileIds?.length) { if (count !== fileIds?.length) {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量更新 // 附件要批量插入
await manager await manager
.createQueryBuilder() .createQueryBuilder()
.relation(CompanyEntity, 'files') .relation(CompanyEntity, 'files')
.of(id) .of(id)
.addAndRemove(fileIds, company.files); .add(fileIds);
} }
}); });
} }

View File

@ -3,6 +3,7 @@ import {
IsArray, IsArray,
IsDate, IsDate,
IsDateString, IsDateString,
IsEnum,
IsIn, IsIn,
IsInt, IsInt,
IsNumber, IsNumber,
@ -13,6 +14,7 @@ import {
} from 'class-validator'; } from 'class-validator';
import { PagerDto } from '~/common/dto/pager.dto'; import { PagerDto } from '~/common/dto/pager.dto';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { ContractStatusEnum } from '~/constants/enum';
export class ContractDto { export class ContractDto {
@ApiProperty({ description: '合同编号' }) @ApiProperty({ description: '合同编号' })
@ -37,15 +39,18 @@ export class ContractDto {
partyB: string; partyB: string;
@ApiProperty({ description: '签订日期' }) @ApiProperty({ description: '签订日期' })
@IsOptional()
@IsDateString() @IsDateString()
signingDate: string; signingDate?: string;
@ApiProperty({ description: '交付期限' }) @ApiProperty({ description: '交付期限' })
@IsOptional()
@IsDateString() @IsDateString()
deliveryDeadline: string; deliveryDeadline?: string;
@ApiProperty({ description: '审核状态(字典)' }) @ApiProperty({ description: '审核状态(字典)' })
@IsIn([0, 1, 2]) @IsOptional()
@IsEnum(ContractStatusEnum)
status: number; status: number;
@ApiProperty({ description: '附件' }) @ApiProperty({ description: '附件' })

View File

@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'; import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { ContractEntity } from './contract.entity'; import { ContractEntity } from './contract.entity';
import { EntityManager, Like, Repository } from 'typeorm'; import { EntityManager, Like, Not, Repository } from 'typeorm';
import { ContractDto, ContractQueryDto, ContractUpdateDto } from './contract.dto'; import { ContractDto, ContractQueryDto, ContractUpdateDto } from './contract.dto';
import { Pagination } from '~/helper/paginate/pagination'; import { Pagination } from '~/helper/paginate/pagination';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
@ -45,23 +45,30 @@ export class ContractService {
/** /**
* *
*/ */
async create(dto: ContractDto): Promise<void> { async create({ contractNumber, ...ext }: ContractDto): Promise<void> {
await this.contractRepository.insert(dto); if (await this.checkIsContractNumberExsit(contractNumber)) {
throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST);
}
await this.contractRepository.insert(
this.contractRepository.create({ contractNumber, ...ext })
);
} }
/** /**
* *
*/ */
async update(id: number, { fileIds, ...data }: Partial<ContractUpdateDto>): Promise<void> { async update(
id: number,
{ fileIds, contractNumber, ...ext }: Partial<ContractUpdateDto>
): Promise<void> {
await this.entityManager.transaction(async manager => { await this.entityManager.transaction(async manager => {
if (await this.checkIsContractNumberExsit(contractNumber, id)) {
throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST);
}
await manager.update(ContractEntity, id, { await manager.update(ContractEntity, id, {
...data ...ext
}); });
const contract = await this.contractRepository
.createQueryBuilder('contract')
.leftJoinAndSelect('contract.files', 'files')
.where('contract.id = :id', { id })
.getOne();
if (fileIds?.length) { if (fileIds?.length) {
const count = await this.storageRepository const count = await this.storageRepository
.createQueryBuilder('storage') .createQueryBuilder('storage')
@ -70,16 +77,24 @@ export class ContractService {
if (count !== fileIds?.length) { if (count !== fileIds?.length) {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量更新 // 附件要批量插入
await manager await manager.createQueryBuilder().relation(ContractEntity, 'files').of(id).add(fileIds);
.createQueryBuilder()
.relation(ContractEntity, 'files')
.of(id)
.addAndRemove(fileIds, contract.files);
} }
}); });
} }
/**
*
* @param contractNumber
*/
async checkIsContractNumberExsit(contractNumber: string, id?: number): Promise<Boolean> {
return !!(await this.contractRepository.findOne({
where: {
contractNumber: contractNumber,
id: Not(id)
}
}));
}
/** /**
* *
*/ */

View File

@ -120,7 +120,7 @@ export class MaterialsInOutEntity extends CommonEntity {
@JoinColumn({ name: 'product_id' }) @JoinColumn({ name: 'product_id' })
product: ProductEntity; product: ProductEntity;
@ManyToMany(() => Storage, storage => storage.materialsInOut) @ManyToMany(() => Storage, storage => storage.materialsInOuts)
@JoinTable({ @JoinTable({
name: 'materials_in_out_storage', name: 'materials_in_out_storage',
joinColumn: { name: 'materials_in_out_id', referencedColumnName: 'id' }, joinColumn: { name: 'materials_in_out_id', referencedColumnName: 'id' },

View File

@ -46,7 +46,7 @@ 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.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');
@ -97,11 +97,6 @@ export class MaterialsInOutService {
await manager.update(MaterialsInOutEntity, id, { await manager.update(MaterialsInOutEntity, id, {
...data ...data
}); });
const materialsInOut = await this.materialsInOutRepository
.createQueryBuilder('materialsInOut')
.leftJoinAndSelect('materialsInOut.files', 'files')
.where('materialsInOut.id = :id', { id })
.getOne();
if (fileIds?.length) { if (fileIds?.length) {
const count = await this.storageRepository const count = await this.storageRepository
.createQueryBuilder('storage') .createQueryBuilder('storage')
@ -110,12 +105,12 @@ export class MaterialsInOutService {
if (count !== fileIds?.length) { if (count !== fileIds?.length) {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量更新 // 附件要批量插入
await manager await manager
.createQueryBuilder() .createQueryBuilder()
.relation(MaterialsInOutEntity, 'files') .relation(MaterialsInOutEntity, 'files')
.of(id) .of(id)
.addAndRemove(fileIds, materialsInOut.files); .add(fileIds);
} }
}); });
} }

View File

@ -90,12 +90,12 @@ export class ProductService {
if (count !== fileIds?.length) { if (count !== fileIds?.length) {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量更新 // 附件要批量插入
await manager await manager
.createQueryBuilder() .createQueryBuilder()
.relation(ProductEntity, 'files') .relation(ProductEntity, 'files')
.of(id) .of(id)
.addAndRemove(fileIds, product.files); .add(fileIds);
} }
}); });
} }

View File

@ -69,12 +69,12 @@ export class ProjectService {
if (count !== fileIds?.length) { if (count !== fileIds?.length) {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量更新 // 附件要批量插入
await manager await manager
.createQueryBuilder() .createQueryBuilder()
.relation(ProjectEntity, 'files') .relation(ProjectEntity, 'files')
.of(id) .of(id)
.addAndRemove(fileIds, project.files); .add(fileIds);
} }
}); });
} }

View File

@ -55,7 +55,7 @@ export class Storage extends CommonEntity {
@ApiHideProperty() @ApiHideProperty()
@ManyToMany(() => MaterialsInOutEntity, materialsInOut => materialsInOut.files) @ManyToMany(() => MaterialsInOutEntity, materialsInOut => materialsInOut.files)
materialsInOut: Relation<MaterialsInOutEntity[]>; materialsInOuts: Relation<MaterialsInOutEntity[]>;
@ApiHideProperty() @ApiHideProperty()
@ManyToMany(() => ProductEntity, product => product.files) @ManyToMany(() => ProductEntity, product => product.files)

View File

@ -10,17 +10,22 @@ export class VehicleUsageDto {
@ApiProperty({ description: '外出使用的车辆名称(字典)' }) @ApiProperty({ description: '外出使用的车辆名称(字典)' })
@IsNumber() @IsNumber()
vechicleId: number; vehicleId: number;
@ApiProperty({ description: '申请人' }) @ApiProperty({ description: '申请人' })
@IsString() @IsString()
applicant: string; applicant: string;
@ApiProperty({ description: '出行司机', nullable: true }) @ApiProperty({ description: '出行司机' })
@IsOptional() @IsOptional()
@IsString() @IsString()
driver: string; driver: string;
@ApiProperty({ description: '随行人员' })
@IsOptional()
@IsString()
partner?: string;
@ApiProperty({ description: '当前车辆里程数(KM)' }) @ApiProperty({ description: '当前车辆里程数(KM)' })
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
@ -69,4 +74,8 @@ export class VehicleUsageUpdateDto extends PartialType(VehicleUsageDto) {
export class VehicleUsageQueryDto extends IntersectionType( export class VehicleUsageQueryDto extends IntersectionType(
PagerDto<VehicleUsageDto>, PagerDto<VehicleUsageDto>,
PartialType(VehicleUsageDto) PartialType(VehicleUsageDto)
) {} ) {
@ApiProperty({ description: '车辆名称或者车牌号' })
@IsOptional()
vehicle?: string;
}

View File

@ -12,7 +12,7 @@ export class VehicleUsageEntity extends CommonEntity {
@Column({ name: 'vehicle_id', type: 'int', comment: '外出使用的车辆名称(字典)' }) @Column({ name: 'vehicle_id', type: 'int', comment: '外出使用的车辆名称(字典)' })
@ApiProperty({ description: '外出使用的车辆名称(字典)' }) @ApiProperty({ description: '外出使用的车辆名称(字典)' })
vechicleId: number; vehicleId: number;
@Column({ @Column({
name: 'applicant', name: 'applicant',
@ -27,11 +27,22 @@ export class VehicleUsageEntity extends CommonEntity {
name: 'driver', name: 'driver',
type: 'varchar', type: 'varchar',
length: 50, length: 50,
comment: '出行司机' comment: '出行司机',
nullable: true
}) })
@ApiProperty({ description: '出行司机', nullable: true }) @ApiProperty({ description: '出行司机' })
driver: string; driver: string;
@Column({
name: 'partner',
type: 'varchar',
length: 50,
comment: '随行人员',
nullable: true
})
@ApiProperty({ description: '随行人员' })
partner: string;
@Column({ name: 'current_mileage', type: 'int', comment: '当前车辆里程数(KM)', nullable: true }) @Column({ name: 'current_mileage', type: 'int', comment: '当前车辆里程数(KM)', nullable: true })
@ApiProperty({ description: '当前车辆里程数(KM)' }) @ApiProperty({ description: '当前车辆里程数(KM)' })
currentMileage: number; currentMileage: number;

View File

@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'; import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository } from 'typeorm'; import { EntityManager, Repository, SelectQueryBuilder } from 'typeorm';
import { VehicleUsageEntity } from './vehicle_usage.entity'; import { VehicleUsageEntity } from './vehicle_usage.entity';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { ErrorEnum } from '~/constants/error-code.constant'; import { ErrorEnum } from '~/constants/error-code.constant';
@ -27,15 +27,14 @@ export class VehicleUsageService {
async findAll({ async findAll({
page, page,
pageSize, pageSize,
...fields ...fields
}: VehicleUsageQueryDto): Promise<Pagination<VehicleUsageEntity>> { }: VehicleUsageQueryDto): Promise<Pagination<VehicleUsageEntity>> {
const { ...ext } = fields; const { vehicle, ...ext } = fields;
const sqb = this.vehicleUsageRepository const sqb = this.buildLeftJoinRelations().where(fieldSearch(ext));
.createQueryBuilder('vehicle_usage') if (vehicle) {
.leftJoin('vehicle_usage.files', 'files') sqb.andWhere('vehicle.label like :vehicleName', { vehicleName: `%${vehicle}%` });
.leftJoin('vehicle_usage.vehicle', 'vehicle') }
.addSelect(['files.id', 'files.path', 'vehicle.id', 'vehicle.label'])
.where(fieldSearch(ext))
return paginate<VehicleUsageEntity>(sqb, { return paginate<VehicleUsageEntity>(sqb, {
page, page,
pageSize pageSize
@ -81,12 +80,12 @@ export class VehicleUsageService {
if (count !== fileIds?.length) { if (count !== fileIds?.length) {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量更新 // 附件要批量插入
await manager await manager
.createQueryBuilder() .createQueryBuilder()
.relation(VehicleUsageEntity, 'files') .relation(VehicleUsageEntity, 'files')
.of(id) .of(id)
.addAndRemove(fileIds, vehicleUsage.files); .add(fileIds);
} }
}); });
} }
@ -102,14 +101,10 @@ export class VehicleUsageService {
* *
*/ */
async info(id: number) { async info(id: number) {
const info = await this.vehicleUsageRepository const info = this.buildLeftJoinRelations()
.createQueryBuilder('vehicle_usage')
.leftJoin('vehicle_usage.company', 'company')
.addSelect(['company.name', 'company.id'])
.where({ .where({
id id
}) })
.andWhere('vehicle_usage.isDelete = 0')
.getOne(); .getOne();
return info; return info;
} }
@ -137,4 +132,15 @@ export class VehicleUsageService {
.addAndRemove(linkedFiles, vehicle_usage.files); .addAndRemove(linkedFiles, vehicle_usage.files);
}); });
} }
/**
*
*/
buildLeftJoinRelations() {
return this.vehicleUsageRepository
.createQueryBuilder('vehicle_usage')
.leftJoin('vehicle_usage.files', 'files')
.leftJoin('vehicle_usage.vehicle', 'vehicle')
.addSelect(['files.id', 'files.path', 'vehicle.id', 'vehicle.label']);
}
} }