disability.integration.test.ts 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367
  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 { UserEntity, Role } from '@d8d/user-module';
  6. import { File } from '@d8d/file-module';
  7. import disabledPersonRoutes from '../../src/routes/disabled-person.routes';
  8. import { DisabledPerson } from '../../src/entities/disabled-person.entity';
  9. import { DisabledBankCard } from '../../src/entities/disabled-bank-card.entity';
  10. import { DisabledPhoto } from '../../src/entities/disabled-photo.entity';
  11. import { DisabledRemark } from '../../src/entities/disabled-remark.entity';
  12. import { DisabledVisit } from '../../src/entities/disabled-visit.entity';
  13. // 设置集成测试钩子 - 包含所有相关实体
  14. setupIntegrationDatabaseHooksWithEntities([
  15. UserEntity,
  16. Role,
  17. File,
  18. DisabledPerson,
  19. DisabledBankCard,
  20. DisabledPhoto,
  21. DisabledRemark,
  22. DisabledVisit
  23. ])
  24. describe('残疾人管理API集成测试', () => {
  25. let client: ReturnType<typeof testClient<typeof disabledPersonRoutes>>;
  26. let testToken: string;
  27. let testUser: UserEntity;
  28. let testFile: File;
  29. beforeEach(async () => {
  30. // 创建测试客户端
  31. client = testClient(disabledPersonRoutes);
  32. // 获取数据源
  33. const dataSource = await IntegrationTestDatabase.getDataSource();
  34. // 创建测试用户
  35. const userRepository = dataSource.getRepository(UserEntity);
  36. testUser = userRepository.create({
  37. username: `test_user_${Date.now()}`,
  38. password: 'test_password',
  39. nickname: '测试用户',
  40. registrationSource: 'web'
  41. });
  42. await userRepository.save(testUser);
  43. // 创建测试文件(用于照片集成测试)
  44. const fileRepository = dataSource.getRepository(File);
  45. testFile = fileRepository.create({
  46. name: 'test_photo.jpg',
  47. path: 'test_photo.jpg',
  48. type: 'image/jpeg',
  49. size: 1024,
  50. uploadUserId: testUser.id,
  51. uploadTime: new Date()
  52. });
  53. await fileRepository.save(testFile);
  54. // 生成测试用户的token
  55. testToken = JWTUtil.generateToken({
  56. id: testUser.id,
  57. username: testUser.username,
  58. roles: [{name:'user'}]
  59. });
  60. });
  61. describe('POST /createDisabledPerson', () => {
  62. it('应该成功创建残疾人基本信息', async () => {
  63. const createData = {
  64. name: '张三',
  65. gender: '男',
  66. idCard: '110101199001011234',
  67. disabilityId: 'D123456789',
  68. disabilityType: '肢体残疾',
  69. disabilityLevel: '一级',
  70. idAddress: '北京市东城区',
  71. phone: '13800138000',
  72. province: '北京市',
  73. city: '北京市',
  74. // 新增字段
  75. canDirectContact: 1,
  76. isInBlackList: 0,
  77. jobStatus: 1,
  78. specificDisability: '左眼视力0.1,右眼视力0.2,需要助听器',
  79. // 日期字段
  80. idValidDate: new Date('2030-12-31'),
  81. disabilityValidDate: new Date('2030-12-31')
  82. };
  83. const response = await client.createDisabledPerson.$post({
  84. json: createData
  85. }, {
  86. headers: {
  87. 'Authorization': `Bearer ${testToken}`
  88. }
  89. });
  90. expect(response.status).toBe(200);
  91. if (response.status === 200) {
  92. const data = await response.json();
  93. expect(data.name).toBe(createData.name);
  94. expect(data.idCard).toBe(createData.idCard);
  95. expect(data.disabilityId).toBe(createData.disabilityId);
  96. // 验证新增字段
  97. expect(data.canDirectContact).toBe(createData.canDirectContact);
  98. expect(data.isInBlackList).toBe(createData.isInBlackList);
  99. expect(data.jobStatus).toBe(createData.jobStatus);
  100. expect(data.specificDisability).toBe(createData.specificDisability);
  101. // 验证日期字段
  102. expect(data.idValidDate).toBeDefined();
  103. expect(data.disabilityValidDate).toBeDefined();
  104. if (data.idValidDate) {
  105. expect(new Date(data.idValidDate).toISOString().split('T')[0]).toBe('2030-12-31');
  106. }
  107. if (data.disabilityValidDate) {
  108. expect(new Date(data.disabilityValidDate).toISOString().split('T')[0]).toBe('2030-12-31');
  109. }
  110. }
  111. });
  112. it('应该验证身份证号唯一性', async () => {
  113. // 先创建一个残疾人
  114. const dataSource = await IntegrationTestDatabase.getDataSource();
  115. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  116. const existingPerson = disabledPersonRepository.create({
  117. name: '李四',
  118. gender: '女',
  119. idCard: '110101199001011235',
  120. disabilityId: 'D123456788',
  121. disabilityType: '视力残疾',
  122. disabilityLevel: '二级',
  123. idAddress: '北京市西城区',
  124. phone: '13900139000',
  125. province: '北京市',
  126. city: '北京市',
  127. // 新增字段
  128. canDirectContact: 0,
  129. isInBlackList: 0,
  130. jobStatus: 2,
  131. // 日期字段
  132. idValidDate: new Date('2035-05-15'),
  133. disabilityValidDate: new Date('2035-05-15')
  134. });
  135. await disabledPersonRepository.save(existingPerson);
  136. // 尝试创建相同身份证号的残疾人
  137. const createData = {
  138. name: '王五',
  139. gender: '男',
  140. idCard: '110101199001011235', // 重复的身份证号
  141. disabilityId: 'D123456777',
  142. disabilityType: '听力残疾',
  143. disabilityLevel: '三级',
  144. idAddress: '北京市朝阳区',
  145. phone: '13700137000',
  146. province: '北京市',
  147. city: '北京市',
  148. // 新增字段
  149. canDirectContact: 1,
  150. isInBlackList: 1,
  151. jobStatus: 3,
  152. // 日期字段
  153. idValidDate: new Date('2043-08-20'),
  154. disabilityValidDate: new Date('2043-08-20')
  155. };
  156. const response = await client.createDisabledPerson.$post({
  157. json: createData
  158. }, {
  159. headers: {
  160. 'Authorization': `Bearer ${testToken}`
  161. }
  162. });
  163. expect(response.status).toBe(400);
  164. });
  165. it('应该验证必填字段', async () => {
  166. const createData = {
  167. name: '', // 空字符串,应该验证失败
  168. gender: '男',
  169. idCard: '110101199001011236',
  170. disabilityId: 'D123456776',
  171. disabilityType: '肢体残疾',
  172. disabilityLevel: '一级',
  173. idAddress: '北京市海淀区',
  174. phone: '13600136000',
  175. province: '北京市',
  176. city: '北京市',
  177. // 新增字段(可选字段,不影响必填验证)
  178. canDirectContact: 1,
  179. isInBlackList: 0,
  180. jobStatus: 1,
  181. // 日期字段(可选字段,不影响必填验证)
  182. idValidDate: new Date('2028-03-10'),
  183. disabilityValidDate: new Date('2028-03-10')
  184. };
  185. const response = await client.createDisabledPerson.$post({
  186. json: createData
  187. }, {
  188. headers: {
  189. 'Authorization': `Bearer ${testToken}`
  190. }
  191. });
  192. expect(response.status).toBe(400);
  193. });
  194. it('应该验证具体残疾部位和情况字段为空值', async () => {
  195. const createData = {
  196. name: '空值测试',
  197. gender: '男',
  198. idCard: '110101199001011236',
  199. disabilityId: 'D123456776',
  200. disabilityType: '肢体残疾',
  201. disabilityLevel: '一级',
  202. idAddress: '北京市海淀区',
  203. phone: '13600136000',
  204. province: '北京市',
  205. city: '北京市',
  206. canDirectContact: 1,
  207. isInBlackList: 0,
  208. jobStatus: 1,
  209. // specificDisability 字段不提供,测试空值
  210. idValidDate: new Date('2028-03-10'),
  211. disabilityValidDate: new Date('2028-03-10')
  212. };
  213. const response = await client.createDisabledPerson.$post({
  214. json: createData
  215. }, {
  216. headers: {
  217. 'Authorization': `Bearer ${testToken}`
  218. }
  219. });
  220. expect(response.status).toBe(200);
  221. if (response.status === 200) {
  222. const data = await response.json();
  223. expect(data.name).toBe(createData.name);
  224. expect(data.specificDisability).toBeNull(); // 应该为null,因为数据库字段nullable: true
  225. }
  226. });
  227. it('应该验证具体残疾部位和情况字段为有效值', async () => {
  228. const createData = {
  229. name: '有效值测试',
  230. gender: '女',
  231. idCard: '110101199001011237',
  232. disabilityId: 'D123456775',
  233. disabilityType: '视力残疾',
  234. disabilityLevel: '二级',
  235. idAddress: '北京市朝阳区',
  236. phone: '13700137000',
  237. province: '北京市',
  238. city: '北京市',
  239. canDirectContact: 0,
  240. isInBlackList: 0,
  241. jobStatus: 0,
  242. specificDisability: '双眼视力均为0.05,需要导盲犬辅助',
  243. idValidDate: new Date('2030-06-15'),
  244. disabilityValidDate: new Date('2030-06-15')
  245. };
  246. const response = await client.createDisabledPerson.$post({
  247. json: createData
  248. }, {
  249. headers: {
  250. 'Authorization': `Bearer ${testToken}`
  251. }
  252. });
  253. expect(response.status).toBe(200);
  254. if (response.status === 200) {
  255. const data = await response.json();
  256. expect(data.name).toBe(createData.name);
  257. expect(data.specificDisability).toBe(createData.specificDisability);
  258. }
  259. });
  260. it('应该验证具体残疾部位和情况字段边界值(500字符)', async () => {
  261. // 生成500字符的字符串
  262. const maxLengthText = 'A'.repeat(500);
  263. const createData = {
  264. name: '边界值测试',
  265. gender: '男',
  266. idCard: '110101199001011238',
  267. disabilityId: 'D123456774',
  268. disabilityType: '听力残疾',
  269. disabilityLevel: '三级',
  270. idAddress: '北京市丰台区',
  271. phone: '13800138001',
  272. province: '北京市',
  273. city: '北京市',
  274. canDirectContact: 1,
  275. isInBlackList: 0,
  276. jobStatus: 1,
  277. specificDisability: maxLengthText,
  278. idValidDate: new Date('2032-08-20'),
  279. disabilityValidDate: new Date('2032-08-20')
  280. };
  281. const response = await client.createDisabledPerson.$post({
  282. json: createData
  283. }, {
  284. headers: {
  285. 'Authorization': `Bearer ${testToken}`
  286. }
  287. });
  288. expect(response.status).toBe(200);
  289. if (response.status === 200) {
  290. const data = await response.json();
  291. expect(data.name).toBe(createData.name);
  292. expect(data.specificDisability).toBe(createData.specificDisability);
  293. expect(data.specificDisability.length).toBe(500);
  294. }
  295. });
  296. it('应该验证具体残疾部位和情况字段超过500字符限制', async () => {
  297. // 生成501字符的字符串
  298. const tooLongText = 'A'.repeat(501);
  299. const createData = {
  300. name: '超长测试',
  301. gender: '女',
  302. idCard: '110101199001011239',
  303. disabilityId: 'D123456773',
  304. disabilityType: '言语残疾',
  305. disabilityLevel: '四级',
  306. idAddress: '北京市石景山区',
  307. phone: '13900139001',
  308. province: '北京市',
  309. city: '北京市',
  310. canDirectContact: 0,
  311. isInBlackList: 0,
  312. jobStatus: 0,
  313. specificDisability: tooLongText,
  314. idValidDate: new Date('2034-12-31'),
  315. disabilityValidDate: new Date('2034-12-31')
  316. };
  317. const response = await client.createDisabledPerson.$post({
  318. json: createData
  319. }, {
  320. headers: {
  321. 'Authorization': `Bearer ${testToken}`
  322. }
  323. });
  324. expect(response.status).toBe(400); // 应该返回400,因为超过长度限制
  325. });
  326. });
  327. describe('POST /deleteDisabledPerson', () => {
  328. it('应该成功删除残疾人', async () => {
  329. // 先创建一个残疾人
  330. const dataSource = await IntegrationTestDatabase.getDataSource();
  331. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  332. const person = disabledPersonRepository.create({
  333. name: '测试删除人员',
  334. gender: '男',
  335. idCard: '110101199001011237',
  336. disabilityId: 'D123456775',
  337. disabilityType: '肢体残疾',
  338. disabilityLevel: '一级',
  339. idAddress: '北京市石景山区',
  340. phone: '13500135000',
  341. province: '北京市',
  342. city: '北京市'
  343. });
  344. await disabledPersonRepository.save(person);
  345. const deleteData = {
  346. id: person.id
  347. };
  348. const response = await client.deleteDisabledPerson.$post({
  349. json: deleteData
  350. }, {
  351. headers: {
  352. 'Authorization': `Bearer ${testToken}`
  353. }
  354. });
  355. expect(response.status).toBe(200);
  356. if (response.status === 200) {
  357. const data = await response.json();
  358. expect(data.success).toBe(true);
  359. // 验证残疾人已被删除
  360. const deletedPerson = await disabledPersonRepository.findOne({ where: { id: person.id } });
  361. expect(deletedPerson).toBeNull();
  362. }
  363. });
  364. it('应该处理不存在的残疾人ID', async () => {
  365. const deleteData = {
  366. id: 99999 // 不存在的ID
  367. };
  368. const response = await client.deleteDisabledPerson.$post({
  369. json: deleteData
  370. }, {
  371. headers: {
  372. 'Authorization': `Bearer ${testToken}`
  373. }
  374. });
  375. expect(response.status).toBe(404);
  376. });
  377. });
  378. describe('POST /updateDisabledPerson', () => {
  379. it('应该成功更新残疾人信息', async () => {
  380. // 先创建一个残疾人
  381. const dataSource = await IntegrationTestDatabase.getDataSource();
  382. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  383. const person = disabledPersonRepository.create({
  384. name: '原始姓名',
  385. gender: '男',
  386. idCard: '110101199001011238',
  387. disabilityId: 'D123456774',
  388. disabilityType: '肢体残疾',
  389. disabilityLevel: '一级',
  390. idAddress: '北京市通州区',
  391. phone: '13400134000',
  392. province: '北京市',
  393. city: '北京市',
  394. // 新增字段初始值
  395. canDirectContact: 1,
  396. isInBlackList: 0,
  397. jobStatus: 1,
  398. // 日期字段初始值
  399. idValidDate: new Date('2023-01-01'),
  400. disabilityValidDate: new Date('2023-01-01')
  401. });
  402. await disabledPersonRepository.save(person);
  403. const updateData = {
  404. id: person.id,
  405. name: '更新后的姓名',
  406. gender: '女',
  407. phone: '13300133000',
  408. // 更新新增字段
  409. canDirectContact: 0,
  410. isInBlackList: 1,
  411. jobStatus: 1,
  412. // 更新日期字段
  413. idValidDate: new Date('2033-01-01'), // 更新有效期
  414. disabilityValidDate: new Date('2033-01-01') // 更新有效期
  415. };
  416. const response = await client.updateDisabledPerson.$post({
  417. json: updateData
  418. }, {
  419. headers: {
  420. 'Authorization': `Bearer ${testToken}`
  421. }
  422. });
  423. expect(response.status).toBe(200);
  424. if (response.status === 200) {
  425. const data = await response.json();
  426. expect(data.name).toBe(updateData.name);
  427. expect(data.gender).toBe(updateData.gender);
  428. expect(data.phone).toBe(updateData.phone);
  429. // 验证新增字段已更新
  430. expect(data.canDirectContact).toBe(updateData.canDirectContact);
  431. expect(data.isInBlackList).toBe(updateData.isInBlackList);
  432. expect(data.jobStatus).toBe(updateData.jobStatus);
  433. // 验证日期字段
  434. expect(data.idValidDate).toBeDefined();
  435. expect(data.disabilityValidDate).toBeDefined();
  436. if (data.idValidDate) {
  437. expect(new Date(data.idValidDate).toISOString().split('T')[0]).toBe('2033-01-01');
  438. }
  439. if (data.disabilityValidDate) {
  440. expect(new Date(data.disabilityValidDate).toISOString().split('T')[0]).toBe('2033-01-01');
  441. }
  442. }
  443. });
  444. it('应该验证身份证号唯一性(更新时)', async () => {
  445. // 创建两个残疾人
  446. const dataSource = await IntegrationTestDatabase.getDataSource();
  447. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  448. const person1 = disabledPersonRepository.create({
  449. name: '人员A',
  450. gender: '男',
  451. idCard: '110101199001011239',
  452. disabilityId: 'D123456773',
  453. disabilityType: '肢体残疾',
  454. disabilityLevel: '一级',
  455. idAddress: '北京市顺义区',
  456. phone: '13200132000',
  457. province: '北京市',
  458. city: '北京市',
  459. // 新增字段
  460. canDirectContact: 1,
  461. isInBlackList: 0,
  462. jobStatus: 1,
  463. // 日期字段
  464. idValidDate: new Date('2028-06-15'),
  465. disabilityValidDate: new Date('2028-06-15')
  466. });
  467. await disabledPersonRepository.save(person1);
  468. const person2 = disabledPersonRepository.create({
  469. name: '人员B',
  470. gender: '女',
  471. idCard: '110101199001011240',
  472. disabilityId: 'D123456772',
  473. disabilityType: '视力残疾',
  474. disabilityLevel: '二级',
  475. idAddress: '北京市大兴区',
  476. phone: '13100131000',
  477. province: '北京市',
  478. city: '北京市',
  479. // 新增字段
  480. canDirectContact: 0,
  481. isInBlackList: 1,
  482. jobStatus: 2,
  483. // 日期字段
  484. idValidDate: new Date('2034-09-20'),
  485. disabilityValidDate: new Date('2034-09-20')
  486. });
  487. await disabledPersonRepository.save(person2);
  488. // 尝试将人员2的身份证号改为人员1的身份证号
  489. const updateData = {
  490. id: person2.id,
  491. idCard: '110101199001011239' // 重复的身份证号
  492. };
  493. const response = await client.updateDisabledPerson.$post({
  494. json: updateData
  495. }, {
  496. headers: {
  497. 'Authorization': `Bearer ${testToken}`
  498. }
  499. });
  500. expect(response.status).toBe(400);
  501. });
  502. it('应该处理不存在的残疾人', async () => {
  503. const updateData = {
  504. id: 99999, // 不存在的ID
  505. name: '新姓名'
  506. };
  507. const response = await client.updateDisabledPerson.$post({
  508. json: updateData
  509. }, {
  510. headers: {
  511. 'Authorization': `Bearer ${testToken}`
  512. }
  513. });
  514. expect(response.status).toBe(404);
  515. });
  516. });
  517. describe('GET /getAllDisabledPersons', () => {
  518. it('应该成功获取残疾人列表(分页)', async () => {
  519. // 创建一些测试数据
  520. const dataSource = await IntegrationTestDatabase.getDataSource();
  521. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  522. for (let i = 1; i <= 5; i++) {
  523. const person = disabledPersonRepository.create({
  524. name: `残疾人${i}`,
  525. gender: i % 2 === 0 ? '女' : '男',
  526. idCard: `1101011990010112${40 + i}`,
  527. disabilityId: `D1234567${70 + i}`,
  528. disabilityType: '肢体残疾',
  529. disabilityLevel: '一级',
  530. idAddress: `北京市测试区${i}`,
  531. phone: `138001380${i}`,
  532. province: '北京市',
  533. city: '北京市'
  534. });
  535. await disabledPersonRepository.save(person);
  536. }
  537. const response = await client.getAllDisabledPersons.$get({
  538. query: {
  539. skip: 0,
  540. take: 10
  541. }
  542. }, {
  543. headers: {
  544. 'Authorization': `Bearer ${testToken}`
  545. }
  546. });
  547. expect(response.status).toBe(200);
  548. if (response.status === 200) {
  549. const data = await response.json();
  550. expect(data.data).toHaveLength(5);
  551. expect(data.total).toBe(5);
  552. expect(data.data[0].name).toBe('残疾人5'); // 按ID降序排列
  553. }
  554. });
  555. it('应该处理分页参数', async () => {
  556. // 创建更多测试数据
  557. const dataSource = await IntegrationTestDatabase.getDataSource();
  558. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  559. for (let i = 1; i <= 15; i++) {
  560. const person = disabledPersonRepository.create({
  561. name: `分页人员${i}`,
  562. gender: i % 2 === 0 ? '女' : '男',
  563. idCard: `1101011990010113${i}`,
  564. disabilityId: `D1234568${i}`,
  565. disabilityType: '肢体残疾',
  566. disabilityLevel: '一级',
  567. idAddress: `北京市分页区${i}`,
  568. phone: `138001381${i}`,
  569. province: '北京市',
  570. city: '北京市'
  571. });
  572. await disabledPersonRepository.save(person);
  573. }
  574. const response = await client.getAllDisabledPersons.$get({
  575. query: {
  576. skip: 5,
  577. take: 5
  578. }
  579. }, {
  580. headers: {
  581. 'Authorization': `Bearer ${testToken}`
  582. }
  583. });
  584. expect(response.status).toBe(200);
  585. if (response.status === 200) {
  586. const data = await response.json();
  587. expect(data.data).toHaveLength(5);
  588. expect(data.total).toBe(15);
  589. }
  590. });
  591. it('应该支持残疾类型筛选', async () => {
  592. // 创建测试数据
  593. const dataSource = await IntegrationTestDatabase.getDataSource();
  594. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  595. // 创建不同残疾类型的人员
  596. const person1 = disabledPersonRepository.create({
  597. name: '视力残疾人',
  598. gender: '男',
  599. idCard: '110101199001011351',
  600. disabilityId: 'D123456851',
  601. disabilityType: '视力残疾',
  602. disabilityLevel: '一级',
  603. idAddress: '北京市测试区',
  604. phone: '1380013851',
  605. province: '北京市',
  606. city: '北京市'
  607. });
  608. await disabledPersonRepository.save(person1);
  609. const person2 = disabledPersonRepository.create({
  610. name: '肢体残疾人',
  611. gender: '女',
  612. idCard: '110101199001011352',
  613. disabilityId: 'D123456852',
  614. disabilityType: '肢体残疾',
  615. disabilityLevel: '二级',
  616. idAddress: '北京市测试区',
  617. phone: '1380013852',
  618. province: '北京市',
  619. city: '北京市'
  620. });
  621. await disabledPersonRepository.save(person2);
  622. // 测试视力残疾筛选
  623. const response = await client.getAllDisabledPersons.$get({
  624. query: {
  625. disabilityType: '视力残疾',
  626. skip: 0,
  627. take: 10
  628. }
  629. }, {
  630. headers: {
  631. 'Authorization': `Bearer ${testToken}`
  632. }
  633. });
  634. expect(response.status).toBe(200);
  635. if (response.status === 200) {
  636. const data = await response.json();
  637. expect(data.data).toHaveLength(1);
  638. expect(data.data[0].disabilityType).toBe('视力残疾');
  639. }
  640. });
  641. it('应该支持残疾级别筛选', async () => {
  642. // 创建测试数据
  643. const dataSource = await IntegrationTestDatabase.getDataSource();
  644. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  645. // 创建不同残疾级别的人员
  646. const person1 = disabledPersonRepository.create({
  647. name: '一级残疾人',
  648. gender: '男',
  649. idCard: '110101199001011361',
  650. disabilityId: 'D123456861',
  651. disabilityType: '肢体残疾',
  652. disabilityLevel: '一级',
  653. idAddress: '北京市测试区',
  654. phone: '1380013861',
  655. province: '北京市',
  656. city: '北京市'
  657. });
  658. await disabledPersonRepository.save(person1);
  659. const person2 = disabledPersonRepository.create({
  660. name: '二级残疾人',
  661. gender: '女',
  662. idCard: '110101199001011362',
  663. disabilityId: 'D123456862',
  664. disabilityType: '肢体残疾',
  665. disabilityLevel: '二级',
  666. idAddress: '北京市测试区',
  667. phone: '1380013862',
  668. province: '北京市',
  669. city: '北京市'
  670. });
  671. await disabledPersonRepository.save(person2);
  672. // 测试一级残疾筛选
  673. const response = await client.getAllDisabledPersons.$get({
  674. query: {
  675. disabilityLevel: '一级',
  676. skip: 0,
  677. take: 10
  678. }
  679. }, {
  680. headers: {
  681. 'Authorization': `Bearer ${testToken}`
  682. }
  683. });
  684. expect(response.status).toBe(200);
  685. if (response.status === 200) {
  686. const data = await response.json();
  687. expect(data.data).toHaveLength(1);
  688. expect(data.data[0].disabilityLevel).toBe('一级');
  689. }
  690. });
  691. it('应该支持省份筛选', async () => {
  692. // 创建测试数据
  693. const dataSource = await IntegrationTestDatabase.getDataSource();
  694. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  695. // 创建不同省份的人员
  696. const person1 = disabledPersonRepository.create({
  697. name: '北京人员',
  698. gender: '男',
  699. idCard: '110101199001011371',
  700. disabilityId: 'D123456871',
  701. disabilityType: '肢体残疾',
  702. disabilityLevel: '一级',
  703. idAddress: '北京市测试区',
  704. phone: '1380013871',
  705. province: '北京市',
  706. city: '北京市'
  707. });
  708. await disabledPersonRepository.save(person1);
  709. const person2 = disabledPersonRepository.create({
  710. name: '上海人员',
  711. gender: '女',
  712. idCard: '310101199001011372',
  713. disabilityId: 'D123456872',
  714. disabilityType: '肢体残疾',
  715. disabilityLevel: '二级',
  716. idAddress: '上海市测试区',
  717. phone: '1380013872',
  718. province: '上海市',
  719. city: '上海市'
  720. });
  721. await disabledPersonRepository.save(person2);
  722. // 测试北京筛选
  723. const response = await client.getAllDisabledPersons.$get({
  724. query: {
  725. province: '北京市',
  726. skip: 0,
  727. take: 10
  728. }
  729. }, {
  730. headers: {
  731. 'Authorization': `Bearer ${testToken}`
  732. }
  733. });
  734. expect(response.status).toBe(200);
  735. if (response.status === 200) {
  736. const data = await response.json();
  737. expect(data.data).toHaveLength(1);
  738. expect(data.data[0].province).toBe('北京市');
  739. }
  740. });
  741. it('应该支持多条件组合筛选', async () => {
  742. // 创建测试数据
  743. const dataSource = await IntegrationTestDatabase.getDataSource();
  744. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  745. // 创建符合多个条件的人员
  746. const person1 = disabledPersonRepository.create({
  747. name: '北京一级视力残疾人',
  748. gender: '男',
  749. idCard: '110101199001011381',
  750. disabilityId: 'D123456881',
  751. disabilityType: '视力残疾',
  752. disabilityLevel: '一级',
  753. idAddress: '北京市测试区',
  754. phone: '1380013881',
  755. province: '北京市',
  756. city: '北京市'
  757. });
  758. await disabledPersonRepository.save(person1);
  759. // 创建不符合全部条件的人员
  760. const person2 = disabledPersonRepository.create({
  761. name: '北京二级肢体残疾人',
  762. gender: '女',
  763. idCard: '110101199001011382',
  764. disabilityId: 'D123456882',
  765. disabilityType: '肢体残疾',
  766. disabilityLevel: '二级',
  767. idAddress: '北京市测试区',
  768. phone: '1380013882',
  769. province: '北京市',
  770. city: '北京市'
  771. });
  772. await disabledPersonRepository.save(person2);
  773. // 测试多条件组合筛选:北京 + 一级 + 视力残疾
  774. const response = await client.getAllDisabledPersons.$get({
  775. query: {
  776. province: '北京市',
  777. disabilityType: '视力残疾',
  778. disabilityLevel: '一级',
  779. skip: 0,
  780. take: 10
  781. }
  782. }, {
  783. headers: {
  784. 'Authorization': `Bearer ${testToken}`
  785. }
  786. });
  787. expect(response.status).toBe(200);
  788. if (response.status === 200) {
  789. const data = await response.json();
  790. expect(data.data).toHaveLength(1);
  791. expect(data.data[0].name).toBe('北京一级视力残疾人');
  792. }
  793. });
  794. });
  795. describe('GET /searchDisabledPersons', () => {
  796. it('应该成功按姓名搜索残疾人', async () => {
  797. // 创建测试数据
  798. const dataSource = await IntegrationTestDatabase.getDataSource();
  799. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  800. const person1 = disabledPersonRepository.create({
  801. name: '张三',
  802. gender: '男',
  803. idCard: '110101199001011241',
  804. disabilityId: 'D123456771',
  805. disabilityType: '肢体残疾',
  806. disabilityLevel: '一级',
  807. idAddress: '北京市昌平区',
  808. phone: '13000130001',
  809. province: '北京市',
  810. city: '北京市'
  811. });
  812. await disabledPersonRepository.save(person1);
  813. const person2 = disabledPersonRepository.create({
  814. name: '李四',
  815. gender: '女',
  816. idCard: '110101199001011242',
  817. disabilityId: 'D123456770',
  818. disabilityType: '视力残疾',
  819. disabilityLevel: '二级',
  820. idAddress: '北京市平谷区',
  821. phone: '13000130002',
  822. province: '北京市',
  823. city: '北京市'
  824. });
  825. await disabledPersonRepository.save(person2);
  826. const response = await client.searchDisabledPersons.$get({
  827. query: {
  828. keyword: '张三',
  829. skip: 0,
  830. take: 10
  831. }
  832. }, {
  833. headers: {
  834. 'Authorization': `Bearer ${testToken}`
  835. }
  836. });
  837. expect(response.status).toBe(200);
  838. if (response.status === 200) {
  839. const data = await response.json();
  840. expect(data.data).toHaveLength(1);
  841. expect(data.data[0].name).toBe('张三');
  842. }
  843. });
  844. it('应该验证搜索关键词不能为空', async () => {
  845. const response = await client.searchDisabledPersons.$get({
  846. query: {
  847. keyword: '', // 空关键词
  848. skip: 0,
  849. take: 10
  850. }
  851. }, {
  852. headers: {
  853. 'Authorization': `Bearer ${testToken}`
  854. }
  855. });
  856. expect(response.status).toBe(400);
  857. });
  858. });
  859. describe('GET /getDisabledPerson/{id}', () => {
  860. it('应该成功获取单个残疾人详情', async () => {
  861. // 先创建一个残疾人
  862. const dataSource = await IntegrationTestDatabase.getDataSource();
  863. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  864. const person = disabledPersonRepository.create({
  865. name: '测试人员详情',
  866. gender: '男',
  867. idCard: '110101199001011243',
  868. disabilityId: 'D123456769',
  869. disabilityType: '肢体残疾',
  870. disabilityLevel: '一级',
  871. idAddress: '北京市怀柔区',
  872. phone: '13000130003',
  873. province: '北京市',
  874. city: '北京市',
  875. canDirectContact: 1,
  876. isMarried: 1
  877. });
  878. await disabledPersonRepository.save(person);
  879. const response = await client.getDisabledPerson[':id'].$get({
  880. param: {
  881. id: person.id
  882. }
  883. }, {
  884. headers: {
  885. 'Authorization': `Bearer ${testToken}`
  886. }
  887. });
  888. expect(response.status).toBe(200);
  889. if (response.status === 200) {
  890. const data = await response.json();
  891. expect(data?.name).toBe('测试人员详情');
  892. expect(data?.canDirectContact).toBe(1);
  893. }
  894. });
  895. it('应该处理不存在的残疾人ID', async () => {
  896. const response = await client.getDisabledPerson[':id'].$get({
  897. param: {
  898. id: 99999 // 不存在的ID
  899. }
  900. }, {
  901. headers: {
  902. 'Authorization': `Bearer ${testToken}`
  903. }
  904. });
  905. expect(response.status).toBe(200); // 返回200,但数据为null
  906. if (response.status === 200) {
  907. const data = await response.json();
  908. expect(data).toBeNull();
  909. }
  910. });
  911. });
  912. describe('GET /getDisabledPersonByIdCard', () => {
  913. it('应该成功根据身份证号查询残疾人', async () => {
  914. // 先创建一个残疾人
  915. const dataSource = await IntegrationTestDatabase.getDataSource();
  916. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  917. const person = disabledPersonRepository.create({
  918. name: '身份证查询测试',
  919. gender: '女',
  920. idCard: '110101199001011244',
  921. disabilityId: 'D123456768',
  922. disabilityType: '听力残疾',
  923. disabilityLevel: '三级',
  924. idAddress: '北京市密云区',
  925. phone: '13000130004',
  926. province: '北京市',
  927. city: '北京市'
  928. });
  929. await disabledPersonRepository.save(person);
  930. const response = await client.findByIdCard[':idCard'].$get({
  931. param: {
  932. idCard: '110101199001011244'
  933. }
  934. }, {
  935. headers: {
  936. 'Authorization': `Bearer ${testToken}`
  937. }
  938. });
  939. expect(response.status).toBe(200);
  940. if (response.status === 200) {
  941. const data = await response.json();
  942. expect(data?.name).toBe('身份证查询测试');
  943. expect(data?.idCard).toBe('110101199001011244');
  944. }
  945. });
  946. it('应该处理不存在的身份证号', async () => {
  947. const response = await client.findByIdCard[':idCard'].$get({
  948. param: {
  949. idCard: '999999999999999999' // 不存在的身份证号
  950. }
  951. }, {
  952. headers: {
  953. 'Authorization': `Bearer ${testToken}`
  954. }
  955. });
  956. expect(response.status).toBe(200); // 返回200,但数据为null
  957. if (response.status === 200) {
  958. const data = await response.json();
  959. expect(data).toBeNull();
  960. }
  961. });
  962. });
  963. describe('POST /createAggregatedDisabledPerson', () => {
  964. it('应该成功创建聚合残疾人信息(包含所有关联数据)', async () => {
  965. const createData = {
  966. personInfo: {
  967. name: '聚合创建测试',
  968. gender: '男',
  969. idCard: '110101199001011245',
  970. disabilityId: 'D123456767',
  971. disabilityType: '肢体残疾',
  972. disabilityLevel: '一级',
  973. idAddress: '北京市延庆区',
  974. phone: '13000130005',
  975. province: '北京市',
  976. city: '北京市',
  977. // 新增字段
  978. canDirectContact: 1,
  979. isInBlackList: 0,
  980. jobStatus: 1,
  981. specificDisability: '左腿截肢,右腿行动不便,需要轮椅',
  982. // 日期字段
  983. idValidDate: new Date('2045-11-30'),
  984. disabilityValidDate: new Date('2045-11-30')
  985. },
  986. bankCards: [
  987. {
  988. subBankName: '北京分行',
  989. bankName: '中国工商银行',
  990. cardNumber: '6222021234567890123',
  991. cardholderName: '聚合创建测试',
  992. fileId: testFile.id,
  993. isDefault: 0
  994. }
  995. ],
  996. photos: [
  997. {
  998. photoType: '身份证照片',
  999. fileId: testFile.id // 使用测试文件ID
  1000. }
  1001. ],
  1002. remarks: [
  1003. {
  1004. remarkContent: '家庭经济困难,需要帮助',
  1005. operatorId: 1
  1006. }
  1007. ],
  1008. visits: [
  1009. {
  1010. visitDate: '2025-12-02T10:00:00Z',
  1011. visitType: '电话回访',
  1012. visitContent: '初次回访,了解基本情况',
  1013. visitorId: 1
  1014. }
  1015. ]
  1016. };
  1017. const response = await client.createAggregatedDisabledPerson.$post({
  1018. json: createData
  1019. }, {
  1020. headers: {
  1021. 'Authorization': `Bearer ${testToken}`
  1022. }
  1023. });
  1024. expect(response.status).toBe(200);
  1025. if (response.status === 200) {
  1026. const data = await response.json();
  1027. expect(data.personInfo.name).toBe('聚合创建测试');
  1028. // 验证新增字段
  1029. expect(data.personInfo.canDirectContact).toBe(1);
  1030. expect(data.personInfo.isInBlackList).toBe(0);
  1031. expect(data.personInfo.jobStatus).toBe(1);
  1032. expect(data.personInfo.specificDisability).toBe('左腿截肢,右腿行动不便,需要轮椅');
  1033. // 验证日期字段
  1034. expect(data.personInfo.idValidDate).toBeDefined();
  1035. expect(data.personInfo.disabilityValidDate).toBeDefined();
  1036. if (data.personInfo.idValidDate) {
  1037. expect(new Date(data.personInfo.idValidDate).toISOString().split('T')[0]).toBe('2045-11-30');
  1038. }
  1039. if (data.personInfo.disabilityValidDate) {
  1040. expect(new Date(data.personInfo.disabilityValidDate).toISOString().split('T')[0]).toBe('2045-11-30');
  1041. }
  1042. expect(data.bankCards).toHaveLength(1);
  1043. expect(data.photos).toHaveLength(1);
  1044. expect(data.remarks).toHaveLength(1);
  1045. expect(data.visits).toHaveLength(1);
  1046. // 验证文件集成
  1047. expect(data.photos[0].fileId).toBe(testFile.id);
  1048. }
  1049. });
  1050. it('应该验证文件ID的有效性', async () => {
  1051. const createData = {
  1052. personInfo: {
  1053. name: '文件验证测试',
  1054. gender: '女',
  1055. idCard: '110101199001011246',
  1056. disabilityId: 'D123456766',
  1057. disabilityType: '视力残疾',
  1058. disabilityLevel: '二级',
  1059. idAddress: '北京市房山区',
  1060. phone: '13000130006',
  1061. province: '北京市',
  1062. city: '北京市',
  1063. // 新增字段
  1064. canDirectContact: 0,
  1065. isInBlackList: 1,
  1066. jobStatus: 2,
  1067. // 日期字段
  1068. idValidDate: new Date('2036-07-25'),
  1069. disabilityValidDate: new Date('2036-07-25')
  1070. },
  1071. photos: [
  1072. {
  1073. photoType: '身份证照片',
  1074. fileId: 99999 // 不存在的文件ID
  1075. }
  1076. ]
  1077. };
  1078. const response = await client.createAggregatedDisabledPerson.$post({
  1079. json: createData
  1080. }, {
  1081. headers: {
  1082. 'Authorization': `Bearer ${testToken}`
  1083. }
  1084. });
  1085. expect(response.status).toBe(400); // 应该返回400,因为文件ID无效
  1086. });
  1087. });
  1088. describe('GET /getAggregatedDisabledPerson/{personId}', () => {
  1089. it('应该成功获取聚合残疾人信息', async () => {
  1090. // 先创建一个完整的残疾人数据(包含所有关联数据)
  1091. const dataSource = await IntegrationTestDatabase.getDataSource();
  1092. // 创建残疾人
  1093. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  1094. const person = disabledPersonRepository.create({
  1095. name: '聚合查询测试',
  1096. gender: '男',
  1097. idCard: '110101199001011247',
  1098. disabilityId: 'D123456765',
  1099. disabilityType: '肢体残疾',
  1100. disabilityLevel: '一级',
  1101. idAddress: '北京市门头沟区',
  1102. phone: '13000130007',
  1103. province: '北京市',
  1104. city: '北京市'
  1105. });
  1106. await disabledPersonRepository.save(person);
  1107. // 创建银行卡
  1108. const bankCardRepository = dataSource.getRepository(DisabledBankCard);
  1109. const bankCard = bankCardRepository.create({
  1110. personId: person.id,
  1111. subBankName: '北京分行',
  1112. bankName: '中国建设银行',
  1113. cardNumber: '6227001234567890123',
  1114. cardholderName: '聚合查询测试',
  1115. fileId: testFile.id,
  1116. isDefault: 0
  1117. });
  1118. await bankCardRepository.save(bankCard);
  1119. // 创建照片(使用测试文件)
  1120. const photoRepository = dataSource.getRepository(DisabledPhoto);
  1121. const photo = photoRepository.create({
  1122. personId: person.id,
  1123. photoType: '身份证照片',
  1124. fileId: testFile.id
  1125. });
  1126. await photoRepository.save(photo);
  1127. // 创建备注
  1128. const remarkRepository = dataSource.getRepository(DisabledRemark);
  1129. const remark = remarkRepository.create({
  1130. personId: person.id,
  1131. remarkContent: '目前无工作,需要就业帮助',
  1132. operatorId: 1
  1133. });
  1134. await remarkRepository.save(remark);
  1135. // 创建回访记录
  1136. const visitRepository = dataSource.getRepository(DisabledVisit);
  1137. const visit = visitRepository.create({
  1138. personId: person.id,
  1139. visitDate: new Date('2025-12-01T14:30:00Z'),
  1140. visitType: '上门回访',
  1141. visitContent: '了解就业需求',
  1142. visitorId: 2
  1143. });
  1144. await visitRepository.save(visit);
  1145. const response = await client.getAggregatedDisabledPerson[':id'].$get({
  1146. param: {
  1147. id: person.id
  1148. }
  1149. }, {
  1150. headers: {
  1151. 'Authorization': `Bearer ${testToken}`
  1152. }
  1153. });
  1154. // 调试:打印响应状态和错误信息
  1155. console.debug('响应状态:', response.status);
  1156. if (response.status !== 200) {
  1157. const errorText = await response.text();
  1158. console.debug('错误响应:', errorText);
  1159. }
  1160. expect(response.status).toBe(200);
  1161. if (response.status === 200) {
  1162. const data = await response.json();
  1163. expect(data).not.toBeNull();
  1164. expect(data!.personInfo.name).toBe('聚合查询测试');
  1165. expect(data!.bankCards).toHaveLength(1);
  1166. expect(data!.photos).toHaveLength(1);
  1167. expect(data!.remarks).toHaveLength(1);
  1168. expect(data!.visits).toHaveLength(1);
  1169. // 验证文件数据完整性
  1170. expect(data!.photos[0].fileId).toBe(testFile.id);
  1171. }
  1172. });
  1173. it('应该处理不存在的残疾人ID', async () => {
  1174. const response = await client.getAggregatedDisabledPerson[':id'].$get({
  1175. param: {
  1176. id: 99999 // 不存在的ID
  1177. }
  1178. }, {
  1179. headers: {
  1180. 'Authorization': `Bearer ${testToken}`
  1181. }
  1182. });
  1183. expect(response.status).toBe(404);
  1184. });
  1185. });
  1186. describe('认证测试', () => {
  1187. it('应该验证所有端点需要认证', async () => {
  1188. // 测试没有token的情况
  1189. const response = await client.createDisabledPerson.$post({
  1190. json: {
  1191. name: '测试人员',
  1192. gender: '男',
  1193. idCard: '110101199001011235',
  1194. disabilityId: 'D123456789',
  1195. disabilityType: '视力残疾',
  1196. disabilityLevel: '一级',
  1197. idAddress: '北京市东城区',
  1198. phone: '13800138000',
  1199. province: '北京市',
  1200. city: '北京市'
  1201. }
  1202. });
  1203. expect(response.status).toBe(401);
  1204. });
  1205. it('应该验证无效token', async () => {
  1206. const response = await client.createDisabledPerson.$post({
  1207. json: {
  1208. name: '测试人员',
  1209. gender: '男',
  1210. idCard: '110101199001011236',
  1211. disabilityId: 'D123456790',
  1212. disabilityType: '视力残疾',
  1213. disabilityLevel: '一级',
  1214. idAddress: '北京市东城区',
  1215. phone: '13800138001',
  1216. province: '北京市',
  1217. city: '北京市'
  1218. }
  1219. }, {
  1220. headers: {
  1221. 'Authorization': 'Bearer invalid_token'
  1222. }
  1223. });
  1224. expect(response.status).toBe(401);
  1225. });
  1226. });
  1227. });