import Foundation // MARK: - JSON Schema Models (Bricks JSON → Codable) /// 根控件定义,对应Bricks JSON顶层结构 public struct ControlSchema: Codable, Identifiable, Sendable { public var id: String? public let widgettype: String public var options: ControlOptions public var binds: [BindSchema]? public var subwidgets: [ControlSchema]? /// 运行时生成的唯一ID(当JSON未提供id时) public var runtimeId: String = UUID().uuidString.prefix(8).lowercased() public var effectiveId: String { id ?? runtimeId } public init( id: String? = nil, widgettype: String, options: ControlOptions = .init(), binds: [BindSchema]? = nil, subwidgets: [ControlSchema]? = nil ) { self.id = id self.widgettype = widgettype self.options = options self.binds = binds self.subwidgets = subwidgets } /// 自定义解码:options缺失时默认为空,避免Filler等无options的widget解码失败 public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decodeIfPresent(String.self, forKey: .id) self.widgettype = try container.decode(String.self, forKey: .widgettype) self.options = try container.decodeIfPresent(ControlOptions.self, forKey: .options) ?? ControlOptions() self.binds = try container.decodeIfPresent([BindSchema].self, forKey: .binds) self.subwidgets = try container.decodeIfPresent([ControlSchema].self, forKey: .subwidgets) } private enum CodingKeys: String, CodingKey { case id, widgettype, options, binds, subwidgets } } /// 控件选项 — 使用字典+Codable混合方式 public struct ControlOptions: Codable, Sendable { // 通用属性 public var width: String? public var height: String? public var cwidth: Double? public var cheight: Double? public var bgcolor: String? public var color: String? public var css: String? public var padding: String? public var cursor: String? public var spacing: Double? public var alignItems: String? // Text/Title public var text: String? public var otext: String? public var i18n: Bool? public var level: Int? // Button public var label: String? public var actiontype: String? public var url: String? public var icon: String? // Input/Textarea public var name: String? public var placeholder: String? public var value: String? public var defaultvalue: String? public var required: Bool? public var uitype: String? public var title: String? public var rules: [ValidationRule]? public var codes: [CodeItem]? // Select/Code public var data: [CodeItem]? public var dataurl: String? public var valueField: String? public var textField: String? // Form public var fields: [FieldSchema]? public var submit_url: String? public var submit_label: String? public var show_label: Bool? // Tabular public var data_url: String? public var data_method: String? public var page_rows: Int? public var row_options: RowOptions? public var toolbar: ToolbarSchema? // TabView public var tabs: [TabItem]? public var activeTab: Int? // DynamicColumn public var col_cwidth: Double? public var col_cgap: Double? public var col_width: Double? // PopupWindow public var popup_options: PopupOptions? public var auto_open: Bool? public var archor: String? public var dismiss_events: [String]? // Menu public var items: [MenuItemSchema]? public var target: String? // HTML public var html: String? // Image public var src: String? public var alt: String? // VideoPlayer public var autoplay: Bool? public var controls: Bool? // Misc public var fontsize: String? public var cfontsize: Double? public init() {} } /// 绑定定义 — event→action映射 public struct BindSchema: Codable, Sendable { public let wid: String // 事件源widget id public let event: String // 事件名 public let actiontype: String // 动作类型(9种) public var target: String? // 目标widget id public var options: BindOptions? public var mode: String? // replace/append public var method: String? // method名(actiontype=method时) public var script: String? // 内联脚本(actiontype=script时) public var popup_options: PopupOptions? public var datawidget: String? // 数据源widget public var event_params: String? } /// 绑定选项 public struct BindOptions: Codable, Sendable { public var url: String? public var params: [String: String]? public init(url: String? = nil, params: [String: String]? = nil) { self.url = url self.params = params } } /// 弹出窗口选项 public struct PopupOptions: Codable, Sendable { public var title: String? public var cwidth: Double? public var cheight: Double? public var width: String? public var height: String? public var archor: String? public var eventpos: Bool? public var dismiss_events: [String]? public init() {} } /// 表单字段定义 public struct FieldSchema: Codable, Sendable { public var name: String public var label: String? public var title: String? public var type: String? public var uitype: String? public var required: Bool? public var cwidth: Double? public var placeholder: String? public var value: String? public var defaultvalue: String? public var codes: [CodeItem]? public var data: [CodeItem]? public var dataurl: String? public var valueField: String? public var textField: String? public var rules: [ValidationRule]? public var effectiveLabel: String { label ?? title ?? name } public var effectiveUitype: String { uitype ?? type ?? "str" } } /// 验证规则 public struct ValidationRule: Codable, Sendable { public let type: String public var value: String? public var message: String? } /// 代码项(下拉选项) public struct CodeItem: Codable, Sendable, Identifiable { public var id: String { value } public let value: String public let text: String } /// Tabular行选项 public struct RowOptions: Codable, Sendable { public var fields: [FieldSchema]? public var browserfields: BrowserFields? } /// 浏览器字段配置 public struct BrowserFields: Codable, Sendable { public var exclouded: [String]? public var cwidths: [String: Double]? public var alters: [String: FieldSchema]? } /// 工具栏定义 public struct ToolbarSchema: Codable, Sendable { public var tools: [ToolbarTool]? } /// 工具栏按钮 public struct ToolbarTool: Codable, Sendable { public var name: String public var label: String? public var icon: String? public var selected_row: Bool? public var css: String? } /// TabView项 public struct TabItem: Codable, Sendable { public var label: String public var icon: String? public var content: ControlSchema? } /// 菜单项 public struct MenuItemSchema: Codable, Sendable { public var name: String public var label: String public var icon: String? public var url: String? public var submenu: [MenuItemSchema]? public var binds: [BindSchema]? } // MARK: - 有效WidgetType枚举 public enum WidgetType: String, CaseIterable, Sendable { // 文本 case text = "Text" case title1 = "Title1", title2 = "Title2", title3 = "Title3" case title4 = "Title4", title5 = "Title5", title6 = "Title6" case label = "Label" // 输入 case input = "Input" case textarea = "Textarea" case select = "Select" case uiCode = "UiCode" case uiStr = "UiStr" case uiNumber = "UiNumber" case uiDate = "UiDate" case uiText = "UiText" // 按钮 case button = "Button" // 布局 case vbox = "VBox" case hbox = "HBox" case vScrollPanel = "VScrollPanel" case hScrollPanel = "HScrollPanel" case filler = "Filler" case dynamicColumn = "DynamicColumn" // 数据 case tabular = "Tabular" case dataViewer = "DataViewer" case form = "Form" case inlineForm = "InlineForm" // 导航 case tabView = "TabView" case menu = "Menu" // 弹窗 case popupWindow = "PopupWindow" // 其他 case card = "Card" case html = "Html" case image = "Image" case urlwidget = "urlwidget" // 特殊 case popup = "Popup" public var isLayout: Bool { [.vbox, .hbox, .vScrollPanel, .hScrollPanel, .dynamicColumn, .card].contains(self) } public var isText: Bool { [.text, .title1, .title2, .title3, .title4, .title5, .title6, .label].contains(self) } public var isInput: Bool { [.input, .textarea, .select, .uiCode, .uiStr, .uiNumber, .uiDate, .uiText].contains(self) } } // MARK: - 有效ActionType枚举 public enum ActionType: String, CaseIterable, Sendable { case newwindow // 新窗口打开 case iframe // iframe加载 case urlwidget // 加载UI内容到目标(最常用) case urldata // 获取数据更新目标 case bricks // 从配置实例化widget case registerfunction // 注册函数 case method // 调用目标widget方法 case script // 执行内联脚本 case event // 派发自定义事件 public static var validNames: [String] { allCases.map { $0.rawValue } } }