AssessmentContent.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. import { DataModel, transformArrayDataModel, transformDataModel, type KeyValue } from '@imengyu/js-request-transform';
  2. import { AppServerRequestModule } from '../RequestModules';
  3. import { transformSomeToArray } from '../Utils';
  4. import ApiCofig from '@/common/config/ApiCofig';
  5. import { appendGetUrlParams } from '@imengyu/imengyu-utils';
  6. import { useAuthStore } from '@/stores/auth';
  7. /**
  8. * 自查评估 / 传承协议相关接口(ShowDoc)
  9. * @see https://www.showdoc.com.cn/minnanCE/11559060626966335 列表
  10. * @see https://www.showdoc.com.cn/minnanCE/11559060626887140 传承协议编辑
  11. * @see https://www.showdoc.com.cn/minnanCE/11559060626966336 评估表编辑/新增
  12. * @see https://www.showdoc.com.cn/minnanCE/11559060626966337 详情
  13. */
  14. /** 计分点项(getCheckItems) */
  15. export class CheckItemInfo extends DataModel<CheckItemInfo> {
  16. constructor() {
  17. super(CheckItemInfo, '自查计分项目');
  18. this.setNameMapperCase('Camel', 'Snake');
  19. this._convertTable = {
  20. id: { clientSide: 'number', serverSide: 'number' },
  21. pid: { clientSide: 'number', serverSide: 'number' },
  22. level: { clientSide: 'number', serverSide: 'number' },
  23. points: { clientSide: 'number', serverSide: 'number' },
  24. isTitle: { clientSide: 'boolean', serverSide: 'number' },
  25. isMulitCheck: { clientSide: 'boolean', serverSide: 'number' },
  26. };
  27. }
  28. id = 0 as number;
  29. pid = 0 as number;
  30. name = '' as string;
  31. level = 0 as number;
  32. points = 0 as number;
  33. isTitle = false;
  34. isMulitCheck = false;
  35. /** 1=单选,2=多选,3=次数 */
  36. checkType = 0 as number;
  37. children: CheckItemInfo[] = [];
  38. }
  39. /** 自查评估表列表行 */
  40. export class SelfAssessmentListRow extends DataModel<SelfAssessmentListRow> {
  41. constructor() {
  42. super(SelfAssessmentListRow, '自查评估表列表项');
  43. this.setNameMapperCase('Camel', 'Snake');
  44. this._convertTable = {
  45. id: { clientSide: 'number', serverSide: 'number' },
  46. userId: { clientSide: 'number', serverSide: 'number' },
  47. year: { clientSide: 'number', serverSide: 'number' },
  48. weigh: { clientSide: 'number', serverSide: 'number' },
  49. deductPoints: { clientSide: 'number', serverSide: 'number' },
  50. points: { clientSide: 'number', serverSide: 'number' },
  51. self: { clientSide: 'number', serverSide: 'number' },
  52. ichUnit: { clientSide: 'number', serverSide: 'number' },
  53. unitPoints: { clientSide: 'number', serverSide: 'number' },
  54. county: { clientSide: 'number', serverSide: 'number' },
  55. countyPoints: { clientSide: 'number', serverSide: 'number' },
  56. district: { clientSide: 'number', serverSide: 'number' },
  57. districtPoints: { clientSide: 'number', serverSide: 'number' },
  58. province: { clientSide: 'number', serverSide: 'number' },
  59. provincePoints: { clientSide: 'number', serverSide: 'number' },
  60. level: { clientSide: 'number', serverSide: 'string' },
  61. };
  62. this._convertKeyType = (key) => {
  63. if (key.endsWith('Text') || key.endsWith('_text')) {
  64. return { clientSide: 'string', serverSide: 'undefined' };
  65. }
  66. return undefined;
  67. };
  68. }
  69. id = 0 as number;
  70. userId = 0 as number;
  71. year = 0 as number;
  72. inheritor = '' as string|null;
  73. unit = '' as string|null;
  74. ichName = '' as string|null;
  75. mobile = '' as string|null;
  76. idCard = '' as string|null;
  77. level = null as number|string|null;
  78. address = '' as string|null;
  79. weigh = 0 as number;
  80. deductPoints = 0 as number;
  81. points = 0 as number;
  82. self = null as number|null;
  83. ichUnit = null as number|null;
  84. unitPoints = 0 as number;
  85. county = null as number|null;
  86. countyPoints = 0 as number;
  87. district = null as number|null;
  88. districtPoints = 0 as number;
  89. province = null as number|null;
  90. provincePoints = 0 as number;
  91. createtime = '' as string;
  92. updatetime = '' as string;
  93. selfText = '' as string;
  94. }
  95. /** 传承协议列表行 */
  96. export class AgreementListRow extends DataModel<AgreementListRow> {
  97. constructor() {
  98. super(AgreementListRow, '传承协议列表项');
  99. this.setNameMapperCase('Camel', 'Snake');
  100. this._convertTable = {
  101. id: { clientSide: 'number', serverSide: 'number' },
  102. userId: { clientSide: 'number', serverSide: 'number' },
  103. year: { clientSide: 'number', serverSide: 'number' },
  104. apprentice: { clientSide: 'number', serverSide: 'number' },
  105. activity: { clientSide: 'number', serverSide: 'number' },
  106. course: { clientSide: 'number', serverSide: 'number' },
  107. level: { clientSide: 'number', serverSide: 'number' },
  108. };
  109. }
  110. id = 0 as number;
  111. userId = 0 as number;
  112. level = null as number|null;
  113. year = 0 as number;
  114. partyA = '' as string|null;
  115. partyB = '' as string|null;
  116. apprentice = 0 as number;
  117. activity = 0 as number;
  118. course = 0 as number;
  119. mobile = '' as string|null;
  120. partyAMobile = '' as string|null;
  121. idCard = '' as string|null;
  122. health = '' as string|null;
  123. ich = '' as string|null;
  124. partyASign = '' as string|null;
  125. partyBSign = '' as string|null;
  126. createtime = '' as string;
  127. updatetime = '' as string;
  128. deletetime = '' as string|null;
  129. }
  130. /** 传承人基础信息(ich/check/basic) */
  131. export class InheritorCheckBasicInfo extends DataModel<InheritorCheckBasicInfo> {
  132. constructor() {
  133. super(InheritorCheckBasicInfo, '传承人自查基础信息');
  134. this.setNameMapperCase('Camel', 'Snake');
  135. this._convertTable = {
  136. userId: { clientSide: 'number', serverSide: 'number' },
  137. level: { clientSide: 'number', serverSide: 'number' },
  138. batch: { clientSide: 'number', serverSide: 'number' },
  139. };
  140. this._convertKeyType = (key) => {
  141. if (key.endsWith('Text') || key.endsWith('_text')) {
  142. return { clientSide: 'string', serverSide: 'undefined' };
  143. }
  144. return undefined;
  145. };
  146. }
  147. userId = 0 as number;
  148. name = '' as string;
  149. region = '' as string;
  150. gender = '' as string;
  151. education = '' as string|null;
  152. ichName = '' as string;
  153. unit = '' as string;
  154. level = 0 as number;
  155. idCard = '' as string;
  156. address = '' as string;
  157. batch = 0 as number;
  158. mobile = '' as string;
  159. genderText = '' as string;
  160. educationText = '' as string;
  161. levelText = '' as string;
  162. regionText = '' as string;
  163. /** 已填写的传承协议ID */
  164. agreementId = 0 as number;
  165. /** 已填写的自查表ID */
  166. checkId = 0 as number;
  167. }
  168. /** 详情中已选计分项 */
  169. export class SelfAssessmentCheckItemAnswer extends DataModel<SelfAssessmentCheckItemAnswer> {
  170. constructor() {
  171. super(SelfAssessmentCheckItemAnswer, '自查计分选项');
  172. this.setNameMapperCase('Camel', 'Snake');
  173. this._convertTable = {
  174. id: { clientSide: 'number', serverSide: 'number' },
  175. points: { clientSide: 'number', serverSide: 'number' },
  176. count: { clientSide: 'number', serverSide: 'number' },
  177. };
  178. this._afterSolveServer = (data) => {
  179. if (data.itemId)
  180. data.id = data.itemId;
  181. }
  182. }
  183. id = 0 as number;
  184. points = 0 as number;
  185. count = 0 as number;
  186. }
  187. /** 自查评估表详情 */
  188. export class SelfAssessmentDetail extends DataModel<SelfAssessmentDetail> {
  189. constructor() {
  190. super(SelfAssessmentDetail, '自查评估表详情');
  191. this.setNameMapperCase('Camel', 'Snake');
  192. this._convertTable = {
  193. id: { clientSide: 'number', serverSide: 'number' },
  194. userId: { clientSide: 'number', serverSide: 'number' },
  195. year: { clientSide: 'number', serverSide: 'number' },
  196. weigh: { clientSide: 'number', serverSide: 'number' },
  197. deductPoints: { clientSide: 'number', serverSide: 'number' },
  198. points: { clientSide: 'number', serverSide: 'number' },
  199. self: { clientSide: 'number', serverSide: 'number' },
  200. ichUnit: { clientSide: 'number', serverSide: 'number' },
  201. unitPoints: { clientSide: 'number', serverSide: 'number' },
  202. county: { clientSide: 'number', serverSide: 'number' },
  203. countyPoints: { clientSide: 'number', serverSide: 'number' },
  204. district: { clientSide: 'number', serverSide: 'number' },
  205. districtPoints: { clientSide: 'number', serverSide: 'number' },
  206. province: { clientSide: 'number', serverSide: 'number' },
  207. provincePoints: { clientSide: 'number', serverSide: 'number' },
  208. level: { clientSide: 'number', serverSide: 'string' },
  209. content: {
  210. customToClientFn: (value) => {
  211. try {
  212. return JSON.parse(value as string);
  213. } catch {
  214. return {};
  215. }
  216. },
  217. customToServerFn: (value) => {
  218. return value;
  219. },
  220. },
  221. awardTime: {
  222. clientSide: 'dayjs',
  223. clientSideDateFormat: 'YYYY-MM-DD',
  224. serverSide: 'string',
  225. serverSideDateFormat: 'YYYY-MM-DD',
  226. },
  227. checkItems: {
  228. customToClientFn: (value) => {
  229. return transformArrayDataModel(SelfAssessmentCheckItemAnswer, transformSomeToArray(value), 'data');
  230. },
  231. customToServerFn: (value) => {
  232. return (value as SelfAssessmentCheckItemAnswer[])
  233. .filter(item => item.count > 0)
  234. .map((item) => {
  235. return {
  236. id: item.id,
  237. count: item.count,
  238. };
  239. });
  240. },
  241. },
  242. };
  243. this._blackList.toServer = [
  244. 'createtime',
  245. 'updatetime',
  246. 'deletetime',
  247. ]
  248. this._convertKeyType = (key) => {
  249. if (key.endsWith('Text') || key.endsWith('_text')) {
  250. return { clientSide: 'string', serverSide: 'undefined' };
  251. }
  252. return undefined;
  253. };
  254. this._beforeSolveClient = (data) => {
  255. if (data.id == 0)
  256. delete data.id;
  257. return data;
  258. }
  259. }
  260. id = 0 as number;
  261. userId = 0 as number;
  262. year = 0 as number;
  263. inheritor = '' as string|null;
  264. unit = '' as string|null;
  265. ichName = '' as string|null;
  266. mobile = '' as string|null;
  267. idCard = '' as string|null;
  268. level = null as number|string|null;
  269. address = '' as string|null;
  270. content : Record<string, any>|null = null;
  271. weigh = 0 as number;
  272. awardTime = new Date();
  273. deductContent = '' as string|null;
  274. deductPoints = 0 as number;
  275. points = 0 as number;
  276. self = null as number|null;
  277. sign = '' as string|null;
  278. ichUnit = null as number|null;
  279. unitPoints = 0 as number;
  280. county = null as number|null;
  281. countyPoints = 0 as number;
  282. district = null as number|null;
  283. districtPoints = 0 as number;
  284. province = null as number|null;
  285. provincePoints = 0 as number;
  286. createtime = '' as string;
  287. updatetime = '' as string;
  288. deletetime = '' as string|null;
  289. selfText = '' as string;
  290. checkItems : SelfAssessmentCheckItemAnswer[] = [];
  291. }
  292. /** 传承协议详情 */
  293. export class AgreementDetail extends DataModel<AgreementDetail> {
  294. constructor() {
  295. super(AgreementDetail, '传承协议详情');
  296. this.setNameMapperCase('Camel', 'Snake');
  297. this._convertTable = {
  298. id: { clientSide: 'number', serverSide: 'number' },
  299. userId: { clientSide: 'number', serverSide: 'number' },
  300. year: { clientSide: 'number', serverSide: 'number' },
  301. apprentice: { clientSide: 'number', serverSide: 'number' },
  302. activity: { clientSide: 'number', serverSide: 'number' },
  303. course: { clientSide: 'number', serverSide: 'number' },
  304. level: { clientSide: 'number', serverSide: 'number' },
  305. updatetime: { clientSide: 'date', serverSide: 'undefined' },
  306. };
  307. this._nameMapperClient = {
  308. partyA: 'party_a',
  309. partyB: 'party_b',
  310. partyASign: 'party_a_sign',
  311. partyBSign: 'party_b_sign',
  312. partyAMobile: 'party_a_mobile',
  313. }
  314. this._blackList.toServer = [
  315. 'createtime',
  316. 'updatetime',
  317. 'deletetime',
  318. ]
  319. this._beforeSolveClient = (data) => {
  320. if (data.id == 0)
  321. delete data.id;
  322. return data;
  323. }
  324. }
  325. id = 0 as number;
  326. userId = 0 as number;
  327. level = null as number|null;
  328. year = 0 as number;
  329. partyA = '' as string|null;
  330. partyB = '' as string|null;
  331. apprentice = 0 as number;
  332. activity = 0 as number;
  333. course = 0 as number;
  334. mobile = '' as string|null;
  335. partyAMobile = '' as string|null;
  336. idCard = '' as string|null;
  337. health = '' as string|null;
  338. ich = '' as string|null;
  339. partyASign = '' as string|null;
  340. partyBSign = '' as string|null;
  341. updatetime = new Date();
  342. }
  343. /** 证明材料附件类型(saveAnnex `type`) */
  344. export const CheckAnnexType = {
  345. Image: 1,
  346. Video: 2,
  347. Audio: 3,
  348. Document: 4,
  349. Other: 5,
  350. ExternalLink: 6,
  351. } as const;
  352. export function getCheckAnnexType(mimetype: string) {
  353. if (mimetype.startsWith('image/')) return CheckAnnexType.Image;
  354. if (mimetype.startsWith('video/')) return CheckAnnexType.Video;
  355. if (mimetype.startsWith('audio/')) return CheckAnnexType.Audio;
  356. if (mimetype.startsWith('application/pdf')) return CheckAnnexType.Document;
  357. return CheckAnnexType.Other;
  358. }
  359. export type CheckAnnexTypeValue = (typeof CheckAnnexType)[keyof typeof CheckAnnexType];
  360. /** 证明材料修改与新增请求体(POST /ich/check/saveAnnex) */
  361. export interface SaveCheckAnnexPayload {
  362. id?: number;
  363. name: string;
  364. formId: number;
  365. url: string;
  366. type: CheckAnnexTypeValue | number;
  367. desc?: string;
  368. mimetype?: string;
  369. attachId?: number;
  370. fileSize?: number;
  371. }
  372. /** 证明材料列表项(getAnnexList) */
  373. export class CheckAnnexListItem extends DataModel<CheckAnnexListItem> {
  374. constructor() {
  375. super(CheckAnnexListItem, '证明材料列表项');
  376. this.setNameMapperCase('Camel', 'Snake');
  377. this._convertTable = {
  378. id: { clientSide: 'number', serverSide: 'number' },
  379. formId: { clientSide: 'number', serverSide: 'number' },
  380. type: { clientSide: 'number', serverSide: 'number' },
  381. attachId: { clientSide: 'number', serverSide: 'number' },
  382. fileSize: { clientSide: 'number', serverSide: 'number' },
  383. };
  384. }
  385. id = 0 as number;
  386. name = '' as string;
  387. formId = 0 as number;
  388. url = '' as string;
  389. type = 0 as number;
  390. desc = '' as string|null;
  391. mimetype = '' as string|null;
  392. attachId = null as number|null;
  393. fileSize = null as number|null;
  394. createtime = '' as string|null;
  395. updatetime = '' as string|null;
  396. }
  397. export type IchCheckPaginated<T> = {
  398. total: number;
  399. perPage: number;
  400. currentPage: number;
  401. lastPage: number;
  402. data: T[];
  403. };
  404. function normalizePaginated<T extends DataModel>(rowClass: new () => T, raw: KeyValue): IchCheckPaginated<T> {
  405. return {
  406. total: Number(raw.total ?? 0),
  407. perPage: Number(raw.per_page ?? 0),
  408. currentPage: Number(raw.current_page ?? 0),
  409. lastPage: Number(raw.last_page ?? 0),
  410. data: transformArrayDataModel(rowClass, transformSomeToArray(raw.data), 'data'),
  411. };
  412. }
  413. function buildPdfUrl(baseUrl: string, path: string, id: number) {
  414. const auth = useAuthStore();
  415. let url = `${baseUrl}${path}?id=${encodeURIComponent(String(id))}`;
  416. url = appendGetUrlParams(url, 'main_body_id', ApiCofig.mainBodyId);
  417. url = appendGetUrlParams(url, 'token', auth.token);
  418. return url;
  419. }
  420. async function downloadPdfBlob(path: string, id: number, baseUrl: string, defaultFilename: string) {
  421. const url = buildPdfUrl(baseUrl, path, id);
  422. const auth = useAuthStore();
  423. const res = await fetch(url, {
  424. method: 'GET',
  425. headers: {
  426. token: auth.token,
  427. __token__: auth.token,
  428. },
  429. });
  430. if (!res.ok)
  431. throw new Error('下载失败,状态码:' + res.status);
  432. const blob = await res.blob();
  433. const objectUrl = URL.createObjectURL(blob);
  434. const a = document.createElement('a');
  435. a.href = objectUrl;
  436. a.download = defaultFilename;
  437. a.rel = 'noopener';
  438. document.body.appendChild(a);
  439. a.click();
  440. document.body.removeChild(a);
  441. URL.revokeObjectURL(objectUrl);
  442. }
  443. export class AssessmentContentApi extends AppServerRequestModule<DataModel> {
  444. constructor() {
  445. super();
  446. }
  447. async getCheckItems(level: number) {
  448. const res = await this.post('/ich/check/getCheckItems', { level }, '自查计分项目');
  449. const list = transformSomeToArray(res.data) as KeyValue[];
  450. const items = transformArrayDataModel<CheckItemInfo>(CheckItemInfo, list, 'data') as CheckItemInfo[];
  451. const map = new Map<number, CheckItemInfo>();
  452. for (const item of items)
  453. map.set(item.id, item);
  454. const top = items.filter((item) => item.pid === 0);
  455. for (const item of items)
  456. item.children = items.filter((i) => i.pid === item.id);
  457. return {
  458. top,
  459. map,
  460. };
  461. }
  462. async getSelfAssessmentList(data: {
  463. userId?: number;
  464. level?: number;
  465. year?: number;
  466. keywords?: string;
  467. page?: number;
  468. pageSize?: number;
  469. }) {
  470. const res = await this.post('/ich/check/getList', {
  471. user_id: data.userId,
  472. level: data.level,
  473. year: data.year,
  474. keywords: data.keywords,
  475. page: data.page,
  476. pageSize: data.pageSize,
  477. }, '评估表列表');
  478. return normalizePaginated<SelfAssessmentListRow>(SelfAssessmentListRow, res.data as KeyValue);
  479. }
  480. async getAgreementList(data: {
  481. userId?: number;
  482. level?: number;
  483. year?: number;
  484. keywords?: string;
  485. page?: number;
  486. pageSize?: number;
  487. }) {
  488. const res = await this.post('/ich/check/getAgreementList', {
  489. user_id: data.userId,
  490. level: data.level,
  491. year: data.year,
  492. keywords: data.keywords,
  493. page: data.page,
  494. pageSize: data.pageSize,
  495. }, '传承协议列表');
  496. return normalizePaginated<AgreementListRow>(AgreementListRow, res.data as KeyValue);
  497. }
  498. async saveAgreement(dataModel: AgreementDetail) {
  499. return this.post('/ich/check/saveAgreement', dataModel.toServerSide(), '传承协议保存');
  500. }
  501. async saveSelfAssessment(dataModel: SelfAssessmentDetail) {
  502. return this.post('/ich/check/save', dataModel.toServerSide(), '自查评估表保存');
  503. }
  504. async downloadSelfAssessmentPdf(id: number) {
  505. await downloadPdfBlob('/pdf/create', id, this.config.baseUrl, `self-assessment-${id}.pdf`);
  506. }
  507. async downloadAgreementPdf(id: number) {
  508. await downloadPdfBlob('/pdf/nationalContract', id, this.config.baseUrl, `agreement-${id}.pdf`);
  509. }
  510. async saveAnnex(payload: SaveCheckAnnexPayload) {
  511. return this.post('/ich/check/saveAnnex', {
  512. id: payload.id,
  513. name: payload.name,
  514. form_id: payload.formId,
  515. url: payload.url,
  516. type: payload.type,
  517. desc: payload.desc,
  518. mimetype: payload.mimetype,
  519. attach_id: payload.attachId,
  520. filesize: payload.fileSize,
  521. }, '证明材料保存');
  522. }
  523. async getAnnexList(formId: number) {
  524. const res = await this.post('/ich/check/getAnnexList', {
  525. form_id: formId,
  526. }, '证明材料列表');
  527. return normalizePaginated<CheckAnnexListItem>(CheckAnnexListItem, res.data as KeyValue);
  528. }
  529. async getInheritorBasic(userId?: number) {
  530. const res = await this.post('/ich/check/basic', {
  531. user_id: userId,
  532. }, '传承人自查基础信息');
  533. return transformDataModel<InheritorCheckBasicInfo>(InheritorCheckBasicInfo, res.data as KeyValue);
  534. }
  535. async getSelfAssessmentDetail(id: number, userId?: number) {
  536. const res = await this.post('/ich/check/detail', { id, user_id: userId }, '评估表详情');
  537. return transformDataModel<SelfAssessmentDetail>(SelfAssessmentDetail, res.data as KeyValue);
  538. }
  539. async getAgreementDetail(id: number, userId?: number) {
  540. const res = await this.post('/ich/check/agreementDetail', { id, user_id: userId }, '传承协议详情');
  541. return transformDataModel<AgreementDetail>(AgreementDetail, res.data as KeyValue);
  542. }
  543. }
  544. export default new AssessmentContentApi();