Skip to content

Commit

Permalink
feat: 支持导出群成员列表头像
Browse files Browse the repository at this point in the history
  • Loading branch information
yzqzy committed May 17, 2024
1 parent ce664f7 commit f2c58a5
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 53 deletions.
26 changes: 4 additions & 22 deletions src/composables/useExport.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,6 @@
import { downloadXlsx, downloadPdf } from '@/utils/export'

interface ExportProps<T> {
title: string
columns: Record<string, string>
data: T
}

export const useExport = () => {
const exportXlsx = async (props: ExportProps<any>) => {
const { title, columns, data } = props
await downloadXlsx(title, columns, data)
}

const exportPdf = async (props: ExportProps<any>) => {
const { title, columns, data } = props
await downloadPdf(title, columns, data)
}

return {
exportXlsx,
exportPdf
}
}
export const useExport = () => ({
exportXlsx: downloadXlsx,
exportPdf: downloadPdf
})
144 changes: 115 additions & 29 deletions src/utils/export.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import exceljs from 'exceljs'
import axios from 'axios'

export const addDateSuffixToFileName = (fileName: string, ext: string) => {
const currentDate = new Date()
Expand All @@ -19,53 +20,138 @@ const frontend_download = (fileName: string, buffer: any) => {
window.URL.revokeObjectURL(href)
}

const insert_image_to_xlsx = (options: any) => {
const { workbook, worksheet, item, index } = options

if (!Array.isArray(item)) return item

item.forEach((value, idx) => {
if (typeof value === 'string' && value.startsWith('data:image/')) {
item[idx] = ''

const imageId = workbook.addImage({
base64: value.replace('data:image/png;base64,', ''),
extension: 'png'
})

worksheet.addImage(imageId, {
tl: { col: idx + 0.5, row: index },
ext: { width: 80, height: 80 },
editAs: 'oneCell'
})
}
})

return item
}

const create_xlsx_data = (options: any) => {
const { list, workbook, worksheet, hasPic } = options

return new Promise((resolve, reject) => {
list.forEach((item: any, index: number) => {
insert_image_to_xlsx({
workbook,
worksheet,
item,
index
})

const row = worksheet.addRow(item)

row.height = hasPic ? 60 : 20

const fontHeight = 12
const cellHeight = row.height || worksheet.properties.defaultRowHeight
const verticalOffset = (cellHeight - fontHeight) / 2
row.alignment = { vertical: 'middle', verticalOffset }

row.commit()
})

resolve(null)
})
}

const create_xlsx_Buffer = async (config: any) => {
const { headers, list } = config
const { headers, list, hasPic } = config
const workbook = new exceljs.Workbook()
const worksheet = workbook.addWorksheet('Sheet1')

worksheet.columns = headers
list.forEach((item: any) => worksheet.addRow(item).commit())
worksheet.properties.defaultColWidth = 20

await create_xlsx_data({ list, workbook, worksheet, hasPic })

const buffer = await workbook.xlsx.writeBuffer()
return buffer
}

const normalizedContent = (columns: Record<string, string>, item: any) => {
return Object.keys(columns).reduce((pre, key) => {
const fields = key.split('.')
pre[key] = fields.reduce((pre, field) => pre[field], item)
return pre
}, {} as any)
const remoteFileToBase64 = async (url: string) => {
return await axios.get(url, { responseType: 'arraybuffer' }).then(res => {
const base64 = btoa(
new Uint8Array(res.data).reduce(
(data, byte) => data + String.fromCharCode(byte),
''
)
)
return `data:image/png;base64,${base64}`
})
}

const normalizedConfig = (columns: Record<string, string>, data: any) => {
const columnsKeys = Object.keys(columns)
const headers = columnsKeys.map(key => ({ key, header: columns[key] }))
const list = data.map((item: any) => normalizedContent(columns, item))
return { headers, list }
const normalizedContent = async (
columns: Record<string, string>,
item: any,
imageFields: string[]
) => {
const keys = Object.keys(columns)
const data = []

for (const key of keys) {
const fields = key.split('.')
const value = fields.reduce((pre, field) => pre[field], item)

if (imageFields.includes(key)) {
item[key] = await remoteFileToBase64(value)
} else {
item[key] = value
}

data.push(item[key])
}

return data
}

export const downloadXlsx = async (
fileName: string,
const normalizedConfig = async (
columns: Record<string, string>,
data: any
data: any[],
imageFields: string[]
) => {
const filename = addDateSuffixToFileName(fileName, 'xlsx')
const config = normalizedConfig(columns, data)
const buffer = await create_xlsx_Buffer(config)
frontend_download(filename, buffer)
const columnsKeys = Object.keys(columns)
const headers = columnsKeys.map(key => ({ key, header: columns[key] }))
const hasPic = imageFields.length > 0
const list = await Promise.all(
data.map((item: any) => normalizedContent(columns, item, imageFields))
)
return { headers, list, hasPic }
}

const create_pdf = async (buffer: any) => {
// TODO: Implement PDF export
export interface ExportProps<T> {
title: string
columns: Record<string, string>
data: T
imageFields?: string[]
}

export const downloadPdf = async (
fileName: string,
columns: Record<string, string>,
data: any
) => {
const filename = addDateSuffixToFileName(fileName, 'pdf')
const config = normalizedConfig(columns, data)
export const downloadXlsx = async (props: ExportProps<any>) => {
const { title, columns, data, imageFields = [] } = props
const filename = addDateSuffixToFileName(title, 'xlsx')
const config = await normalizedConfig(columns, data, imageFields)
const buffer = await create_xlsx_Buffer(config)
frontend_download(filename, buffer)
}

export const downloadPdf = async (props: ExportProps<any>) => {
// TODO: Implement PDF export
}
6 changes: 4 additions & 2 deletions src/views/chatroom/ChatRoomTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ const handleExportXlsx = async () => {
columns: {
wxid: 'ID',
nickname: '昵称',
account: '微信号'
account: '微信号',
headImage: '头像'
},
data: filterData.value
imageFields: ['headImage'],
data: filterData.value,
})
}
</script>
Expand Down

0 comments on commit f2c58a5

Please sign in to comment.