feat: Domain develop

This commit is contained in:
louis 2024-04-16 14:06:02 +08:00
parent 8ad1a48c60
commit cd32cc1ac0
33 changed files with 334 additions and 61 deletions

View File

@ -31,6 +31,7 @@ import { ProductModule } from './modules/product/product.module';
import { ProjectModule } from './modules/project/project.module'; import { ProjectModule } from './modules/project/project.module';
import { VehicleUsageModule } from './modules/vehicle_usage/vehicle_usage.module'; import { VehicleUsageModule } from './modules/vehicle_usage/vehicle_usage.module';
import { SaleQuotationModule } from './modules/sale_quotation/sale_quotation.module'; import { SaleQuotationModule } from './modules/sale_quotation/sale_quotation.module';
import { DomainModule } from './modules/domian/domain.module';
@Module({ @Module({
imports: [ imports: [
@ -77,7 +78,9 @@ import { SaleQuotationModule } from './modules/sale_quotation/sale_quotation.mod
VehicleUsageModule, VehicleUsageModule,
//报价管理 //报价管理
SaleQuotationModule SaleQuotationModule,
//域
DomainModule
], ],
providers: [ providers: [
{ provide: APP_FILTER, useClass: AllExceptionsFilter }, { provide: APP_FILTER, useClass: AllExceptionsFilter },

View File

@ -0,0 +1,18 @@
import { ExecutionContext, createParamDecorator } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional } from 'class-validator';
import type { FastifyRequest } from 'fastify';
/**
*
*/
export const Domain = createParamDecorator((_, context: ExecutionContext) => {
const request = context.switchToHttp().getRequest<FastifyRequest>();
return request.headers['sk-domain'];
});
export type SkDomain = number;
export class DomainType {
@ApiProperty({ description: '所属域' })
@IsOptional()
domain: SkDomain;
}

View File

@ -5,6 +5,7 @@ import type { FastifyRequest } from 'fastify';
import { getIp, getIsMobile } from '~/utils/ip.util'; import { getIp, getIsMobile } from '~/utils/ip.util';
/** /**
* IP * IP
*/ */

View File

@ -65,6 +65,8 @@ export enum ErrorEnum {
// SaleQuotation // SaleQuotation
SALE_QUOTATION_COMPONENT_DUPLICATED = '1412:存在名称,价格,规格都相同的配件,请检查是否重复录入', SALE_QUOTATION_COMPONENT_DUPLICATED = '1412:存在名称,价格,规格都相同的配件,请检查是否重复录入',
SALE_QUOTATION_TEMPLATE_NAME_DUPLICATE = '1413:模板名已存在' SALE_QUOTATION_TEMPLATE_NAME_DUPLICATE = '1413:模板名已存在',
//domain
DOMAIN_TITLE_DUPLICATE = '1414:域标题已存在'
} }

View File

@ -14,6 +14,7 @@ import { LoginToken } from './models/auth.model';
import { CaptchaService } from './services/captcha.service'; import { CaptchaService } from './services/captcha.service';
import { AuthUser } from './decorators/auth-user.decorator'; import { AuthUser } from './decorators/auth-user.decorator';
import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator'; import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator';
@ApiTags('Auth - 认证模块') @ApiTags('Auth - 认证模块')
@UseGuards(LocalGuard) @UseGuards(LocalGuard)
@ -35,7 +36,7 @@ export class AuthController {
@IsMobile() isMobile: boolean, @IsMobile() isMobile: boolean,
@Headers('user-agent') ua: string @Headers('user-agent') ua: string
): Promise<LoginToken> { ): Promise<LoginToken> {
if(!isMobile){ if (!isMobile) {
await this.captchaService.checkImgCaptcha(dto.captchaId, dto.verifyCode); await this.captchaService.checkImgCaptcha(dto.captchaId, dto.verifyCode);
} }
const token = await this.authService.login(dto.username, dto.password, ip, ua); const token = await this.authService.login(dto.username, dto.password, ip, ua);
@ -53,7 +54,7 @@ export class AuthController {
@Post('register') @Post('register')
@ApiOperation({ summary: '注册' }) @ApiOperation({ summary: '注册' })
async register(@Body() dto: RegisterDto): Promise<void> { async register(@Domain() domain: SkDomain, @Body() dto: RegisterDto): Promise<void> {
await this.userService.register(dto); await this.userService.register(dto, domain);
} }
} }

View File

@ -16,6 +16,7 @@ import { AccountMenus, AccountUpdateDto } from '../dto/account.dto';
import { JwtAuthGuard } from '../guards/jwt-auth.guard'; import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { IsMobile } from '~/common/decorators/http.decorator'; import { IsMobile } from '~/common/decorators/http.decorator';
import { ResourceDeviceEnum } from '~/constants/enum'; import { ResourceDeviceEnum } from '~/constants/enum';
import { Domain } from '~/common/decorators/domain.decorator';
@ApiTags('Account - 账户模块') @ApiTags('Account - 账户模块')
@ApiSecurityAuth() @ApiSecurityAuth()

View File

@ -16,6 +16,7 @@ import { ApiResult } from '~/common/decorators/api-result.decorator';
import { CompanyEntity } from './company.entity'; import { CompanyEntity } from './company.entity';
import { CompanyDto, CompanyQueryDto, CompanyUpdateDto } from './company.dto'; import { CompanyDto, CompanyQueryDto, CompanyUpdateDto } from './company.dto';
import { IdParam } from '~/common/decorators/id-param.decorator'; import { IdParam } from '~/common/decorators/id-param.decorator';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('app:company', { export const permissions = definePermission('app:company', {
LIST: 'list', LIST: 'list',
CREATE: 'create', CREATE: 'create',
@ -34,8 +35,8 @@ export class CompanyController {
@ApiOperation({ summary: '获取公司列表' }) @ApiOperation({ summary: '获取公司列表' })
@ApiResult({ type: [CompanyEntity], isPage: true }) @ApiResult({ type: [CompanyEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: CompanyQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: CompanyQueryDto) {
return this.companyService.findAll(dto); return this.companyService.findAll({ ...dto, domain });
} }
@Get(':id') @Get(':id')
@ -49,8 +50,8 @@ export class CompanyController {
@Post() @Post()
@ApiOperation({ summary: '新增公司' }) @ApiOperation({ summary: '新增公司' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: CompanyDto): Promise<void> { async create(@Domain() domain: SkDomain, @Body() dto: CompanyDto): Promise<void> {
await this.companyService.create(dto); await this.companyService.create({ ...dto, domain });
} }
@Put(':id') @Put(':id')

View File

@ -15,8 +15,9 @@ import { PagerDto } from '~/common/dto/pager.dto';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { IsUnique } from '~/shared/database/constraints/unique.constraint'; import { IsUnique } from '~/shared/database/constraints/unique.constraint';
import { CompanyEntity } from './company.entity'; import { CompanyEntity } from './company.entity';
import { DomainType, SkDomain } from '~/common/decorators/domain.decorator';
export class CompanyDto { export class CompanyDto extends DomainType {
@ApiProperty({ description: '公司名称' }) @ApiProperty({ description: '公司名称' })
@IsUnique(CompanyEntity, { message: '已存在同名公司' }) @IsUnique(CompanyEntity, { message: '已存在同名公司' })
@IsString() @IsString()
@ -42,7 +43,8 @@ export class ComapnyCreateDto extends PartialType(CompanyDto) {
export class CompanyQueryDto extends IntersectionType( export class CompanyQueryDto extends IntersectionType(
PagerDto<CompanyDto>, PagerDto<CompanyDto>,
PartialType(CompanyDto) PartialType(CompanyDto),
DomainType
) { ) {
@ApiProperty({ description: '公司名称' }) @ApiProperty({ description: '公司名称' })
@IsOptional() @IsOptional()

View File

@ -3,6 +3,7 @@ import { Column, Entity, JoinTable, ManyToMany, OneToMany, Relation } from 'type
import { CommonEntity } from '~/common/entity/common.entity'; import { CommonEntity } from '~/common/entity/common.entity';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { ProductEntity } from '../product/product.entity'; import { ProductEntity } from '../product/product.entity';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Entity({ name: 'company' }) @Entity({ name: 'company' })
export class CompanyEntity extends CommonEntity { export class CompanyEntity extends CommonEntity {
@ -20,6 +21,10 @@ export class CompanyEntity extends CommonEntity {
@ApiProperty({ description: '删除状态0未删除1已删除' }) @ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number; isDelete: number;
@Column({ type: 'int', default: 1, comment: '所属域' })
@ApiProperty({ description: '所属域' })
domain: SkDomain;
@ApiHideProperty() @ApiHideProperty()
@OneToMany(() => ProductEntity, product => product.company) @OneToMany(() => ProductEntity, product => product.company)
products: Relation<ProductEntity[]>; products: Relation<ProductEntity[]>;

View File

@ -9,6 +9,7 @@ import { Storage } from '../tools/storage/storage.entity';
import { BusinessException } from '~/common/exceptions/biz.exception'; import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant'; import { ErrorEnum } from '~/constants/error-code.constant';
import { fieldSearch } from '~/shared/database/field-search'; import { fieldSearch } from '~/shared/database/field-search';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Injectable() @Injectable()
export class CompanyService { export class CompanyService {
@ -70,11 +71,7 @@ export class CompanyService {
throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND);
} }
// 附件要批量插入 // 附件要批量插入
await manager await manager.createQueryBuilder().relation(CompanyEntity, 'files').of(id).add(fileIds);
.createQueryBuilder()
.relation(CompanyEntity, 'files')
.of(id)
.add(fileIds);
} }
}); });
} }

View File

@ -16,6 +16,7 @@ import { ApiResult } from '~/common/decorators/api-result.decorator';
import { ContractEntity } from './contract.entity'; import { ContractEntity } from './contract.entity';
import { ContractDto, ContractQueryDto, ContractUpdateDto } from './contract.dto'; import { ContractDto, ContractQueryDto, ContractUpdateDto } from './contract.dto';
import { IdParam } from '~/common/decorators/id-param.decorator'; import { IdParam } from '~/common/decorators/id-param.decorator';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('app:contract', { export const permissions = definePermission('app:contract', {
LIST: 'list', LIST: 'list',
CREATE: 'create', CREATE: 'create',
@ -34,8 +35,8 @@ export class ContractController {
@ApiOperation({ summary: '获取合同列表' }) @ApiOperation({ summary: '获取合同列表' })
@ApiResult({ type: [ContractEntity], isPage: true }) @ApiResult({ type: [ContractEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: ContractQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: ContractQueryDto) {
return this.contractService.findAll(dto); return this.contractService.findAll({ ...dto, domain });
} }
@Get(':id') @Get(':id')
@ -49,8 +50,8 @@ export class ContractController {
@Post() @Post()
@ApiOperation({ summary: '新增合同' }) @ApiOperation({ summary: '新增合同' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: ContractDto): Promise<void> { async create(@Domain() domain: SkDomain, @Body() dto: ContractDto): Promise<void> {
await this.contractService.create(dto); await this.contractService.create({ ...dto, domain });
} }
@Put(':id') @Put(':id')
@ -70,8 +71,10 @@ export class ContractController {
@Put('unlink-attachments/:id') @Put('unlink-attachments/:id')
@ApiOperation({ summary: '附件解除关联' }) @ApiOperation({ summary: '附件解除关联' })
@Perm(permissions.UPDATE) @Perm(permissions.UPDATE)
async unlinkAttachments(@IdParam() id: number, @Body() {fileIds}: ContractUpdateDto): Promise<void> { async unlinkAttachments(
@IdParam() id: number,
@Body() { fileIds }: ContractUpdateDto
): Promise<void> {
await this.contractService.unlinkAttachments(id, fileIds); await this.contractService.unlinkAttachments(id, fileIds);
} }
} }

View File

@ -15,8 +15,9 @@ import {
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'; import { ContractStatusEnum } from '~/constants/enum';
import { DomainType, SkDomain } from '~/common/decorators/domain.decorator';
export class ContractDto { export class ContractDto extends DomainType {
@ApiProperty({ description: '合同编号' }) @ApiProperty({ description: '合同编号' })
@Matches(/^[a-z0-9A-Z]+$/, { message: '合同编号只能包含字母和数字' }) @Matches(/^[a-z0-9A-Z]+$/, { message: '合同编号只能包含字母和数字' })
@IsString() @IsString()
@ -65,5 +66,7 @@ export class ContractUpdateDto extends PartialType(ContractDto) {
} }
export class ContractQueryDto extends IntersectionType( export class ContractQueryDto extends IntersectionType(
PagerDto<ContractDto>, PagerDto<ContractDto>,
PartialType(ContractDto) PartialType(ContractDto),
DomainType
) {} ) {}

View File

@ -2,6 +2,7 @@ import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
import { Column, Entity, JoinTable, ManyToMany, Relation } from 'typeorm'; import { Column, Entity, JoinTable, ManyToMany, Relation } from 'typeorm';
import { CommonEntity } from '~/common/entity/common.entity'; import { CommonEntity } from '~/common/entity/common.entity';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Entity({ name: 'contract' }) @Entity({ name: 'contract' })
export class ContractEntity extends CommonEntity { export class ContractEntity extends CommonEntity {
@ -47,6 +48,10 @@ export class ContractEntity extends CommonEntity {
@ApiProperty({ description: '删除状态0未删除1已删除' }) @ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number; isDelete: number;
@Column({ type: 'int', default: 1, comment: '所属域' })
@ApiProperty({ description: '所属域' })
domain: SkDomain;
@ManyToMany(() => Storage, storage => storage.contracts) @ManyToMany(() => Storage, storage => storage.contracts)
@JoinTable({ @JoinTable({
name: 'contract_storage', name: 'contract_storage',

View File

@ -10,6 +10,7 @@ import { Storage } from '../tools/storage/storage.entity';
import { BusinessException } from '~/common/exceptions/biz.exception'; import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant'; import { ErrorEnum } from '~/constants/error-code.constant';
import { fieldSearch } from '~/shared/database/field-search'; import { fieldSearch } from '~/shared/database/field-search';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Injectable() @Injectable()
export class ContractService { export class ContractService {

View File

@ -0,0 +1,69 @@
import {
Body,
Controller,
Get,
Query,
Put,
Delete,
Post,
BadRequestException
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Perm, definePermission } from '../auth/decorators/permission.decorator';
import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator';
import { DomainService } from './domain.service';
import { ApiResult } from '~/common/decorators/api-result.decorator';
import { DomainEntity } from './domain.entity';
import { DomainDto, DomainQueryDto, DomainUpdateDto } from './domain.dto';
import { IdParam } from '~/common/decorators/id-param.decorator';
export const permissions = definePermission('app:domain', {
LIST: 'list',
CREATE: 'create',
READ: 'read',
UPDATE: 'update',
DELETE: 'delete'
} as const);
@ApiTags('Domain - 域')
@ApiSecurityAuth()
@Controller('domain')
export class DomainController {
constructor(private domainService: DomainService) {}
@Get()
@ApiOperation({ summary: '获取域列表' })
@ApiResult({ type: [DomainEntity], isPage: true })
@Perm(permissions.LIST)
async list(@Query() dto: DomainQueryDto) {
return this.domainService.findAll(dto);
}
@Get(':id')
@ApiOperation({ summary: '获取域信息' })
@ApiResult({ type: DomainDto })
@Perm(permissions.READ)
async info(@IdParam() id: number) {
return this.domainService.info(id);
}
@Post()
@ApiOperation({ summary: '新增域' })
@Perm(permissions.CREATE)
async create(@Body() dto: DomainDto): Promise<void> {
await this.domainService.create(dto);
}
@Put(':id')
@ApiOperation({ summary: '更新域' })
@Perm(permissions.UPDATE)
async update(@IdParam() id: number, @Body() dto: DomainUpdateDto): Promise<void> {
await this.domainService.update(id, dto);
}
@Delete(':id')
@ApiOperation({ summary: '删除域' })
@Perm(permissions.DELETE)
async delete(@IdParam() id: number): Promise<void> {
await this.domainService.delete(id);
}
}

View File

@ -0,0 +1,12 @@
import { ApiProperty, IntersectionType, PartialType } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { PagerDto } from '~/common/dto/pager.dto';
export class DomainDto {
@ApiProperty({ description: '域标题' })
@IsString()
title: string;
}
export class DomainUpdateDto extends PartialType(DomainDto) {}
export class DomainQueryDto extends IntersectionType(PagerDto<DomainDto>, PartialType(DomainDto)) {}

View File

@ -0,0 +1,15 @@
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
import { Column, Entity, JoinTable, ManyToMany, Relation } from 'typeorm';
import { CommonEntity } from '~/common/entity/common.entity';
import { Storage } from '../tools/storage/storage.entity';
@Entity({ name: 'domain' })
export class DomainEntity extends CommonEntity {
@Column({ name: 'title', type: 'varchar', length: 255, comment: '域标题' })
@ApiProperty({ description: '域标题' })
title: string;
@Column({ name: 'is_delete', type: 'tinyint', default: 0, comment: '是否删除' })
@ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number;
}

View File

@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { DomainController } from './domain.controller';
import { DomainService } from './domain.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DomainEntity } from './domain.entity';
@Module({
imports: [TypeOrmModule.forFeature([DomainEntity])],
controllers: [DomainController],
providers: [DomainService]
})
export class DomainModule {}

View File

@ -0,0 +1,95 @@
import { Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { DomainEntity } from './domain.entity';
import { EntityManager, Like, Not, Repository } from 'typeorm';
import { DomainDto, DomainQueryDto, DomainUpdateDto } from './domain.dto';
import { Pagination } from '~/helper/paginate/pagination';
import { isNumber } from 'lodash';
import { paginate } from '~/helper/paginate';
import { Storage } from '../tools/storage/storage.entity';
import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant';
import { fieldSearch } from '~/shared/database/field-search';
@Injectable()
export class DomainService {
constructor(
@InjectEntityManager() private entityManager: EntityManager,
@InjectRepository(DomainEntity)
private domainRepository: Repository<DomainEntity>
) {}
/**
*
*/
async findAll({ page, pageSize, ...fields }: DomainQueryDto): Promise<Pagination<DomainEntity>> {
const queryBuilder = this.domainRepository
.createQueryBuilder('domain')
.where(fieldSearch(fields))
.andWhere('domain.isDelete = 0');
return paginate<DomainEntity>(queryBuilder, {
page,
pageSize
});
}
/**
*
*/
async create({ title, ...ext }: DomainDto): Promise<void> {
if (await this.checkIsDomainExsit(title)) {
throw new BusinessException(ErrorEnum.DOMAIN_TITLE_DUPLICATE);
}
await this.domainRepository.insert(this.domainRepository.create({ title, ...ext }));
}
/**
*
*/
async update(id: number, { title, ...ext }: Partial<DomainUpdateDto>): Promise<void> {
await this.entityManager.transaction(async manager => {
if (title && (await this.checkIsDomainExsit(title, id))) {
throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST);
}
await manager.update(DomainEntity, id, {
...ext,
title
});
});
}
/**
*
* @param title
*/
async checkIsDomainExsit(title: string, id?: number): Promise<Boolean> {
return !!(await this.domainRepository.findOne({
where: {
title: title,
id: Not(id)
}
}));
}
/**
*
*/
async delete(id: number): Promise<void> {
// 域比较重要,做逻辑删除
await this.domainRepository.update(id, { isDelete: 1 });
}
/**
*
*/
async info(id: number) {
const info = await this.domainRepository
.createQueryBuilder('domain')
.where({
id
})
.andWhere('domain.isDelete = 0')
.getOne();
return info;
}
}

View File

@ -11,6 +11,7 @@ import {
MaterialsInOutDto, MaterialsInOutDto,
MaterialsInOutUpdateDto MaterialsInOutUpdateDto
} from './materials_in_out.dto'; } from './materials_in_out.dto';
import { Domain, DomainType, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('materials_inventory:history_in_out', { export const permissions = definePermission('materials_inventory:history_in_out', {
LIST: 'list', LIST: 'list',
@ -29,8 +30,8 @@ export class MaterialsInOutController {
@ApiOperation({ summary: '获取原材料出入库记录列表' }) @ApiOperation({ summary: '获取原材料出入库记录列表' })
@ApiResult({ type: [MaterialsInOutEntity], isPage: true }) @ApiResult({ type: [MaterialsInOutEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: MaterialsInOutQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: MaterialsInOutQueryDto) {
return this.materialsInOutService.findAll(dto); return this.materialsInOutService.findAll({ ...dto, domain });
} }
@Get(':id') @Get(':id')
@ -44,8 +45,8 @@ export class MaterialsInOutController {
@Post() @Post()
@ApiOperation({ summary: '新增原材料出入库记录' }) @ApiOperation({ summary: '新增原材料出入库记录' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: MaterialsInOutDto): Promise<number> { async create(@Domain() domain: SkDomain, @Body() dto: MaterialsInOutDto): Promise<number> {
return this.materialsInOutService.create(dto); return this.materialsInOutService.create({ ...dto, domain });
} }
@Put(':id') @Put(':id')

View File

@ -17,12 +17,13 @@ import {
isNumber isNumber
} from 'class-validator'; } from 'class-validator';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { DomainType } from '~/common/decorators/domain.decorator';
import { PagerDto } from '~/common/dto/pager.dto'; import { PagerDto } from '~/common/dto/pager.dto';
import { MaterialsInOrOutEnum } from '~/constants/enum'; import { MaterialsInOrOutEnum } from '~/constants/enum';
import { Storage } from '~/modules/tools/storage/storage.entity'; import { Storage } from '~/modules/tools/storage/storage.entity';
import { formatToDate } from '~/utils'; import { formatToDate } from '~/utils';
export class MaterialsInOutDto { export class MaterialsInOutDto extends DomainType {
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
@ApiProperty({ description: '项目Id' }) @ApiProperty({ description: '项目Id' })
@ -100,7 +101,10 @@ export class MaterialsInOutUpdateDto extends PartialType(MaterialsInOutDto) {
@IsArray() @IsArray()
fileIds: number[]; fileIds: number[];
} }
export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutQueryDto> { export class MaterialsInOutQueryDto extends IntersectionType(
PagerDto<MaterialsInOutQueryDto>,
DomainType
) {
@ApiProperty({ description: '出入库时间YYYY-MM-DD' }) @ApiProperty({ description: '出入库时间YYYY-MM-DD' })
@IsOptional() @IsOptional()
// @IsString() // @IsString()

View File

@ -20,6 +20,7 @@ import { ProjectEntity } from '~/modules/project/project.entity';
import { ParamConfigEntity } from '~/modules/system/param-config/param-config.entity'; import { ParamConfigEntity } from '~/modules/system/param-config/param-config.entity';
import { Storage } from '~/modules/tools/storage/storage.entity'; import { Storage } from '~/modules/tools/storage/storage.entity';
import { MaterialsInventoryEntity } from '../materials_inventory.entity'; import { MaterialsInventoryEntity } from '../materials_inventory.entity';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Entity({ name: 'materials_in_out' }) @Entity({ name: 'materials_in_out' })
export class MaterialsInOutEntity extends CommonEntity { export class MaterialsInOutEntity extends CommonEntity {
@Column({ @Column({
@ -129,6 +130,10 @@ export class MaterialsInOutEntity extends CommonEntity {
@JoinColumn({ name: 'product_id' }) @JoinColumn({ name: 'product_id' })
product: ProductEntity; product: ProductEntity;
@Column({ type: 'int', default: 1, comment: '所属域' })
@ApiProperty({ description: '所属域' })
domain: SkDomain;
@ManyToMany(() => Storage, storage => storage.materialsInOuts) @ManyToMany(() => Storage, storage => storage.materialsInOuts)
@JoinTable({ @JoinTable({
name: 'materials_in_out_storage', name: 'materials_in_out_storage',

View File

@ -13,6 +13,7 @@ import { MaterialsInventoryService } from './materials_inventory.service';
import { MaterialsInventoryEntity } from './materials_inventory.entity'; import { MaterialsInventoryEntity } from './materials_inventory.entity';
import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator'; import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import { Domain, DomainType, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('app:materials_inventory', { export const permissions = definePermission('app:materials_inventory', {
LIST: 'list', LIST: 'list',
@ -33,10 +34,11 @@ export class MaterialsInventoryController {
@ApiOperation({ summary: '导出原材料盘点表' }) @ApiOperation({ summary: '导出原材料盘点表' })
@Perm(permissions.EXPORT) @Perm(permissions.EXPORT)
async exportMaterialsInventoryCheck( async exportMaterialsInventoryCheck(
@Domain() domain: SkDomain,
@Query() dto: MaterialsInventoryExportDto, @Query() dto: MaterialsInventoryExportDto,
@Res() res: FastifyReply @Res() res: FastifyReply
): Promise<void> { ): Promise<void> {
await this.miService.exportMaterialsInventoryCheck(dto, res); await this.miService.exportMaterialsInventoryCheck({ ...dto, domain }, res);
} }
@Get() @Get()

View File

@ -18,13 +18,15 @@ import { Transform } from 'class-transformer';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { formatToDate } from '~/utils'; import { formatToDate } from '~/utils';
import { HasInventoryStatusEnum } from '~/constants/enum'; import { HasInventoryStatusEnum } from '~/constants/enum';
import { DomainType } from '~/common/decorators/domain.decorator';
export class MaterialsInventoryDto {} export class MaterialsInventoryDto extends DomainType {}
export class MaterialsInventoryUpdateDto extends PartialType(MaterialsInventoryDto) {} export class MaterialsInventoryUpdateDto extends PartialType(MaterialsInventoryDto) {}
export class MaterialsInventoryQueryDto extends IntersectionType( export class MaterialsInventoryQueryDto extends IntersectionType(
PagerDto<MaterialsInventoryDto>, PagerDto<MaterialsInventoryDto>,
PartialType(MaterialsInventoryDto) PartialType(MaterialsInventoryDto),
DomainType
) { ) {
@ApiProperty({ description: '产品名' }) @ApiProperty({ description: '产品名' })
@IsOptional() @IsOptional()
@ -46,7 +48,7 @@ export class MaterialsInventoryQueryDto extends IntersectionType(
@IsNumber() @IsNumber()
projectId: number; projectId: number;
} }
export class MaterialsInventoryExportDto { export class MaterialsInventoryExportDto extends DomainType {
@ApiProperty({ description: '项目' }) @ApiProperty({ description: '项目' })
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()

View File

@ -13,6 +13,7 @@ import { CommonEntity } from '~/common/entity/common.entity';
import { ProductEntity } from '../product/product.entity'; import { ProductEntity } from '../product/product.entity';
import { ProjectEntity } from '../project/project.entity'; import { ProjectEntity } from '../project/project.entity';
import { MaterialsInOutEntity } from './in_out/materials_in_out.entity'; import { MaterialsInOutEntity } from './in_out/materials_in_out.entity';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Entity({ name: 'materials_inventory' }) @Entity({ name: 'materials_inventory' })
export class MaterialsInventoryEntity extends CommonEntity { export class MaterialsInventoryEntity extends CommonEntity {
@ -70,6 +71,10 @@ export class MaterialsInventoryEntity extends CommonEntity {
@ApiProperty({ description: '删除状态0未删除1已删除' }) @ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number; isDelete: number;
@Column({ type: 'int', default: 1, comment: '所属域' })
@ApiProperty({ description: '所属域' })
domain: SkDomain;
@ManyToOne(() => ProjectEntity) @ManyToOne(() => ProjectEntity)
@JoinColumn({ name: 'project_id' }) @JoinColumn({ name: 'project_id' })
project: ProjectEntity; project: ProjectEntity;

View File

@ -41,7 +41,7 @@ export class MaterialsInventoryService {
* *
*/ */
async exportMaterialsInventoryCheck( async exportMaterialsInventoryCheck(
{ time, projectId }: MaterialsInventoryExportDto, { time, projectId, domain }: MaterialsInventoryExportDto,
res: FastifyReply res: FastifyReply
): Promise<void> { ): Promise<void> {
const ROW_HEIGHT = 20; const ROW_HEIGHT = 20;

View File

@ -16,6 +16,7 @@ import { ApiResult } from '~/common/decorators/api-result.decorator';
import { ProductEntity } from './product.entity'; import { ProductEntity } from './product.entity';
import { ProductDto, ProductQueryDto, ProductUpdateDto } from './product.dto'; import { ProductDto, ProductQueryDto, ProductUpdateDto } from './product.dto';
import { IdParam } from '~/common/decorators/id-param.decorator'; import { IdParam } from '~/common/decorators/id-param.decorator';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('app:product', { export const permissions = definePermission('app:product', {
LIST: 'list', LIST: 'list',
CREATE: 'create', CREATE: 'create',
@ -34,8 +35,8 @@ export class ProductController {
@ApiOperation({ summary: '获取产品列表' }) @ApiOperation({ summary: '获取产品列表' })
@ApiResult({ type: [ProductEntity], isPage: true }) @ApiResult({ type: [ProductEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: ProductQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: ProductQueryDto) {
return this.productService.findAll(dto); return this.productService.findAll({ ...dto, domain });
} }
@Get(':id') @Get(':id')
@ -49,8 +50,8 @@ export class ProductController {
@Post() @Post()
@ApiOperation({ summary: '新增产品' }) @ApiOperation({ summary: '新增产品' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: ProductDto): Promise<void> { async create(@Domain() domain: SkDomain, @Body() dto: ProductDto): Promise<void> {
await this.productService.create(dto); await this.productService.create({ ...dto, domain });
} }
@Put(':id') @Put(':id')

View File

@ -2,13 +2,13 @@ import { ApiProperty, IntersectionType, PartialType } from '@nestjs/swagger';
import { IsArray, IsNumber, IsOptional, IsString } from 'class-validator'; import { IsArray, IsNumber, IsOptional, IsString } 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 { DomainType } from '~/common/decorators/domain.decorator';
export class ProductDto { export class ProductDto extends DomainType {
@ApiProperty({ description: '产品名称' }) @ApiProperty({ description: '产品名称' })
@IsString() @IsString()
name: string; name: string;
@ApiProperty({ description: '产品规格' }) @ApiProperty({ description: '产品规格' })
@IsOptional() @IsOptional()
@IsString() @IsString()
@ -42,7 +42,8 @@ export class ProductUpdateDto extends PartialType(ProductDto) {
export class ProductQueryDto extends IntersectionType( export class ProductQueryDto extends IntersectionType(
PagerDto<ProductDto>, PagerDto<ProductDto>,
PartialType(ProductDto) PartialType(ProductDto),
DomainType
) { ) {
@ApiProperty({ description: '所属公司名称' }) @ApiProperty({ description: '所属公司名称' })
@IsOptional() @IsOptional()
@ -58,5 +59,4 @@ export class ProductQueryDto extends IntersectionType(
@IsOptional() @IsOptional()
@IsString() @IsString()
keyword?: string; keyword?: string;
} }

View File

@ -15,6 +15,7 @@ import { Storage } from '../tools/storage/storage.entity';
import { CompanyEntity } from '../company/company.entity'; import { CompanyEntity } from '../company/company.entity';
import pinyin from 'pinyin'; import pinyin from 'pinyin';
import { DictItemEntity } from '../system/dict-item/dict-item.entity'; import { DictItemEntity } from '../system/dict-item/dict-item.entity';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Entity({ name: 'product' }) @Entity({ name: 'product' })
export class ProductEntity extends CommonEntity { export class ProductEntity extends CommonEntity {
@Column({ @Column({
@ -71,6 +72,10 @@ export class ProductEntity extends CommonEntity {
@JoinColumn({ name: 'unit_id' }) @JoinColumn({ name: 'unit_id' })
unit: DictItemEntity; unit: DictItemEntity;
@Column({ type: 'int', default: 1, comment: '所属域' })
@ApiProperty({ description: '所属域' })
domain: SkDomain;
@ApiHideProperty() @ApiHideProperty()
@Column({ @Column({
name: 'name_pinyin', name: 'name_pinyin',

View File

@ -22,6 +22,7 @@ import { UserPasswordDto } from './dto/password.dto';
import { UserDto, UserQueryDto, UserUpdateDto } from './dto/user.dto'; import { UserDto, UserQueryDto, UserUpdateDto } from './dto/user.dto';
import { UserEntity } from './user.entity'; import { UserEntity } from './user.entity';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('system:user', { export const permissions = definePermission('system:user', {
LIST: 'list', LIST: 'list',
@ -47,8 +48,8 @@ export class UserController {
@ApiOperation({ summary: '获取用户列表' }) @ApiOperation({ summary: '获取用户列表' })
@ApiResult({ type: [UserEntity], isPage: true }) @ApiResult({ type: [UserEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: UserQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: UserQueryDto) {
return this.userService.list(dto); return this.userService.list(dto, domain);
} }
@Get(':id') @Get(':id')

View File

@ -13,6 +13,7 @@ import {
OneToMany, OneToMany,
Relation Relation
} from 'typeorm'; } from 'typeorm';
import { SkDomain } from '~/common/decorators/domain.decorator';
import { CommonEntity } from '~/common/entity/common.entity'; import { CommonEntity } from '~/common/entity/common.entity';
@ -73,6 +74,9 @@ export class UserEntity extends CommonEntity {
@Column({ type: 'tinyint', nullable: true, default: 1 }) @Column({ type: 'tinyint', nullable: true, default: 1 })
status: number; status: number;
@Column({ type: 'int', default: 1, comment: '所属域' })
domain: SkDomain;
@ManyToMany(() => RoleEntity, role => role.users) @ManyToMany(() => RoleEntity, role => role.users)
@JoinTable({ @JoinTable({
name: 'sys_user_roles', name: 'sys_user_roles',

View File

@ -28,6 +28,7 @@ import { PasswordUpdateDto } from './dto/password.dto';
import { UserDto, UserQueryDto, UserUpdateDto } from './dto/user.dto'; import { UserDto, UserQueryDto, UserUpdateDto } from './dto/user.dto';
import { UserEntity } from './user.entity'; import { UserEntity } from './user.entity';
import { AccountInfo } from './user.model'; import { AccountInfo } from './user.model';
import { SkDomain } from '~/common/decorators/domain.decorator';
@Injectable() @Injectable()
export class UserService { export class UserService {
@ -243,16 +244,10 @@ export class UserService {
/** /**
* *
*/ */
async list({ async list(
page, { page, pageSize, username, nickname, deptId, email, status, keyword }: UserQueryDto,
pageSize, domain: SkDomain
username, ): Promise<Pagination<UserEntity>> {
nickname,
deptId,
email,
status,
keyword
}: UserQueryDto): Promise<Pagination<UserEntity>> {
const queryBuilder = this.userRepository const queryBuilder = this.userRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.leftJoinAndSelect('user.dept', 'dept') .leftJoinAndSelect('user.dept', 'dept')
@ -337,7 +332,7 @@ export class UserService {
/** /**
* *
*/ */
async register({ username, ...data }: RegisterDto): Promise<void> { async register({ username, ...data }: RegisterDto, domain: SkDomain): Promise<void> {
const exists = await this.userRepository.findOneBy({ const exists = await this.userRepository.findOneBy({
username username
}); });
@ -352,7 +347,8 @@ export class UserService {
username, username,
password, password,
status: 1, status: 1,
psalt: salt psalt: salt,
domain
}); });
const user = await manager.save(u); const user = await manager.save(u);

View File

@ -1,5 +1,6 @@
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { Between, Like, ObjectLiteral, ObjectType } from 'typeorm'; import { Between, Like, ObjectLiteral } from 'typeorm';
import { SkDomain } from '~/common/decorators/domain.decorator';
export const fieldSearch = <T>(entity: Partial<T>): ObjectLiteral => { export const fieldSearch = <T>(entity: Partial<T>): ObjectLiteral => {
let result = {}; let result = {};
for (let key in entity) { for (let key in entity) {