Files
invest-mind-store/apps/api/src/modules/position-change/position-change.service.ts
2026-01-13 16:46:18 +08:00

150 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Injectable,
NotFoundException,
ForbiddenException,
Logger,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { PositionChange } from './position-change.entity';
import { CreatePositionChangeDto } from './dto/create-position-change.dto';
import { UpdatePositionChangeDto } from './dto/update-position-change.dto';
import { QueryPositionChangeDto } from './dto/query-position-change.dto';
import { PaginationInfo } from '@/common/dto/pagination.dto';
import { Position } from '../position/position.entity';
@Injectable()
export class PositionChangeService {
private readonly logger = new Logger(PositionChangeService.name);
constructor(
@InjectRepository(PositionChange)
private readonly positionChangeRepository: Repository<PositionChange>,
@InjectRepository(Position)
private readonly positionRepository: Repository<Position>,
) {}
/**
* 分页查询单个持仓的所有变更记录
*/
async findAllByPositionId(
positionId: number,
userId: number,
queryDto: QueryPositionChangeDto,
): Promise<{
list: PositionChange[];
pagination: PaginationInfo;
}> {
// 验证持仓是否属于当前用户
const position = await this.positionRepository.findOne({
where: { positionId, userId },
});
if (!position) {
throw new NotFoundException(`持仓不存在ID ${positionId}`);
}
// 分页参数
const page = queryDto.page || 1;
const limit = queryDto.limit || 10;
const skip = (page - 1) * limit;
// 查询总数
const total = await this.positionChangeRepository.count({
where: { positionId },
});
// 查询分页数据(按变更日期和创建时间倒序)
const list = await this.positionChangeRepository.find({
where: { positionId },
order: {
changeDate: 'DESC',
createdAt: 'DESC',
},
skip,
take: limit,
});
// 计算总页数
const total_page = Math.ceil(total / limit);
return {
list,
pagination: {
total,
total_page,
page_size: limit,
current_page: page,
},
};
}
/**
* 创建持仓变更记录
*/
async create(
userId: number,
createPositionChangeDto: CreatePositionChangeDto,
): Promise<PositionChange> {
// 验证持仓是否属于当前用户
const position = await this.positionRepository.findOne({
where: {
positionId: createPositionChangeDto.positionId,
userId,
},
});
if (!position) {
throw new NotFoundException(
`持仓不存在ID ${createPositionChangeDto.positionId}`,
);
}
// 创建变更记录
const positionChange = this.positionChangeRepository.create({
...createPositionChangeDto,
changeDate: new Date(createPositionChangeDto.changeDate),
});
return this.positionChangeRepository.save(positionChange);
}
/**
* 更新持仓变更记录的备注/思考
*/
async update(
changeId: number,
userId: number,
updatePositionChangeDto: UpdatePositionChangeDto,
): Promise<PositionChange> {
// 查找变更记录
const positionChange = await this.positionChangeRepository.findOne({
where: { changeId },
relations: [], // 不加载关联,后面手动验证
});
if (!positionChange) {
throw new NotFoundException(`变更记录不存在ID ${changeId}`);
}
// 验证持仓是否属于当前用户
const position = await this.positionRepository.findOne({
where: {
positionId: positionChange.positionId,
userId,
},
});
if (!position) {
throw new ForbiddenException('无权访问该持仓的变更记录');
}
// 只更新备注字段
if (updatePositionChangeDto.notes !== undefined) {
positionChange.notes = updatePositionChangeDto.notes;
}
return this.positionChangeRepository.save(positionChange);
}
}