Merge pull request #6823 from nwind/feat-export-excel-color-background-color

feat: export-excel 支持文字颜色及背景色 Closes #6174
This commit is contained in:
hsm-lv 2023-05-09 09:27:24 +08:00 committed by GitHub
commit 75c90ad630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 6 deletions

View File

@ -158,7 +158,8 @@ export default {
}, },
{ {
name: 'engine.name', name: 'engine.name',
label: '引擎' label: '引擎',
className: 'text-primary'
}, },
{ {
name: 'browser', name: 'browser',
@ -170,9 +171,11 @@ export default {
}, },
{ {
name: 'engine.version', name: 'engine.version',
label: 'CSS版本', label: '引擎版本',
type: 'tpl', type: 'tpl',
tpl: '<b>${engine.version}</b>' tpl: '<b>${engine.version}</b>',
classNameExpr:
"<%= data.engine.version > 4 ? 'bg-green-100' : 'bg-red-50' %>"
}, },
{ {
name: 'grade', name: 'grade',

View File

@ -15,10 +15,8 @@ import {
import {isPureVariable, resolveVariableAndFilter} from 'amis-core'; import {isPureVariable, resolveVariableAndFilter} from 'amis-core';
import {BaseSchema} from '../../Schema'; import {BaseSchema} from '../../Schema';
import {toDataURL, getImageDimensions} from 'amis-core'; import {toDataURL, getImageDimensions} from 'amis-core';
import {TplSchema} from '../Tpl'; import memoize from 'lodash/memoize';
import {MappingSchema} from '../Mapping';
import {getSnapshot} from 'mobx-state-tree'; import {getSnapshot} from 'mobx-state-tree';
import {DateSchema} from '../Date';
import moment from 'moment'; import moment from 'moment';
import type {TableProps, ExportExcelToolbar} from './index'; import type {TableProps, ExportExcelToolbar} from './index';
@ -38,6 +36,123 @@ const getAbsoluteUrl = (function () {
}; };
})(); })();
interface CellStyleFont {
name?: string;
color?: {argb: string};
underline?: boolean;
bold?: boolean;
italic?: boolean;
}
interface CellStyleFill {
type?: string;
pattern?: string;
fgColor?: {argb: string};
}
interface CellStyle {
font?: CellStyleFont;
fill?: CellStyleFill;
}
/**
* computedStyle rgba argb hex
*/
const rgba2argb = memoize((rgba: string) => {
const color = `${rgba
.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/)!
.slice(1)
.map((n, i) =>
(i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n))
.toString(16)
.padStart(2, '0')
.replace('NaN', '')
)
.join('')}`;
if (color.length === 6) {
return 'FF' + color;
}
return color;
});
/**
* classname excel
*/
const getCellStyleByClassName = memoize((className: string): CellStyle => {
if (!className) return {};
const classNameElm = document.getElementsByClassName(className).item(0);
if (classNameElm) {
const computedStyle = getComputedStyle(classNameElm);
const font: CellStyleFont = {};
let fill: CellStyleFill = {};
if (computedStyle.color && computedStyle.color.indexOf('rgb') !== -1) {
const color = rgba2argb(computedStyle.color);
// 似乎不支持完全透明的情况,所以就不设置
if (!color.startsWith('00')) {
font['color'] = {argb: color};
}
}
if (computedStyle.fontWeight && parseInt(computedStyle.fontWeight) >= 700) {
font['bold'] = true;
}
if (
computedStyle.backgroundColor &&
computedStyle.backgroundColor.indexOf('rgb') !== -1
) {
const color = rgba2argb(computedStyle.backgroundColor);
if (!color.startsWith('00')) {
fill = {
type: 'pattern',
pattern: 'solid',
fgColor: {argb: color}
};
}
}
return {font, fill};
}
return {};
});
/**
*
*/
const applyCellStyle = (
sheetRow: any,
columIndex: number,
schema: any,
data: any
) => {
let cellStyle: CellStyle = {};
if (schema.className) {
for (const className of schema.className.split(/\s+/)) {
const style = getCellStyleByClassName(className);
if (style) {
cellStyle = {...cellStyle, ...style};
}
}
}
if (schema.classNameExpr) {
const classNames = filter(schema.classNameExpr, data);
if (classNames) {
for (const className of classNames.split(/\s+/)) {
const style = getCellStyleByClassName(className);
if (style) {
cellStyle = {...cellStyle, ...style};
}
}
}
}
if (cellStyle.font && Object.keys(cellStyle.font).length > 0) {
sheetRow.getCell(columIndex).font = cellStyle.font;
}
if (cellStyle.fill && Object.keys(cellStyle.fill).length > 0) {
sheetRow.getCell(columIndex).fill = cellStyle.fill;
}
};
export async function exportExcel( export async function exportExcel(
ExcelJS: any, ExcelJS: any,
props: TableProps, props: TableProps,
@ -173,6 +288,8 @@ export async function exportExcel(
} }
} }
applyCellStyle(sheetRow, columIndex, column.pristine, rowData);
const type = (column as BaseSchema).type || 'plain'; const type = (column as BaseSchema).type || 'plain';
// TODO: 这里很多组件都是拷贝对应渲染的逻辑实现的,导致每种都得实现一遍 // TODO: 这里很多组件都是拷贝对应渲染的逻辑实现的,导致每种都得实现一遍
if ((type === 'image' || (type as any) === 'static-image') && value) { if ((type === 'image' || (type as any) === 'static-image') && value) {