fastlion-amis
Version:
一种MIS页面生成工具
800 lines (735 loc) • 39.7 kB
text/typescript
import { decode } from "js-base64"
import { PrinterParam, TableColumn, ColumnInfo, SettingValues, OptionValues, IFPTableValue, DetailOptionValues } from "../../renderers/Lion/LabelPrint/types"
import {
FormTemplate, LabelNumber, LabelTemplate, LabelPageParam, LabelCodeType, LabelPrintStyleParam,
LabelText, LabelBarCode, LabelEllipse, LabelHtml, LabelLine, LabelRect, LabelShape, LabelTable, LabelImage, Rect, DetailTemplate, CodeRect, TitleRect
} from "./type"
import moment from 'moment'
import { calcFn, sortFn } from "../utils"
import { getCellValue } from "../../store/utils/commonTableFunction"
import { flatMap } from "lodash"
type ColumnDataType = IFPTableValue
type TemplateSetting = Pick<SettingValues, 'width' | 'height' | 'direction' | 'left' | 'right' | 'bottom' | 'top'>
export const buildDetailTemplate = (settings: TemplateSetting, options: DetailOptionValues & { subTitle?: string, extraTitle: string, codeValue?: string, codeLabel?: string }): DetailTemplate => {
const userInfo = sessionStorage.getItem('userInfo') ?? '{}'
const userObj = userInfo && JSON.parse(userInfo)
const { width, height, direction, top: defaultTop, bottom: defaultBottom, left: defaultLeft, right: defaultRight } = settings
const { showLogo, title, showTitle, showDynamicSubTitles, dynamicSubTiltes, showPrinter, showDate, subTitle, extraTitle, showPageNum, showBarCode, showQRCode, codeLabel, codeValue } = options
const pageWidth = direction == 'vertical' ? width : height
const pageHeight = direction == 'vertical' ? height : width
const headerHeight = 15
const codeWidth = (showBarCode || showQRCode) ? showBarCode ? 60 : 25 : 0
const codeHeight = (showBarCode || showQRCode) ? showBarCode ? 15 : 25 : 0
const titleHeight = showTitle ? 5 : 0
const titleMarginTop = 3
const subTitleHeight = showDynamicSubTitles ? 6 : 0
const subTitleMarginTop = showDynamicSubTitles ? 3 : 0
const subTitleCount = dynamicSubTiltes.length
const htmlMarginTop = 3
const htmlMarginBottom = 8
const footerHeight = 4
const pageNumWidth = 12
const rect: Rect = { top: defaultTop, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: pageHeight - defaultTop - defaultBottom }
const headerRect: Rect = { top: rect.top, left: rect.left, width: rect.width, height: headerHeight }
const logoRect: Rect = { top: headerRect.top, left: headerRect.left, width: showLogo ? headerRect.height : 0, height: showLogo ? headerRect.height : 0, content: showLogo ? `<img src="./public/images/sanfu.png"/>` : '' }
const codeRect: CodeRect = { top: headerRect.top, left: headerRect.width + headerRect.left - codeWidth, width: codeWidth, height: codeHeight, label: '', codeType: showQRCode ? 'QRCode' : 'code39', content: (showBarCode || showQRCode) ? codeValue : undefined }
const codeLabelRect: Rect = { top: codeRect.top + codeRect.height + 1, left: codeRect.left, width: codeRect.width + 5, height: 10, content: `${codeLabel}:${codeValue}` }
const extraTitleRect: Rect = { top: headerRect.top, left: headerRect.left + logoRect.width, width: headerRect.width - logoRect.width, height: headerRect.height, content: extraTitle }
const titleRect: Rect = { top: headerRect.top + headerRect.height + titleMarginTop, left: rect.left, width: rect.width, height: titleHeight, content: showTitle ? title + (subTitle ? `[${subTitle}]` : '') : '' }
const subTitleRect: Rect = { top: titleRect.top + titleRect.height + subTitleMarginTop, left: defaultLeft, width: rect.width, height: subTitleHeight }
const subTitleRect1: Rect = { top: subTitleRect.top, left: subTitleRect.left, width: subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showDynamicSubTitles ? dynamicSubTiltes[0] : undefined }
const subTitleRect2: Rect = { top: subTitleRect.top, left: subTitleCount <= 1 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount), width: subTitleCount <= 1 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showDynamicSubTitles ? dynamicSubTiltes[1] : undefined }
const subTitleRect3: Rect = { top: subTitleRect.top, left: subTitleCount <= 2 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount * (subTitleCount - 1)), width: subTitleCount <= 2 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showDynamicSubTitles ? dynamicSubTiltes[2] : undefined }
const footerRect: Rect = { top: rect.height + defaultTop - footerHeight, left: rect.left, width: rect.width, height: footerHeight }
const printerRect: Rect = { top: footerRect.top, left: rect.left, width: footerRect.width * 0.3, height: showPrinter ? footerRect.height : 0, content: showPrinter ? `打印者:${userObj.user_name ?? ''}` : '' }
const dateRect: Rect = { top: footerRect.top, left: footerRect.left + printerRect.width, width: footerRect.width * 0.4, height: showDate ? footerRect.height : 0, content: showDate ? `打印时间:${moment(new Date()).format('YYYY-MM-DD HH:mm:ss')}` : '' }
const numRect: Rect = { top: footerRect.top, left: footerRect.left + printerRect.width + dateRect.width + (footerRect.width * 0.3 - pageNumWidth * 2) - 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '第#页' : '' }
const sumRect: Rect = { top: footerRect.top, left: numRect.left + numRect.width + 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '共#页' : '' }
const htmlRect: Rect = {
top: subTitleRect.top + subTitleRect.height + htmlMarginTop,
left: rect.left,
width: rect.width,
height: footerRect.top - (subTitleRect.top + subTitleRect.height + htmlMarginTop) - htmlMarginBottom
}
return {
header: headerRect, logo: logoRect, code: codeRect, codeLabel: codeLabelRect, extraTitle: extraTitleRect, title: titleRect,
subTitle: subTitleRect, subTitle1: subTitleRect1, subTitle2: subTitleRect2, subTitle3: subTitleRect3,
html: htmlRect, date: dateRect, printer: printerRect, footer: footerRect, num: numRect, sum: sumRect
}
}
export const buildFormTemplate = (settings: TemplateSetting, options: OptionValues): FormTemplate => {
const userInfo = sessionStorage.getItem('userInfo') ?? '{}'
const userObj = userInfo && JSON.parse(userInfo)
const { width, height, direction, top: defaultTop, bottom: defaultBottom, left: defaultLeft, right: defaultRight } = settings
const { showHeaderTitle, headerTitle, showHeaderLine, showLogo, showTitle, titleAllPrint, title, showSubTitle, subTitleAllPrint, subTitle = [], showFooterLine, showFooterTitle, footerTitle, showPrinter, showDate, showPageNum } = options
const pageWidth = direction == 'vertical' ? width : height
const pageHeight = direction == 'vertical' ? height : width
const headerHeight = (showLogo || showHeaderTitle || showHeaderLine) ? 18 : 0
const footerHeight = 5
const titleHeight = 3.4
const subTitleHeight = showSubTitle ? 6 : 0
const subTitleMarginTop = showSubTitle ? 3 : 0
const subTitleCount = subTitle.length
const pageNumWidth = 12
const lineHeight = 0.3
const headerRect: Rect = { top: defaultTop, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: headerHeight }
const headerLineRect = { top: headerRect.top + headerRect.height + 2, left: headerRect.left, width: headerRect.width, height: showHeaderLine ? lineHeight : 0 }
const logoRect: Rect = { top: headerRect.top, left: headerRect.left, width: showLogo ? headerRect.height : 0, height: showLogo ? headerRect.height : 0, content: showLogo ? `<img src="./public/images/sanfu.png"/>` : '' }
const headerTitleRect: Rect = { top: headerRect.top + (headerRect.height / 2 - 2), left: headerRect.left + logoRect.width + 5, width: headerRect.width - logoRect.width - 5, height: titleHeight, content: showHeaderTitle ? headerTitle : '' }
const footerRect: Rect = { top: pageHeight - defaultBottom - footerHeight, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: footerHeight }
const footerTitleRect: Rect = { top: footerRect.top - footerHeight, left: footerRect.left, width: footerRect.width, height: showFooterTitle ? footerHeight : 0, content: showFooterTitle ? footerTitle : '' }
const footerLineRect: Rect = { top: footerRect.top, left: footerRect.left, width: footerRect.width, height: showFooterLine ? lineHeight : 0 }
const printerRect: Rect = { top: footerRect.top + 2, left: footerRect.left, width: footerRect.width * 0.3, height: footerRect.height, content: showPrinter ? `打印者:${userObj.user_name ?? ''}` : '' }
const dateRect: Rect = { top: footerRect.top + 2, left: footerRect.left + printerRect.width, width: footerRect.width * 0.4, height: footerRect.height, content: showDate ? `打印时间:${moment(new Date()).format('YYYY-MM-DD HH:mm:ss')}` : '' }
const numRect: Rect = { top: footerRect.top + 2, left: footerRect.left + printerRect.width + dateRect.width + (footerRect.width * 0.3 - pageNumWidth * 2) - 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '第#页' : '' }
const sumRect: Rect = { top: footerRect.top + 2, left: numRect.left + numRect.width + 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '共#页' : '' }
const bodyRect: Rect = { top: 5 + headerRect.top + headerRect.height, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: pageHeight - (headerRect.top + headerRect.height + 3) - (footerRect.height + defaultBottom + 3) - (showFooterTitle ? footerHeight : 0) }
const titleRect: TitleRect = { top: bodyRect.top, left: bodyRect.left, width: bodyRect.width, height: titleHeight, content: showTitle ? title : '', itemType: titleAllPrint ? 1 : 0 }
const subTitleRect: Rect = { top: titleRect.top + titleRect.height + subTitleMarginTop, left: bodyRect.left, width: bodyRect.width, height: subTitleHeight }
const subTitleRect1: TitleRect = { top: subTitleRect.top, left: subTitleRect.left, width: subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showSubTitle ? subTitle[0] : undefined, itemType: subTitleAllPrint ? 1 : 0 }
const subTitleRect2: TitleRect = { top: subTitleRect.top, left: subTitleCount <= 1 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount), width: subTitleCount <= 1 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showSubTitle ? subTitle[1] : undefined, itemType: subTitleAllPrint ? 1 : 0 }
const subTitleRect3: TitleRect = { top: subTitleRect.top, left: subTitleCount <= 2 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount * (subTitleCount - 1)), width: subTitleCount <= 2 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showSubTitle ? subTitle[2] : undefined, itemType: subTitleAllPrint ? 1 : 0 }
const tableRect: Rect = { top: subTitleRect.top + subTitleRect.height + 3, left: bodyRect.left, width: bodyRect.width, height: bodyRect.height - titleRect.height - subTitleRect.height - subTitleMarginTop - 9 }
return {
header: headerRect, logo: logoRect, headerLine: headerLineRect, headerTitle: headerTitleRect,
body: bodyRect, title: titleRect, subTitle: subTitleRect, subTitle1: subTitleRect1, subTitle2: subTitleRect2, subTitle3: subTitleRect3,
table: tableRect,
footer: footerRect, footerLine: footerLineRect, footerTitle: footerTitleRect,
printer: printerRect, date: dateRect, num: numRect, sum: sumRect
}
}
// 计算每行放的个最大数
export const getMaxCount = (templateWidth: number, pageWidth: number, spacing: number): number => {
let count = 1
while ((count * templateWidth + (count - 1) * spacing) <= pageWidth) {
count++
if (count > 50) {
break
}
}
return (count - 1) || 1
}
// 解析base64内容构造标签模板
export const buildLabelTemplate = (templateContent: string): LabelTemplate => {
const getParams = (dataStr: string): string[] => {
const start = dataStr.indexOf('(') + 1
const end = dataStr.lastIndexOf(')')
const str = dataStr.substring(start, end)
const params = str.split(',')
return params.map(value => {
const left = value.startsWith('"') ? value.substring(1) : value
const right = left.endsWith('"') ? left.substring(0, left.length - 1) : left
return right.replaceAll('\\"', '"').replaceAll('\\r', '').replaceAll('\\n', '')
})
}
const getStyleParams = (dataStr: string): LabelPrintStyleParam => {
const isNumber = (value: string): boolean => {
return /^[0-9]+.?[0-9]*/.test(value)
}
const params = getParams(dataStr)
const id = isNumber(params[0]) ? Number(params[0]) : params[0]
const name = params[1]
const value = isNumber(params[2]) ? Number(params[2]) : params[2]
return [id, name, value]
}
const labelTemplate: LabelTemplate = {
tempTop: new LabelNumber(0, 297),
tempLeft: new LabelNumber(0, 210),
tempWidth: new LabelNumber(0, 210),
tempHeight: new LabelNumber(0, 297),
labelTexts: [],
labelHtmls: [],
labelImages: [],
labelTables: [],
labelBarCodes: [],
labelRects: [],
labelEllipses: [],
labelShapes: [],
labelLines: []
}
const value = decode(templateContent)
const tempDatas = value.split('LODOP')
const exprs = [LabelCodeType.ADD_RECT, LabelCodeType.ADD_ELLIPSE, LabelCodeType.ADD_LINE]
const initData = tempDatas.find(data => data.includes(LabelCodeType.INITA))!
const initParams = getParams(initData)
const tempWidth = new LabelNumber(initParams[2])
const tempHeight = new LabelNumber(initParams[3])
labelTemplate.tempTop = new LabelNumber(initParams[0])
labelTemplate.tempLeft = new LabelNumber(initParams[1])
labelTemplate.tempWidth = tempWidth
labelTemplate.tempHeight = tempHeight
for (let i = 0; i < tempDatas.length; i++) {
const data = tempDatas[i]
let j = i + 1
const params = getParams(data)
// 添加文本
if (data.includes(LabelCodeType.ADD_TEXT)) {
const styles: LabelPrintStyleParam[] = []
while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
const param = getStyleParams(tempDatas[j])
styles.push(param)
j++
}
const labelText: LabelText = data.includes(LabelCodeType.ADD_TEXTA) ? {
fieldName: params[0],
top: new LabelNumber(params[1], tempHeight.number),
left: new LabelNumber(params[2], tempWidth.number),
width: new LabelNumber(params[3], tempWidth.number),
height: new LabelNumber(params[4], tempHeight.number),
content: params[5],
styles
} : {
top: new LabelNumber(params[0], tempHeight.number),
left: new LabelNumber(params[1], tempWidth.number),
width: new LabelNumber(params[2], tempWidth.number),
height: new LabelNumber(params[3], tempHeight.number),
content: params[4],
styles
}
labelTemplate.labelTexts.push(labelText)
}
// 添加富文本和图片
if (data.includes(LabelCodeType.ADD_HTML)) {
const styles: LabelPrintStyleParam[] = []
while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
const param = getStyleParams(tempDatas[j])
styles.push(param)
j++
}
const fieldName = styles.find(([_id, name]) => name === 'ItemName')?.[2] as string | undefined
const labelHtml: LabelHtml = {
top: new LabelNumber(params[0], tempHeight.number),
left: new LabelNumber(params[1], tempWidth.number),
width: new LabelNumber(params[2], tempWidth.number),
height: new LabelNumber(params[3], tempHeight.number),
content: params[4],
fieldName,
styles
}
labelTemplate.labelHtmls.push(labelHtml)
}
// 添加图片
if (data.includes(LabelCodeType.ADD_IMAGE)) {
const styles: LabelPrintStyleParam[] = []
while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
const param = getStyleParams(tempDatas[j])
styles.push(param)
j++
}
const fieldName = styles.find(([_id, name]) => name === 'ItemName')?.[2] as string | undefined
const labelImage: LabelImage = {
top: new LabelNumber(params[0], tempHeight.number),
left: new LabelNumber(params[1], tempWidth.number),
width: new LabelNumber(params[2], tempWidth.number),
height: new LabelNumber(params[3], tempHeight.number),
url: params.slice(4).join(),
fieldName,
styles
}
labelTemplate.labelImages.push(labelImage)
}
// 添加表格
if (data.includes(LabelCodeType.ADD_TABLE)) {
const styles: LabelPrintStyleParam[] = []
while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
const param = getStyleParams(tempDatas[j])
styles.push(param)
j++
}
const fieldName = styles.find(([_id, name]) => name === 'ItemName')?.[2] as string | undefined
const labelTable: LabelTable = {
top: new LabelNumber(params[0], tempHeight.number),
left: new LabelNumber(params[1], tempWidth.number),
width: new LabelNumber(params[2], tempWidth.number),
height: new LabelNumber(params[3], tempHeight.number),
content: params.slice(4).join(),
fieldName,
styles
}
labelTemplate.labelTables.push(labelTable)
}
// 添加条码
if (data.includes(LabelCodeType.ADD_BARCODE)) {
const styles: LabelPrintStyleParam[] = []
while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
const param = getStyleParams(tempDatas[j])
styles.push(param)
j++
}
const labelBarCode: LabelBarCode = data.includes(LabelCodeType.ADD_BARCODEA) ? {
fieldName: params[0],
top: new LabelNumber(params[1], tempHeight.number),
left: new LabelNumber(params[2], tempWidth.number),
width: new LabelNumber(params[3], tempWidth.number),
height: new LabelNumber(params[4], tempHeight.number),
codeType: params[5],
codeValue: params[6],
styles
} : {
top: new LabelNumber(params[0], tempHeight.number),
left: new LabelNumber(params[1], tempWidth.number),
width: new LabelNumber(params[2], tempWidth.number),
height: new LabelNumber(params[3], tempHeight.number),
codeType: params[4],
codeValue: params[5],
styles
}
labelTemplate.labelBarCodes.push(labelBarCode)
}
// 添加其它图形
if (data.includes(LabelCodeType.ADD_SHAPE)) {
const labelShape: LabelShape = {
shapeType: Number(params[0]),
top: new LabelNumber(params[1], tempHeight.number),
left: new LabelNumber(params[2], tempWidth.number),
width: new LabelNumber(params[3], tempWidth.number),
height: new LabelNumber(params[4], tempHeight.number),
lineStyle: Number(params[5]),
lineWidth: Number(params[6]),
fillColor: params[7]
}
labelTemplate.labelShapes.push(labelShape)
}
// 添加图形
const expr = exprs.find(expr => data.includes(expr))
if (expr) {
const label: LabelLine = {
top: new LabelNumber(params[0], tempHeight.number),
left: new LabelNumber(params[1], tempWidth.number),
width: new LabelNumber(params[2], tempWidth.number),
height: new LabelNumber(params[3], tempHeight.number),
lineStyle: Number(params[4]),
lineWidth: Number(params[5])
}
switch (expr) {
case LabelCodeType.ADD_RECT:
labelTemplate.labelRects.push(label)
break
case LabelCodeType.ADD_ELLIPSE:
labelTemplate.labelEllipses.push(label)
break
case LabelCodeType.ADD_LINE:
labelTemplate.labelLines.push(label)
break
default: break
}
}
}
return labelTemplate
}
// 设置模板内标签的数据,一页放一个模板
export const setLabelTemplateData = (labelTemplate: LabelTemplate, printData: any[], baseUrl?: string, tableColumn?: TableColumn): LabelTemplate[][] => {
const { labelTexts, labelHtmls, labelImages, labelBarCodes, labelTables } = labelTemplate
const labelDatas: LabelTemplate[][] = []
for (let i = 0; i < printData.length; i++) {
const tempTexts: LabelText[] = []
const tempHtmls: LabelHtml[] = []
const tempImages: LabelImage[] = []
const tempTables: LabelTable[] = []
const tempBarCodes: LabelBarCode[] = []
const labelData = printData[i]
const fields = Object.keys(labelData)
labelTexts.forEach(text => {
let content = text.content
const field = fields.find(field => field === text.fieldName)
if (field) {
const data = labelData[field]
if (data) {
if (content.includes(`[${field}]`)) {
content = content.replaceAll(`[${field}]`, data)
} else {
content = data
}
}
}
tempTexts.push({ ...text, content })
})
labelHtmls.forEach(html => {
let content = html.content
const field = fields.find(field => field === html.fieldName)
if (field) {
const data = labelData[field]
if (data) {
const info = data.info
if (info) {
const url = baseUrl ? (baseUrl + info[0].addr) : info[0].addr
content = `<img style="width:100%" src=${url} alt="" />`
} else if (typeof data === 'string') {
content = data.replaceAll('text-decoration-line', 'text-decoration')
} else {
content = data
}
}
}
tempHtmls.push({ ...html, content })
})
labelImages.forEach(image => {
let url = image.url
const field = fields.find(field => field === image.fieldName)
if (field) {
const data = labelData[field]
if (data) {
url = `<img style="width:100%" src=${data} alt="" />`
}
}
tempImages.push({ ...image, url })
})
labelTables.forEach(table => {
let content = table.content
const field = fields.find(field => field === table.fieldName)
if (field) {
const data = labelData[field]
if (typeof data !== 'string' && tableColumn) {
content = buildTableData(tableColumn[field], data)
}
}
tempTables.push({ ...table, content })
})
labelBarCodes.forEach(barCode => {
let codeValue = barCode.codeValue
const field = fields.find(field => field === barCode.fieldName)
if (field) {
const data = labelData[field]
if (data) {
codeValue = data
}
}
tempBarCodes.push({ ...barCode, codeValue })
})
labelDatas.push([
{
...labelTemplate,
labelTexts: tempTexts,
labelHtmls: tempHtmls,
labelTables: tempTables,
labelBarCodes: tempBarCodes,
}
])
}
return labelDatas
}
// 设置模板内标签的数据,一页放多个模板
export const setLabelTemplateDataWithArrange = (labelTemplate: LabelTemplate, printData: any[], printerParam: PrinterParam, countOfPage: number, countOfColumn: number, baseUrl?: string): LabelTemplate[][] => {
const labelCount = printData.length
const { tempWidth, tempHeight, labelTexts, labelHtmls, labelImages, labelBarCodes, labelRects, labelEllipses, labelLines, labelShapes } = labelTemplate
const { colSpacing, rowSpacing } = printerParam
const pageParams: LabelPageParam[] = []
for (let i = 0; i < labelCount; i++) {
const labelData = printData[i]
const tempTexts: LabelText[] = []
const tempHtmls: LabelHtml[] = []
const tempImages: LabelImage[] = []
const tempBarCodes: LabelBarCode[] = []
const tempShapes: LabelShape[] = []
const tempRects: LabelRect[] = []
const tempEllipses: LabelEllipse[] = []
const tempLines: LabelLine[] = []
const pageIndex = Math.floor(i / countOfPage)
const column = i % countOfColumn
const row = Math.floor(i % countOfPage / countOfColumn)
const left = tempWidth.number * column + column * colSpacing
const top = tempHeight.number * row + row * rowSpacing
const fields = Object.keys(labelData)
labelTexts.forEach(text => {
let content = text.content
const field = fields.find(field => field === text.fieldName)
if (field) {
const data = labelData[field]
if (data) {
if (content.includes(`[${field}]`)) {
content = content.replaceAll(`[${field}]`, data)
} else {
content = data
}
}
}
const textLeft = new LabelNumber(left + text.left.number)
const textTop = new LabelNumber(top + text.top.number)
tempTexts.push({ ...text, content, left: textLeft, top: textTop })
})
labelHtmls.forEach(html => {
let content = html.content
const field = fields.find(field => field === html.fieldName)
if (field) {
const data = labelData[field]
if (data) {
const info = data.info
if (info) {
const url = baseUrl ? (baseUrl + info[0].addr) : info[0].addr
content = `<img style="width:100%" src=${url} alt="" />`
} else if (typeof data === 'string') {
content = data.replaceAll('text-decoration-line', 'text-decoration')
} else {
content = data
}
}
}
const htmlLeft = new LabelNumber(left + html.left.number)
const htmlTop = new LabelNumber(top + html.top.number)
tempHtmls.push({ ...html, content, left: htmlLeft, top: htmlTop })
})
labelImages.forEach(image => {
let url = image.url
const field = fields.find(field => field === image.fieldName)
if (field) {
const data = labelData[field]
if (url) {
url = `<img style="width:100%" src=${data} alt="" />`
}
}
const imageLeft = new LabelNumber(left + image.left.number)
const imageTop = new LabelNumber(top + image.top.number)
tempImages.push({ ...image, url, left: imageLeft, top: imageTop })
})
labelBarCodes.forEach(barCode => {
let codeValue = barCode.codeValue
const field = fields.find(field => field === barCode.fieldName)
if (field) {
const data = labelData[field]
if (data) {
codeValue = data
}
}
const barCodeLeft = new LabelNumber(left + barCode.left.number)
const barCodeTop = new LabelNumber(top + barCode.top.number)
tempBarCodes.push({ ...barCode, codeValue, left: barCodeLeft, top: barCodeTop })
})
labelShapes.forEach(shape => {
const shapeLeft = new LabelNumber(left + shape.left.number)
const shapeTop = new LabelNumber(top + shape.top.number)
tempShapes.push({ ...shape, left: shapeLeft, top: shapeTop })
})
labelEllipses.forEach(ellipse => {
const ellipseLeft = new LabelNumber(left + ellipse.left.number)
const ellipseTop = new LabelNumber(top + ellipse.top.number)
tempEllipses.push({ ...ellipse, left: ellipseLeft, top: ellipseTop })
})
labelRects.forEach(rect => {
const rectLeft = new LabelNumber(left + rect.left.number)
const rectTop = new LabelNumber(top + rect.top.number)
tempRects.push({ ...rect, left: rectLeft, top: rectTop })
})
labelLines.forEach(line => {
const lineLeft = new LabelNumber(left + line.left.number)
const lineTop = new LabelNumber(top + line.top.number)
tempLines.push({ ...line, left: lineLeft, top: lineTop })
})
pageParams.push([pageIndex, {
...labelTemplate,
tempTop: new LabelNumber(top),
tempLeft: new LabelNumber(left),
labelTexts: tempTexts,
labelHtmls: tempHtmls,
labelBarCodes: tempBarCodes,
labelShapes: tempShapes,
labelEllipses: tempEllipses,
labelRects: tempRects,
labelLines: tempLines
}])
}
const pageIndexs = Array.from(new Set(pageParams.map(rect => rect[0])))
const labelDatas: LabelTemplate[][] = []
for (let i = 0; i < pageIndexs.length; i++) {
const pageIndex = pageIndexs[i]
const tempDatas: LabelTemplate[] = []
for (let j = 0; j < pageParams.length; j++) {
const pageParam = pageParams[j];
const pageTemplate = pageParam[1]
if (pageParam[0] === pageIndex) {
tempDatas.push(pageTemplate)
}
}
labelDatas.push(tempDatas)
}
return labelDatas
}
const buildTableData = (columnInfo: ColumnInfo, rowDatas: any[]) => {
const { columns, statistics } = columnInfo
columns.forEach(column => {
const stastic = statistics?.find(stastic => stastic.field === column.name)
column.statistics = stastic?.property
})
const div = document.createElement('div')
const table = document.createElement('table')
table.setAttribute('border', '1')
table.setAttribute('cellSpacing', '0')
table.setAttribute('width', '100%')
table.setAttribute('style', 'border-collapse:collapse')
table.setAttribute('bordercolor', '#333333')
const thead = document.createElement('thead')
const tr = document.createElement('tr')
for (let i = 0; i < columns.length; i++) {
const th = document.createElement('th')
const column = columns[i]
th.textContent = column.label
tr.appendChild(th)
}
thead.appendChild(tr)
table.appendChild(thead)
const tbody = document.createElement('tbody')
for (let i = 0; i < rowDatas.length; i++) {
const row = rowDatas[i]
const tr = document.createElement('tr')
for (let j = 0; j < columns.length; j++) {
const td = document.createElement('td')
const column = columns[j]
td.textContent = row[column.name]
tr.appendChild(td)
}
tbody.appendChild(tr)
}
table.appendChild(tbody)
if (statistics) {
const tfoot = document.createElement('tfoot')
const maxRow = statistics.map(item => item.property.length).sort((a, b) => b - a)?.[0] ?? 0
for (let i = 0; i < maxRow; i++) {
const tr = document.createElement('tr')
for (let j = 0; j < columns.length; j++) {
const column = columns[j]
const statistic = column.statistics?.[i]
const td = document.createElement('td')
if (statistic) {
td.textContent = statistic.label
td.setAttribute('format', statistic.format)
td.setAttribute('tdata', statistic.tdata)
}
tr.appendChild(td)
}
tfoot.appendChild(tr)
}
table.appendChild(tfoot)
}
div.appendChild(table)
return div.innerHTML
}
export const buildTableHtml = (tableStyle: OptionValues & { tableWidth: number }, tableColumns: ColumnDataType[], tableHeadRows: any[], tableData: any[], range: [number, number], isLastTask: boolean) => {
const [start, end] = range
const showColumns = tableColumns.filter(column => column.printType != 'none' && column.width != 0 && column.width != undefined)
let width = 0
let idx = showColumns.length
for (let i = 0; i < showColumns.length; i++) {
const column = showColumns[i]
width += column.width!
if (width > tableStyle.tableWidth) {
idx = i
break
}
}
const columns = showColumns.slice(0, idx)
const hasStatistic = columns.some(column => column.statistic != 'none')
const wrap = document.createElement('div')
const div = document.createElement('div')
div.setAttribute('style', `text-align: center; overflow: hidden`)
const table = document.createElement('table')
table.setAttribute('border', tableStyle.lineWidth.toString())
table.setAttribute('cellSpacing', '0')
table.setAttribute('style', `font-size: 13px; width: ${width}px; border-collapse:collapse; margin: 0 auto; border: ${tableStyle.borderWidth}px solid; table-layout: fixed;`)
table.setAttribute('bordercolor', '#333333')
const colgroup = document.createElement('colgroup')
columns.forEach(column => {
const col = document.createElement('col')
if (column.width) {
col.style.setProperty('width', `${column.width * 3.78}px`)
}
colgroup.appendChild(col)
})
table.appendChild(colgroup)
const thead = document.createElement('thead')
thead.setAttribute('style', 'display: table-header-group')
for (let i = 0; i < tableHeadRows.length; i++) {
const headRow = tableHeadRows[i]
const tr = document.createElement('tr')
headRow.forEach((item: any) => {
const temp = item.rowspan == tableHeadRows.length - i
const th = document.createElement('th')
th.textContent = temp ? item.column.label : item.label
th.setAttribute('colspan', item.colspan.toString())
th.setAttribute('rowspan', item.rowspan.toString())
tr.appendChild(th)
})
thead.appendChild(tr)
}
table.appendChild(thead)
const sortColumnNames = flatMap(columns ?? [], column => column.sort != 'none' ? { name: column.name, func: column.sort } : [])
const tbody = document.createElement('tbody')
const data = sortArray(tableData.slice(start, end), sortColumnNames)
for (let i = 0; i < data.length; i++) {
const row = data[i]
const tr = document.createElement('tr')
for (let j = 0; j < columns.length; j++) {
const td = document.createElement('td')
const column = columns[j]
const value = getCellValue(row[column.name], column)
td.textContent = value
td.setAttribute('style', `white-space: pre-line; word-wrap: break-word; text-align: ${column.align || 'left'}; padding: ${tableStyle.rowPadding * 3.78}px ${tableStyle.colPadding * 3.78}px ; `)
tr.appendChild(td)
}
tbody.appendChild(tr)
}
const dataTypeArr = ['number', 'static-number', 'input-number', 'progress', 'static-progress']
if (isLastTask && !tableStyle.countAllPage && hasStatistic) {
const tr = document.createElement('tr')
for (let j = 0; j < columns.length; j++) {
const td = document.createElement('td')
if (j == 0) {
td.textContent = '合计:'
}
const column = columns[j]
if (column.statistic == 'Sum') {
if (dataTypeArr.includes(column.type) || column.pristine.isNumerical) {
const value = calcFn('sum', column.name, tableData)
td.textContent = getCellValue(value, column)
} else {
const value = data.filter(item => item[column.name]).length
td.textContent = value.toString()
}
td.setAttribute('style', `white-space: pre-line; word-wrap: break-word; text-align: ${column.align || 'left'}`)
}
tr.appendChild(td)
}
tbody.appendChild(tr)
}
table.appendChild(tbody)
if (tableStyle.countAllPage && hasStatistic) {
const tfoot = document.createElement('tfoot')
const tr = document.createElement('tr')
columns.forEach((column, index) => {
const td = document.createElement('td')
if (index == 0) {
td.textContent = '合计:'
}
if (column.statistic == 'Sum') {
if (dataTypeArr.includes(column.type) || column.pristine.isNumerical) {
const value = calcFn('sum', column.name, tableData)
td.textContent = getCellValue(value, column)
} else {
const value = data.filter(item => item[column.name]).length
td.textContent = value.toString()
}
td.setAttribute('style', `white-space: pre-line; word-wrap: break-word; text-align: ${column.align || 'left'}`)
}
tr.appendChild(td)
})
tfoot.appendChild(tr)
table.append(tfoot)
}
div.appendChild(table)
wrap.appendChild(div)
return wrap.innerHTML
}
const sortArray = (datas: any[], columns: { name: string, func: 'asc' | 'desc' }[]) => {
if (columns.length > 0) {
const column = columns.pop()
if (column) {
const name = column.name
const func = column.func
datas = datas.sort((a, b) => {
const valueA = a[name]
const valueB = b[name]
return sortFn(valueA, valueB, func)
})
sortArray(datas, columns)
}
}
return datas
}