order.service.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. import { GenericCrudService } from '@d8d/shared-crud';
  2. import { DataSource, Repository, DataSourceOptions, In, Not } from 'typeorm';
  3. import { EmploymentOrder } from '../entities/employment-order.entity';
  4. import { OrderPerson } from '../entities/order-person.entity';
  5. import { OrderPersonAsset, AssetType, AssetFileType } from '../entities/order-person-asset.entity';
  6. import { FileService, File } from '@d8d/file-module';
  7. import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
  8. export class OrderService extends GenericCrudService<EmploymentOrder> {
  9. private readonly orderPersonRepository: Repository<OrderPerson>;
  10. private readonly orderPersonAssetRepository: Repository<OrderPersonAsset>;
  11. private readonly fileRepository: Repository<File>;
  12. private fileService: FileService;
  13. constructor(dataSource: DataSource) {
  14. super(dataSource, EmploymentOrder);
  15. this.orderPersonRepository = dataSource.getRepository(OrderPerson);
  16. this.orderPersonAssetRepository = dataSource.getRepository(OrderPersonAsset);
  17. this.fileRepository = dataSource.getRepository(File);
  18. this.fileService = new FileService(dataSource);
  19. }
  20. /**
  21. * 创建订单 - 覆盖父类方法,添加验证和业务逻辑
  22. */
  23. async create(data: Partial<EmploymentOrder>, userId?: string | number): Promise<EmploymentOrder> {
  24. // 验证枚举值
  25. if (data.orderStatus && !Object.values(OrderStatus).includes(data.orderStatus)) {
  26. throw new Error('订单状态无效');
  27. }
  28. if (data.workStatus && !Object.values(WorkStatus).includes(data.workStatus)) {
  29. throw new Error('工作状态无效');
  30. }
  31. // 设置默认值
  32. const orderData = {
  33. ...data,
  34. orderStatus: data.orderStatus || OrderStatus.DRAFT,
  35. workStatus: data.workStatus || WorkStatus.NOT_WORKING,
  36. };
  37. return super.create(orderData, userId);
  38. }
  39. /**
  40. * 更新订单 - 覆盖父类方法,添加验证
  41. */
  42. async update(id: number, data: Partial<EmploymentOrder>, userId?: string | number): Promise<EmploymentOrder | null> {
  43. // 验证枚举值
  44. if (data.orderStatus && !Object.values(OrderStatus).includes(data.orderStatus)) {
  45. throw new Error('订单状态无效');
  46. }
  47. if (data.workStatus && !Object.values(WorkStatus).includes(data.workStatus)) {
  48. throw new Error('工作状态无效');
  49. }
  50. return super.update(id, data, userId);
  51. }
  52. /**
  53. * 分页查询订单 - 自定义方法,返回源服务的格式
  54. */
  55. async findAll(query: {
  56. orderName?: string;
  57. platformId?: number;
  58. companyId?: number;
  59. channelId?: number;
  60. orderStatus?: OrderStatus;
  61. page?: number;
  62. limit?: number;
  63. }): Promise<{ data: any[]; total: number }> {
  64. const {
  65. orderName,
  66. platformId,
  67. companyId,
  68. channelId,
  69. orderStatus,
  70. page = 1,
  71. limit = 10
  72. } = query;
  73. const queryBuilder = this.repository.createQueryBuilder('order');
  74. // 构建查询条件
  75. if (orderName) {
  76. queryBuilder.andWhere('order.orderName LIKE :orderName', { orderName: `%${orderName}%` });
  77. }
  78. if (platformId) {
  79. queryBuilder.andWhere('order.platformId = :platformId', { platformId });
  80. }
  81. if (companyId) {
  82. queryBuilder.andWhere('order.companyId = :companyId', { companyId });
  83. }
  84. if (channelId) {
  85. queryBuilder.andWhere('order.channelId = :channelId', { channelId });
  86. }
  87. if (orderStatus) {
  88. queryBuilder.andWhere('order.orderStatus = :orderStatus', { orderStatus });
  89. }
  90. // 获取总数
  91. const total = await queryBuilder.getCount();
  92. // 获取数据
  93. const data = await queryBuilder
  94. .skip((page - 1) * limit)
  95. .take(limit)
  96. .orderBy('order.createTime', 'DESC')
  97. .getMany();
  98. // 获取每个订单的人员数量
  99. const orderIds = data.map(order => order.id);
  100. let personCounts: Array<{ orderId: number; count: number }> = [];
  101. if (orderIds.length > 0) {
  102. const personCountQuery = await this.orderPersonRepository
  103. .createQueryBuilder('orderPerson')
  104. .select('orderPerson.orderId', 'orderId')
  105. .addSelect('COUNT(orderPerson.id)', 'count')
  106. .where('orderPerson.orderId IN (:...orderIds)', { orderIds })
  107. .groupBy('orderPerson.orderId')
  108. .getRawMany();
  109. personCounts = personCountQuery.map(item => ({
  110. orderId: item.orderId,
  111. count: parseInt(item.count)
  112. }));
  113. }
  114. // 格式化返回数据
  115. const formattedData = data.map(order => {
  116. const personCount = personCounts.find(pc => pc.orderId === order.id)?.count || 0;
  117. return {
  118. orderId: order.id,
  119. orderName: order.orderName,
  120. platformId: order.platformId,
  121. companyId: order.companyId,
  122. channelId: order.channelId,
  123. expectedStartDate: order.expectedStartDate,
  124. actualStartDate: order.actualStartDate,
  125. actualEndDate: order.actualEndDate,
  126. orderStatus: order.orderStatus,
  127. workStatus: order.workStatus,
  128. createTime: order.createTime,
  129. updateTime: order.updateTime,
  130. personCount
  131. };
  132. });
  133. return { data: formattedData, total };
  134. }
  135. /**
  136. * 查询单个订单详情 - 自定义方法
  137. */
  138. async findOne(id: number): Promise<any | null> {
  139. const order = await this.repository.findOne({
  140. where: { id },
  141. relations: ['orderPersons']
  142. });
  143. if (!order) {
  144. return null;
  145. }
  146. // 获取订单人员详情(这里简化处理,实际可能需要关联更多信息)
  147. const orderPersons = order.orderPersons || [];
  148. return {
  149. orderId: order.id,
  150. orderName: order.orderName,
  151. platformId: order.platformId,
  152. companyId: order.companyId,
  153. channelId: order.channelId,
  154. expectedStartDate: order.expectedStartDate,
  155. actualStartDate: order.actualStartDate,
  156. actualEndDate: order.actualEndDate,
  157. orderStatus: order.orderStatus,
  158. workStatus: order.workStatus,
  159. createTime: order.createTime,
  160. updateTime: order.updateTime,
  161. orderPersons: orderPersons.map(person => ({
  162. opId: person.id,
  163. orderId: person.orderId,
  164. personId: person.personId,
  165. joinDate: person.joinDate,
  166. leaveDate: person.leaveDate,
  167. workStatus: person.workStatus,
  168. salaryDetail: person.salaryDetail
  169. }))
  170. };
  171. }
  172. /**
  173. * 订单激活 - 自定义业务方法
  174. */
  175. async activateOrder(orderId: number): Promise<boolean> {
  176. const queryRunner = this.dataSource.createQueryRunner();
  177. await queryRunner.connect();
  178. await queryRunner.startTransaction();
  179. try {
  180. // 查询订单
  181. const order = await queryRunner.manager.findOne(EmploymentOrder, {
  182. where: { id: orderId }
  183. });
  184. if (!order) {
  185. throw new Error(`订单ID ${orderId} 不存在`);
  186. }
  187. if (order.orderStatus !== OrderStatus.DRAFT) {
  188. throw new Error(`只有草稿状态的订单才能激活,当前订单状态为: ${order.orderStatus}`);
  189. }
  190. // 更新订单状态为已确认
  191. order.orderStatus = OrderStatus.CONFIRMED;
  192. order.actualStartDate = new Date();
  193. await queryRunner.manager.save(order);
  194. // 更新订单人员状态为待就业
  195. await queryRunner.manager.update(OrderPerson,
  196. { orderId: orderId },
  197. { workStatus: WorkStatus.PRE_WORKING }
  198. );
  199. await queryRunner.commitTransaction();
  200. return true;
  201. } catch (error) {
  202. await queryRunner.rollbackTransaction();
  203. throw error;
  204. } finally {
  205. await queryRunner.release();
  206. }
  207. }
  208. /**
  209. * 订单关闭 - 自定义业务方法
  210. */
  211. async closeOrder(orderId: number): Promise<boolean> {
  212. const queryRunner = this.dataSource.createQueryRunner();
  213. await queryRunner.connect();
  214. await queryRunner.startTransaction();
  215. try {
  216. // 查询订单
  217. const order = await queryRunner.manager.findOne(EmploymentOrder, {
  218. where: { id: orderId }
  219. });
  220. if (!order) {
  221. throw new Error(`订单ID ${orderId} 不存在`);
  222. }
  223. if (order.orderStatus !== OrderStatus.CONFIRMED && order.orderStatus !== OrderStatus.IN_PROGRESS) {
  224. throw new Error(`只有已确认或进行中的订单才能关闭,当前订单状态为: ${order.orderStatus}`);
  225. }
  226. // 更新订单状态为已完成
  227. order.orderStatus = OrderStatus.COMPLETED;
  228. order.actualEndDate = new Date();
  229. await queryRunner.manager.save(order);
  230. // 更新订单人员状态为已离职
  231. await queryRunner.manager.update(OrderPerson,
  232. { orderId: orderId },
  233. {
  234. workStatus: WorkStatus.RESIGNED,
  235. leaveDate: new Date()
  236. }
  237. );
  238. await queryRunner.commitTransaction();
  239. return true;
  240. } catch (error) {
  241. await queryRunner.rollbackTransaction();
  242. throw error;
  243. } finally {
  244. await queryRunner.release();
  245. }
  246. }
  247. /**
  248. * 批量添加人员到订单 - 自定义业务方法
  249. */
  250. async batchAddPersons(orderId: number, persons: Array<{
  251. personId: number;
  252. joinDate: Date;
  253. salaryDetail: number;
  254. }>): Promise<{ success: boolean; message: string; addedCount: number }> {
  255. // 验证订单是否存在
  256. const order = await this.repository.findOne({
  257. where: { id: orderId }
  258. });
  259. if (!order) {
  260. throw new Error(`订单ID ${orderId} 不存在`);
  261. }
  262. if (order.orderStatus === OrderStatus.COMPLETED || order.orderStatus === OrderStatus.CANCELLED) {
  263. throw new Error(`订单ID ${orderId} 已结束或已取消,无法添加人员`);
  264. }
  265. // 检查哪些人员已经在订单中
  266. const existingPersons = await this.orderPersonRepository.find({
  267. where: { orderId }
  268. });
  269. const existingPersonIds = existingPersons.map(p => p.personId);
  270. // 过滤掉已存在的人员
  271. const newPersons = persons.filter(p => !existingPersonIds.includes(p.personId));
  272. if (newPersons.length === 0) {
  273. return { success: true, message: '所有人员都已在此订单中', addedCount: 0 };
  274. }
  275. // 使用事务添加新人员
  276. const queryRunner = this.dataSource.createQueryRunner();
  277. await queryRunner.connect();
  278. await queryRunner.startTransaction();
  279. try {
  280. // 创建订单人员关联
  281. const orderPersons = newPersons.map(person => {
  282. return queryRunner.manager.create(OrderPerson, {
  283. orderId: orderId,
  284. personId: person.personId,
  285. joinDate: person.joinDate,
  286. workStatus: WorkStatus.NOT_WORKING,
  287. salaryDetail: person.salaryDetail,
  288. });
  289. });
  290. await queryRunner.manager.save(orderPersons);
  291. await queryRunner.commitTransaction();
  292. return {
  293. success: true,
  294. message: `成功添加 ${newPersons.length} 个人员到订单`,
  295. addedCount: newPersons.length
  296. };
  297. } catch (error) {
  298. await queryRunner.rollbackTransaction();
  299. throw error;
  300. } finally {
  301. await queryRunner.release();
  302. }
  303. }
  304. /**
  305. * 验证文件ID是否存在
  306. */
  307. async validateFileId(fileId: number): Promise<boolean> {
  308. try {
  309. const file = await this.fileRepository.findOne({ where: { id: fileId } });
  310. return !!file;
  311. } catch (error) {
  312. console.error('验证文件ID失败:', error);
  313. return false;
  314. }
  315. }
  316. /**
  317. * 创建订单人员资产 - 自定义业务方法
  318. */
  319. async createOrderPersonAsset(data: {
  320. orderId: number;
  321. personId: number;
  322. assetType: AssetType;
  323. assetFileType: AssetFileType;
  324. fileId: number;
  325. relatedTime?: Date;
  326. }): Promise<OrderPersonAsset> {
  327. // 验证文件ID是否存在
  328. const fileExists = await this.validateFileId(data.fileId);
  329. if (!fileExists) {
  330. throw new Error('文件不存在');
  331. }
  332. // 验证订单和人员关联是否存在
  333. const orderPerson = await this.orderPersonRepository.findOne({
  334. where: { orderId: data.orderId, personId: data.personId }
  335. });
  336. if (!orderPerson) {
  337. throw new Error(`人员ID ${data.personId} 不在订单ID ${data.orderId} 中`);
  338. }
  339. // 创建资产记录
  340. const asset = new OrderPersonAsset({
  341. orderId: data.orderId,
  342. personId: data.personId,
  343. assetType: data.assetType,
  344. assetFileType: data.assetFileType,
  345. fileId: data.fileId,
  346. relatedTime: data.relatedTime || new Date()
  347. });
  348. return await this.orderPersonAssetRepository.save(asset);
  349. }
  350. /**
  351. * 查询订单人员资产 - 自定义业务方法
  352. */
  353. async queryOrderPersonAsset(query: {
  354. orderId?: number;
  355. personId?: number;
  356. assetType?: string;
  357. assetFileType?: string;
  358. page?: number;
  359. limit?: number;
  360. }): Promise<{ data: OrderPersonAsset[]; total: number }> {
  361. const {
  362. orderId,
  363. personId,
  364. assetType,
  365. assetFileType,
  366. page = 1,
  367. limit = 10
  368. } = query;
  369. const queryBuilder = this.orderPersonAssetRepository.createQueryBuilder('asset');
  370. // 构建查询条件
  371. if (orderId) {
  372. queryBuilder.andWhere('asset.orderId = :orderId', { orderId });
  373. }
  374. if (personId) {
  375. queryBuilder.andWhere('asset.personId = :personId', { personId });
  376. }
  377. if (assetType) {
  378. queryBuilder.andWhere('asset.assetType = :assetType', { assetType });
  379. }
  380. if (assetFileType) {
  381. queryBuilder.andWhere('asset.assetFileType = :assetFileType', { assetFileType });
  382. }
  383. // 获取总数
  384. const total = await queryBuilder.getCount();
  385. // 获取数据
  386. const data = await queryBuilder
  387. .skip((page - 1) * limit)
  388. .take(limit)
  389. .orderBy('asset.updateTime', 'DESC')
  390. .getMany();
  391. return { data, total };
  392. }
  393. /**
  394. * 删除订单人员资产 - 自定义业务方法
  395. */
  396. async deleteOrderPersonAsset(id: number): Promise<{ success: boolean; message: string }> {
  397. const asset = await this.orderPersonAssetRepository.findOne({
  398. where: { id }
  399. });
  400. if (!asset) {
  401. throw new Error(`资产ID ${id} 不存在`);
  402. }
  403. await this.orderPersonAssetRepository.delete({ id });
  404. return {
  405. success: true,
  406. message: `成功删除资产ID ${id}`
  407. };
  408. }
  409. }