成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

怎么利用node生成word文檔?使用庫分享

怎么利用node生成word文檔?下面本篇文章給大家介紹一下使用node生成word文檔的方法,分享一個實用庫,聊聊該庫的使用方法,希望對大家有所幫助!

怎么利用node生成word文檔?使用庫分享

最近有項目需要用到生成word文檔,平時經常用的都是通過模板生成,里面變量使用占位符替換,好處是快捷、方便、簡單、不需要通過代碼調word樣式,確定是很多庫不支持圖片繪制(很多都是付費功能),找一圈,發現一個很有意思的庫,正好也滿足我們的需求,特此分享一下

依賴

// https://docx.js.org/#/ npm i docx   // https://www.npmjs.com/package/download npm i download

說明,因為docx繪圖只支持文件流,所以要把網絡文件下載到本地轉成buffer

代碼

話不多說,上代碼

import * as fs from "fs" import { Document, Packer, Paragraph, TextRun, ImageRun, HeadingLevel, AlignmentType, convertInchesToTwip, Table, TableRow, TableCell, WidthType, VerticalAlign, BorderStyle } from "docx" const download = require('download')  // 性別 enum Gender {   Male = 'male',   Female = 'female' }  // 選手 type PlayerSchema = {   name: string   gender: string   idCard?: string   birthday?: string   weight?: string   remark?: string   avatar?: string   localAvatar?: string   level: string } type GroupSchema = {   // gender: Gender   institution: string   leader: string   phone: string   coach: string   doctor: string   players: PlayerSchema[] }  // 所有數據 interface DataSchema  {   [key: string]: GroupSchema }  // 表格無邊框 const noBoder = {   top: {     style: BorderStyle.NIL,     size: 0,     color: 'FFFFFF'   },   bottom: {     style: BorderStyle.NIL,     size: 0,     color: 'FFFFFF'   },   left: {     style: BorderStyle.NIL,     size: 0,     color: 'FFFFFF'   },   right: {     style: BorderStyle.NIL,     size: 0,     color: 'FFFFFF'   } }  // 刪除下載的照片及文件夾 function delStaticFile(groupNames: string[]) {   for (let groupName of groupNames) {     if (fs.existsSync(groupName)) {       const files = fs.readdirSync(groupName)       files.map((file: string) => {         let curPath = groupName + "/" + file         // 刪除選手招聘         fs.unlinkSync(curPath)       })       fs.rmdirSync(groupName)     }   } }  // 生成word async function generate (data: DataSchema) {   const groupNames = Object.keys(data)    // 比較粗糙的控制單元格長度邏輯   const longHeaders = ['身份證號', '備注']    // 下載遠程資源到本地   for (let groupName of groupNames) {     if (!fs.existsSync(groupName)) {       fs.mkdirSync(groupName)     }      const players = data[groupName].players     for (let player of players) {       if (player.avatar) {         const avatarArr = player.avatar.split('/')         const fileName = `${groupName}/${avatarArr[avatarArr.length - 1]}`          if (!fs.existsSync(fileName)) {           await download(player.avatar, groupName)         }         // 下載后的本地的資源路徑         player.localAvatar = fileName       }     }   }    // 需要多個文件合一   const sections = groupNames.map(groupName => {     const info = data[groupName]     const { institution, leader, phone, coach, doctor, players } = info     // 標頭內容     // let headers = ['序號', '照片', '姓名', '性別', '出生年月', '體重', '級別', '備注']     let headers = ['序號', '照片', '姓名', '性別', '身份證號', '級別', '備注']      // 表格數據     let tableData: any[][] = []     tableData.push(headers)      // 填充選手信息     let index = 1     for (let player of players) {       tableData.push([         index.toString(),         player.localAvatar || '',         player.name,         player.gender === Gender.Male ? '男' : '女',         player.idCard,         // player.birthday,         // player.weight,         player.level,         player.remark,       ])       index++     }      // 表格渲染     const tableRows = tableData.map(colums => {       return new TableRow({         children: colums.map(cell => {         return new TableCell({           verticalAlign: VerticalAlign.CENTER,           width: {             // 設置寬度 dxa長度單位 https://stackoverflow.com/questions/14360183/default-wordml-unit-measurement-pixel-or-point-or-inches             size: longHeaders.some(j => cell === j) ? 3000 : 800,             type: WidthType.DXA,           },           children: cell && colums.findIndex(i => i === cell) === 1 && cell !== '照片' ?               [new Paragraph({                 alignment: AlignmentType.CENTER,                 children: [                   new ImageRun({                     // 將圖片轉化為buffer                     data: fs.readFileSync(cell),                     transformation: {                       width: 100,                       height: 129,                     },                   })                 ]               })]:             [new Paragraph({               alignment: AlignmentType.CENTER,               children:[                 new TextRun(cell || '')               ]             })]           })         })       })     })      // 渲染報名表格     const table = new Table({       alignment: AlignmentType.CENTER,       rows: tableRows     })      return {       properties: {},       children: [         // new Paragraph({         //   style: "wellSpaced",         //   children: [         //     new TextRun({         //       text: '附件 4',         //       color: '999999',         //     })         //   ],         // }),          // 表頭信息         new Paragraph({           spacing: {             before: 400,             after: 400           },           style: "Title",           text: `自 由 搏 擊 比 賽 報 名 表(${groupName === Gender.Male ? '男子' : '女子'})`,           heading: HeadingLevel.TITLE,           alignment: AlignmentType.CENTER         }),          // 隊伍信息         new Table({           style: "wellSpaced",           alignment: AlignmentType.CENTER,           borders: noBoder,           rows: [             new TableRow({             children: [               new TableCell({                 width: {                   size: 600,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`單位: `),                 ],               }),               new TableCell({                 width: {                   size: 1800,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`${institution}`)                 ],               }),               new TableCell({                 width: {                   size: 700,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`  領隊: `),                 ],               }),               new TableCell({                 width: {                   size: 1200,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`${leader}`)                 ],               }),               new TableCell({                 width: {                   size: 1100,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`  聯系電話: `),                 ],               }),               new TableCell({                 width: {                   size: 1400,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`${phone}`)                 ],               }),               new TableCell({                 width: {                   size: 700,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`  教練: `),                 ],               }),               new TableCell({                 width: {                   size: 1300,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`${coach}`)                 ],               }),               new TableCell({                 width: {                   size: 700,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`  隊醫: `),                 ],               }),               new TableCell({                 width: {                   size: 1300,                   type: WidthType.DXA,                 },                 borders: noBoder,                 children: [                   new Paragraph(`${doctor}`)                 ],               }),             ],           }),           ]         }),          // 用于段落距離(table無法設置spacing屬性)         new Paragraph({           spacing: {             // 通過調整before值來調整段落漸進             before: 400,           },           text: ``,         }),          // 選手信息         table,          // 印章和時間         new Paragraph({           style: "wellSpaced",           children: [             new TextRun({               text: 'tttt報名單位章:tttttt',             }),             new TextRun({               text: '年tt'             }),             new TextRun({               text: '月tt'             }),             new TextRun({               text: '日'             })           ]         })       ]     }   })    // 創建整個文檔   const doc = new Document({     styles: {       paragraphStyles: [         {           id: "Title",           name: "title",           basedOn: "Normal",           next: "Normal",           quickFormat: true,           run: {               size: 30,               bold: true,               color: "000000"           }         },         {           id: "wellSpaced",           name: "Well Spaced",           basedOn: "Normal",           quickFormat: true,           paragraph: {             indent: {               left: convertInchesToTwip(0.5),             },             spacing: {               before: 400,             },           },         },       ],     },     sections   })      // 生成word文檔   Packer.toBuffer(doc).then((buffer) => {     fs.writeFileSync("enrolls.docx", buffer)   })    // 刪除下載的選手照片   delStaticFile(groupNames) }  const group: GroupSchema = {   institution: '江蘇省南京市舜禹集團總部',   leader: '王猛(男)',   phone: '18861856665',   coach: '劉國梁(男)',   doctor: '楊永信(女)',   players: [     {       name: '萊昂納多迪卡普里奧',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/13.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/7.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       idCard: '320888199001019878',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     },     {       name: '張三',       gender: Gender.Male,       idCard: '320888199001019878',       birthday: '1999-01-02',       weight: '60kg',       avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png',       remark: '',       level: '60kg'     }   ] }  const data: DataSchema = {   [Gender.Male]: group,   [Gender.Female]: group, }  generate(data)

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
男人J进女人屁网站免费| 成人午夜视频精品一区| 久久久久久久久久久精品| 亚洲成av人片在线观看无码| 国产女人水真多18毛片18精品| 婷婷亚洲综合五月天小说| 东京热无码AV一区二区| 日韩 无码 偷拍 中文字幕| 啊轻点灬大JI巴太粗太长了欧美| 欧美极品JIZZHD欧美| 99国产精品久久久久久久成人| 免费稀缺拗女一区二区| 12末发育娇小性色XXXX| 女技师强制高潮18XXXX按摩| 97久久精品人人爽人人爽蜜臀 | 国产丰满饥渴老女人HD| 脱色摇床THERMO网站| 国产成人亚洲精品无码最新 | 在线精品亚洲观看不卡欧| 麻豆极品JK丝袜自慰喷水久久| 玉蒲团Ⅲ艳乳叶媚子| 麻批好紧日起要舒服死了| 中文字幕色偷偷人妻久久| 嫩模超大胆大尺度人体写真| 97精品伊人久久久大香线蕉| 欧美乱人伦中文字幕在线| XX娇小嫩XX中国XX| 日韩国产成人精品视频| 丰满岳乱妇在线观看中字无码| 天美传媒蜜桃传媒精东| 国产精品免费_区二区三区观看| 新X8X8拨牐拨牐永久免费AP| 国内偷窥一区二区三区视频| 亚洲国产精品久久久天堂麻豆宅男| 精品无码日韩国产不卡AV| 一二三四免费观看在线视频| 免费高清AV一区二区三区| 99久久久无码国产精品性| 人妻无码一区二区视频| 成人夜间av大片免费观看| 天堂√最新版中文在线地址| 国产免费AV片在线观看麻豆| 亚洲国产成人精品无码区在线观看 | 国产AV无码专区亚洲AV中文| 无遮挡粉嫩小泬久久久久久久动漫| 国内精品久久久久久久久电影网 | 少妇人妻无码专区视频免费| 国产精品亚洲专区无码导航| 亚洲国产成人无码AV在线| 久久婷婷五月综合色国产免费观看| 自拍偷自拍亚洲精品播放| 欧美综合天天夜夜久久| 夫妻免费无码V看片| 性生大片免费观看网站| 九九视频麻婆豆腐在线观看| 最新中文字幕AV专区| 日本久久久WWW成人免费毛片丨| 国产精华液一线二线三线| 亚洲国产另类久久久精品小说 | 从你的全世界路过| 香蕉久久久久久久AV网站| 久久国产精品免费一区| 97SE亚洲国产综合自在线尤物| 日韩精品成熟妇人Av一区二区| 国产精品无码一区二区三区| 亚洲熟妇丰满美女XXXXX| 男朋友想吻我腿中间那个部位 | 国产亚洲AV片在线观看播放| 一本久道中文无码字幕AV| 秋霞午夜久久午夜精品| 国产旡码高清一区二区三区| 亚洲欧洲精品成人久久曰影片| 免费观看交性大片| 大胆极品美軳人人体| 亚洲 春色 另类 小说| 老赵抱着媛媛在厨房做| 成年美女黄网站18禁免费| 亚洲AV乱码一区二区三区林ゆな| 两毫米的小洞你却稳稳命中| 初尝禁果稚嫩宫交H| 亚洲风情亚Aⅴ在线发布| 农村野外性BBW| 国产成人午夜福利院| 亚洲色欲色欲WWW在线看小说| 欧洲VODAFONEWIFI喷| 国产乱码精品一区二区三区中文| 一边做饭一边暴躁怎么办 | 国产亚洲日韩一区二区三区| 永久免费AV网站可以直接看的| 日韩精品无码中文字幕第一区 | 吃瓜网最新官网地址| 亚洲MV砖码砖区2021在线| 女教师的凌脣教室在线| 国产精品无码V在线观看| 尤物AV无码色AV无码麻豆| 搡老女人老熟妇HHD| 精品少妇人妻AV免费久久洗澡| V与子敌伦刺激对白播放| 性欧美大战久久久久久久久| 妺妺窝人体色77777777| 国产精品午夜无码AV体验区| 中文字幕亚洲综合小综合在线| 玩弄JAPAN白嫩少妇HD小说| 老奶奶能叫WOMAN吗| 国产AV无码专区亚洲AV手机麻 | 婷婷久久久亚洲欧洲日产国码AV| 久久亚洲日韩看片无码| 国产A国产片国产| 影音先锋无码A∨男人资源站| 太平公主秘史在线观看免费| 看久久久久久A级毛片| 国产放荡对白视频在线观看| 18禁裸乳啪啪无遮裆网站| 西西人体大胆WWW.4444| 嫩BBB槡BBBB搡BBBB| 国产性一交一乱一伦一色一情| AV在线中文字幕不卡电影网| 亚洲AV无码一区毛片AV| 人妻熟妇女的欲乱系列| 精品一区二区三区免费乱码视频| 当着老公的面被别人欺负该怎么办| 夜先锋AV资源网站| 天堂А√在线最新版中文下载 | 国产蜜臀AV在线一区尤物| GOGO高清大胆全人艺术| 亚洲精品乱码久久久久久不卡 | 亚洲乱码一区二区三区在线观看 | 少妇又色又紧又爽又刺激视频| 乳荡的小痍子免费播放| 视频一区欧美日韩| 日本不卡高清兔费V| 欧美人伦禁忌DVD| 欧美高大丰满FREESEX| 男女无遮挡XX00动态图1| 日韩AV无码午夜免费福利制服 | 性一交一乱一色一视频| 日产无码精品一区二区三区| 欧美牲交视频免费观看| 久久月本道色综合久久| 激情综合亚洲色婷婷五月APP| 黑人巨大无码中文字幕无码| 娇妻借朋友高H繁交H| 女人不怕粗短就怕蘑菇头什么意 | 羞羞在线版免费阅读入口 | 巨大黑人XXXXX高潮后处理| 国产区在线观看成人精品| 成熟女人牲交片免费观看视频| HEZYO东京热无码专区| 中文字幕天天躁日日躁狠狠躁免费| 亚洲乱码1卡2卡3乱码在线芒果| 亚洲AV福利天堂一区二区三| 亚洲AV成人片无码网站网| 无码日韩做暖暖大全免费不卡| 日韩精品人妻系列无码AV东京| 欧美综合在线激情专区| 欧美午夜精品久久久久久浪潮| 女学生14毛片视频片二毛| 哦┅┅快┅┅用力啊┅┅| 嫩BBB槡BBBB搡BBBB| 欧美高清精品一区二区| 女人张开腿让男人桶爽免| 美女高潮流白浆娇喘免费网站| 人人妻人人爽人人狠狠| 挺进大幂幂的滋润花苞御女天下| 小13箩利洗澡无码视频网站| 性色AV无码中文AV有码VR| 婷婷五月综合缴情在线视频| 天天摸天天摸色综合舒服网| 无人区乱码一区二区三区| 午夜无码人妻AV大片色欲| 亚洲AⅤ精品无码一区二区PRO| 亚洲AV色香蕉一区二区蜜桃| 亚洲成AV人片一区二区| 在线观看亚洲AV每日更新无码| 中文字幕乱码亚洲无线码| 99国内精品久久久久影院| 国产成人无码精品一区二区三区| 国产亚洲精品黑人粗大精选| 青青草原综合久久大伊人| 亚洲综合色区另类小说| 国产精品不卡无码AV在线播放| 欧美成人精品手机在线| 欧美日韩在线亚洲一区蜜芽| 亚洲成AV人片天堂网| 丰满人妻被快递员侵犯的电影| 美女裸体跪姿扒开屁股无内裤| 亚洲AV中文无码乱人伦在线R▽| 大肉大捧一进一出视频| 免费夜里18款禁用B站软粉色| 亚洲国产欧美在线人成大黄瓜| 国产成人高清精品免费软件| 拍摄AV现场失控高潮数次| 中国女人内射69XXXXⅩ视频| 精品麻豆国产色欲色欲色欲WWW | 国产成人亚洲精品无码H| 日本日本熟妇中文在线视频| 亚洲日本VA午夜在线影院| 中国少妇嫖妓BBWBBW| 波多野结衣的电影| 久久久久人妻精品一区|