Files
label-designer/src/types.ts
2026-06-23 15:26:51 +08:00

375 lines
14 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export type TextFormat = 'text' | 'number' | 'percent' | 'currency';
/** 数值格式下的显示部分:完整 / 仅整数 / 仅小数(含小数点) */
export type NumberPartDisplay = 'full' | 'integer' | 'fraction';
/** 文本变量值提取方式 */
export type TextExtractMode = 'none' | 'split' | 'prefix' | 'suffix';
export const TEXT_EXTRACT_MODE_LABELS: Record<TextExtractMode, string> = {
none: '无',
split: '按分隔符',
prefix: '前 N 位',
suffix: '后 N 位',
};
/** 变量/内容值提取配置(元素、表格单元格、显示条件等共用) */
export interface ValueExtractConfig {
textExtractMode?: TextExtractMode;
textSplitDelimiter?: string;
textSplitIndex?: number;
textExtractLength?: number;
/** 反选:从原值中去掉「显示前缀 + 提取段 + 显示后缀」 */
textExtractInverse?: boolean;
textDisplayPrefix?: string;
textDisplaySuffix?: string;
}
export type ElementVisibilityMode = 'always' | 'conditional';
export type VisibilityOperator =
| 'empty'
| 'not_empty'
| 'gt'
| 'lt'
| 'eq'
| 'neq'
| 'contains'
| 'not_contains';
/** 显示条件判断对象:变量值 或 本元素解析后的内容值 */
export type VisibilityRuleTarget = 'variable' | 'content';
export interface VisibilityRule extends ValueExtractConfig {
/** 条件对象,默认 variable */
target?: VisibilityRuleTarget;
variable: string;
operator: VisibilityOperator;
/** gt / lt / eq / neq / contains / not_contains 时的比较目标值,支持 {变量名} */
value?: string;
/** 为 false 时跳过该条件;默认启用 */
enabled?: boolean;
}
export const VISIBILITY_RULE_TARGET_LABELS: Record<VisibilityRuleTarget, string> = {
variable: '变量',
content: '内容值',
};
export const VISIBILITY_OPERATOR_LABELS: Record<VisibilityOperator, string> = {
empty: '为空',
not_empty: '不为空',
gt: '大于',
lt: '小于',
eq: '等于',
neq: '不等于',
contains: '包含',
not_contains: '不包含',
};
export type ElementSide = 'top' | 'right' | 'bottom' | 'left';
export type ElementCorner = 'tl' | 'tr' | 'br' | 'bl';
/** 表格单元格数据;键为 `${row},${col}` */
export interface TableCellData {
/** 被合并单元格指向主单元格坐标 */
mergeAnchor?: { row: number; col: number };
/** 主单元格合并行数,默认 1 */
rowSpan?: number;
/** 主单元格合并列数,默认 1 */
colSpan?: number;
content?: string;
fontSize?: number;
textAlign?: 'left' | 'center' | 'right';
verticalAlign?: 'top' | 'middle' | 'bottom';
fontWeight?: 'normal' | 'bold';
fontStyle?: 'normal' | 'italic';
textUnderline?: boolean;
textLineThrough?: boolean;
textScaleX?: number;
textScaleY?: number;
letterSpacing?: number;
textWritingMode?: 'horizontal' | 'vertical';
textColor?: string;
backgroundColor?: string;
wordWrap?: boolean;
/** 最大显示行数(横排为行、竖排为列);未设置或 0 表示不限制 */
textMaxLines?: number;
/** 超出最大行数时末行/末列显示省略号 */
textEllipsis?: boolean;
fontFamily?: 'sans' | 'serif' | 'mono';
textFormat?: TextFormat;
decimalPlaces?: number;
numberPartDisplay?: NumberPartDisplay;
textExtractMode?: TextExtractMode;
textSplitDelimiter?: string;
textSplitIndex?: number;
textExtractLength?: number;
/** 反选:从原值中去掉「显示前缀 + 提取段 + 显示后缀」 */
textExtractInverse?: boolean;
textDisplayPrefix?: string;
textDisplaySuffix?: string;
}
export interface TemplateElement {
id: string;
type: 'text' | 'barcode' | 'qrcode' | 'image' | 'table';
name: string;
/** 用户是否手动修改过图层名称;为 true 时不再根据内容自动同步名称 */
nameCustomized?: boolean;
x: number; // in mm
y: number; // in mm
width: number; // in mm
height: number; // in mm
/** 旋转角度(度),顺时针,默认 0 */
rotation?: number;
content: string; // static text or variable binding, e.g. "{货位}" or "格式化文本 {货位}"
/** 显示控制conditional 时按 visibilityRules 判断 */
visibilityMode?: ElementVisibilityMode;
/** 显示控制条件;全部满足时才渲染(设计预览按变量默认值判断) */
visibilityRules?: VisibilityRule[];
/** @deprecated 使用 visibilityRules */
visibilityVariables?: string[];
/** @deprecated 使用 visibilityMode=conditional */
hideWhenNoData?: boolean;
/** @deprecated 使用 visibilityRules */
visibilityVariable?: string;
fontSize: number; // in pt
textAlign: 'left' | 'center' | 'right';
/** 文本垂直对齐,仅 type=text */
verticalAlign?: 'top' | 'middle' | 'bottom';
/** 是否自动换行,仅 type=text默认 true */
wordWrap?: boolean;
/** 最大显示行数(横排为行、竖排为列);未设置或 0 表示不限制,仅 type=text */
textMaxLines?: number;
/** 超出最大行数时显示省略号,仅 type=text */
textEllipsis?: boolean;
/** 文本排列方向,仅 type=text默认 horizontal */
textWritingMode?: 'horizontal' | 'vertical';
fontWeight: 'normal' | 'bold';
/** 斜体,仅 type=text */
fontStyle?: 'normal' | 'italic';
/** 下划线,仅 type=text */
textUnderline?: boolean;
/** 删除线,仅 type=text */
textLineThrough?: boolean;
/** 水平拉伸倍数1 为默认,仅 type=text */
textScaleX?: number;
/** 垂直拉伸倍数1 为默认,仅 type=text */
textScaleY?: number;
/** 字间距 (mm),仅 type=text */
letterSpacing?: number;
barcodeFormat: 'CODE128' | 'CODE39' | 'EAN13' | 'ITF';
showText: boolean; // For barcode human-readable text below
fontFamily: 'sans' | 'serif' | 'mono';
backgroundColor?: string;
/** 背景不透明度 0100100 为完全不透明0 或 backgroundColor 为 transparent 时不绘制背景 */
backgroundOpacity?: number;
textColor?: string;
/** 内边距 (mm),所有元素类型均有效 */
padding?: number;
paddingTop?: number;
paddingRight?: number;
paddingBottom?: number;
paddingLeft?: number;
locked?: boolean;
/** 图层是否隐藏;隐藏后在预览、导出、打印及画布中均不显示 */
hidden?: boolean;
/** 图片缩放方式,仅 type=image 时有效 */
imageFit?: 'contain' | 'cover' | 'fill';
/** 默认图片 URL 或 data URI主图加载失败时使用仅 type=image 时有效 */
defaultImage?: string;
/** 输出模式下内容值为空时仍渲染;条码/二维码/图片有效,默认 false */
showWhenContentEmpty?: boolean;
/** 文本显示格式,仅 type=text 时有效 */
textFormat?: TextFormat;
/** 数值/百分比/货币的小数位数,默认 2 */
decimalPlaces?: number;
/** 数值格式下显示整数或小数部分,仅 type=text 且 textFormat≠text */
numberPartDisplay?: NumberPartDisplay;
/** 变量值提取方式(文本/条码/二维码/图片内容均有效) */
textExtractMode?: TextExtractMode;
/** 按分隔符拆分时使用的分隔符 */
textSplitDelimiter?: string;
/** 分隔后显示第几位(从 1 开始),段数不足时显示为空 */
textSplitIndex?: number;
/** 前 N / 后 N 位提取时的位数 */
textExtractLength?: number;
/** 反选:从原值中去掉「显示前缀 + 提取段 + 显示后缀」 */
textExtractInverse?: boolean;
/** 提取后在显示文本前追加的前缀字符,仅 type=text不参与内容值条件 */
textDisplayPrefix?: string;
/** 提取后在显示文本后追加的后缀字符,仅 type=text不参与内容值条件 */
textDisplaySuffix?: string;
/** 边框宽度 (mm)0 为无边框;各边留空时沿用此值 */
borderWidth?: number;
borderColor?: string;
borderWidthTop?: number;
borderWidthRight?: number;
borderWidthBottom?: number;
borderWidthLeft?: number;
borderColorTop?: string;
borderColorRight?: string;
borderColorBottom?: string;
borderColorLeft?: string;
/** @deprecated 使用各边 borderWidth*0 为不显示) */
borderSides?: Partial<Record<ElementSide, boolean>>;
/** 圆角半径 (mm),可被各角覆盖 */
borderRadius?: number;
/** 指定哪些角应用圆角,默认四角 */
borderRadiusCorners?: Partial<Record<ElementCorner, boolean>>;
borderRadiusTL?: number;
borderRadiusTR?: number;
borderRadiusBR?: number;
borderRadiusBL?: number;
/** 表格行数,仅 type=table */
tableRows?: number;
/** 表格列数,仅 type=table */
tableCols?: number;
/** 各行高度 (mm),仅 type=table */
tableRowHeights?: number[];
/** 各列宽度 (mm),仅 type=table */
tableColWidths?: number[];
/** 单元格数据,键 `${row},${col}`,仅 type=table */
tableCells?: Record<string, TableCellData>;
/** 单元格网格线宽 (mm),仅 type=table默认 0.2 */
tableBorderWidth?: number;
/** 单元格网格线颜色,仅 type=table */
tableBorderColor?: string;
/** 图层蒙版;在预览与导出时裁剪元素可见区域 */
mask?: ElementMaskConfig;
}
export type ElementMaskShape = 'rect' | 'image';
export interface ElementMaskConfig {
/** 是否启用蒙版 */
enabled?: boolean;
/** 蒙版形状:矩形矢量区域或图片 alpha */
type?: ElementMaskShape;
/** 相对元素左上角的 X 偏移 (mm) */
x?: number;
/** 相对元素左上角的 Y 偏移 (mm) */
y?: number;
/** 蒙版区域宽度 (mm),默认与元素同宽 */
width?: number;
/** 蒙版区域高度 (mm),默认与元素同高 */
height?: number;
/** 圆角半径 (mm) */
borderRadius?: number;
borderRadiusTL?: number;
borderRadiusTR?: number;
borderRadiusBR?: number;
borderRadiusBL?: number;
/** 图片蒙版data URI / URLtype=image 时使用 */
image?: string;
/** 图片蒙版在区域内的适应方式 */
imageFit?: 'contain' | 'cover' | 'fill';
/** include=保留蒙版区域内exclude=保留区域外;默认 include */
mode?: 'include' | 'exclude';
}
export interface DataSourceMeta {
fileName: string;
sheets: string[];
currentSheet: string;
columns: string[];
rowCount: number;
}
export type CutLineStyle = 'dashed' | 'solid';
export interface CutLineConfig {
enabled: boolean;
style: CutLineStyle;
/** 线宽 (mm) */
width: number;
color: string;
}
export type ExportRangeMode = 'all' | 'odd' | 'even' | 'custom';
export interface ExportRangeConfig {
mode: ExportRangeMode;
/** 自定义范围1-based 序号,如 "1,3,5-10"(排版过滤,不写入模板) */
custom?: string;
}
export interface LabelTemplate {
id?: string;
name?: string;
width: number; // in mm
height: number; // in mm
elements: TemplateElement[];
/** 模板声明的变量名(统一管理;内容/显示控制从此选取) */
variableList?: string[];
/** 设计预览用:变量名 → 默认展示值 */
variableDefaults?: Record<string, string>;
/** 数据过滤条件(写入模板);全部满足的数据行才参与排版/导出 */
dataFilterRules?: VisibilityRule[];
/** 整页排版配置(每模板独立) */
paper?: PaperConfig;
/** PDF 裁切参考线配置 */
cutLine?: CutLineConfig;
/** 设计画布预览参考背景URL / data URI */
previewReferenceBackground?: string;
/** 预览参考背景不透明度 0100默认 100 */
previewReferenceBackgroundOpacity?: number;
/** 预览参考背景适应方式,默认 cover */
previewReferenceBackgroundFit?: 'contain' | 'cover' | 'fill';
/** 设计预览(画布、模板列表缩略图)是否显示参考背景,默认 true */
enablePreviewReferenceBackground?: boolean;
/** 生成 PDF / 打印 / 排版预览输出时是否绘制参考背景,默认 false */
includeReferenceBackgroundInOutput?: boolean;
/** 排版整页背景图URL / data URI */
layoutPageBackground?: string;
/** 排版整页背景不透明度 0100默认 100 */
layoutPageBackgroundOpacity?: number;
/** 排版整页背景适应方式,默认 cover */
layoutPageBackgroundFit?: 'contain' | 'cover' | 'fill';
/** 排版预览是否显示整页背景,默认 true */
enableLayoutPageBackground?: boolean;
/** PDF / 打印输出时是否绘制整页背景,默认 false */
includeLayoutPageBackgroundInOutput?: boolean;
/** 批量导出图片时的文件名模板,支持 {#SEQ}、{#INDEX}、{变量名};留空则按序号补零命名 */
exportImageFileNamePattern?: string;
/** 批量导出图片all=全部导出conditional=按条件过滤 */
exportImageFilterMode?: ElementVisibilityMode;
/** 批量导出图片过滤条件;全部满足时才导出该枚标签 */
exportImageFilterRules?: VisibilityRule[];
}
export type PaperType = 'A4' | 'A5' | 'A6' | 'custom';
/** 排版/印刷输出色彩模式 */
export type PrintColorMode = 'rgb' | 'grayscale' | 'cmyk';
export const PRINT_COLOR_MODE_LABELS: Record<PrintColorMode, string> = {
rgb: '标准(轻度印刷补偿)',
grayscale: '黑白(灰度)',
cmyk: 'CMYK 印刷模拟(推荐)',
};
export interface PaperConfig {
type: PaperType;
width: number; // in mm
height: number; // in mm
orientation: 'portrait' | 'landscape';
marginTop: number; // in mm
marginRight: number; // in mm
marginBottom: number; // in mm
marginLeft: number; // in mm
columnGap: number; // in mm (horizontal spacing between labels)
rowGap: number; // in mm (vertical spacing between labels)
flow: 'top-bottom-left-right' | 'left-right-top-bottom'; // how cells flow
/** 排版预览与导出时的色彩模式,默认 rgb */
printColorMode?: PrintColorMode;
}
export interface RecordRow {
[key: string]: string;
}
export interface ImportData {
fileName: string;
sheets: string[];
currentSheet: string;
columns: string[];
rows: RecordRow[];
}