order.integration.test.ts 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622
  1. import { describe, it, expect, beforeEach } from 'vitest';
  2. import { testClient } from 'hono/testing';
  3. import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
  4. import { JWTUtil } from '@d8d/shared-utils';
  5. import { JWTPayload } from '@d8d/shared-types';
  6. import { UserEntity, Role } from '@d8d/user-module';
  7. import { File } from '@d8d/file-module';
  8. import { DisabledPerson, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit } from '@d8d/allin-disability-module';
  9. import { BankName } from '@d8d/bank-names-module';
  10. import { Company } from '@d8d/allin-company-module/entities';
  11. import { Platform } from '@d8d/allin-platform-module';
  12. import { DataSource } from 'typeorm';
  13. import orderRoutes from '../../src/routes/order.routes';
  14. import { EmploymentOrder } from '../../src/entities/employment-order.entity';
  15. import { OrderPerson } from '../../src/entities/order-person.entity';
  16. import { OrderPersonAsset } from '../../src/entities/order-person-asset.entity';
  17. import { AssetType, AssetFileType, AssetStatus, DownloadScope } from '../../src/schemas/order.schema';
  18. import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
  19. import { OrderTestDataFactory } from '../utils/test-data-factory';
  20. // 设置集成测试钩子
  21. setupIntegrationDatabaseHooksWithEntities([UserEntity, File, Role, Platform, Company, DisabledPerson, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit, BankName, EmploymentOrder, OrderPerson, OrderPersonAsset])
  22. describe('订单管理API集成测试', () => {
  23. let client: ReturnType<typeof testClient<typeof orderRoutes>>;
  24. let testToken: string;
  25. let testUser: UserEntity;
  26. let testFile: File;
  27. let testDisabledPerson: DisabledPerson;
  28. beforeEach(async () => {
  29. // 创建测试客户端
  30. client = testClient(orderRoutes);
  31. // 获取数据源
  32. const dataSource = await IntegrationTestDatabase.getDataSource();
  33. // 创建测试用户
  34. const userRepository = dataSource.getRepository(UserEntity);
  35. testUser = userRepository.create({
  36. username: `test_user_${Date.now()}`,
  37. password: 'test_password',
  38. nickname: '测试用户',
  39. registrationSource: 'web'
  40. });
  41. await userRepository.save(testUser);
  42. // 生成测试用户的token
  43. testToken = JWTUtil.generateToken({
  44. id: testUser.id,
  45. username: testUser.username,
  46. roles: [{name:'user'}]
  47. });
  48. // 创建测试文件
  49. const fileRepository = dataSource.getRepository(File);
  50. testFile = fileRepository.create({
  51. name: 'test_file.pdf',
  52. type: 'application/pdf',
  53. size: 1024,
  54. path: `test/${Date.now()}_test_file.pdf`,
  55. uploadUserId: testUser.id,
  56. uploadTime: new Date(),
  57. createdAt: new Date(),
  58. updatedAt: new Date()
  59. });
  60. await fileRepository.save(testFile);
  61. // 创建测试银行名称记录(用于DisabledBankCard外键约束)
  62. const bankNameRepository = dataSource.getRepository(BankName);
  63. const testBankName = bankNameRepository.create({
  64. name: '测试银行',
  65. code: 'TEST001',
  66. remark: '测试银行',
  67. createdBy: testUser.id,
  68. updatedBy: testUser.id,
  69. status: 1
  70. });
  71. await bankNameRepository.save(testBankName);
  72. // 创建测试残疾人记录(用于外键约束)
  73. testDisabledPerson = await OrderTestDataFactory.createTestDisabledPerson(dataSource);
  74. });
  75. describe('POST /order/create', () => {
  76. it('应该成功创建订单', async () => {
  77. const createData = {
  78. orderName: '测试订单',
  79. platformId: 1,
  80. companyId: 1,
  81. channelId: 1,
  82. expectedStartDate: new Date().toISOString(),
  83. orderStatus: OrderStatus.DRAFT,
  84. workStatus: WorkStatus.NOT_WORKING
  85. };
  86. const response = await client.create.$post({
  87. json: createData
  88. }, {
  89. headers: {
  90. 'Authorization': `Bearer ${testToken}`
  91. }
  92. });
  93. if (response.status !== 200) {
  94. const error = await response.json();
  95. console.debug('创建订单失败:', JSON.stringify(error, null, 2));
  96. }
  97. expect(response.status).toBe(200);
  98. if (response.status === 200) {
  99. const data = await response.json();
  100. expect(data.id).toBeDefined();
  101. expect(data.orderName).toBe('测试订单');
  102. expect(data.orderStatus).toBe(OrderStatus.DRAFT);
  103. expect(data.workStatus).toBe(WorkStatus.NOT_WORKING);
  104. }
  105. });
  106. it('应该验证订单状态枚举值', async () => {
  107. const createData = {
  108. orderName: '测试订单',
  109. platformId: 1,
  110. companyId: 1,
  111. channelId: 1,
  112. expectedStartDate: new Date().toISOString(),
  113. orderStatus: 'invalid_status', // 无效的状态
  114. workStatus: WorkStatus.NOT_WORKING
  115. };
  116. const response = await client.create.$post({
  117. json: createData as any // 使用any绕过类型检查,因为这里故意测试无效的枚举值
  118. }, {
  119. headers: {
  120. 'Authorization': `Bearer ${testToken}`
  121. }
  122. });
  123. expect(response.status).toBe(400);
  124. });
  125. it('应该验证工作状态枚举值', async () => {
  126. const createData = {
  127. orderName: '测试订单',
  128. platformId: 1,
  129. companyId: 1,
  130. channelId: 1,
  131. expectedStartDate: new Date().toISOString(),
  132. orderStatus: OrderStatus.DRAFT,
  133. workStatus: 'invalid_status' // 无效的状态
  134. };
  135. const response = await client.create.$post({
  136. json: createData as any // 使用any绕过类型检查,因为这里故意测试无效的枚举值
  137. }, {
  138. headers: {
  139. 'Authorization': `Bearer ${testToken}`
  140. }
  141. });
  142. expect(response.status).toBe(400);
  143. });
  144. });
  145. describe('GET /order/list', () => {
  146. let testOrder: EmploymentOrder;
  147. beforeEach(async () => {
  148. // 创建测试订单数据
  149. const dataSource = await IntegrationTestDatabase.getDataSource();
  150. const orderRepository = dataSource.getRepository(EmploymentOrder);
  151. testOrder = new EmploymentOrder({
  152. orderName: '测试订单1',
  153. platformId: 1,
  154. companyId: 1,
  155. channelId: 1,
  156. expectedStartDate: new Date(),
  157. orderStatus: OrderStatus.DRAFT,
  158. workStatus: WorkStatus.NOT_WORKING
  159. });
  160. await orderRepository.save(testOrder);
  161. const testOrder2 = new EmploymentOrder({
  162. orderName: '测试订单2',
  163. platformId: 2,
  164. companyId: 2,
  165. channelId: 2,
  166. expectedStartDate: new Date(),
  167. orderStatus: OrderStatus.CONFIRMED,
  168. workStatus: WorkStatus.PRE_WORKING
  169. });
  170. await orderRepository.save(testOrder2);
  171. });
  172. it('应该返回所有订单列表', async () => {
  173. const response = await client.list.$get({
  174. query: {}
  175. }, {
  176. headers: {
  177. 'Authorization': `Bearer ${testToken}`
  178. }
  179. });
  180. expect(response.status).toBe(200);
  181. if (response.status === 200) {
  182. const data = await response.json();
  183. expect(data).toHaveProperty('data');
  184. expect(data).toHaveProperty('total');
  185. expect(data.data).toHaveLength(2);
  186. expect(data.total).toBe(2);
  187. }
  188. });
  189. it('应该支持按订单名称搜索', async () => {
  190. const response = await client.list.$get({
  191. query: {
  192. orderName: '测试订单1'
  193. }
  194. }, {
  195. headers: {
  196. 'Authorization': `Bearer ${testToken}`
  197. }
  198. });
  199. expect(response.status).toBe(200);
  200. if (response.status === 200) {
  201. const data = await response.json();
  202. expect(data.data).toHaveLength(1);
  203. expect(data.data[0].orderName).toBe('测试订单1');
  204. }
  205. });
  206. it('应该支持按订单状态过滤', async () => {
  207. const response = await client.list.$get({
  208. query: {
  209. orderStatus: OrderStatus.CONFIRMED
  210. }
  211. }, {
  212. headers: {
  213. 'Authorization': `Bearer ${testToken}`
  214. }
  215. });
  216. expect(response.status).toBe(200);
  217. if (response.status === 200) {
  218. const data = await response.json();
  219. expect(data.data).toHaveLength(1);
  220. expect(data.data[0].orderStatus).toBe(OrderStatus.CONFIRMED);
  221. }
  222. });
  223. it('应该支持分页查询', async () => {
  224. const response = await client.list.$get({
  225. query: {
  226. page: '1',
  227. limit: '1'
  228. }
  229. }, {
  230. headers: {
  231. 'Authorization': `Bearer ${testToken}`
  232. }
  233. });
  234. expect(response.status).toBe(200);
  235. if (response.status === 200) {
  236. const data = await response.json();
  237. expect(data.data).toHaveLength(1);
  238. expect(data.total).toBe(2);
  239. }
  240. });
  241. });
  242. describe('GET /order/detail/:id', () => {
  243. let testOrder: EmploymentOrder;
  244. beforeEach(async () => {
  245. // 创建测试订单数据
  246. const dataSource = await IntegrationTestDatabase.getDataSource();
  247. const orderRepository = dataSource.getRepository(EmploymentOrder);
  248. testOrder = new EmploymentOrder({
  249. orderName: '测试订单详情',
  250. platformId: 1,
  251. companyId: 1,
  252. channelId: 1,
  253. expectedStartDate: new Date(),
  254. orderStatus: OrderStatus.DRAFT,
  255. workStatus: WorkStatus.NOT_WORKING
  256. });
  257. await orderRepository.save(testOrder);
  258. });
  259. it('应该返回指定ID的订单详情', async () => {
  260. const response = await client.detail[':id'].$get({
  261. param: { id: testOrder.id.toString() }
  262. }, {
  263. headers: {
  264. 'Authorization': `Bearer ${testToken}`
  265. }
  266. });
  267. if (response.status !== 200) {
  268. const error = await response.json();
  269. console.debug('获取订单详情失败:', JSON.stringify(error, null, 2));
  270. }
  271. expect(response.status).toBe(200);
  272. if (response.status === 200) {
  273. const data = await response.json();
  274. expect(data?.id).toBe(testOrder.id);
  275. expect(data?.orderName).toBe('测试订单详情');
  276. expect(data?.orderStatus).toBe(OrderStatus.DRAFT);
  277. }
  278. });
  279. it('应该处理不存在的订单ID', async () => {
  280. const response = await client.detail[':id'].$get({
  281. param: { id: '999999' }
  282. }, {
  283. headers: {
  284. 'Authorization': `Bearer ${testToken}`
  285. }
  286. });
  287. expect(response.status).toBe(404);
  288. });
  289. });
  290. describe('POST /order/activate/:orderId', () => {
  291. let testOrder: EmploymentOrder;
  292. beforeEach(async () => {
  293. // 创建测试订单数据
  294. const dataSource = await IntegrationTestDatabase.getDataSource();
  295. const orderRepository = dataSource.getRepository(EmploymentOrder);
  296. testOrder = new EmploymentOrder({
  297. orderName: '待激活订单',
  298. platformId: 1,
  299. companyId: 1,
  300. channelId: 1,
  301. expectedStartDate: new Date(),
  302. orderStatus: OrderStatus.DRAFT,
  303. workStatus: WorkStatus.NOT_WORKING
  304. });
  305. await orderRepository.save(testOrder);
  306. });
  307. it('应该成功激活草稿状态的订单', async () => {
  308. const response = await client.activate[':orderId'].$post({
  309. param: { orderId: testOrder.id.toString() }
  310. }, {
  311. headers: {
  312. 'Authorization': `Bearer ${testToken}`
  313. }
  314. });
  315. expect(response.status).toBe(200);
  316. if (response.status === 200) {
  317. const data = await response.json();
  318. expect(data.success).toBe(true);
  319. // 验证订单状态已更新
  320. const dataSource = await IntegrationTestDatabase.getDataSource();
  321. const orderRepository = dataSource.getRepository(EmploymentOrder);
  322. const updatedOrder = await orderRepository.findOne({
  323. where: { id: testOrder.id }
  324. });
  325. expect(updatedOrder?.orderStatus).toBe(OrderStatus.CONFIRMED);
  326. expect(updatedOrder?.actualStartDate).toBeDefined();
  327. }
  328. });
  329. it('应该处理非草稿状态的订单激活', async () => {
  330. // 更新订单状态为已确认
  331. const dataSource = await IntegrationTestDatabase.getDataSource();
  332. const orderRepository = dataSource.getRepository(EmploymentOrder);
  333. await orderRepository.update(testOrder.id, { orderStatus: OrderStatus.CONFIRMED });
  334. const response = await client.activate[':orderId'].$post({
  335. param: { orderId: testOrder.id.toString() }
  336. }, {
  337. headers: {
  338. 'Authorization': `Bearer ${testToken}`
  339. }
  340. });
  341. expect(response.status).toBe(400);
  342. });
  343. it('应该处理不存在的订单ID', async () => {
  344. const response = await client.activate[':orderId'].$post({
  345. param: { orderId: '999999' }
  346. }, {
  347. headers: {
  348. 'Authorization': `Bearer ${testToken}`
  349. }
  350. });
  351. expect(response.status).toBe(404);
  352. });
  353. });
  354. describe('POST /order/close/:orderId', () => {
  355. let testOrder: EmploymentOrder;
  356. beforeEach(async () => {
  357. // 创建测试订单数据
  358. const dataSource = await IntegrationTestDatabase.getDataSource();
  359. const orderRepository = dataSource.getRepository(EmploymentOrder);
  360. testOrder = new EmploymentOrder({
  361. orderName: '待关闭订单',
  362. platformId: 1,
  363. companyId: 1,
  364. channelId: 1,
  365. expectedStartDate: new Date(),
  366. actualStartDate: new Date(),
  367. orderStatus: OrderStatus.CONFIRMED,
  368. workStatus: WorkStatus.PRE_WORKING,
  369. });
  370. await orderRepository.save(testOrder);
  371. });
  372. it('应该成功关闭已确认状态的订单', async () => {
  373. const response = await client.close[':orderId'].$post({
  374. param: { orderId: testOrder.id.toString() }
  375. }, {
  376. headers: {
  377. 'Authorization': `Bearer ${testToken}`
  378. }
  379. });
  380. expect(response.status).toBe(200);
  381. if (response.status === 200) {
  382. const data = await response.json();
  383. expect(data.success).toBe(true);
  384. // 验证订单状态已更新
  385. const dataSource = await IntegrationTestDatabase.getDataSource();
  386. const orderRepository = dataSource.getRepository(EmploymentOrder);
  387. const updatedOrder = await orderRepository.findOne({
  388. where: { id: testOrder.id }
  389. });
  390. expect(updatedOrder?.orderStatus).toBe(OrderStatus.COMPLETED);
  391. expect(updatedOrder?.actualEndDate).toBeDefined();
  392. }
  393. });
  394. it('应该处理非已确认或进行中状态的订单关闭', async () => {
  395. // 更新订单状态为草稿
  396. const dataSource = await IntegrationTestDatabase.getDataSource();
  397. const orderRepository = dataSource.getRepository(EmploymentOrder);
  398. await orderRepository.update(testOrder.id, { orderStatus: OrderStatus.DRAFT });
  399. const response = await client.close[':orderId'].$post({
  400. param: { orderId: testOrder.id.toString() }
  401. }, {
  402. headers: {
  403. 'Authorization': `Bearer ${testToken}`
  404. }
  405. });
  406. expect(response.status).toBe(400);
  407. });
  408. it('应该处理不存在的订单ID', async () => {
  409. const response = await client.close[':orderId'].$post({
  410. param: { orderId: '999999' }
  411. }, {
  412. headers: {
  413. 'Authorization': `Bearer ${testToken}`
  414. }
  415. });
  416. expect(response.status).toBe(404);
  417. });
  418. });
  419. describe('POST /order/:orderId/persons/batch', () => {
  420. let testOrder: EmploymentOrder;
  421. beforeEach(async () => {
  422. // 创建测试订单数据
  423. const dataSource = await IntegrationTestDatabase.getDataSource();
  424. const orderRepository = dataSource.getRepository(EmploymentOrder);
  425. testOrder = new EmploymentOrder({
  426. orderName: '批量添加人员测试订单',
  427. platformId: 1,
  428. companyId: 1,
  429. channelId: 1,
  430. expectedStartDate: new Date(),
  431. orderStatus: OrderStatus.DRAFT,
  432. workStatus: WorkStatus.NOT_WORKING,
  433. });
  434. await orderRepository.save(testOrder);
  435. });
  436. it('应该成功批量添加人员到订单', async () => {
  437. // 创建两个测试残疾人记录
  438. const dataSource = await IntegrationTestDatabase.getDataSource();
  439. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  440. // 直接创建最简单的DisabledPerson记录
  441. const disabledPerson1 = disabledPersonRepository.create({
  442. name: '测试1',
  443. gender: '男',
  444. idCard: '1',
  445. disabilityId: '1',
  446. disabilityType: '肢体',
  447. disabilityLevel: '三级',
  448. idAddress: '地址',
  449. phone: '13800138000',
  450. canDirectContact: 1,
  451. province: '省',
  452. city: '市',
  453. district: '区',
  454. detailedAddress: '地址',
  455. isInBlackList: 0,
  456. jobStatus: 0,
  457. createTime: new Date(),
  458. updateTime: new Date()
  459. });
  460. await disabledPersonRepository.save(disabledPerson1);
  461. const disabledPerson2 = disabledPersonRepository.create({
  462. name: '测试2',
  463. gender: '女',
  464. idCard: '2',
  465. disabilityId: '2',
  466. disabilityType: '视力',
  467. disabilityLevel: '二级',
  468. idAddress: '地址',
  469. phone: '13800138001',
  470. canDirectContact: 1,
  471. province: '省',
  472. city: '市',
  473. district: '区',
  474. detailedAddress: '地址',
  475. isInBlackList: 0,
  476. jobStatus: 0,
  477. createTime: new Date(),
  478. updateTime: new Date()
  479. });
  480. await disabledPersonRepository.save(disabledPerson2);
  481. const batchData = {
  482. persons: [
  483. {
  484. personId: disabledPerson1.id,
  485. joinDate: new Date().toISOString(),
  486. salaryDetail: 5000.00
  487. },
  488. {
  489. personId: disabledPerson2.id,
  490. joinDate: new Date().toISOString(),
  491. salaryDetail: 6000.00
  492. }
  493. ]
  494. };
  495. const response = await client[':orderId'].persons.batch.$post({
  496. param: { orderId: testOrder.id.toString() },
  497. json: batchData
  498. }, {
  499. headers: {
  500. 'Authorization': `Bearer ${testToken}`
  501. }
  502. });
  503. expect(response.status).toBe(200);
  504. if (response.status === 200) {
  505. const data = await response.json();
  506. expect(data.success).toBe(true);
  507. expect(data.addedCount).toBe(2);
  508. // 验证人员已添加到订单
  509. const dataSource = await IntegrationTestDatabase.getDataSource();
  510. const orderPersonRepository = dataSource.getRepository(OrderPerson);
  511. const orderPersons = await orderPersonRepository.find({
  512. where: { orderId: testOrder.id }
  513. });
  514. expect(orderPersons).toHaveLength(2);
  515. }
  516. });
  517. it('应该处理重复的人员添加', async () => {
  518. // 创建两个测试残疾人记录
  519. const dataSource = await IntegrationTestDatabase.getDataSource();
  520. const [disabledPerson1, disabledPerson2] = await OrderTestDataFactory.createTestDisabledPersons(dataSource, 2);
  521. const orderPersonRepository = dataSource.getRepository(OrderPerson);
  522. // 先添加一个人员
  523. const existingPerson = orderPersonRepository.create({
  524. orderId: testOrder.id,
  525. personId: disabledPerson1.id,
  526. joinDate: new Date(),
  527. workStatus: WorkStatus.NOT_WORKING,
  528. salaryDetail: 5000.00
  529. });
  530. await orderPersonRepository.save(existingPerson);
  531. const batchData = {
  532. persons: [
  533. {
  534. personId: disabledPerson1.id, // 已存在的人员
  535. joinDate: new Date().toISOString(),
  536. salaryDetail: 5000.00
  537. },
  538. {
  539. personId: disabledPerson2.id, // 新人员
  540. joinDate: new Date().toISOString(),
  541. salaryDetail: 6000.00
  542. }
  543. ]
  544. };
  545. const response = await client[':orderId'].persons.batch.$post({
  546. param: { orderId: testOrder.id.toString() },
  547. json: batchData
  548. }, {
  549. headers: {
  550. 'Authorization': `Bearer ${testToken}`
  551. }
  552. });
  553. expect(response.status).toBe(200);
  554. if (response.status === 200) {
  555. const data = await response.json();
  556. expect(data.success).toBe(true);
  557. expect(data.addedCount).toBe(1); // 只添加了一个新人员
  558. }
  559. });
  560. it('应该处理已结束或已取消的订单', async () => {
  561. // 更新订单状态为已完成
  562. const dataSource = await IntegrationTestDatabase.getDataSource();
  563. const orderRepository = dataSource.getRepository(EmploymentOrder);
  564. await orderRepository.update(testOrder.id, { orderStatus: OrderStatus.COMPLETED });
  565. const batchData = {
  566. persons: [
  567. {
  568. personId: 1001,
  569. joinDate: new Date().toISOString(),
  570. salaryDetail: 5000.00
  571. }
  572. ]
  573. };
  574. const response = await client[':orderId'].persons.batch.$post({
  575. param: { orderId: testOrder.id.toString() },
  576. json: batchData
  577. }, {
  578. headers: {
  579. 'Authorization': `Bearer ${testToken}`
  580. }
  581. });
  582. expect(response.status).toBe(400);
  583. });
  584. it('应该处理不存在的订单ID', async () => {
  585. const batchData = {
  586. persons: [
  587. {
  588. personId: 1001,
  589. joinDate: new Date().toISOString(),
  590. salaryDetail: 5000.00
  591. }
  592. ]
  593. };
  594. const response = await client[':orderId'].persons.batch.$post({
  595. param: { orderId: '999999' },
  596. json: batchData
  597. }, {
  598. headers: {
  599. 'Authorization': `Bearer ${testToken}`
  600. }
  601. });
  602. expect(response.status).toBe(404);
  603. });
  604. });
  605. describe('POST /order/assets/create', () => {
  606. let testOrder: EmploymentOrder;
  607. let testOrderPerson: OrderPerson;
  608. beforeEach(async () => {
  609. // 创建测试订单数据
  610. const dataSource = await IntegrationTestDatabase.getDataSource();
  611. const orderRepository = dataSource.getRepository(EmploymentOrder);
  612. const orderPersonRepository = dataSource.getRepository(OrderPerson);
  613. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  614. testOrder = new EmploymentOrder({
  615. orderName: '资产测试订单',
  616. platformId: 1,
  617. companyId: 1,
  618. channelId: 1,
  619. expectedStartDate: new Date(),
  620. orderStatus: OrderStatus.DRAFT,
  621. workStatus: WorkStatus.NOT_WORKING,
  622. });
  623. await orderRepository.save(testOrder);
  624. // 先创建残疾人记录
  625. const testDisabledPerson = await OrderTestDataFactory.createTestDisabledPerson(dataSource);
  626. testOrderPerson = orderPersonRepository.create({
  627. orderId: testOrder.id,
  628. personId: testDisabledPerson.id,
  629. joinDate: new Date(),
  630. workStatus: WorkStatus.NOT_WORKING,
  631. salaryDetail: 5000.00
  632. });
  633. await orderPersonRepository.save(testOrderPerson);
  634. });
  635. it('应该成功创建订单人员资产', async () => {
  636. const assetData = {
  637. orderId: testOrder.id,
  638. personId: testOrderPerson.personId,
  639. assetType: AssetType.DISABILITY_CERT,
  640. assetFileType: AssetFileType.IMAGE,
  641. fileId: testFile.id,
  642. relatedTime: new Date().toISOString()
  643. };
  644. const response = await client.assets.create.$post({
  645. json: assetData
  646. }, {
  647. headers: {
  648. 'Authorization': `Bearer ${testToken}`
  649. }
  650. });
  651. if (response.status !== 200) {
  652. const error = await response.json();
  653. console.debug('创建订单人员资产失败:', JSON.stringify(error, null, 2));
  654. }
  655. expect(response.status).toBe(200);
  656. if (response.status === 200) {
  657. const data = await response.json();
  658. expect(data.id).toBeDefined();
  659. expect(data.orderId).toBe(testOrder.id);
  660. expect(data.personId).toBe(testOrderPerson.personId);
  661. expect(data.assetType).toBe(AssetType.DISABILITY_CERT);
  662. expect(data.fileId).toBe(testFile.id);
  663. }
  664. });
  665. it('应该处理不存在的文件ID', async () => {
  666. const assetData = {
  667. orderId: testOrder.id,
  668. personId: testOrderPerson.personId,
  669. assetType: AssetType.DISABILITY_CERT,
  670. assetFileType: AssetFileType.IMAGE,
  671. fileId: 999999, // 不存在的文件ID
  672. relatedTime: new Date().toISOString()
  673. };
  674. const response = await client.assets.create.$post({
  675. json: assetData
  676. }, {
  677. headers: {
  678. 'Authorization': `Bearer ${testToken}`
  679. }
  680. });
  681. expect(response.status).toBe(400);
  682. });
  683. it('应该处理人员不在订单中的情况', async () => {
  684. const assetData = {
  685. orderId: testOrder.id,
  686. personId: 999999, // 不在订单中的人员
  687. assetType: AssetType.DISABILITY_CERT,
  688. assetFileType: AssetFileType.IMAGE,
  689. fileId: testFile.id,
  690. relatedTime: new Date().toISOString()
  691. };
  692. const response = await client.assets.create.$post({
  693. json: assetData
  694. }, {
  695. headers: {
  696. 'Authorization': `Bearer ${testToken}`
  697. }
  698. });
  699. expect(response.status).toBe(404);
  700. });
  701. });
  702. describe('GET /order/assets/query', () => {
  703. let testOrder: EmploymentOrder;
  704. let testOrderPerson: OrderPerson;
  705. let testAsset: OrderPersonAsset;
  706. beforeEach(async () => {
  707. // 创建测试数据
  708. const dataSource = await IntegrationTestDatabase.getDataSource();
  709. const orderRepository = dataSource.getRepository(EmploymentOrder);
  710. const orderPersonRepository = dataSource.getRepository(OrderPerson);
  711. const assetRepository = dataSource.getRepository(OrderPersonAsset);
  712. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  713. testOrder = new EmploymentOrder({
  714. orderName: '资产查询测试订单',
  715. platformId: 1,
  716. companyId: 1,
  717. channelId: 1,
  718. expectedStartDate: new Date(),
  719. orderStatus: OrderStatus.DRAFT,
  720. workStatus: WorkStatus.NOT_WORKING,
  721. });
  722. await orderRepository.save(testOrder);
  723. // 先创建残疾人记录
  724. const testDisabledPerson = await OrderTestDataFactory.createTestDisabledPerson(dataSource);
  725. testOrderPerson = orderPersonRepository.create({
  726. orderId: testOrder.id,
  727. personId: testDisabledPerson.id,
  728. joinDate: new Date(),
  729. workStatus: WorkStatus.NOT_WORKING,
  730. salaryDetail: 5000.00
  731. });
  732. await orderPersonRepository.save(testOrderPerson);
  733. testAsset = new OrderPersonAsset({
  734. orderId: testOrder.id,
  735. personId: testOrderPerson.personId,
  736. assetType: AssetType.DISABILITY_CERT,
  737. assetFileType: AssetFileType.IMAGE,
  738. fileId: testFile.id,
  739. relatedTime: new Date()
  740. });
  741. await assetRepository.save(testAsset);
  742. // 创建第二个资产
  743. const testAsset2 = new OrderPersonAsset({
  744. orderId: testOrder.id,
  745. personId: testOrderPerson.personId,
  746. assetType: AssetType.OTHER,
  747. assetFileType: AssetFileType.IMAGE,
  748. fileId: testFile.id,
  749. relatedTime: new Date()
  750. });
  751. await assetRepository.save(testAsset2);
  752. });
  753. it('应该查询所有订单人员资产', async () => {
  754. const response = await client.assets.query.$get({
  755. query: {}
  756. }, {
  757. headers: {
  758. 'Authorization': `Bearer ${testToken}`
  759. }
  760. });
  761. expect(response.status).toBe(200);
  762. if (response.status === 200) {
  763. const data = await response.json();
  764. expect(data).toHaveProperty('data');
  765. expect(data).toHaveProperty('total');
  766. expect(data.data).toHaveLength(2);
  767. expect(data.total).toBe(2);
  768. }
  769. });
  770. it('应该支持按订单ID查询', async () => {
  771. const response = await client.assets.query.$get({
  772. query: {
  773. orderId: testOrder.id.toString()
  774. }
  775. }, {
  776. headers: {
  777. 'Authorization': `Bearer ${testToken}`
  778. }
  779. });
  780. expect(response.status).toBe(200);
  781. if (response.status === 200) {
  782. const data = await response.json();
  783. expect(data.data).toHaveLength(2);
  784. expect(data.data[0].orderId).toBe(testOrder.id);
  785. }
  786. });
  787. it('应该支持按人员ID查询', async () => {
  788. const response = await client.assets.query.$get({
  789. query: {
  790. personId: testOrderPerson.personId.toString()
  791. }
  792. }, {
  793. headers: {
  794. 'Authorization': `Bearer ${testToken}`
  795. }
  796. });
  797. expect(response.status).toBe(200);
  798. if (response.status === 200) {
  799. const data = await response.json();
  800. expect(data.data).toHaveLength(2);
  801. expect(data.data[0].personId).toBe(testOrderPerson.personId);
  802. }
  803. });
  804. it('应该支持按资产类型查询', async () => {
  805. const response = await client.assets.query.$get({
  806. query: {
  807. assetType: AssetType.DISABILITY_CERT
  808. }
  809. }, {
  810. headers: {
  811. 'Authorization': `Bearer ${testToken}`
  812. }
  813. });
  814. expect(response.status).toBe(200);
  815. if (response.status === 200) {
  816. const data = await response.json();
  817. expect(data.data).toHaveLength(1);
  818. expect(data.data[0].assetType).toBe(AssetType.DISABILITY_CERT);
  819. }
  820. });
  821. it('应该支持分页查询', async () => {
  822. const response = await client.assets.query.$get({
  823. query: {
  824. page: '1',
  825. limit: '1'
  826. }
  827. }, {
  828. headers: {
  829. 'Authorization': `Bearer ${testToken}`
  830. }
  831. });
  832. expect(response.status).toBe(200);
  833. if (response.status === 200) {
  834. const data = await response.json();
  835. expect(data.data).toHaveLength(1);
  836. expect(data.total).toBe(2);
  837. }
  838. });
  839. });
  840. describe('DELETE /order/assets/delete/:id', () => {
  841. let testAsset: OrderPersonAsset;
  842. beforeEach(async () => {
  843. // 创建测试数据
  844. const dataSource = await IntegrationTestDatabase.getDataSource();
  845. const orderRepository = dataSource.getRepository(EmploymentOrder);
  846. const orderPersonRepository = dataSource.getRepository(OrderPerson);
  847. const assetRepository = dataSource.getRepository(OrderPersonAsset);
  848. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  849. const testOrder = new EmploymentOrder({
  850. orderName: '资产删除测试订单',
  851. platformId: 1,
  852. companyId: 1,
  853. channelId: 1,
  854. expectedStartDate: new Date(),
  855. orderStatus: OrderStatus.DRAFT,
  856. workStatus: WorkStatus.NOT_WORKING,
  857. });
  858. await orderRepository.save(testOrder);
  859. // 先创建残疾人记录
  860. const testDisabledPerson = await OrderTestDataFactory.createTestDisabledPerson(dataSource);
  861. const testOrderPerson = orderPersonRepository.create({
  862. orderId: testOrder.id,
  863. personId: testDisabledPerson.id,
  864. joinDate: new Date(),
  865. workStatus: WorkStatus.NOT_WORKING,
  866. salaryDetail: 5000.00
  867. });
  868. await orderPersonRepository.save(testOrderPerson);
  869. testAsset = new OrderPersonAsset({
  870. orderId: testOrder.id,
  871. personId: testOrderPerson.personId,
  872. assetType: AssetType.DISABILITY_CERT,
  873. assetFileType: AssetFileType.IMAGE,
  874. fileId: testFile.id,
  875. relatedTime: new Date()
  876. });
  877. await assetRepository.save(testAsset);
  878. });
  879. it('应该成功删除订单人员资产', async () => {
  880. const response = await client.assets.delete[':id'].$delete({
  881. param: { id: testAsset.id.toString() }
  882. }, {
  883. headers: {
  884. 'Authorization': `Bearer ${testToken}`
  885. }
  886. });
  887. expect(response.status).toBe(200);
  888. if (response.status === 200) {
  889. const data = await response.json();
  890. expect(data.success).toBe(true);
  891. // 验证资产已删除
  892. const dataSource = await IntegrationTestDatabase.getDataSource();
  893. const assetRepository = dataSource.getRepository(OrderPersonAsset);
  894. const deletedAsset = await assetRepository.findOne({
  895. where: { id: testAsset.id }
  896. });
  897. expect(deletedAsset).toBeNull();
  898. }
  899. });
  900. it('应该处理不存在的资产ID', async () => {
  901. const response = await client.assets.delete[':id'].$delete({
  902. param: { id: '999999' }
  903. }, {
  904. headers: {
  905. 'Authorization': `Bearer ${testToken}`
  906. }
  907. });
  908. expect(response.status).toBe(404);
  909. });
  910. });
  911. describe('认证测试', () => {
  912. it('应该要求认证', async () => {
  913. const response = await client.list.$get({
  914. query: {}
  915. // 不提供Authorization header
  916. });
  917. expect(response.status).toBe(401);
  918. });
  919. it('应该验证无效token', async () => {
  920. const response = await client.list.$get({
  921. query: {}
  922. }, {
  923. headers: {
  924. 'Authorization': 'Bearer invalid_token'
  925. }
  926. });
  927. expect(response.status).toBe(401);
  928. });
  929. });
  930. describe('订单统计API测试', () => {
  931. let testCompany: Company;
  932. beforeEach(async () => {
  933. // 创建测试公司
  934. const dataSource = await IntegrationTestDatabase.getDataSource();
  935. const companyRepository = dataSource.getRepository(Company);
  936. testCompany = companyRepository.create({
  937. companyName: '统计测试公司',
  938. contactPerson: '测试联系人',
  939. contactPhone: '13800138000',
  940. status: 1
  941. });
  942. await companyRepository.save(testCompany);
  943. });
  944. describe('GET /order/checkin-statistics', () => {
  945. it('应该返回正确的打卡视频数量统计', async () => {
  946. // 测试实现待补充
  947. expect(true).toBe(true);
  948. });
  949. });
  950. describe('GET /order/video-statistics', () => {
  951. it('应该按类型分类返回视频统计结果', async () => {
  952. // 测试实现待补充
  953. expect(true).toBe(true);
  954. });
  955. });
  956. describe('GET /order/company-orders', () => {
  957. it('应该支持按企业ID过滤,返回完整订单信息', async () => {
  958. // 测试实现待补充
  959. expect(true).toBe(true);
  960. });
  961. });
  962. });
  963. describe('企业维度视频管理API测试', () => {
  964. let testCompany: Company;
  965. let testOrder: EmploymentOrder;
  966. let testOrderPerson: OrderPerson;
  967. let testVideoAssets: OrderPersonAsset[];
  968. beforeEach(async () => {
  969. // 创建测试公司
  970. const dataSource = await IntegrationTestDatabase.getDataSource();
  971. const companyRepository = dataSource.getRepository(Company);
  972. testCompany = companyRepository.create({
  973. companyName: '视频管理测试公司',
  974. contactPerson: '测试联系人',
  975. contactPhone: '13800138001',
  976. status: 1
  977. });
  978. await companyRepository.save(testCompany);
  979. // 为测试用户生成包含companyId的token,添加enterprise角色
  980. testToken = JWTUtil.generateToken({
  981. id: testUser.id,
  982. username: testUser.username,
  983. roles: [{name:'user'}, {name:'enterprise'}]
  984. }, { companyId: testCompany.id } as Partial<JWTPayload & { companyId: number }>);
  985. // 更新用户实体的companyId(如果字段存在)
  986. const userRepository = dataSource.getRepository(UserEntity);
  987. await userRepository.update(testUser.id, { companyId: testCompany.id } as any);
  988. // 创建测试订单
  989. const orderRepository = dataSource.getRepository(EmploymentOrder);
  990. testOrder = new EmploymentOrder({
  991. orderName: '视频管理测试订单',
  992. platformId: 1,
  993. companyId: testCompany.id,
  994. channelId: 1,
  995. expectedStartDate: new Date(),
  996. orderStatus: OrderStatus.DRAFT,
  997. workStatus: WorkStatus.NOT_WORKING,
  998. });
  999. await orderRepository.save(testOrder);
  1000. // 创建测试残疾人记录
  1001. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  1002. const testDisabledPerson = disabledPersonRepository.create({
  1003. name: '视频测试人员',
  1004. gender: '男',
  1005. idCard: '3',
  1006. disabilityId: '3',
  1007. disabilityType: '肢体',
  1008. disabilityLevel: '三级',
  1009. idAddress: '地址',
  1010. phone: '13800138002',
  1011. canDirectContact: 1,
  1012. province: '省',
  1013. city: '市',
  1014. district: '区',
  1015. detailedAddress: '地址',
  1016. isInBlackList: 0,
  1017. jobStatus: 0,
  1018. createTime: new Date(),
  1019. updateTime: new Date()
  1020. });
  1021. await disabledPersonRepository.save(testDisabledPerson);
  1022. // 创建订单人员关联
  1023. const orderPersonRepository = dataSource.getRepository(OrderPerson);
  1024. testOrderPerson = orderPersonRepository.create({
  1025. orderId: testOrder.id,
  1026. personId: testDisabledPerson.id,
  1027. joinDate: new Date(),
  1028. workStatus: WorkStatus.NOT_WORKING,
  1029. salaryDetail: 5000.00
  1030. });
  1031. await orderPersonRepository.save(testOrderPerson);
  1032. // 创建测试视频资产
  1033. const assetRepository = dataSource.getRepository(OrderPersonAsset);
  1034. testVideoAssets = [
  1035. new OrderPersonAsset({
  1036. orderId: testOrder.id,
  1037. personId: testOrderPerson.personId,
  1038. assetType: AssetType.CHECKIN_VIDEO,
  1039. assetFileType: AssetFileType.VIDEO,
  1040. fileId: testFile.id,
  1041. relatedTime: new Date(),
  1042. status: AssetStatus.PENDING
  1043. }),
  1044. new OrderPersonAsset({
  1045. orderId: testOrder.id,
  1046. personId: testOrderPerson.personId,
  1047. assetType: AssetType.WORK_VIDEO,
  1048. assetFileType: AssetFileType.VIDEO,
  1049. fileId: testFile.id,
  1050. relatedTime: new Date(Date.now() - 86400000), // 昨天
  1051. status: AssetStatus.VERIFIED
  1052. }),
  1053. new OrderPersonAsset({
  1054. orderId: testOrder.id,
  1055. personId: testOrderPerson.personId,
  1056. assetType: AssetType.SALARY_VIDEO,
  1057. assetFileType: AssetFileType.VIDEO,
  1058. fileId: testFile.id,
  1059. relatedTime: new Date(Date.now() - 172800000), // 前天
  1060. status: AssetStatus.REJECTED
  1061. })
  1062. ];
  1063. await assetRepository.save(testVideoAssets);
  1064. });
  1065. describe('GET /order/company-videos', () => {
  1066. it('应该返回企业维度视频列表', async () => {
  1067. const response = await client['company-videos'].$get({
  1068. query: {
  1069. companyId: testCompany.id.toString()
  1070. }
  1071. }, {
  1072. headers: {
  1073. 'Authorization': `Bearer ${testToken}`
  1074. }
  1075. });
  1076. expect(response.status).toBe(200);
  1077. if (response.status === 200) {
  1078. const data = await response.json();
  1079. expect(data).toHaveProperty('data');
  1080. expect(data).toHaveProperty('total');
  1081. expect(data.data).toHaveLength(3); // 应该返回所有视频
  1082. expect(data.total).toBe(3);
  1083. // 验证数据结构
  1084. expect(data.data[0]).toHaveProperty('id');
  1085. expect(data.data[0]).toHaveProperty('orderId');
  1086. expect(data.data[0]).toHaveProperty('personId');
  1087. expect(data.data[0]).toHaveProperty('assetType');
  1088. expect(data.data[0]).toHaveProperty('assetFileType');
  1089. expect(data.data[0]).toHaveProperty('file');
  1090. }
  1091. });
  1092. it('应该支持按视频类型过滤', async () => {
  1093. const response = await client['company-videos'].$get({
  1094. query: {
  1095. companyId: testCompany.id.toString(),
  1096. assetType: AssetType.CHECKIN_VIDEO
  1097. }
  1098. }, {
  1099. headers: {
  1100. 'Authorization': `Bearer ${testToken}`
  1101. }
  1102. });
  1103. expect(response.status).toBe(200);
  1104. if (response.status === 200) {
  1105. const data = await response.json();
  1106. expect(data.data).toHaveLength(1);
  1107. expect(data.data[0].assetType).toBe(AssetType.CHECKIN_VIDEO);
  1108. }
  1109. });
  1110. it('应该支持分页查询', async () => {
  1111. const response = await client['company-videos'].$get({
  1112. query: {
  1113. companyId: testCompany.id.toString(),
  1114. page: '1',
  1115. pageSize: '2'
  1116. }
  1117. }, {
  1118. headers: {
  1119. 'Authorization': `Bearer ${testToken}`
  1120. }
  1121. });
  1122. expect(response.status).toBe(200);
  1123. if (response.status === 200) {
  1124. const data = await response.json();
  1125. expect(data.data).toHaveLength(2);
  1126. expect(data.total).toBe(3);
  1127. }
  1128. });
  1129. it('应该支持按关联时间排序', async () => {
  1130. const response = await client['company-videos'].$get({
  1131. query: {
  1132. companyId: testCompany.id.toString(),
  1133. sortBy: 'relatedTime',
  1134. sortOrder: 'ASC'
  1135. }
  1136. }, {
  1137. headers: {
  1138. 'Authorization': `Bearer ${testToken}`
  1139. }
  1140. });
  1141. expect(response.status).toBe(200);
  1142. if (response.status === 200) {
  1143. const data = await response.json();
  1144. expect(data.data).toHaveLength(3);
  1145. // 验证排序:relatedTime 最早的应该在第一个
  1146. const firstDate = new Date(data.data[0].relatedTime).getTime();
  1147. const lastDate = new Date(data.data[2].relatedTime).getTime();
  1148. expect(firstDate).toBeLessThan(lastDate);
  1149. }
  1150. });
  1151. it('应该验证企业ID必填', async () => {
  1152. const response = await client['company-videos'].$get({
  1153. query: {}
  1154. }, {
  1155. headers: {
  1156. 'Authorization': `Bearer ${testToken}`
  1157. }
  1158. });
  1159. // 由于token中包含companyId,即使查询参数中没有companyId,API也能从token中获取
  1160. // 所以应该返回200而不是400
  1161. expect(response.status).toBe(200);
  1162. if (response.status === 200) {
  1163. const data = await response.json();
  1164. expect(data).toHaveProperty('data');
  1165. expect(data).toHaveProperty('total');
  1166. }
  1167. });
  1168. it('应该验证企业ID有效性', async () => {
  1169. const response = await client['company-videos'].$get({
  1170. query: {
  1171. companyId: '999999' // 不存在的企业ID
  1172. }
  1173. }, {
  1174. headers: {
  1175. 'Authorization': `Bearer ${testToken}`
  1176. }
  1177. });
  1178. // 注意:API可能会返回空列表而不是错误
  1179. // 根据实际实现,可能返回200且空列表,或返回404
  1180. // 这里我们假设返回200且空列表
  1181. expect(response.status).toBe(200);
  1182. if (response.status === 200) {
  1183. const data = await response.json();
  1184. expect(data.data).toHaveLength(0);
  1185. expect(data.total).toBe(0);
  1186. }
  1187. });
  1188. });
  1189. describe('POST /order/batch-download', () => {
  1190. it('应该成功批量下载企业维度视频', async () => {
  1191. const requestData = {
  1192. downloadScope: DownloadScope.COMPANY,
  1193. companyId: testCompany.id,
  1194. assetTypes: [AssetType.CHECKIN_VIDEO, AssetType.WORK_VIDEO]
  1195. };
  1196. const response = await client['batch-download'].$post({
  1197. json: requestData
  1198. }, {
  1199. headers: {
  1200. 'Authorization': `Bearer ${testToken}`
  1201. }
  1202. });
  1203. expect(response.status).toBe(200);
  1204. if (response.status === 200) {
  1205. const data = await response.json();
  1206. expect(data.success).toBe(true);
  1207. expect(data.message).toContain('批量下载成功');
  1208. expect(data.files).toHaveLength(2); // CHECKIN_VIDEO 和 WORK_VIDEO
  1209. expect(data.totalFiles).toBe(2);
  1210. // 验证文件项结构
  1211. const fileItem = data.files[0];
  1212. expect(fileItem).toHaveProperty('id');
  1213. expect(fileItem).toHaveProperty('name');
  1214. expect(fileItem).toHaveProperty('size');
  1215. expect(fileItem).toHaveProperty('url');
  1216. expect(fileItem).toHaveProperty('assetType');
  1217. expect(fileItem).toHaveProperty('orderId');
  1218. expect(fileItem).toHaveProperty('personId');
  1219. expect(fileItem).toHaveProperty('relatedTime');
  1220. }
  1221. });
  1222. it('应该成功批量下载个人维度视频', async () => {
  1223. const requestData = {
  1224. downloadScope: DownloadScope.PERSON,
  1225. companyId: testCompany.id,
  1226. personId: testOrderPerson.personId,
  1227. assetTypes: [AssetType.CHECKIN_VIDEO]
  1228. };
  1229. const response = await client['batch-download'].$post({
  1230. json: requestData
  1231. }, {
  1232. headers: {
  1233. 'Authorization': `Bearer ${testToken}`
  1234. }
  1235. });
  1236. expect(response.status).toBe(200);
  1237. if (response.status === 200) {
  1238. const data = await response.json();
  1239. expect(data.success).toBe(true);
  1240. expect(data.files).toHaveLength(1);
  1241. expect(data.files[0].assetType).toBe(AssetType.CHECKIN_VIDEO);
  1242. }
  1243. });
  1244. it('应该验证个人维度下载需要personId', async () => {
  1245. const requestData = {
  1246. downloadScope: DownloadScope.PERSON,
  1247. companyId: testCompany.id
  1248. // 缺少personId
  1249. };
  1250. const response = await client['batch-download'].$post({
  1251. json: requestData
  1252. }, {
  1253. headers: {
  1254. 'Authorization': `Bearer ${testToken}`
  1255. }
  1256. });
  1257. expect(response.status).toBe(400);
  1258. });
  1259. it('应该支持指定文件ID列表下载', async () => {
  1260. // 获取测试视频资产的文件ID
  1261. const fileIds = [testFile.id];
  1262. const requestData = {
  1263. downloadScope: DownloadScope.COMPANY,
  1264. companyId: testCompany.id,
  1265. fileIds: fileIds
  1266. };
  1267. const response = await client['batch-download'].$post({
  1268. json: requestData
  1269. }, {
  1270. headers: {
  1271. 'Authorization': `Bearer ${testToken}`
  1272. }
  1273. });
  1274. expect(response.status).toBe(200);
  1275. if (response.status === 200) {
  1276. const data = await response.json();
  1277. expect(data.success).toBe(true);
  1278. // 3个视频资产都使用同一个文件ID,所以应该返回3个文件项
  1279. expect(data.files).toHaveLength(3);
  1280. // 所有文件项的id都应该是指定的文件ID
  1281. data.files.forEach((fileItem: any) => {
  1282. expect(fileItem.id).toBe(fileIds[0]);
  1283. });
  1284. }
  1285. });
  1286. it('应该处理没有符合条件的视频文件', async () => {
  1287. const requestData = {
  1288. downloadScope: DownloadScope.COMPANY,
  1289. companyId: 999999, // 不存在的企业
  1290. assetTypes: [AssetType.CHECKIN_VIDEO]
  1291. };
  1292. const response = await client['batch-download'].$post({
  1293. json: requestData
  1294. }, {
  1295. headers: {
  1296. 'Authorization': `Bearer ${testToken}`
  1297. }
  1298. });
  1299. expect(response.status).toBe(200);
  1300. if (response.status === 200) {
  1301. const data = await response.json();
  1302. expect(data.success).toBe(true);
  1303. expect(data.files).toHaveLength(0);
  1304. expect(data.totalFiles).toBe(0);
  1305. expect(data.message).toContain('未找到符合条件的视频文件');
  1306. }
  1307. });
  1308. });
  1309. describe('PUT /order/videos/{id}/status', () => {
  1310. it('应该成功更新视频审核状态', async () => {
  1311. const testAsset = testVideoAssets[0];
  1312. const requestData = {
  1313. status: AssetStatus.VERIFIED as const
  1314. };
  1315. const response = await client.videos[':id'].status.$put({
  1316. param: { id: testAsset.id.toString() },
  1317. json: requestData
  1318. }, {
  1319. headers: {
  1320. 'Authorization': `Bearer ${testToken}`
  1321. }
  1322. });
  1323. expect(response.status).toBe(200);
  1324. if (response.status === 200) {
  1325. const data = await response.json();
  1326. expect(data.id).toBe(testAsset.id);
  1327. expect(data.status).toBe('verified');
  1328. // 验证数据库中的状态已更新
  1329. const dataSource = await IntegrationTestDatabase.getDataSource();
  1330. const assetRepository = dataSource.getRepository(OrderPersonAsset);
  1331. const updatedAsset = await assetRepository.findOne({
  1332. where: { id: testAsset.id }
  1333. });
  1334. expect(updatedAsset?.status).toBe('verified');
  1335. }
  1336. });
  1337. it('应该支持更新状态为已拒绝', async () => {
  1338. const testAsset = testVideoAssets[1]; // 当前是verified
  1339. const requestData = {
  1340. status: AssetStatus.REJECTED as const
  1341. };
  1342. const response = await client.videos[':id'].status.$put({
  1343. param: { id: testAsset.id.toString() },
  1344. json: requestData
  1345. }, {
  1346. headers: {
  1347. 'Authorization': `Bearer ${testToken}`
  1348. }
  1349. });
  1350. expect(response.status).toBe(200);
  1351. if (response.status === 200) {
  1352. const data = await response.json();
  1353. expect(data.status).toBe('rejected');
  1354. }
  1355. });
  1356. it('应该处理不存在的视频资产ID', async () => {
  1357. const requestData = {
  1358. status: AssetStatus.VERIFIED as const
  1359. };
  1360. const response = await client.videos[':id'].status.$put({
  1361. param: { id: '999999' },
  1362. json: requestData
  1363. }, {
  1364. headers: {
  1365. 'Authorization': `Bearer ${testToken}`
  1366. }
  1367. });
  1368. expect(response.status).toBe(404);
  1369. });
  1370. it('应该验证状态值的有效性', async () => {
  1371. const testAsset = testVideoAssets[0];
  1372. const requestData = {
  1373. status: 'invalid_status' as any // 无效的状态
  1374. };
  1375. const response = await client.videos[':id'].status.$put({
  1376. param: { id: testAsset.id.toString() },
  1377. json: requestData
  1378. }, {
  1379. headers: {
  1380. 'Authorization': `Bearer ${testToken}`
  1381. }
  1382. });
  1383. expect(response.status).toBe(400);
  1384. });
  1385. it('应该支持状态更新为待审核', async () => {
  1386. const testAsset = testVideoAssets[2]; // 当前是rejected
  1387. const requestData = {
  1388. status: AssetStatus.PENDING as const
  1389. };
  1390. const response = await client.videos[':id'].status.$put({
  1391. param: { id: testAsset.id.toString() },
  1392. json: requestData
  1393. }, {
  1394. headers: {
  1395. 'Authorization': `Bearer ${testToken}`
  1396. }
  1397. });
  1398. expect(response.status).toBe(200);
  1399. if (response.status === 200) {
  1400. const data = await response.json();
  1401. expect(data.status).toBe('pending');
  1402. }
  1403. });
  1404. });
  1405. });
  1406. });