最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解使用koa2完成Excel導(dǎo)入導(dǎo)出

 更新時(shí)間:2023年03月31日 09:47:22   作者:我擱這敲代碼呢  
這篇文章主要為大家介紹了詳解使用koa2完成Excel導(dǎo)入導(dǎo)出示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、安裝 node-xlsx

npm i node-xlsx

二、導(dǎo)出excel表

首先是查詢(xún)出數(shù)據(jù)庫(kù)內(nèi)所有的表的信息,然后傳至下一個(gè)下劃線轉(zhuǎn)大小寫(xiě)的公用函數(shù),進(jìn)行key的轉(zhuǎn)換,然后就進(jìn)行數(shù)據(jù)的加工;

大小寫(xiě)轉(zhuǎn)換函數(shù)封裝可看此篇文章

因?yàn)閷?dǎo)出except表的宮功能會(huì)在業(yè)務(wù)中頻繁使用,所以我們需要給它封裝成一個(gè)公用函數(shù),其他的業(yè)務(wù)使用直接傳參調(diào)用即可!

1、封裝公用函數(shù)

/**
 * excel 導(dǎo)出
 * list:[{}]
 * headers:表頭中文名
 * headerKeys:與表頭中文名一一對(duì)應(yīng)的數(shù)據(jù)區(qū)key
 * tableName:導(dǎo)出的表名稱(chēng)以什么開(kāi)頭
 */
export const excelExport = (list, headers, headerKeys, tableName = 'excel') => {
  // excel 通用樣式
  const sheetOptions = { '!cols': [] }
  headers.forEach(() => {
    sheetOptions['!cols'].push({
      wch: 20
    })
  })
  const data = []
  list.forEach((item) => {
    let arr = []
    const item2 = flatten(item)
    headerKeys.forEach((key) => {
      if (excelMap.changDictExport[key]) {
        arr.push(excelMap.changDictExport[key][item[key]])
      } else {
        arr.push(item2[key])
      }
    })
    data.push(arr)
  })
  data.unshift(headers)
  const buffer = xlsx.build(
    [{ options: {}, name: `${tableName}_${new Date().valueOf()}`, data: data }],
    { sheetOptions }
  )
  return buffer
}

2、headers例子:

  userHeader: [
    '用戶(hù)序號(hào)',
    '登錄名稱(chēng)',
    '用戶(hù)郵箱',
    '手機(jī)號(hào)碼',
    '用戶(hù)性別',
    '帳號(hào)狀態(tài)',
    '最后登錄IP',
    '最后登錄時(shí)間',
    '部門(mén)名稱(chēng)',
    '部門(mén)負(fù)責(zé)人'
  ],

3、headerKeys例子:

  userHeaderKeys: [
    'userId',
    'userName',
    'email',
    'phonenumber',
    'sex',
    'status',
    'loginIp',
    'loginDate',
    'dept.deptName',
    'dept.leader'
  ]

4、因?yàn)閿?shù)據(jù)可能存在跨表查詢(xún),會(huì)出現(xiàn)對(duì)象嵌套結(jié)構(gòu),故需要封裝對(duì)象扁平化函數(shù)flatten,將多層結(jié)構(gòu)的key變成dept.deptName這種格式

/**
 * 對(duì)象扁平化
 */
export const flatten = (obj) => {
  let result = {}
  let process = (key, value) => {
    // 首先判斷是基礎(chǔ)數(shù)據(jù)類(lèi)型還是引用數(shù)據(jù)類(lèi)型
    if (Object(value) !== value) {
      // 基礎(chǔ)數(shù)據(jù)類(lèi)型
      if (key) {
        result[key] = value
      }
    } else if (Array.isArray(value)) {
      for (let i = 0; i < value.length; i++) {
        process(`${key}[${i}]`, value[i])
      }
      if (value.length === 0) {
        result[key] = []
      }
    } else {
      let objArr = Object.keys(value)
      objArr.forEach((item) => {
        process(key ? `${key}.${item}` : `${item}`, value[item])
      })
      if (objArr.length === 0 && key) {
        result[key] = {}
      }
    }
  }
  process('', obj)
  return result
}

5、node-xlsx接收的數(shù)據(jù)格式

 [
  [
    '用戶(hù)序號(hào)',
    '登錄名稱(chēng)',
    '用戶(hù)郵箱',
    '手機(jī)號(hào)碼',
    '用戶(hù)性別',
    '帳號(hào)狀態(tài)',
    '最后登錄IP',
    '最后登錄時(shí)間',
    '部門(mén)名稱(chēng)',
    '部門(mén)負(fù)責(zé)人'
  ],
  [
    1,
    'admin',
    '12012311715@163.com',
    '12012311715',
    '男',
    '正常',
    '',
    '00:00:00',
    '深圳總公司',
    'wen'
  ],
  [
    2,          'password',
    null,       null,
    '未知',     '正常',
    null,       null,
    '研發(fā)部門(mén)', 'wen'
  ]
 ]

6、在業(yè)務(wù)函數(shù)中調(diào)用導(dǎo)出excel表的數(shù)據(jù)

 const buffer = excelExport(
      users,
      excelExportMap.userHeader,
      excelExportMap.userHeaderKeys,
      'user'
    )

7、最終excel導(dǎo)出的效果

三、導(dǎo)入excel表

因?yàn)閷?dǎo)入的情況比較復(fù)雜,會(huì)分為多種情況上傳excel文件:

1、單文件單工作表;

2、單文件多工作表;

3、多文件(單)多工作表;

我個(gè)人解決辦法是獲取放置excel文件的文件夾內(nèi)所有的excel文件,然后進(jìn)行數(shù)據(jù)的提取,在提取完數(shù)據(jù)后,就將該次的excel文件刪除掉,當(dāng)然導(dǎo)入excel功能也是需要進(jìn)行公用封裝的;

1、解析本次導(dǎo)入的所有excel文件內(nèi)數(shù)據(jù)

// 導(dǎo)入excel--解析
export const importExcelsMid = (tableMap: string) => {
  return async (ctx: Context, next: () => Promise<void>) => {
    try {
      const fileExistPath = path.resolve() + '\src\upload'
      let fileName = [] // 多個(gè)excel文件保存地
      fs.readdirSync(path.format({ dir: fileExistPath })).forEach((excel) => {
        if (excel.split('.')[excel.split('.').length - 1] === 'xlsx' && 'xls') {
          fileName.push(excel)
        }
      })
      // 拿去多個(gè)excel文件
      const workSheetsFromBuffer = []
      fileName.forEach((item) => {
        const absoluteFilePath = fileExistPath + '\' + item //整個(gè)文件的絕對(duì)路徑
        workSheetsFromBuffer.push(xlsx.parse(fs.readFileSync(absoluteFilePath))) //這種方式是解析buffer
      })
      // 生成默認(rèn)用戶(hù)密碼
      const salt = bcrypt.genSaltSync(10)
      const hash = bcrypt.hashSync('123456', salt)
      const arr = [] // 存儲(chǔ)sql批量創(chuàng)建的信息 object[]
      workSheetsFromBuffer.forEach((element) => {
        element.forEach((item: any) => {
          // 此層是遍歷表數(shù)量(單表數(shù)據(jù)提取)
          const data = item.data
          for (let j = 1; j < data.length; j++) {
            // 此層是加入每行數(shù)據(jù)
            const obj = {
              password: hash
            }
            for (let i = 0; i < data[0].length; i++) {
              let key = excelMap[tableMap][data[0][i]]
              if (excelMap.changDict[key]) {
                obj[key] = excelMap.changDict[key][data[j][i]]
              } else {
                obj[key] = data[j][i]
              }
            }
            arr.push(obj)
          }
        })
      })
      // 獲取數(shù)據(jù)后刪除excel文件
      fileName.forEach((path) => {
        removeSpecifyFile(path)
      })
      ctx.state.excelData = arr
    } catch (error) {
      console.error('用戶(hù)excel上傳表頭格式不正確!', ctx.request['body'])
      return ctx.app.emit('error', importUserListErr, ctx)
    }
    await next()
  }
}

2、寫(xiě)入本次導(dǎo)入的所有excel文件內(nèi)數(shù)據(jù)

updates:是控制你更新哪些的key數(shù)組

 [    'dept_id',    'user_name',    'nick_name',    'email',    'phonenumber',    'sex',    'status'  ]

updates案例 ?

// 導(dǎo)入excel--新增修改sql
export const judegImportMid = (table, updates) => {
  return async (ctx: Context, next: () => Promise<void>) => {
    const { updateSupport } = ctx.query
    try {
      if (updateSupport === '1') {
        // 新增 且 修改
        await table.bulkCreate(ctx.state.excelData, {
          updateOnDuplicate: updates
        })
      } else {
        // 不更改 只新增
        await table.bulkCreate(ctx.state.excelData)
      }
      ctx.body = {
        code: 200,
        message: '用戶(hù)信息上傳成功!'
      }
    } catch (error) {
      console.error('user excel新增與修改錯(cuò)誤', ctx.request['body'])
      return ctx.app.emit('error', { code: '400', message: error.errors[0].message }, ctx)
    }
  }
}

3、導(dǎo)入的案例excel

4、解析后的數(shù)據(jù)

[
  {
    password: '$2a$10$Mp19aHpTTIZXwAYpwAg8QuOUQ6DmBswHFhwR8iRqjduNw9tQU.xRO',
    undefined: 'test',
    user_name: 'test',
    email: 'test',
    phonenumber: 'test',
    sex: '0',
    status: '0'
  }
]

5、已寫(xiě)入數(shù)據(jù)庫(kù)

結(jié)語(yǔ)

上面的功能僅僅是完成了基本的excel導(dǎo)入和導(dǎo)出,更多關(guān)于koa2導(dǎo)入導(dǎo)出Excel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序getPhoneNumber獲取用戶(hù)手機(jī)號(hào)

    微信小程序getPhoneNumber獲取用戶(hù)手機(jī)號(hào)

    這篇文章主要介紹了 微信小程序getPhoneNumber獲取用戶(hù)手機(jī)號(hào)的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • JS輕量級(jí)函數(shù)式編程實(shí)現(xiàn)XDM二

    JS輕量級(jí)函數(shù)式編程實(shí)現(xiàn)XDM二

    這篇文章主要為大家介紹了JS函數(shù)式編程實(shí)現(xiàn)XDM示例詳解第2/3篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 微信小程序 數(shù)組(增,刪,改,查)等操作實(shí)例詳解

    微信小程序 數(shù)組(增,刪,改,查)等操作實(shí)例詳解

    這篇文章主要介紹了微信小程序 數(shù)組(增,刪,改,查)等操作實(shí)例詳解的相關(guān)資料,這里對(duì)小程序的數(shù)組進(jìn)行操作,簡(jiǎn)單實(shí)例,需要的朋友可以參考下
    2017-01-01
  • 淺談js中的宏任務(wù)和微任務(wù)

    淺談js中的宏任務(wù)和微任務(wù)

    這篇文章我們主要談一談js中的宏任務(wù)和微任務(wù),JavaScript是一門(mén)單線程語(yǔ)言,即一次只能完成一個(gè)任務(wù),若有多個(gè)任務(wù)要執(zhí)行,則必須排隊(duì)按照隊(duì)列來(lái)執(zhí)行,下面我們就來(lái)簡(jiǎn)單談?wù)凧avaScript吧,需要的朋友可以參考下面文章內(nèi)容的具體內(nèi)容
    2021-09-09
  • 前端JavaScript中的反射和代理

    前端JavaScript中的反射和代理

    這篇文章主要介紹的是前端JavaScript中的反射和代理,本文主要圍繞JavaScript中的內(nèi)置Reflect、JavaScript中的內(nèi)置Proxy、Proxy實(shí)現(xiàn)觀察者模式三個(gè)話題展開(kāi)文章內(nèi)容,需要的朋友可以參一考下
    2021-10-10
  • Selection與Range 對(duì)象操作示例指南

    Selection與Range 對(duì)象操作示例指南

    這篇文章主要為大家介紹了Selection與Range 對(duì)象操作示例指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 微信小程序左右滑動(dòng)切換頁(yè)面詳解及實(shí)例代碼

    微信小程序左右滑動(dòng)切換頁(yè)面詳解及實(shí)例代碼

    這篇文章主要介紹了微信小程序左右滑動(dòng)切換頁(yè)面詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Wireshark基本介紹和學(xué)習(xí)TCP三次握手

    Wireshark基本介紹和學(xué)習(xí)TCP三次握手

    本文主要介紹Wireshark基本介紹和學(xué)習(xí)TCP三次握手,這里詳細(xì)整理了相關(guān)資料,并給出詳細(xì)流程,有需要的小伙伴可以參考下
    2016-08-08
  • 淺談TypeScript 索引簽名的理解

    淺談TypeScript 索引簽名的理解

    這篇文章主要給大家分享的是TypeScript 索引簽名的理解,索引簽名由方括號(hào)中的索引名稱(chēng)及其類(lèi)型組成,后面是冒號(hào)和值類(lèi)型:{ [indexName: KeyType]: ValueType }, KeyType 可以是一個(gè) string、number 或 symbol,而ValueType 可以是任何類(lèi)型,下面就倆簡(jiǎn)單了解一下吧
    2021-10-10
  • Three.js實(shí)現(xiàn)雪糕地球的使用示例詳解

    Three.js實(shí)現(xiàn)雪糕地球的使用示例詳解

    這篇文章主要為大家介紹了Three.js實(shí)現(xiàn)雪糕地球的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07

最新評(píng)論

永年县| 遂昌县| 德江县| 班戈县| 舟山市| 长岛县| 临澧县| 中方县| 新乐市| 汉寿县| 黎川县| 平阳县| 安新县| 宜兰县| 阿拉善左旗| 大城县| 吴忠市| 道孚县| 大洼县| 元谋县| 青神县| 南丰县| 新建县| 额济纳旗| 葵青区| 万载县| 扎囊县| 峡江县| 盈江县| 闻喜县| 尉氏县| 延寿县| 井冈山市| 平安县| 绿春县| 昌吉市| 岳阳县| 惠来县| 金湖县| 黎平县| 盐源县|