exportTemplates.ts 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. import { cloneDeep, isNumber } from 'lodash'
  2. import ExcelJS from 'exceljs'
  3. import { exportWordDocx, getBase64Sync } from './exportWord'
  4. import { baseURL } from './http'
  5. import { resJiLianFu } from './history'
  6. import {
  7. arrangeImages,
  8. calcTablePages,
  9. getExcelColumnLetter,
  10. getImageUrlsFromHtml,
  11. ITEMPLATE,
  12. numberToChinese,
  13. removeHtmlTags
  14. } from './exportWordUtils'
  15. import { getDesensitizeTxt, myTableTransferSize } from '@/components/MyTable'
  16. import dayjs from 'dayjs'
  17. import { D7CEHCK_COLLECTION_RESULT_OPTIONS } from '@/pages/D_storeManage/D7check/constants'
  18. import { exportTempExcel, getImageBase64Extension } from './exportExcelUtils'
  19. import { selectObj } from './select'
  20. import { MEDIA_TYPES } from '@/pages/C_goodsManage/C21wealth/constants'
  21. export enum EXPORT_WORD_ENUM {
  22. /** 借用藏品点交凭证 */
  23. BORROW = 1,
  24. /** 藏品馆内提退凭单 */
  25. HALL_PUT_BACK = 2,
  26. /** 分库藏品提退出入库记录单 */
  27. SUB_PUT_BACK = 3,
  28. /** 分库藏品入库记录单 */
  29. SUB_PUT_IN = 4,
  30. /** 入馆凭证 */
  31. VOUCHER = 5,
  32. /** 藏品图片及相关数字化信息使用申请单 */
  33. FORM_FOR_DIGITAL = 6,
  34. /** 藏品档案 */
  35. COLLECTION_ARCHIVES = 7,
  36. /** 拟征集藏品清单 */
  37. COLLECTION_LIST = 8,
  38. /** 文物鉴定书 */
  39. CERTIFICATE = 9,
  40. /** 入藏凭证 */
  41. STORAGE_VOUCHER = 10,
  42. /** 藏品卡片 */
  43. COLLECTION_CARD = 11,
  44. /** 藏品注销凭证 */
  45. CANCEL_VOUCHER = 12,
  46. /** 藏品移库 */
  47. COLLECTION_RELOCATION = 13,
  48. /** 藏品盘点记录单 */
  49. COLLECTION_INVENTORY = 14,
  50. /** 馆内人员进库申请单 */
  51. INSIDER_FORM = 15,
  52. /** 文物库房外来人员出入库审批表 */
  53. OUTSIDER_FORM = 16,
  54. /** 文物修复单 */
  55. RELIC_REPAIR_LIST = 17,
  56. /** 事故处理凭证 */
  57. ACCIDENT_HANDLING_CERTIFICATE = 18,
  58. /** 藏品现状登记 */
  59. COLLECTION_CURRENT_STATUS = 19,
  60. /** 馆内展览借用藏品登记台账 */
  61. REGISTER_LEDGER = 20,
  62. /** 藏品总账 */
  63. COLLECTION_LEDGER = 21,
  64. /** 藏品提退出入库登记流水账 */
  65. COLLECTION_LOG = 22
  66. }
  67. export const EXPORT_TEMPLATE_MAP: Record<EXPORT_WORD_ENUM, ITEMPLATE> = {
  68. [EXPORT_WORD_ENUM.COLLECTION_LOG]: {
  69. fileName: '藏品提退出入库登记流水账',
  70. options: {
  71. sheetHeader: [
  72. '序号',
  73. '藏品总登记号',
  74. '分类号',
  75. '点交凭证单号',
  76. '藏品名称',
  77. '计件数量',
  78. '文物现状',
  79. ['出库记录', '提用人', '点交人', '出库时间'],
  80. ['退库记录', '退还人', '点收人', '退库时间'],
  81. '备注'
  82. ],
  83. sheetFilter: [
  84. 'index',
  85. 'num',
  86. 'numType',
  87. 'orderNum',
  88. 'name',
  89. 'pcs',
  90. 'preserveState',
  91. 'ckUser1',
  92. 'ckUser2',
  93. 'ckDate',
  94. 'tkUser1',
  95. 'tkUser2',
  96. 'tkDate',
  97. 'snapRtf'
  98. ],
  99. columnWidths: [5, 14, 8, 10, 15, 10, 10, 10, 10, 14, 10, 10, 14, 10]
  100. }
  101. },
  102. [EXPORT_WORD_ENUM.COLLECTION_LEDGER]: {
  103. fileName: '藏品总账',
  104. options: {
  105. sheetHeader: [
  106. ['登记日期', '年', '月', '日'],
  107. '藏品总登记号',
  108. '分类号',
  109. '藏品名称',
  110. '时代',
  111. ['计件', '单位', '件数'],
  112. '尺寸、重量',
  113. '质地',
  114. '完残情况',
  115. '来源',
  116. '采集地点',
  117. ['入馆日期', '年', '月', '日'],
  118. '入馆凭证号',
  119. '注销凭证号',
  120. '级别',
  121. '备注'
  122. ],
  123. sheetFilter: [
  124. 'year',
  125. 'month',
  126. 'day',
  127. 'num',
  128. 'numType',
  129. 'name',
  130. 'dictAge',
  131. 'pcsUnit',
  132. '_pcs',
  133. 'size',
  134. 'dictTexture',
  135. 'dictTorn',
  136. 'source',
  137. '',
  138. 'year2',
  139. 'month2',
  140. 'day2',
  141. 'inHouseNum',
  142. '',
  143. 'dictLevel',
  144. 'rtf'
  145. ],
  146. columnWidths: [5, 5, 5, 10, 5, 10, 10, 5, 5, 10, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10]
  147. }
  148. },
  149. [EXPORT_WORD_ENUM.COLLECTION_CURRENT_STATUS]: {
  150. fileName: '藏品现状登记',
  151. templateName: '16.docx'
  152. },
  153. [EXPORT_WORD_ENUM.ACCIDENT_HANDLING_CERTIFICATE]: {
  154. fileName: '藏品事故处理凭证',
  155. templateName: '15.docx'
  156. },
  157. [EXPORT_WORD_ENUM.RELIC_REPAIR_LIST]: {
  158. fileName: '义乌市博物馆文物修复单',
  159. templateName: '14.docx',
  160. // 每个字段单行最大字符数
  161. perLine: {
  162. name: 9,
  163. dictLevel: 24,
  164. txt2: 4
  165. },
  166. row: {
  167. // 首页最大行数
  168. maxRowFirstPage: 3,
  169. // 尾页最大行数
  170. maxRowLastPage: 6,
  171. // 每页最大行数
  172. maxRowPage: 8,
  173. // 首页单行最大字符行数
  174. maxFirstCharLine: 20,
  175. // 尾页单行最大字符行数
  176. maxLastCharLine: 18,
  177. // 每页最大字符行数
  178. maxCharLine: 26,
  179. // 表格每行最小字符行数
  180. minRowCharLine: 3
  181. }
  182. },
  183. [EXPORT_WORD_ENUM.OUTSIDER_FORM]: {
  184. fileName: '文物库房外来人员出入库审批表',
  185. templateName: '13.docx'
  186. },
  187. [EXPORT_WORD_ENUM.INSIDER_FORM]: {
  188. fileName: '馆内人员进库申请单',
  189. templateName: '12.docx'
  190. },
  191. [EXPORT_WORD_ENUM.COLLECTION_INVENTORY]: {
  192. fileName: '义乌市博物馆分库藏品盘点记录单',
  193. templateName: '11.docx'
  194. },
  195. [EXPORT_WORD_ENUM.COLLECTION_RELOCATION]: {
  196. fileName: '义乌博物馆分库藏品移库记录单',
  197. templateName: '10.docx'
  198. },
  199. [EXPORT_WORD_ENUM.CANCEL_VOUCHER]: {
  200. fileName: '馆藏品注销凭证',
  201. options: {
  202. sheetHeader: [
  203. '藏品总账号',
  204. '藏品分类号',
  205. '名称',
  206. '年代',
  207. '数量',
  208. '尺寸、重量',
  209. '完残情况',
  210. '登记账页码数',
  211. '注销后去向',
  212. '注销原因',
  213. '备注'
  214. ],
  215. sheetFilter: [
  216. 'num',
  217. 'numType',
  218. 'name',
  219. 'dictAge',
  220. 'pcs',
  221. 'size',
  222. 'torn',
  223. '',
  224. 'txt1',
  225. 'txt2',
  226. 'txt3'
  227. ],
  228. columnWidths: [10, 10, 10, 15, 10, 15, 15, 12, 15, 15, 15]
  229. }
  230. },
  231. [EXPORT_WORD_ENUM.REGISTER_LEDGER]: {
  232. fileName: '义乌市博物馆馆内展览借用藏品登记台账',
  233. options: {
  234. sheetHeader: [
  235. '序号',
  236. '年度',
  237. '借用部门',
  238. '展览名称',
  239. '借用文物 实际数量(合计)',
  240. ['借用藏品基本情况', '藏品总登记号', '藏品名称'],
  241. '出借时间',
  242. ['出借经手人', '甲方', '乙方'],
  243. '藏品提用审批单号',
  244. '馆内提退凭证号',
  245. '预计归还日期',
  246. '归还时间',
  247. ['归还经手人', '甲方', '乙方'],
  248. '记录人',
  249. '备注'
  250. ],
  251. sheetFilter: [
  252. 'index',
  253. 'year',
  254. 'sonUnit',
  255. 'typeName',
  256. 'pcs',
  257. 'num',
  258. 'name',
  259. 'lendDate',
  260. 'lenderA',
  261. 'lenderb',
  262. 'sonNum',
  263. 'sonNum2',
  264. 'expectedReturnDate',
  265. 'returnDate',
  266. 'handlerA',
  267. 'handlerB',
  268. 'recorder',
  269. 'remark'
  270. ],
  271. columnWidths: [5, 5, 12, 15, 12, 10, 15, 12, 10, 10, 15, 15, 15, 15, 10, 10, 10, 15]
  272. }
  273. },
  274. [EXPORT_WORD_ENUM.CERTIFICATE]: {
  275. fileName: '义乌市博物馆馆藏文物鉴定书',
  276. options: {
  277. sheetHeader: [
  278. '编号',
  279. '总登记号',
  280. '分类号',
  281. '文物名称',
  282. '图片',
  283. '数量',
  284. '质地',
  285. '时代',
  286. '尺寸(cm)或重量(g)',
  287. '现状概述',
  288. '鉴定等级',
  289. '备注'
  290. ],
  291. sheetFilter: [
  292. 'index',
  293. 'num',
  294. 'numType',
  295. 'name',
  296. 'thumb',
  297. 'pcs',
  298. 'dictTexture',
  299. 'dictAge',
  300. 'size',
  301. 'dictTorn',
  302. 'dictLevel',
  303. 'intro'
  304. ],
  305. columnWidths: [5, 12, 7, 15, 10, 7, 15, 35, 20, 10, 10, 20]
  306. }
  307. },
  308. [EXPORT_WORD_ENUM.COLLECTION_LIST]: {
  309. fileName: '拟征集藏品清单',
  310. options: {
  311. sheetHeader: ['序号', '藏品名称', '初定年代', '报价(万元)', '原持有人', '征集方式'],
  312. sheetFilter: ['index', 'name', 'dictAgeFirst', 'offer', 'holder', 'source'],
  313. columnWidths: [5, 15, 40, 15, 10, 10]
  314. }
  315. },
  316. [EXPORT_WORD_ENUM.BORROW]: {
  317. fileName: '义乌市博物馆借用藏品点交凭证',
  318. templateName: '1.docx',
  319. // 每个字段单行最大字符数
  320. perLine: {
  321. num: 9,
  322. name: 14,
  323. rtf: 11,
  324. dictAge: 6,
  325. dictTexture3: 6
  326. },
  327. row: {
  328. // 首页最大行数
  329. maxRowFirstPage: 1,
  330. // 尾页最大行数
  331. maxRowLastPage: 2,
  332. // 每页最大行数
  333. maxRowPage: 5,
  334. // 首页单行最大字符行数
  335. maxFirstCharLine: 9,
  336. // 尾页单行最大字符行数
  337. maxLastCharLine: 11,
  338. // 每页最大字符行数
  339. maxCharLine: 27,
  340. // 表格每行最小字符行数
  341. minRowCharLine: 4
  342. }
  343. },
  344. [EXPORT_WORD_ENUM.HALL_PUT_BACK]: {
  345. fileName: '义乌市博物馆藏品馆内提退凭单',
  346. templateName: '2.docx',
  347. // 每个字段单行最大字符数
  348. perLine: {
  349. num: 9,
  350. name: 24,
  351. pcsUnit: 4,
  352. rtf: 6
  353. },
  354. row: {
  355. // 首页最大行数
  356. maxRowFirstPage: 3,
  357. // 尾页最大行数
  358. maxRowLastPage: 6,
  359. // 每页最大行数
  360. maxRowPage: 8,
  361. // 首页单行最大字符行数
  362. maxFirstCharLine: 20,
  363. // 尾页单行最大字符行数
  364. maxLastCharLine: 18,
  365. // 每页最大字符行数
  366. maxCharLine: 26,
  367. // 表格每行最小字符行数
  368. minRowCharLine: 3
  369. }
  370. },
  371. [EXPORT_WORD_ENUM.SUB_PUT_BACK]: {
  372. fileName: '义乌市博物馆分库藏品提退出入库记录单',
  373. templateName: '3.docx'
  374. },
  375. [EXPORT_WORD_ENUM.SUB_PUT_IN]: {
  376. fileName: '义乌市博物馆分库藏品入库记录单',
  377. templateName: '4.docx'
  378. },
  379. [EXPORT_WORD_ENUM.VOUCHER]: {
  380. fileName: '义乌市博物馆入馆凭证',
  381. templateName: '5.docx'
  382. },
  383. [EXPORT_WORD_ENUM.FORM_FOR_DIGITAL]: {
  384. fileName: '义乌市博物馆藏品图片及相关数字化信息使用申请单',
  385. templateName: '6.docx'
  386. },
  387. [EXPORT_WORD_ENUM.COLLECTION_ARCHIVES]: {
  388. fileName: '藏品档案样本电子版',
  389. templateName: '7.docx'
  390. },
  391. [EXPORT_WORD_ENUM.STORAGE_VOUCHER]: {
  392. fileName: '义乌市博物馆入藏凭证',
  393. templateName: '8.docx'
  394. },
  395. [EXPORT_WORD_ENUM.COLLECTION_CARD]: {
  396. fileName: '藏品卡片',
  397. templateName: '9.docx'
  398. }
  399. }
  400. /**
  401. * 根据业务类型导出数据
  402. */
  403. export const exportWordHandler = async (type: EXPORT_WORD_ENUM, data: Record<any, any>) => {
  404. let temp = cloneDeep(data)
  405. let page = 1
  406. let excelHandler: (worksheet: ExcelJS.Worksheet) => void = () => {}
  407. const date = dayjs()
  408. const item = EXPORT_TEMPLATE_MAP[type]
  409. temp.sizeUnit && (temp.sizeUnit = resJiLianFu(temp.sizeUnit))
  410. temp.qualityUnit && (temp.qualityUnit = resJiLianFu(temp.qualityUnit))
  411. temp.dictAge && (temp.dictAge = resJiLianFu(temp.dictAge))
  412. temp.pcsUnit && (temp.pcsUnit = resJiLianFu(temp.pcsUnit))
  413. temp.goods =
  414. (Array.isArray(temp.snaps) && temp.snaps.length
  415. ? temp.snaps.map((i: any) => JSON.parse(i.snap || ''))
  416. : temp.collects) ?? []
  417. if (temp.goods.length) {
  418. for (let i = 0; i < temp.goods.length; i++) {
  419. const good = temp.goods[i]
  420. good.index = i + 1
  421. good.rtf && (good.rtf = removeHtmlTags(JSON.parse(good.rtf).txtArr[0].txt))
  422. // excel 需要判断表格中是否需要图片
  423. if (!item.templateName ? item.options?.sheetFilter.includes('thumb') : good.thumb) {
  424. try {
  425. // good.thumb = await getBase64Sync(
  426. // 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
  427. // )
  428. good.thumb = await getBase64Sync(baseURL + good.thumb)
  429. } catch (err) {
  430. console.log('thumb conversion to base64 faild:', err)
  431. good.thumb = ''
  432. }
  433. }
  434. good.dictAge && (good.dictAge = resJiLianFu(good.dictAge))
  435. good.pcsUnit && (good.pcsUnit = resJiLianFu(good.pcsUnit))
  436. if (good.pcs) {
  437. good._pcs = good.pcs
  438. good.pcs = good.pcs + good.pcsUnit
  439. }
  440. good.accountType &&
  441. (good.accountType = selectObj['入藏去向'].find(i => i.value === good.accountType)?.label)
  442. good.dictTexture3 && (good.dictTexture = resJiLianFu(good.dictTexture3))
  443. good.dictTorn && (good.dictTorn = resJiLianFu(good.dictTorn))
  444. good.source && (good.source = resJiLianFu(good.source))
  445. good.dictAgeFirst && (good.dictAgeFirst = resJiLianFu(good.dictAgeFirst))
  446. good.qualityUnit && (good.qualityUnit = resJiLianFu(good.qualityUnit))
  447. if (good.sizeUnit || good.quality) {
  448. const arr: string[] = []
  449. if (good.sizeUnit) arr.push(myTableTransferSize(good))
  450. if (good.quality) arr.push('重' + good.quality + good.qualityUnit)
  451. good.size = arr.join('、')
  452. }
  453. }
  454. } else {
  455. temp.goods = []
  456. }
  457. if (item.perLine) {
  458. // @ts-ignore
  459. page = calcTablePages(temp.goods, item)
  460. }
  461. // 处理业务数据
  462. switch (type) {
  463. case EXPORT_WORD_ENUM.BORROW:
  464. temp = {
  465. ...temp,
  466. group: numberToChinese(temp.goods.length),
  467. num: numberToChinese(temp.goods.reduce((sum: number, i: any) => sum + (i._pcs || 0), 0)),
  468. page: numberToChinese(page),
  469. borrowDate: dayjs(temp.createTime).format('YYYY年MM月DD日')
  470. }
  471. break
  472. case EXPORT_WORD_ENUM.HALL_PUT_BACK:
  473. temp = {
  474. ...temp,
  475. year: date.format('YYYY'),
  476. group: numberToChinese(temp.goods.length),
  477. page: numberToChinese(page),
  478. date: dayjs(temp.date).format('YYYY-MM-DD')
  479. }
  480. break
  481. case EXPORT_WORD_ENUM.SUB_PUT_BACK:
  482. temp = {
  483. ...temp,
  484. num: dayjs(temp.date).format('YYYY') + temp.num,
  485. date: dayjs(temp.date).format('YYYY年MM月DD日')
  486. }
  487. temp.goods.forEach((i: any) => {
  488. if (i.numName !== '藏品总登记号') {
  489. i.num = ''
  490. }
  491. })
  492. break
  493. case EXPORT_WORD_ENUM.COLLECTION_INVENTORY:
  494. temp = {
  495. ...temp,
  496. sonNum2: dayjs(temp.date).format('YYYY') + temp.num
  497. }
  498. temp.goods.forEach((i: any) => {
  499. i.checker = i.cusForm[`${i.id}-checker`]
  500. i.remark = i.cusForm[`${i.id}-remark`]
  501. i.cusForm[`${i.id}-statusCheck`] &&
  502. (i.statusCheck = D7CEHCK_COLLECTION_RESULT_OPTIONS.find(
  503. ii => ii.value === i.cusForm[`${i.id}-statusCheck`]
  504. )?.label)
  505. })
  506. break
  507. case EXPORT_WORD_ENUM.VOUCHER:
  508. case EXPORT_WORD_ENUM.STORAGE_VOUCHER:
  509. const _date = dayjs(temp.date)
  510. temp = {
  511. ...temp,
  512. year: _date.format('YYYY'),
  513. month: _date.format('MM'),
  514. day: _date.format('DD'),
  515. group: numberToChinese(temp.goods.length),
  516. page: numberToChinese(page)
  517. }
  518. break
  519. case EXPORT_WORD_ENUM.FORM_FOR_DIGITAL:
  520. const __date = dayjs(temp.createTime)
  521. temp = {
  522. ...temp,
  523. effect: resJiLianFu(temp.effect),
  524. sonTypeName: MEDIA_TYPES.filter(media => temp.sonTypeName.split(',').includes(media.value))
  525. .map(media => media.label)
  526. .join(','),
  527. year2: date.format('YYYY'),
  528. year: __date.format('YYYY'),
  529. month: __date.format('MM'),
  530. day: __date.format('DD')
  531. }
  532. break
  533. case EXPORT_WORD_ENUM.SUB_PUT_IN:
  534. temp = {
  535. ...temp,
  536. sonSource: resJiLianFu(temp.sonSource),
  537. sonNum2: dayjs(temp.date).format('YYYY') + temp.num,
  538. date: dayjs(temp.date).format('YYYY年MM月DD日')
  539. }
  540. break
  541. case EXPORT_WORD_ENUM.COLLECTION_RELOCATION:
  542. temp = {
  543. ...temp,
  544. sonNum2: dayjs(temp.date).format('YYYY') + temp.num,
  545. date: dayjs(temp.date).format('YYYY年MM月DD日')
  546. }
  547. break
  548. case EXPORT_WORD_ENUM.ACCIDENT_HANDLING_CERTIFICATE:
  549. temp = {
  550. ...temp,
  551. year: date.format('YYYY'),
  552. rtf: temp.rtf ? removeHtmlTags(JSON.parse(temp.rtf).txtArr[0].txt) : '',
  553. authInfoRtf: removeHtmlTags(JSON.parse(temp.authInfoRtf).txtArr[0].txt),
  554. authResultRtf: removeHtmlTags(JSON.parse(temp.authResultRtf).txtArr[0].txt)
  555. }
  556. break
  557. case EXPORT_WORD_ENUM.COLLECTION_ARCHIVES:
  558. case EXPORT_WORD_ENUM.COLLECTION_CARD:
  559. const rtf2 = temp.rtf ? JSON.parse(temp.rtf).txtArr[0].txt : ''
  560. const stack2 = []
  561. for (const url of getImageUrlsFromHtml(rtf2)) {
  562. stack2.push(await getBase64Sync(url))
  563. }
  564. temp = {
  565. ...temp,
  566. year: date.format('YYYY'),
  567. month: date.format('MM'),
  568. day: date.format('DD'),
  569. createTime: dayjs(temp.createTime).format('YYYY-MM-DD'),
  570. size: myTableTransferSize(temp),
  571. quality: temp.quality + temp.qualityUnit,
  572. deptName: (temp.records || []).length ? temp.records[0].deptName : '',
  573. recordDate: (temp.records || []).length ? temp.records[0].createTime : '',
  574. dictTexture: resJiLianFu(temp.dictTexture3),
  575. records: (temp.records || []).map(
  576. (item: any) =>
  577. `[${item.dictLevel}],[${item.date.split(' ')[0]}][${item.deptName}][${
  578. item.creatorName
  579. }]意见。`
  580. ),
  581. repairs: (temp.repairs || []).map(
  582. (item: any) =>
  583. `[${item.txt1}],[${item.txt2}],[${item.date.split(' ')[0]}][${item.authUnit}]交修。`
  584. ),
  585. status: (temp.status || []).map(
  586. (item: any) => `[${item.reason}],[${item.date.split(' ')[0]}][${item.sonUser}]登记。`
  587. ),
  588. source: resJiLianFu(temp.source),
  589. rtf: removeHtmlTags(rtf2),
  590. preserveState: resJiLianFu(temp.preserveState),
  591. imgs: stack2
  592. }
  593. if (temp.numName !== '藏品总登记号') {
  594. temp.num2 = temp.num
  595. temp.num = ''
  596. }
  597. if (type === EXPORT_WORD_ENUM.COLLECTION_ARCHIVES) {
  598. temp.imagePages = await arrangeImages(temp.imagePages)
  599. } else if (temp.thumb) {
  600. temp.thumb = await getBase64Sync(temp.thumb)
  601. }
  602. break
  603. case EXPORT_WORD_ENUM.OUTSIDER_FORM:
  604. const memberss = JSON.parse(temp.memberIds)
  605. temp = {
  606. ...temp,
  607. time: dayjs(temp.date).format('HH:mm:ss'),
  608. date: dayjs(temp.date).format('YYYY-MM-DD'),
  609. members: memberss.map((i: any) => i.name),
  610. companys: memberss.map((i: any) => i.remark || '空'),
  611. idCards: memberss.map((i: any) => i.papers || '空'),
  612. phones: memberss.map((i: any) => (i.phone ? getDesensitizeTxt(i.phone) : '空'))
  613. }
  614. break
  615. case EXPORT_WORD_ENUM.RELIC_REPAIR_LIST:
  616. case EXPORT_WORD_ENUM.COLLECTION_CURRENT_STATUS:
  617. const ___date = dayjs(temp.date)
  618. const rtf = JSON.parse(temp.rtf).txtArr[0].txt
  619. const stack = []
  620. try {
  621. for (const url of getImageUrlsFromHtml(rtf)) {
  622. stack.push(await getBase64Sync(url))
  623. }
  624. } catch (err) {}
  625. temp = {
  626. ...temp,
  627. year: ___date.format('YYYY'),
  628. page,
  629. rtf: removeHtmlTags(rtf),
  630. imgs: stack
  631. }
  632. if (type === EXPORT_WORD_ENUM.COLLECTION_CURRENT_STATUS) {
  633. temp.goodsNum = temp.numName === '藏品总登记号' ? temp.goodsNum : ``
  634. }
  635. break
  636. case EXPORT_WORD_ENUM.COLLECTION_LIST:
  637. temp.goods.push({
  638. index: '合计',
  639. name: temp.goods.length,
  640. dictAgeFirst: '合计',
  641. offer: temp.goods.reduce((sum: number, cur: any) => sum + Number(cur.offer), 0)
  642. })
  643. excelHandler = worksheet => {
  644. worksheet.insertRow(1, ['拟征集藏品清单'])
  645. worksheet.mergeCells('A1:F1')
  646. const mergedCell = worksheet.getCell('A1')
  647. mergedCell.style = {
  648. fill: {
  649. type: 'pattern',
  650. pattern: 'solid',
  651. fgColor: { argb: 'cce8cf' }
  652. },
  653. font: {
  654. name: '黑体',
  655. size: 18
  656. }
  657. }
  658. const borderStyle: ExcelJS.Border = {
  659. style: 'thin',
  660. color: { argb: 'FF000000' }
  661. }
  662. for (let row = 2; row <= temp.goods.length + 2; row++) {
  663. for (let col = 1; col <= 6; col++) {
  664. const cell = worksheet.getCell(row, col)
  665. cell.border = {
  666. top: borderStyle,
  667. left: borderStyle,
  668. bottom: borderStyle,
  669. right: borderStyle
  670. }
  671. }
  672. }
  673. worksheet.eachRow(row => {
  674. row.eachCell(cell => {
  675. cell.alignment = {
  676. vertical: 'middle',
  677. horizontal: 'center',
  678. wrapText: true
  679. }
  680. })
  681. })
  682. }
  683. break
  684. case EXPORT_WORD_ENUM.CERTIFICATE:
  685. const resultText = Object.entries(
  686. // @ts-ignore
  687. temp.goods.reduce((acc, { dictLevel }) => {
  688. acc[dictLevel] = (acc[dictLevel] || 0) + 1
  689. return acc
  690. }, {})
  691. )
  692. // @ts-ignore
  693. .filter(([_, count]) => count > 0)
  694. .map(
  695. ([level, count]) =>
  696. `${level === '一般' ? level + '珍贵文物' : level + '文物'}${count}件/组;`
  697. )
  698. .join('\n')
  699. temp.goods.push({
  700. index: '鉴\n定\n人\n员',
  701. num: temp.authUser,
  702. thumb: '鉴\n定\n单\n位',
  703. pcs: temp.authUnit,
  704. dictAge: '核\n准\n单\n位',
  705. dictTorn: '说\n\n明',
  706. size: temp.confirmUnit,
  707. dictLevel: `鉴定日期:${temp.date}\n鉴定总数${temp.goods.length}件/组,其中:\n${resultText}`
  708. })
  709. excelHandler = worksheet => {
  710. const lastIndex = temp.goods.length + 2
  711. worksheet.insertRow(1, ['单位:义乌市博物馆'])
  712. worksheet.mergeCells('A1:H1')
  713. worksheet.mergeCells('I1:L1')
  714. worksheet.mergeCells(`B${lastIndex}:D${lastIndex}`)
  715. worksheet.mergeCells(`F${lastIndex}:G${lastIndex}`)
  716. worksheet.mergeCells(`K${lastIndex}:L${lastIndex}`)
  717. worksheet.eachRow(row => {
  718. const col5 = row.getCell(5)
  719. if (isNumber(col5.value)) {
  720. worksheet.addImage(col5.value, `${col5.address}:${col5.address}`)
  721. }
  722. row.eachCell(cell => {
  723. cell.style = {
  724. font: {
  725. name: '宋体',
  726. size: 10
  727. }
  728. }
  729. cell.alignment = {
  730. vertical: 'middle',
  731. horizontal: 'center',
  732. wrapText: true
  733. }
  734. })
  735. })
  736. const titleCell = worksheet.getCell('A1')
  737. const dateCell = worksheet.getCell('I1')
  738. const lastCell = worksheet.getRow(lastIndex)
  739. const borderStyle: ExcelJS.Border = {
  740. style: 'thin',
  741. color: { argb: 'FF000000' }
  742. }
  743. lastCell.height = 80
  744. titleCell.style = {
  745. fill: {
  746. type: 'pattern',
  747. pattern: 'solid',
  748. fgColor: { argb: 'cce8cf' }
  749. },
  750. font: {
  751. size: 16
  752. },
  753. alignment: {
  754. horizontal: 'left',
  755. vertical: 'middle'
  756. }
  757. }
  758. dateCell.value = '日期:' + temp.createTime.split(' ')[0]
  759. dateCell.style = {
  760. fill: {
  761. type: 'pattern',
  762. pattern: 'solid',
  763. fgColor: { argb: 'cce8cf' }
  764. },
  765. font: {
  766. size: 16
  767. },
  768. alignment: {
  769. horizontal: 'right',
  770. vertical: 'middle'
  771. }
  772. }
  773. for (let row = 1; row <= lastIndex; row++) {
  774. for (let col = 1; col <= 12; col++) {
  775. const cell = worksheet.getCell(row, col)
  776. cell.border = {
  777. top: borderStyle,
  778. left: borderStyle,
  779. bottom: borderStyle,
  780. right: borderStyle
  781. }
  782. }
  783. }
  784. }
  785. break
  786. case EXPORT_WORD_ENUM.CANCEL_VOUCHER:
  787. temp.goods.push({
  788. num: '法定代表人:',
  789. dictAge: '保管部负责人:',
  790. torn: '保管员:',
  791. txt1: '珍贵文物注销审批文号:'
  792. })
  793. excelHandler = worksheet => {
  794. const lastIndex = temp.goods.length + 4
  795. const borderStyle: ExcelJS.Border = {
  796. style: 'thin',
  797. color: { argb: 'FF000000' }
  798. }
  799. worksheet.eachRow(row => {
  800. row.eachCell(cell => {
  801. cell.style = {
  802. font: {
  803. name: '宋体',
  804. size: 10
  805. }
  806. }
  807. cell.alignment = {
  808. vertical: 'middle',
  809. horizontal: 'center',
  810. wrapText: true
  811. }
  812. })
  813. })
  814. worksheet.insertRow(1, [])
  815. worksheet.mergeCells('A1:K1')
  816. worksheet.getCell('A1').value = {
  817. richText: [
  818. { font: { size: 20, name: '黑体' }, text: '馆藏品注销凭证 ' },
  819. { font: { size: 11 }, text: `(编号:${temp.num}) ` }
  820. ]
  821. }
  822. worksheet.getRow(1).height = 60
  823. worksheet.getCell('A1').style = {
  824. alignment: {
  825. horizontal: 'center',
  826. vertical: 'middle'
  827. }
  828. }
  829. worksheet.insertRow(2, [dayjs(temp.createTime).format('YYYY年MM月DD日')])
  830. worksheet.mergeCells('A2:K2')
  831. worksheet.getRow(2).height = 30
  832. worksheet.getCell('A2').style = {
  833. font: {
  834. size: 11,
  835. name: '仿宋_GB2312'
  836. },
  837. alignment: {
  838. horizontal: 'right',
  839. vertical: 'middle'
  840. }
  841. }
  842. worksheet.insertRow(3, [
  843. // @ts-ignore
  844. `现将藏品_${
  845. temp.goods.length - 1
  846. }_件注销,清单开列如下,本凭证连同附页全份共___页(含附件)`
  847. ])
  848. worksheet.mergeCells('A3:K3')
  849. worksheet.getRow(3).height = 30
  850. worksheet.getCell('A3').style = {
  851. font: {
  852. size: 11,
  853. name: '仿宋_GB2312'
  854. },
  855. alignment: {
  856. horizontal: 'center',
  857. vertical: 'middle'
  858. }
  859. }
  860. worksheet.mergeCells(`A${lastIndex}:C${lastIndex}`)
  861. worksheet.mergeCells(`D${lastIndex}:F${lastIndex}`)
  862. worksheet.mergeCells(`G${lastIndex}:H${lastIndex}`)
  863. worksheet.mergeCells(`I${lastIndex}:K${lastIndex}`)
  864. for (let row = 1; row <= lastIndex; row++) {
  865. for (let col = 1; col <= 11; col++) {
  866. const cell = worksheet.getCell(row, col)
  867. cell.border = {
  868. top: borderStyle,
  869. left: borderStyle,
  870. bottom: borderStyle,
  871. right: borderStyle
  872. }
  873. }
  874. }
  875. }
  876. break
  877. case EXPORT_WORD_ENUM.REGISTER_LEDGER:
  878. const totalPcs = temp.goods.reduce((sum: number, i: any) => sum + (i._pcs || 0), 0)
  879. temp.goods.forEach((i: any) => {
  880. i.year = date.format('YYYY') + '年度'
  881. i.sonUnit = temp.sonUnit
  882. i.typeName = temp.typeName
  883. i.lendDate = dayjs(i.cusForm[`${i.id}-lendDate`]).format('YYYY年MM月DD日')
  884. i.lenderA = i.cusForm[`${i.id}-lenderA`]
  885. i.lenderb = i.cusForm[`${i.id}-lenderb`]
  886. i.sonNum = temp.sonNum
  887. i.sonNum2 = temp.sonNum2
  888. i.handlerA = i.cusForm[`${i.id}-handlerA`]
  889. i.handlerB = i.cusForm[`${i.id}-handlerB`]
  890. i.recorder = i.cusForm[`${i.id}-recorder`]
  891. i.remark = i.cusForm[`${i.id}-remark`]
  892. i.pcs = `${i.pcs},计${totalPcs}件`
  893. const expectedReturnDate = i.cusForm[`${i.id}-expectedReturnDate`]
  894. expectedReturnDate &&
  895. (i.expectedReturnDate = dayjs(expectedReturnDate).format('YYYY年MM月DD日'))
  896. const returnDate = i.cusForm[`${i.id}-returnDate`]
  897. returnDate && (i.returnDate = dayjs(returnDate).format('YYYY年MM月DD日'))
  898. })
  899. excelHandler = worksheet => {
  900. const borderStyle: ExcelJS.Border = {
  901. style: 'thin',
  902. color: { argb: 'FF000000' }
  903. }
  904. for (let row = 1; row <= temp.goods.length + 2; row++) {
  905. for (let col = 1; col <= 18; col++) {
  906. const cell = worksheet.getCell(row, col)
  907. cell.border = {
  908. top: borderStyle,
  909. left: borderStyle,
  910. bottom: borderStyle,
  911. right: borderStyle
  912. }
  913. }
  914. }
  915. worksheet.eachRow(row => {
  916. row.eachCell(cell => {
  917. cell.alignment = {
  918. vertical: 'middle',
  919. horizontal: 'center',
  920. wrapText: true
  921. }
  922. })
  923. })
  924. }
  925. break
  926. case EXPORT_WORD_ENUM.COLLECTION_LOG:
  927. excelHandler = worksheet => {
  928. const borderStyle: ExcelJS.Border = {
  929. style: 'thin',
  930. color: { argb: 'FF000000' }
  931. }
  932. for (let row = 1; row <= temp.goods.length + 2; row++) {
  933. for (let col = 1; col <= 14; col++) {
  934. const cell = worksheet.getCell(row, col)
  935. cell.border = {
  936. top: borderStyle,
  937. left: borderStyle,
  938. bottom: borderStyle,
  939. right: borderStyle
  940. }
  941. }
  942. }
  943. worksheet.eachRow(row => {
  944. row.eachCell(cell => {
  945. cell.alignment = {
  946. vertical: 'middle',
  947. horizontal: 'center',
  948. wrapText: true
  949. }
  950. })
  951. })
  952. }
  953. break
  954. case EXPORT_WORD_ENUM.COLLECTION_LEDGER:
  955. temp.goods.forEach((i: any) => {
  956. const createTime = dayjs(i.createTime)
  957. const inHouseTime = dayjs(i.createTime)
  958. i.year = createTime.format('YYYY')
  959. i.month = createTime.format('MM')
  960. i.day = createTime.format('DD')
  961. i.year2 = inHouseTime.format('YYYY')
  962. i.month2 = inHouseTime.format('MM')
  963. i.day2 = inHouseTime.format('DD')
  964. })
  965. excelHandler = worksheet => {
  966. const borderStyle: ExcelJS.Border = {
  967. style: 'thin',
  968. color: { argb: 'FF000000' }
  969. }
  970. for (let row = 1; row <= temp.goods.length + 2; row++) {
  971. for (let col = 1; col <= 21; col++) {
  972. const cell = worksheet.getCell(row, col)
  973. cell.border = {
  974. top: borderStyle,
  975. left: borderStyle,
  976. bottom: borderStyle,
  977. right: borderStyle
  978. }
  979. }
  980. }
  981. worksheet.eachRow(row => {
  982. row.eachCell(cell => {
  983. cell.alignment = {
  984. vertical: 'middle',
  985. horizontal: 'center',
  986. wrapText: true
  987. }
  988. })
  989. })
  990. }
  991. break
  992. }
  993. if (!item.templateName) {
  994. // 没有templateName则输出 excel
  995. exportTempExcel(item.fileName, (worksheet, workbook) => {
  996. let mergeHeadNum = 0
  997. let headTemp: string[] = []
  998. let fatherHeadTemp: {
  999. title: string
  1000. position: string[]
  1001. }[] = []
  1002. // 表头需要占据的行数
  1003. const headRow = Math.max(
  1004. ...item.options?.sheetHeader.map((head: string | string[]) => (Array.isArray(head) ? 2 : 1))
  1005. )
  1006. item.options?.sheetHeader.forEach((head: string | string[], index: number) => {
  1007. if (Array.isArray(head)) {
  1008. fatherHeadTemp.push({
  1009. title: head.shift() || '',
  1010. position: [
  1011. `${getExcelColumnLetter(index + mergeHeadNum)}1`,
  1012. `${getExcelColumnLetter(index + head.length - 1 + mergeHeadNum)}1`
  1013. ]
  1014. })
  1015. headTemp.push(...head)
  1016. mergeHeadNum += head.length - 1
  1017. } else {
  1018. headTemp.push(head)
  1019. }
  1020. })
  1021. worksheet.addRow(headTemp)
  1022. if (fatherHeadTemp.length) {
  1023. // 存在需要合并的父级表头
  1024. worksheet.insertRow(1, [])
  1025. fatherHeadTemp.forEach(head => {
  1026. const cell = worksheet.getCell(head.position[0])
  1027. cell.value = head.title
  1028. worksheet.mergeCells(`${head.position[0]}:${head.position[1]}`)
  1029. })
  1030. }
  1031. if (headRow > 1) {
  1032. // 合并表头列
  1033. headTemp.forEach((head, index) => {
  1034. const pos = `${getExcelColumnLetter(index)}1:${getExcelColumnLetter(index)}${headRow}`
  1035. const cell = worksheet.getCell(`${getExcelColumnLetter(index)}1`)
  1036. if (!cell.isMerged) {
  1037. worksheet.mergeCells(pos)
  1038. cell.value = head
  1039. }
  1040. })
  1041. }
  1042. temp.goods.forEach((good: Record<string, any>, goodIndex: number) => {
  1043. const _temp: string[] = []
  1044. item.options?.sheetFilter.forEach((key: string, index: number) => {
  1045. if (key === 'thumb' && Boolean(good[key])) {
  1046. const extension = getImageBase64Extension(good[key])
  1047. if (extension) {
  1048. // 插入图片
  1049. const imageId = workbook.addImage({
  1050. base64: good[key],
  1051. extension
  1052. })
  1053. good[key] = imageId
  1054. }
  1055. }
  1056. _temp.push(good[key])
  1057. })
  1058. worksheet.addRow(_temp)
  1059. })
  1060. // 设置宽度
  1061. item.options?.columnWidths.forEach((width: number, index: number) => {
  1062. worksheet.getColumn(index + 1).width = width
  1063. })
  1064. excelHandler(worksheet)
  1065. })
  1066. } else {
  1067. // 输出 word
  1068. exportWordDocx(`./templates/${item.templateName}`, temp, item.fileName)
  1069. }
  1070. }