123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- import { getBase64Sync } from './exportWord'
- import { baseURL } from './http'
- type WallItem = {
- url: string
- width: number
- height: number
- img: string
- }
- export const numberToChinese = (num: number) => {
- if (isNaN(num)) {
- throw new Error('输入必须是一个有效的数字')
- }
- if (num < 0 || num > 9999) {
- throw new Error('输入数字超出范围 (0-9999)')
- }
- if (num === 0) {
- return '零'
- }
- const chineseNumbers = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
- const chineseUnits = ['', '拾', '佰', '仟']
- let result = ''
- const numStr = num.toString()
- const length = numStr.length
- for (let i = 0; i < length; i++) {
- const digit = parseInt(numStr[i])
- const unit = length - i - 1
- if (digit !== 0) {
- result += chineseNumbers[digit] + chineseUnits[unit]
- } else {
- // 处理连续的零,只保留一个
- if (i < length - 1 && numStr[i + 1] !== '0') {
- result += chineseNumbers[digit]
- }
- }
- }
- // 处理10-19的情况,去掉开头的"壹"
- if (num >= 10 && num < 20) {
- result = result.replace('壹拾', '拾')
- }
- return result
- }
- export const getImageDimensions = (url: string): Promise<{ width: number; height: number }> => {
- return new Promise(resolve => {
- const img = new Image()
- img.onload = () => {
- resolve({ width: img.width, height: img.height })
- }
- img.onerror = () => {
- resolve({ width: 100, height: 100 })
- }
- img.src = url
- })
- }
- /**
- * 将一维数组根据图片宽高比转成三维数组
- */
- export const arrangeImages = async (images: { thumb: string }[]) => {
- const MAX_WALL_WIDTH = 520
- const MAX_WALL_HEIGHT = 750
- const MAX_ROWS_PER_WALL = 3
- const walls: Array<Array<Array<WallItem>>> = []
- let currentWall: Array<Array<WallItem>> = []
- let currentRow: Array<WallItem> = []
- let currentRowHeight = 0
- let currentX = 0
- const imagesWithDimensions = await Promise.all(
- images.map(async img => {
- const url = baseURL + img.thumb
- const dimensions = await getImageDimensions(url)
- return {
- url,
- originalWidth: dimensions.width,
- originalHeight: dimensions.height
- }
- })
- )
- for (const img of imagesWithDimensions) {
- const maxRowHeight = MAX_WALL_HEIGHT / MAX_ROWS_PER_WALL
- const aspectRatio = img.originalWidth / img.originalHeight
- let scaledWidth, scaledHeight
- scaledHeight = maxRowHeight
- scaledWidth = maxRowHeight * aspectRatio
- if (scaledWidth > MAX_WALL_WIDTH) {
- scaledWidth = MAX_WALL_WIDTH
- scaledHeight = MAX_WALL_WIDTH / aspectRatio
- }
- // TOFIX: 暂时无法解决图片并列渲染问题
- if (currentX + scaledWidth <= MAX_WALL_WIDTH && false) {
- currentRow.push({
- url: img.url,
- width: scaledWidth,
- height: scaledHeight,
- img: await getBase64Sync(img.url)
- })
- currentX += scaledWidth
- currentRowHeight = Math.max(currentRowHeight, scaledHeight)
- } else {
- if (currentRow.length > 0) {
- // eslint-disable-next-line no-loop-func
- currentRow.forEach(item => {
- item.height = currentRowHeight
- })
- currentWall.push(currentRow)
- }
- if (currentWall.length >= MAX_ROWS_PER_WALL) {
- walls.push(currentWall)
- currentWall = []
- }
- currentRow = [
- {
- url: img.url,
- width: scaledWidth,
- height: scaledHeight,
- img: await getBase64Sync(img.url)
- }
- ]
- currentX = scaledWidth
- currentRowHeight = scaledHeight
- }
- }
- if (currentRow.length > 0) {
- currentWall.push(currentRow)
- }
- if (currentWall.length > 0) {
- walls.push(currentWall)
- }
- return walls
- }
- export const getEffectiveLength = (str: string) => {
- let length = 0
- for (const char of str) {
- // 全角字符(包括中文、全角符号等)的 Unicode 范围判断
- if (char.match(/[\u4e00-\u9fa5\u3000-\u303f\uff00-\uffef]/)) {
- length += 2 // 全角算2字符
- } else {
- length += 1 // 半角算1字符
- }
- }
- return length
- }
- export const calculateRowCharLines = (
- row: Record<string, string>,
- perLine: Record<string, number>
- ) => {
- let maxCharLines = 0
- for (const [field, text] of Object.entries(row)) {
- if (!perLine[field]) continue
- const fieldLength = getEffectiveLength(text)
- const fieldCharLines = Math.ceil(fieldLength / perLine[field])
- maxCharLines = Math.max(maxCharLines, fieldCharLines)
- }
- return maxCharLines || 1
- }
- export const removeHtmlTags = (html: string) => {
- return html
- .replace(/<[^>]*>/g, '') // 移除HTML标签
- .replace(/\s+/g, ' ') // 合并多个空格
- .replace(/ /g, ' ') // 替换HTML空格实体
- .replace(/&/g, '&') // 替换HTML & 实体
- .replace(/</g, '<') // 替换HTML < 实体
- .replace(/>/g, '>') // 替换HTML > 实体
- .replace(/"/g, '"') // 替换HTML " 实体
- .replace(/'/g, "'") // 替换HTML ' 实体
- .trim() // 去除首尾空格
- }
|