exportTemplates.ts 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  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. temp.goods.forEach((i: any) => {
  472. if (i.numName !== '藏品总登记号') {
  473. i.num = ''
  474. }
  475. })
  476. break
  477. case EXPORT_WORD_ENUM.HALL_PUT_BACK:
  478. temp = {
  479. ...temp,
  480. year: date.format('YYYY'),
  481. group: numberToChinese(temp.goods.length),
  482. page: numberToChinese(page),
  483. date: dayjs(temp.date).format('YYYY-MM-DD')
  484. }
  485. break
  486. case EXPORT_WORD_ENUM.SUB_PUT_BACK:
  487. temp = {
  488. ...temp,
  489. num: dayjs(temp.date).format('YYYY') + temp.num,
  490. date: dayjs(temp.date).format('YYYY年MM月DD日')
  491. }
  492. temp.goods.forEach((i: any) => {
  493. if (i.numName !== '藏品总登记号') {
  494. i.num = ''
  495. }
  496. })
  497. break
  498. case EXPORT_WORD_ENUM.COLLECTION_INVENTORY:
  499. temp = {
  500. ...temp,
  501. sonNum2: dayjs(temp.date).format('YYYY') + temp.num
  502. }
  503. temp.goods.forEach((i: any) => {
  504. i.checker = i.cusForm[`${i.id}-checker`]
  505. i.remark = i.cusForm[`${i.id}-remark`]
  506. i.cusForm[`${i.id}-statusCheck`] &&
  507. (i.statusCheck = D7CEHCK_COLLECTION_RESULT_OPTIONS.find(
  508. ii => ii.value === i.cusForm[`${i.id}-statusCheck`]
  509. )?.label)
  510. })
  511. break
  512. case EXPORT_WORD_ENUM.VOUCHER:
  513. case EXPORT_WORD_ENUM.STORAGE_VOUCHER:
  514. const _date = dayjs(temp.date)
  515. temp = {
  516. ...temp,
  517. year: _date.format('YYYY'),
  518. month: _date.format('MM'),
  519. day: _date.format('DD'),
  520. group: numberToChinese(temp.goods.length),
  521. page: numberToChinese(page)
  522. }
  523. temp.goods.forEach((i: any) => {
  524. i.pcsActual = i.pcsActual || i.pcs.match(/\d+\.?\d*/)?.[0]
  525. })
  526. break
  527. case EXPORT_WORD_ENUM.FORM_FOR_DIGITAL:
  528. const __date = dayjs(temp.createTime)
  529. temp = {
  530. ...temp,
  531. effect: resJiLianFu(temp.effect),
  532. sonTypeName: MEDIA_TYPES.filter(media => temp.sonTypeName.split(',').includes(media.value))
  533. .map(media => media.label)
  534. .join(','),
  535. year2: date.format('YYYY'),
  536. year: __date.format('YYYY'),
  537. month: __date.format('MM'),
  538. day: __date.format('DD')
  539. }
  540. break
  541. case EXPORT_WORD_ENUM.SUB_PUT_IN:
  542. temp = {
  543. ...temp,
  544. sonSource: resJiLianFu(temp.sonSource),
  545. sonNum2: dayjs(temp.date).format('YYYY') + temp.num,
  546. date: dayjs(temp.date).format('YYYY年MM月DD日')
  547. }
  548. break
  549. case EXPORT_WORD_ENUM.COLLECTION_RELOCATION:
  550. temp = {
  551. ...temp,
  552. sonNum2: dayjs(temp.date).format('YYYY') + temp.num,
  553. date: dayjs(temp.date).format('YYYY年MM月DD日')
  554. }
  555. break
  556. case EXPORT_WORD_ENUM.ACCIDENT_HANDLING_CERTIFICATE:
  557. temp = {
  558. ...temp,
  559. year: date.format('YYYY'),
  560. rtf: temp.rtf ? removeHtmlTags(JSON.parse(temp.rtf).txtArr[0].txt) : '',
  561. authInfoRtf: removeHtmlTags(JSON.parse(temp.authInfoRtf).txtArr[0].txt),
  562. authResultRtf: removeHtmlTags(JSON.parse(temp.authResultRtf).txtArr[0].txt)
  563. }
  564. break
  565. case EXPORT_WORD_ENUM.COLLECTION_ARCHIVES:
  566. case EXPORT_WORD_ENUM.COLLECTION_CARD:
  567. const rtf2 = temp.rtf ? JSON.parse(temp.rtf).txtArr[0].txt : ''
  568. const stack2 = []
  569. try {
  570. for (const url of getImageUrlsFromHtml(rtf2)) {
  571. stack2.push(await getBase64Sync(url))
  572. }
  573. } catch (err) {
  574. console.log(`rtf img transfer base64 error: `, err)
  575. }
  576. temp = {
  577. ...temp,
  578. year: date.format('YYYY'),
  579. month: date.format('MM'),
  580. day: date.format('DD'),
  581. createTime: dayjs(temp.createTime).format('YYYY-MM-DD'),
  582. size: myTableTransferSize(temp),
  583. quality: temp.quality + temp.qualityUnit,
  584. deptName: (temp.records || []).length ? temp.records[0].deptName : '',
  585. recordDate: (temp.records || []).length ? temp.records[0].createTime : '',
  586. dictTexture: resJiLianFu(temp.dictTexture3),
  587. records: (temp.records || []).map(
  588. (item: any) =>
  589. `[${item.dictLevel}],[${item.date.split(' ')[0]}][${item.deptName}][${
  590. item.creatorName
  591. }]意见。`
  592. ),
  593. repairs: (temp.repairs || []).map(
  594. (item: any) =>
  595. `[${item.txt1}],[${item.txt2}],[${item.date.split(' ')[0]}][${item.authUnit}]交修。`
  596. ),
  597. status: (temp.status || []).map(
  598. (item: any) => `[${item.reason}],[${item.date.split(' ')[0]}][${item.sonUser}]登记。`
  599. ),
  600. source: resJiLianFu(temp.source),
  601. rtf: removeHtmlTags(rtf2),
  602. preserveState: resJiLianFu(temp.preserveState),
  603. imgs: stack2
  604. }
  605. if (temp.numName !== '藏品总登记号') {
  606. temp.num2 = temp.num
  607. temp.num = ''
  608. }
  609. try {
  610. if (type === EXPORT_WORD_ENUM.COLLECTION_ARCHIVES) {
  611. temp.imagePages = await arrangeImages(temp.imagePages)
  612. } else if (temp.thumb) {
  613. temp.thumb = await getBase64Sync(temp.thumb)
  614. }
  615. } catch (err) {
  616. console.log(err)
  617. temp.imagePages = []
  618. }
  619. break
  620. case EXPORT_WORD_ENUM.OUTSIDER_FORM:
  621. const memberss = JSON.parse(temp.memberIds)
  622. temp = {
  623. ...temp,
  624. time: dayjs(temp.date).format('HH:mm:ss'),
  625. date: dayjs(temp.date).format('YYYY-MM-DD'),
  626. members: memberss.map((i: any) => i.name),
  627. companys: memberss.map((i: any) => i.remark || '空'),
  628. idCards: memberss.map((i: any) => i.papers || '空'),
  629. phones: memberss.map((i: any) => (i.phone ? getDesensitizeTxt(i.phone) : '空'))
  630. }
  631. break
  632. case EXPORT_WORD_ENUM.RELIC_REPAIR_LIST:
  633. case EXPORT_WORD_ENUM.COLLECTION_CURRENT_STATUS:
  634. const ___date = dayjs(temp.date)
  635. const rtf = JSON.parse(temp.rtf).txtArr[0].txt
  636. const stack = []
  637. try {
  638. for (const url of getImageUrlsFromHtml(rtf)) {
  639. stack.push(await getBase64Sync(url))
  640. }
  641. } catch (err) {}
  642. temp = {
  643. ...temp,
  644. year: ___date.format('YYYY'),
  645. page,
  646. rtf: removeHtmlTags(rtf),
  647. imgs: stack
  648. }
  649. if (type === EXPORT_WORD_ENUM.COLLECTION_CURRENT_STATUS) {
  650. temp.goodsNum = temp.numName === '藏品总登记号' ? temp.goodsNum : ``
  651. }
  652. break
  653. case EXPORT_WORD_ENUM.COLLECTION_LIST:
  654. temp.goods.push({
  655. index: '合计',
  656. name: temp.goods.length,
  657. dictAgeFirst: '合计',
  658. offer: temp.goods.reduce((sum: number, cur: any) => sum + Number(cur.offer), 0)
  659. })
  660. excelHandler = worksheet => {
  661. worksheet.insertRow(1, ['拟征集藏品清单'])
  662. worksheet.mergeCells('A1:F1')
  663. const mergedCell = worksheet.getCell('A1')
  664. mergedCell.style = {
  665. fill: {
  666. type: 'pattern',
  667. pattern: 'solid',
  668. fgColor: { argb: 'cce8cf' }
  669. },
  670. font: {
  671. name: '黑体',
  672. size: 18
  673. }
  674. }
  675. const borderStyle: ExcelJS.Border = {
  676. style: 'thin',
  677. color: { argb: 'FF000000' }
  678. }
  679. for (let row = 2; row <= temp.goods.length + 2; row++) {
  680. for (let col = 1; col <= 6; col++) {
  681. const cell = worksheet.getCell(row, col)
  682. cell.border = {
  683. top: borderStyle,
  684. left: borderStyle,
  685. bottom: borderStyle,
  686. right: borderStyle
  687. }
  688. }
  689. }
  690. worksheet.eachRow(row => {
  691. row.eachCell(cell => {
  692. cell.alignment = {
  693. vertical: 'middle',
  694. horizontal: 'center',
  695. wrapText: true
  696. }
  697. })
  698. })
  699. }
  700. break
  701. case EXPORT_WORD_ENUM.CERTIFICATE:
  702. const resultText = Object.entries(
  703. // @ts-ignore
  704. temp.goods.reduce((acc, { dictLevel }) => {
  705. acc[dictLevel] = (acc[dictLevel] || 0) + 1
  706. return acc
  707. }, {})
  708. )
  709. // @ts-ignore
  710. .filter(([_, count]) => count > 0)
  711. .map(
  712. ([level, count]) =>
  713. `${level === '一般' ? level + '珍贵文物' : level + '文物'}${count}件/组;`
  714. )
  715. .join('\n')
  716. temp.goods.push({
  717. index: '鉴\n定\n人\n员',
  718. num: temp.authUser,
  719. thumb: '鉴\n定\n单\n位',
  720. pcs: temp.authUnit,
  721. dictAge: '核\n准\n单\n位',
  722. dictTorn: '说\n\n明',
  723. size: temp.confirmUnit,
  724. dictLevel: `鉴定日期:${temp.date}\n鉴定总数${temp.goods.length}件/组,其中:\n${resultText}`
  725. })
  726. excelHandler = worksheet => {
  727. const lastIndex = temp.goods.length + 2
  728. worksheet.insertRow(1, ['单位:义乌市博物馆'])
  729. worksheet.mergeCells('A1:H1')
  730. worksheet.mergeCells('I1:L1')
  731. worksheet.mergeCells(`B${lastIndex}:D${lastIndex}`)
  732. worksheet.mergeCells(`F${lastIndex}:G${lastIndex}`)
  733. worksheet.mergeCells(`K${lastIndex}:L${lastIndex}`)
  734. worksheet.eachRow(row => {
  735. const col5 = row.getCell(5)
  736. if (isNumber(col5.value)) {
  737. worksheet.addImage(col5.value, `${col5.address}:${col5.address}`)
  738. }
  739. row.eachCell(cell => {
  740. cell.style = {
  741. font: {
  742. name: '宋体',
  743. size: 10
  744. }
  745. }
  746. cell.alignment = {
  747. vertical: 'middle',
  748. horizontal: 'center',
  749. wrapText: true
  750. }
  751. })
  752. })
  753. const titleCell = worksheet.getCell('A1')
  754. const dateCell = worksheet.getCell('I1')
  755. const lastCell = worksheet.getRow(lastIndex)
  756. const borderStyle: ExcelJS.Border = {
  757. style: 'thin',
  758. color: { argb: 'FF000000' }
  759. }
  760. lastCell.height = 80
  761. titleCell.style = {
  762. fill: {
  763. type: 'pattern',
  764. pattern: 'solid',
  765. fgColor: { argb: 'cce8cf' }
  766. },
  767. font: {
  768. size: 16
  769. },
  770. alignment: {
  771. horizontal: 'left',
  772. vertical: 'middle'
  773. }
  774. }
  775. dateCell.value = '日期:' + temp.createTime.split(' ')[0]
  776. dateCell.style = {
  777. fill: {
  778. type: 'pattern',
  779. pattern: 'solid',
  780. fgColor: { argb: 'cce8cf' }
  781. },
  782. font: {
  783. size: 16
  784. },
  785. alignment: {
  786. horizontal: 'right',
  787. vertical: 'middle'
  788. }
  789. }
  790. for (let row = 1; row <= lastIndex; row++) {
  791. for (let col = 1; col <= 12; col++) {
  792. const cell = worksheet.getCell(row, col)
  793. cell.border = {
  794. top: borderStyle,
  795. left: borderStyle,
  796. bottom: borderStyle,
  797. right: borderStyle
  798. }
  799. }
  800. }
  801. }
  802. break
  803. case EXPORT_WORD_ENUM.CANCEL_VOUCHER:
  804. temp.goods.push({
  805. num: '法定代表人:',
  806. dictAge: '保管部负责人:',
  807. torn: '保管员:',
  808. txt1: '珍贵文物注销审批文号:'
  809. })
  810. excelHandler = worksheet => {
  811. const lastIndex = temp.goods.length + 4
  812. const borderStyle: ExcelJS.Border = {
  813. style: 'thin',
  814. color: { argb: 'FF000000' }
  815. }
  816. worksheet.eachRow(row => {
  817. row.eachCell(cell => {
  818. cell.style = {
  819. font: {
  820. name: '宋体',
  821. size: 10
  822. }
  823. }
  824. cell.alignment = {
  825. vertical: 'middle',
  826. horizontal: 'center',
  827. wrapText: true
  828. }
  829. })
  830. })
  831. worksheet.insertRow(1, [])
  832. worksheet.mergeCells('A1:K1')
  833. worksheet.getCell('A1').value = {
  834. richText: [
  835. { font: { size: 20, name: '黑体' }, text: '馆藏品注销凭证 ' },
  836. { font: { size: 11 }, text: `(编号:${temp.num}) ` }
  837. ]
  838. }
  839. worksheet.getRow(1).height = 60
  840. worksheet.getCell('A1').style = {
  841. alignment: {
  842. horizontal: 'center',
  843. vertical: 'middle'
  844. }
  845. }
  846. worksheet.insertRow(2, [dayjs(temp.createTime).format('YYYY年MM月DD日')])
  847. worksheet.mergeCells('A2:K2')
  848. worksheet.getRow(2).height = 30
  849. worksheet.getCell('A2').style = {
  850. font: {
  851. size: 11,
  852. name: '仿宋_GB2312'
  853. },
  854. alignment: {
  855. horizontal: 'right',
  856. vertical: 'middle'
  857. }
  858. }
  859. worksheet.insertRow(3, [
  860. // @ts-ignore
  861. `现将藏品_${
  862. temp.goods.length - 1
  863. }_件注销,清单开列如下,本凭证连同附页全份共___页(含附件)`
  864. ])
  865. worksheet.mergeCells('A3:K3')
  866. worksheet.getRow(3).height = 30
  867. worksheet.getCell('A3').style = {
  868. font: {
  869. size: 11,
  870. name: '仿宋_GB2312'
  871. },
  872. alignment: {
  873. horizontal: 'center',
  874. vertical: 'middle'
  875. }
  876. }
  877. worksheet.mergeCells(`A${lastIndex}:C${lastIndex}`)
  878. worksheet.mergeCells(`D${lastIndex}:F${lastIndex}`)
  879. worksheet.mergeCells(`G${lastIndex}:H${lastIndex}`)
  880. worksheet.mergeCells(`I${lastIndex}:K${lastIndex}`)
  881. for (let row = 1; row <= lastIndex; row++) {
  882. for (let col = 1; col <= 11; col++) {
  883. const cell = worksheet.getCell(row, col)
  884. cell.border = {
  885. top: borderStyle,
  886. left: borderStyle,
  887. bottom: borderStyle,
  888. right: borderStyle
  889. }
  890. }
  891. }
  892. }
  893. break
  894. case EXPORT_WORD_ENUM.REGISTER_LEDGER:
  895. const totalPcs = temp.goods.reduce((sum: number, i: any) => sum + (i._pcs || 0), 0)
  896. temp.goods.forEach((i: any) => {
  897. i.year = date.format('YYYY') + '年度'
  898. i.sonUnit = temp.sonUnit
  899. i.typeName = temp.typeName
  900. i.lendDate = dayjs(i.cusForm[`${i.id}-lendDate`]).format('YYYY年MM月DD日')
  901. i.lenderA = i.cusForm[`${i.id}-lenderA`]
  902. i.lenderb = i.cusForm[`${i.id}-lenderb`]
  903. i.sonNum = temp.sonNum
  904. i.sonNum2 = temp.sonNum2
  905. i.handlerA = i.cusForm[`${i.id}-handlerA`]
  906. i.handlerB = i.cusForm[`${i.id}-handlerB`]
  907. i.recorder = i.cusForm[`${i.id}-recorder`]
  908. i.remark = i.cusForm[`${i.id}-remark`]
  909. i.pcs = `${i.pcs},计${totalPcs}件`
  910. const expectedReturnDate = i.cusForm[`${i.id}-expectedReturnDate`]
  911. expectedReturnDate &&
  912. (i.expectedReturnDate = dayjs(expectedReturnDate).format('YYYY年MM月DD日'))
  913. const returnDate = i.cusForm[`${i.id}-returnDate`]
  914. returnDate && (i.returnDate = dayjs(returnDate).format('YYYY年MM月DD日'))
  915. })
  916. excelHandler = worksheet => {
  917. const borderStyle: ExcelJS.Border = {
  918. style: 'thin',
  919. color: { argb: 'FF000000' }
  920. }
  921. for (let row = 1; row <= temp.goods.length + 2; row++) {
  922. for (let col = 1; col <= 18; col++) {
  923. const cell = worksheet.getCell(row, col)
  924. cell.border = {
  925. top: borderStyle,
  926. left: borderStyle,
  927. bottom: borderStyle,
  928. right: borderStyle
  929. }
  930. }
  931. }
  932. worksheet.eachRow(row => {
  933. row.eachCell(cell => {
  934. cell.alignment = {
  935. vertical: 'middle',
  936. horizontal: 'center',
  937. wrapText: true
  938. }
  939. })
  940. })
  941. }
  942. break
  943. case EXPORT_WORD_ENUM.COLLECTION_LOG:
  944. excelHandler = worksheet => {
  945. const borderStyle: ExcelJS.Border = {
  946. style: 'thin',
  947. color: { argb: 'FF000000' }
  948. }
  949. for (let row = 1; row <= temp.goods.length + 2; row++) {
  950. for (let col = 1; col <= 14; col++) {
  951. const cell = worksheet.getCell(row, col)
  952. cell.border = {
  953. top: borderStyle,
  954. left: borderStyle,
  955. bottom: borderStyle,
  956. right: borderStyle
  957. }
  958. }
  959. }
  960. worksheet.eachRow(row => {
  961. row.eachCell(cell => {
  962. cell.alignment = {
  963. vertical: 'middle',
  964. horizontal: 'center',
  965. wrapText: true
  966. }
  967. })
  968. })
  969. }
  970. break
  971. case EXPORT_WORD_ENUM.COLLECTION_LEDGER:
  972. temp.goods.forEach((i: any) => {
  973. const createTime = dayjs(i.createTime)
  974. const inHouseTime = dayjs(i.createTime)
  975. i.year = createTime.format('YYYY')
  976. i.month = createTime.format('MM')
  977. i.day = createTime.format('DD')
  978. i.year2 = inHouseTime.format('YYYY')
  979. i.month2 = inHouseTime.format('MM')
  980. i.day2 = inHouseTime.format('DD')
  981. })
  982. excelHandler = worksheet => {
  983. const borderStyle: ExcelJS.Border = {
  984. style: 'thin',
  985. color: { argb: 'FF000000' }
  986. }
  987. for (let row = 1; row <= temp.goods.length + 2; row++) {
  988. for (let col = 1; col <= 21; col++) {
  989. const cell = worksheet.getCell(row, col)
  990. cell.border = {
  991. top: borderStyle,
  992. left: borderStyle,
  993. bottom: borderStyle,
  994. right: borderStyle
  995. }
  996. }
  997. }
  998. worksheet.eachRow(row => {
  999. row.eachCell(cell => {
  1000. cell.alignment = {
  1001. vertical: 'middle',
  1002. horizontal: 'center',
  1003. wrapText: true
  1004. }
  1005. })
  1006. })
  1007. }
  1008. break
  1009. }
  1010. if (!item.templateName) {
  1011. // 没有templateName则输出 excel
  1012. exportTempExcel(item.fileName, (worksheet, workbook) => {
  1013. let mergeHeadNum = 0
  1014. let headTemp: string[] = []
  1015. let fatherHeadTemp: {
  1016. title: string
  1017. position: string[]
  1018. }[] = []
  1019. // 表头需要占据的行数
  1020. const headRow = Math.max(
  1021. ...item.options?.sheetHeader.map((head: string | string[]) => (Array.isArray(head) ? 2 : 1))
  1022. )
  1023. item.options?.sheetHeader.forEach((head: string | string[], index: number) => {
  1024. if (Array.isArray(head)) {
  1025. fatherHeadTemp.push({
  1026. title: head.shift() || '',
  1027. position: [
  1028. `${getExcelColumnLetter(index + mergeHeadNum)}1`,
  1029. `${getExcelColumnLetter(index + head.length - 1 + mergeHeadNum)}1`
  1030. ]
  1031. })
  1032. headTemp.push(...head)
  1033. mergeHeadNum += head.length - 1
  1034. } else {
  1035. headTemp.push(head)
  1036. }
  1037. })
  1038. worksheet.addRow(headTemp)
  1039. if (fatherHeadTemp.length) {
  1040. // 存在需要合并的父级表头
  1041. worksheet.insertRow(1, [])
  1042. fatherHeadTemp.forEach(head => {
  1043. const cell = worksheet.getCell(head.position[0])
  1044. cell.value = head.title
  1045. worksheet.mergeCells(`${head.position[0]}:${head.position[1]}`)
  1046. })
  1047. }
  1048. if (headRow > 1) {
  1049. // 合并表头列
  1050. headTemp.forEach((head, index) => {
  1051. const pos = `${getExcelColumnLetter(index)}1:${getExcelColumnLetter(index)}${headRow}`
  1052. const cell = worksheet.getCell(`${getExcelColumnLetter(index)}1`)
  1053. if (!cell.isMerged) {
  1054. worksheet.mergeCells(pos)
  1055. cell.value = head
  1056. }
  1057. })
  1058. }
  1059. temp.goods.forEach((good: Record<string, any>, goodIndex: number) => {
  1060. const _temp: string[] = []
  1061. item.options?.sheetFilter.forEach((key: string, index: number) => {
  1062. if (key === 'thumb' && Boolean(good[key])) {
  1063. const extension = getImageBase64Extension(good[key])
  1064. if (extension) {
  1065. // 插入图片
  1066. const imageId = workbook.addImage({
  1067. base64: good[key],
  1068. extension
  1069. })
  1070. good[key] = imageId
  1071. }
  1072. }
  1073. _temp.push(good[key])
  1074. })
  1075. worksheet.addRow(_temp)
  1076. })
  1077. // 设置宽度
  1078. item.options?.columnWidths.forEach((width: number, index: number) => {
  1079. worksheet.getColumn(index + 1).width = width
  1080. })
  1081. excelHandler(worksheet)
  1082. })
  1083. } else {
  1084. // 输出 word
  1085. exportWordDocx(`./templates/${item.templateName}`, temp, item.fileName)
  1086. }
  1087. }