7 小时以前 35722562e9e13f0504acc15b740d042ecb810199
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
 * 质量组件协议(Quality Component Protocol)
 * <p>
 * 设计器只认这套协议,不认具体业务组件:新增质量组件=注册一个新 definition,
 * 不需要改动 GrapesJS 集成代码,也不需要改动设计器页面(方案设计 §9)。
 */
 
/** 组件分类,顺序即设计器左侧面板的分组顺序 */
export const QUALITY_CATEGORY = {
  BASIC: '基础组件',
  HEADER: '报告组件',
  INSPECTION: '检验组件',
  RESULT: '结果组件',
} as const;
 
export type QualityCategory = (typeof QUALITY_CATEGORY)[keyof typeof QUALITY_CATEGORY];
 
/** 分类的展示顺序 */
export const QUALITY_CATEGORY_ORDER: QualityCategory[] = [
  QUALITY_CATEGORY.BASIC,
  QUALITY_CATEGORY.HEADER,
  QUALITY_CATEGORY.INSPECTION,
  QUALITY_CATEGORY.RESULT,
];
 
/** 属性字段的值类型,决定属性面板用什么控件 */
export type QualityFieldType =
  | 'boolean'
  | 'enum'
  | 'number'
  | 'string'
  | 'text';
 
/** 属性字段的可选项 */
export interface QualityFieldOption {
  label: string;
  value: number | string;
}
 
/**
 * 一个业务属性 / 可绑定数据字段的描述。
 * <p>
 * propertySchema 描述「设计期用户能改什么」,dataSchema 描述「渲染期能绑什么」,
 * 两者共用一个结构,区别只在用途。
 */
export interface QualityFieldSchema {
  /** 字段键,同时是写入画布 attributes 的 data-qc-<key> 名 */
  key: string;
  label: string;
  type: QualityFieldType;
  /** 默认值,必须与 type 对应 */
  defaultValue?: boolean | number | string;
  /** type 为 enum 时的候选项 */
  options?: QualityFieldOption[];
  placeholder?: string;
  /** 输入提示,展示在属性面板字段下方 */
  tip?: string;
  /** 是否必填(校验用) */
  required?: boolean;
  /**
   * 是否允许绑定数据源表达式({{path}})。
   * 为 false 时属性面板不提供「绑定数据」入口。
   */
  bindable?: boolean;
  /**
   * bindable 为 true 时,从数据字段里挑中后写回属性值的形式。
   * <p>
   * - text(默认):写成 {{path}},渲染期按绑定协议替换成数据值,适用于标题、文本、结论等;
   * - path:直接写裸路径,渲染期把它当作结构化路径用(如按数组逐行生成的检验项数据源),
   *   包上 {{}} 反而会让渲染期找不到数组。
   */
  bindAs?: 'path' | 'text';
}
 
/** 业务属性的运行时取值 */
export type QualityProps = Record<string, boolean | number | string | undefined>;
 
/** GrapesJS 组件内容,等价于 BlockProperties['content'] 的常用子集 */
export interface QualityComponentContent {
  tagName?: string;
  /** 子组件:HTML 字符串或组件描述对象数组 */
  components?: QualityComponentContent[] | string;
  content?: string;
  attributes?: Record<string, string>;
  style?: Record<string, string>;
}
 
/**
 * 质量组件定义:注册进 registry 的唯一协议。
 */
export interface QualityComponentDefinition {
  /** 唯一类型标识,写入画布的 data-quality-type,也是 Schema.components[].qualityType */
  type: string;
  /** 英文名,用于代码内引用 */
  name: string;
  /** 设计器左侧面板与属性面板的显示名 */
  label: string;
  category: QualityCategory;
  /** 左侧面板的图标(内联 SVG 字符串) */
  icon: string;
  /** 新组件落到画布时的初始业务属性 */
  defaults: QualityProps;
  /** 设计期可编辑的业务属性 */
  propertySchema: QualityFieldSchema[];
  /** 渲染期可绑定的数据字段 */
  dataSchema: QualityFieldSchema[];
  /**
   * 组件的可见文本对应的属性 key。
   * <p>
   * 声明后,用户在画布内直接改文字会同步回该属性,属性面板改值也会同步回画布;
   * 内容由多个元素拼成的组件(页眉、表格)不声明,避免整块 HTML 被当成文本。
   */
  contentKey?: string;
  /**
   * 给 AI 导入用的选型说明:这个组件用来放什么、不要用来放什么。
   * <p>
   * 不进设计器界面,只随积木清单进提示词。写它是因为清单里只有 label 时,
   * 模型面对「报告抬头」这类内容会在 Heading / Text / ReportHeader 之间瞎猜,
   * 而只会看到中文标签的它没有任何理由不挑最通用的那个。
   * <p>
   * 必须包含「不要用来放什么」:只讲用途挡不住误用,讲清边界才有用。
   */
  aiHint?: string;
  /**
   * 生成画布内容。properties 已经收敛过默认值,实现里可以直接用。
   */
  buildContent: (properties: QualityProps) => QualityComponentContent;
  /**
   * 校验业务属性,返回错误信息数组;空数组表示通过。
   * 仅在保存/发布前调用,正常设计过程不应触发。
   */
  validate?: (properties: QualityProps) => string[];
}