diff --git a/WordFormatUI/index.html b/WordFormatUI/index.html index e193111..c239904 100644 --- a/WordFormatUI/index.html +++ b/WordFormatUI/index.html @@ -5,10 +5,6 @@ WordFormat - 论文格式自动化处理工具 - - - - diff --git a/WordFormatUI/src/App.vue b/WordFormatUI/src/App.vue index ca29ff6..6277724 100644 --- a/WordFormatUI/src/App.vue +++ b/WordFormatUI/src/App.vue @@ -16,6 +16,9 @@ + @@ -34,16 +37,20 @@ - -
- - + +
+ + +
+ + - - + + - - + + +
@@ -62,6 +69,7 @@ import {ref, onMounted} from 'vue'; import GlobalToast from "./components/GlobalToast.vue"; import DocTagChecker from "./components/DocTagChecker.vue"; import ConfigGenerator from "./config-generator/ConfigGenerator.vue"; +import ConfigSidebar from "./components/ConfigSidebar.vue"; import SettingsPage from "./components/SettingsPage.vue"; import yaml from 'js-yaml'; import {defaultConfig, mergeWithDefaults} from "./config-generator/utils"; @@ -149,6 +157,45 @@ const onConfigFileSelected = async (e) => { } }; +// 保存配置到服务器 configs 目录 +const API_BASE = window.__API_BASE__ || ''; +const saveConfigToServer = async () => { + if (!generatedConfig.value) return; + try { + const yamlContent = yaml.dump(generatedConfig.value, { indent: 2, skipInvalid: true }); + const fn = prompt('请输入配置文件名(如 my-thesis.yaml):', 'custom.yaml'); + if (!fn) return; + const res = await fetch(`${API_BASE}/configs/save`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ filename: fn, content: yamlContent }), + }); + const json = await res.json(); + if (json.code === 200) { + toastRef.value?.toast.success(json.msg); + } else { + toastRef.value?.toast.error(json.msg || '保存失败'); + } + } catch (error) { + toastRef.value?.toast.error('保存配置失败:' + error.message); + } +}; + +// 从服务器侧边栏加载配置 +const onServerConfigSelected = ({ filename, content }) => { + try { + const config = yaml.load(content); + const merged = mergeWithDefaults(config, defaultConfig); + generatedConfig.value = merged; + if (configGeneratorRef.value) { + configGeneratorRef.value.importConfig(merged); + } + toastRef.value?.toast.success(`已加载配置: ${filename}`); + } catch (error) { + toastRef.value?.toast.error('解析配置失败:' + error.message); + } +}; + diff --git a/WordFormatUI/src/components/DocTagChecker.vue b/WordFormatUI/src/components/DocTagChecker.vue index 4f3fa69..f421b3c 100644 --- a/WordFormatUI/src/components/DocTagChecker.vue +++ b/WordFormatUI/src/components/DocTagChecker.vue @@ -442,7 +442,7 @@ watch(isFileLoaded, (loaded) => { .header-bar { background-color: #1e293b; border-bottom: 1px solid #334155; padding: 0.75rem 1.5rem; } .header-content { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; max-width: 1280px; margin: 0 auto; width: 100%; } .header-left { display: flex; flex-direction: column; gap: 0.25rem; } -.tool-title { font-size: 1.15rem; font-weight: 600; color: #f1f5f9; margin: 0; font-family: 'Crimson Pro', serif; } +.tool-title { font-size: 1.15rem; font-weight: 600; color: #f1f5f9; margin: 0; font-family: 'Georgia, Times New Roman', serif; } .stats-info { font-size: 0.8125rem; color: #64748b; } .stats-info span { font-weight: 600; color: #22c55e; } .header-right { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; } diff --git a/WordFormatUI/src/components/SettingsPage.vue b/WordFormatUI/src/components/SettingsPage.vue index 8d6a1a6..3d21b37 100644 --- a/WordFormatUI/src/components/SettingsPage.vue +++ b/WordFormatUI/src/components/SettingsPage.vue @@ -57,7 +57,7 @@ function resetDefaults() { resetSettings(); host.value = backendSettings.host; p diff --git a/WordFormatUI/src/config-generator/components/TablesConfig.vue b/WordFormatUI/src/config-generator/components/TablesConfig.vue index ab299d9..5ce59e9 100644 --- a/WordFormatUI/src/config-generator/components/TablesConfig.vue +++ b/WordFormatUI/src/config-generator/components/TablesConfig.vue @@ -5,10 +5,17 @@
+
+ +
+
题注格式
-

表格内容格式(单元格内文字)

+
表格对象格式(表格整体对齐、环绕)
+ + +
表格内容格式(单元格内文字)
@@ -25,83 +32,22 @@ const props = defineProps({ diff --git a/WordFormatUI/src/config-generator/utils.js b/WordFormatUI/src/config-generator/utils.js index b417d70..b0edf00 100644 --- a/WordFormatUI/src/config-generator/utils.js +++ b/WordFormatUI/src/config-generator/utils.js @@ -28,22 +28,23 @@ export const createConfigWithGlobalInheritance = (baseConfig = {}) => { // 默认配置 export const defaultConfig = { + template_name: "未知模板", style_checks_warning: { - bold: false, + bold: true, italic: false, underline: false, - font_size: false, - font_name: false, + font_size: true, + font_name: true, font_color: false, - alignment: false, - space_before: false, - space_after: false, - line_spacing: false, - line_spacingrule: false, - left_indent: false, - right_indent: false, - first_line_indent: false, - builtin_style_name: false + alignment: true, + space_before: true, + space_after: true, + line_spacing: true, + line_spacingrule: true, + left_indent: true, + right_indent: true, + first_line_indent: true, + builtin_style_name: true }, global_format: { ...defaultGlobalFormat @@ -64,7 +65,8 @@ export const defaultConfig = { english_title: createConfigWithGlobalInheritance({ alignment: "居中对齐", first_line_indent: "0字符", - font_size: "四号" + font_size: "四号", + bold: false }), english_content: createConfigWithGlobalInheritance({ alignment: "两端对齐" @@ -72,23 +74,30 @@ export const defaultConfig = { }, keywords: { chinese: createConfigWithGlobalInheritance({ + alignment: "两端对齐", + first_line_indent: "2字符", + font_size: "小四", label: createConfigWithGlobalInheritance({ chinese_font_name: '黑体', font_size: '四号', bold: false }), - count_min: 3, - count_max: 5, - trailing_punct_forbidden: true + rules: { + keyword_count: { enabled: true, count_min: 3, count_max: 5 }, + trailing_punctuation: { enabled: true, forbidden_chars: ";,。、" } + } }), english: createConfigWithGlobalInheritance({ + alignment: "两端对齐", + first_line_indent: "2字符", + font_size: "小四", label: createConfigWithGlobalInheritance({ font_size: '四号', bold: false }), - count_min: 3, - count_max: 5, - trailing_punct_forbidden: true + rules: { + keyword_count: { enabled: true, count_min: 3, count_max: 5 } + } }) } }, @@ -121,13 +130,24 @@ export const defaultConfig = { builtin_style_name: "Heading 3" }) }, - body_text: createConfigWithGlobalInheritance(), + body_text: createConfigWithGlobalInheritance({ + rules: { + punctuation: { enabled: true } + } + }), figures: createConfigWithGlobalInheritance({ alignment: "居中对齐", first_line_indent: "0字符", font_size: "五号", builtin_style_name: "题注", - caption_prefix: "图" + caption_prefix: "图", + image: createConfigWithGlobalInheritance({ + alignment: "居中对齐", + first_line_indent: "0字符" + }), + rules: { + caption_numbering: { enabled: true, separator: '.', label_number_space: false } + } }), tables: createConfigWithGlobalInheritance({ alignment: "居中对齐", @@ -135,16 +155,23 @@ export const defaultConfig = { font_size: "五号", builtin_style_name: "题注", caption_prefix: "表", + object: createConfigWithGlobalInheritance({ + alignment: "居中对齐", + first_line_indent: "0字符" + }), content: createConfigWithGlobalInheritance({ chinese_font_name: '宋体', english_font_name: 'Times New Roman', font_size: '五号', - line_spacingrule: '1.5倍行距', + line_spacingrule: '单倍行距', alignment: '居中对齐', first_line_indent: '0字符', space_before: "0行", space_after: "0行" - }) + }), + rules: { + caption_numbering: { enabled: true, separator: '.', label_number_space: false } + } }), references: { title: createConfigWithGlobalInheritance({ diff --git a/configs/undergrad_thesis.yaml b/configs/undergrad_thesis.yaml new file mode 100644 index 0000000..f5e1765 --- /dev/null +++ b/configs/undergrad_thesis.yaml @@ -0,0 +1,330 @@ +# =========================================================================== +# 本科毕业论文格式配置示例 +# =========================================================================== +# 本文件展示所有可配置字段及其默认值。 +# 使用 YAML 锚点 &global_format 定义全局基础格式, +# 各章节通过 <<: *global_format 继承后覆写特定字段。 +# +# 支持的单位格式: +# 字号:小四 / 四号 / 三号 / 小二 / 五号 / 数值(pt) +# 间距:0行 / 0.5行 / 1行 / 12磅 / 0.5cm +# 缩进:2字符 / -2.2字符(悬挂) / 0.75cm / 24磅 +# 行距:单倍行距 / 1.5倍行距 / 2倍行距 / 最小值 / 固定值 / 多倍行距 +# 字体颜色:黑色 / 红色 / 蓝色 等 +# 对齐:左对齐 / 居中对齐 / 右对齐 / 两端对齐 / 分散对齐 +# =========================================================================== + +template_name: "山西晋中理工学院(毕业设计)" + +# --------------------------------------------------------------------------- +# 预警开关:控制各字段差异是否在批注中显示(false=不显示该类型差异) +# --------------------------------------------------------------------------- +style_checks_warning: + bold: true + italic: false + underline: false + font_size: true + font_name: true + font_color: false + alignment: true + space_before: true + space_after: true + line_spacing: true + line_spacingrule: true + left_indent: true + right_indent: true + first_line_indent: true + builtin_style_name: true + +# --------------------------------------------------------------------------- +# 全局基础格式(其他节通过 <<: *global_format 继承后再覆写) +# --------------------------------------------------------------------------- +global_format: &global_format + # -- 段落格式 -- + alignment: '两端对齐' # 左对齐/居中对齐/右对齐/两端对齐/分散对齐 + space_before: "0行" # 段前间距 + space_after: "0行" # 段后间距 + line_spacingrule: "1.5倍行距" # 单倍行距/1.5倍行距/2倍行距/最小值/固定值/多倍行距 + line_spacing: '1.5倍' # 行距参数 + left_indent: "0字符" # 左侧缩进 + right_indent: "0字符" # 右侧缩进 + first_line_indent: '2字符' # 首行缩进(正值)/ 悬挂缩进(负值,如 -2.2字符) + builtin_style_name: '正文' # Word 内置样式名(Heading 1, Heading 2, 正文, 题注 等) + # -- 字符格式 -- + chinese_font_name: '宋体' # 中文字体 + english_font_name: 'Times New Roman' # 英文字体 + font_size: '小四' # 字号(四号/三号/小二/五号 等) + font_color: '黑色' # 字体颜色 + bold: false # 加粗 + italic: false # 斜体 + underline: false # 下划线 + +# =========================================================================== +# 摘要(中英文) +# =========================================================================== +abstract: + # ----------------------------------------------------------------------- + # 中文摘要 + # ----------------------------------------------------------------------- + chinese: + # -- 中文摘要标题("摘要"二字)-- + chinese_title: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + chinese_font_name: '黑体' + font_size: '四号' + bold: false + + # -- 中文摘要正文 -- + chinese_content: + <<: *global_format + alignment: '两端对齐' + + # ----------------------------------------------------------------------- + # 英文摘要 + # ----------------------------------------------------------------------- + english: + # -- 英文摘要标题("Abstract")-- + english_title: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + font_size: '四号' + bold: false + + # -- 英文摘要正文 -- + english_content: + <<: *global_format + alignment: '两端对齐' + + # ----------------------------------------------------------------------- + # 关键词(中英文) + # ----------------------------------------------------------------------- + keywords: + chinese: + # 从 global_format 继承,再覆写关键词特有字段 + <<: *global_format + alignment: '两端对齐' + first_line_indent: '2字符' + font_size: '小四' + # -- 关键词标签("关键词:")的字符格式 -- + label: + <<: *global_format + chinese_font_name: '黑体' + font_size: '四号' + bold: false + # -- 关键词业务规则(均通过 enabled 开关控制) -- + rules: + keyword_count: + enabled: true + count_min: 3 # 最少关键词数 + count_max: 5 # 最多关键词数 + trailing_punctuation: + enabled: true + forbidden_chars: ";,。、" # 中文关键词末尾禁止出现的标点 + + english: + <<: *global_format + alignment: '两端对齐' + first_line_indent: '2字符' + font_size: '小四' + label: + <<: *global_format + font_size: '四号' + bold: false + rules: + keyword_count: + enabled: true + count_min: 3 + count_max: 5 + +# =========================================================================== +# 各级标题(章、节、小节) +# =========================================================================== +headings: + # -- 一级标题(第1章)-- + level_1: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + chinese_font_name: '黑体' + font_size: '小二' + bold: false + space_before: "0.5行" + space_after: "0.5行" + builtin_style_name: 'Heading 1' + + # -- 二级标题(1.1)-- + level_2: + <<: *global_format + alignment: '左对齐' + first_line_indent: '0字符' + chinese_font_name: '黑体' + font_size: '三号' + bold: false + space_before: "0行" + space_after: "0行" + builtin_style_name: 'Heading 2' + + # -- 三级标题(1.1.1)-- + level_3: + <<: *global_format + alignment: '左对齐' + first_line_indent: '0字符' + chinese_font_name: '黑体' + font_size: '小四' + bold: false + space_before: "0行" + space_after: "0行" + builtin_style_name: 'Heading 3' + +# =========================================================================== +# 正文段落 +# =========================================================================== +body_text: + <<: *global_format + rules: + punctuation: + enabled: true + +# =========================================================================== +# 插图题注(Figure) +# =========================================================================== +figures: + <<: *global_format + font_size: '五号' + builtin_style_name: '题注' + alignment: '居中对齐' + first_line_indent: '0字符' + # -- 插图特有字段 -- + caption_prefix: '图' # 图注编号前缀 + # -- 图片段落格式(包含内联图片的段落)-- + image: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false + +# =========================================================================== +# 表格(题注 + 表格对象 + 表格内容) +# =========================================================================== +tables: + <<: *global_format + font_size: '五号' + builtin_style_name: '题注' + alignment: '居中对齐' + first_line_indent: '0字符' + # -- 表格题注特有字段 -- + caption_prefix: '表' # 表注编号前缀 + # -- 表格对象格式(表格整体对齐、环绕)-- + object: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + # -- 表格内容格式(单元格内文字)-- + content: + <<: *global_format + chinese_font_name: '宋体' + english_font_name: 'Times New Roman' + font_size: '五号' + line_spacingrule: '单倍行距' + alignment: '居中对齐' + first_line_indent: '0字符' + space_before: "0行" + space_after: "0行" + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false + +# =========================================================================== +# 参考文献 +# =========================================================================== +references: + # -- 参考文献标题("参考文献")-- + title: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + chinese_font_name: '黑体' + font_size: '三号' + bold: false + + # -- 参考文献条目内容 -- + content: + <<: *global_format + alignment: '两端对齐' + first_line_indent: '-2.2字符' # 悬挂缩进(负值=悬挂) + left_indent: '0.26字符' # 文本之前 + chinese_font_name: '宋体' + english_font_name: 'Times New Roman' + font_size: '五号' + +# =========================================================================== +# 致谢 +# =========================================================================== +acknowledgements: + # -- 致谢标题("致谢")-- + title: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + chinese_font_name: '黑体' + font_size: '小二' + bold: false + + # -- 致谢正文 -- + content: + <<: *global_format + alignment: '两端对齐' + font_size: '五号' + +# =========================================================================== +# 标题自动编号 +# =========================================================================== +numbering: + enabled: true # 总开关:是否启用自动编号 + + # -- 题注编号校验/修正 -- + captions: + enabled: true # 是否启用题注编号校验/修正 + separator: '.' # 章节号与题注编号间的分隔符 + label_number_space: false # 标签与编号间加空格(图 1.1 vs 图1.1) + + # -- 一级标题编号(如"第1章")-- + level_1: + enabled: true + template: '%1' # %1=本级序号 + suffix: 'space' # 编号后分隔符:tab / space / nothing + numbering_indent: # [可选] 编号缩进,如 '0字符' + text_indent: # [可选] 文本缩进(悬挂缩进),如 '0.75cm' + + # -- 二级标题编号(如"1.1")-- + level_2: + enabled: true + template: '%1.%2' # %1=上级序号, %2=本级序号 + suffix: 'space' + numbering_indent: + text_indent: + + # -- 三级标题编号(如"1.1.1")-- + level_3: + enabled: true + template: '%1.%2.%3' + suffix: 'space' + numbering_indent: + text_indent: + + # -- 参考文献条目编号(如"[1]")-- + references: + enabled: true + template: '[%1]' + suffix: 'space' + numbering_indent: + text_indent: # 悬挂缩进,如 '2.2字符'(优先级高于 references.content.first_line_indent) diff --git a/docs/configuration.md b/docs/configuration.md index d1e8df2..76518e0 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -91,9 +91,14 @@ abstract: chinese_font_name: '黑体' font_size: '四号' bold: true - count_min: 3 - count_max: 5 - trailing_punct_forbidden: true + rules: # 业务规则(均通过 enabled 开关控制) + keyword_count: + enabled: true + count_min: 3 + count_max: 5 + trailing_punctuation: + enabled: true + forbidden_chars: ";,。、" english: <<: *global_format alignment: '左对齐' @@ -103,9 +108,11 @@ abstract: <<: *global_format font_size: '四号' bold: true - count_min: 3 - count_max: 5 - trailing_punct_forbidden: true + rules: + keyword_count: + enabled: true + count_min: 3 + count_max: 5 ``` ### 4. 各级标题格式(headings) @@ -151,25 +158,28 @@ body_text: ``` ### 6. 插图格式(figures) -配置图片及其题注的格式,题注默认位于图片下方。 +配置图片及其题注的格式和编号规则。 ```yaml figures: <<: *global_format - caption_position: 'below' caption_prefix: '图' font_size: '五号' builtin_style_name: '题注' alignment: '居中对齐' first_line_indent: '0字符' + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false ``` ### 7. 表格格式(tables) -配置表格题注及表格内容(单元格内文字)的格式。题注默认位于表格上方,`content` 子配置控制表格内文字。 +配置表格题注及表格内容(单元格内文字)的格式和编号规则。`content` 子配置控制表格内文字。 ```yaml tables: <<: *global_format - caption_position: 'above' caption_prefix: '表' font_size: '五号' builtin_style_name: '题注' @@ -185,6 +195,11 @@ tables: first_line_indent: '0字符' space_before: "0行" space_after: "0行" + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false ``` ### 8. 参考文献格式(references) @@ -313,19 +328,26 @@ numbering: ### 关键词专用字段 | 配置项 | 说明 | 取值 | |-------|------|--------| -| label | 关键词标签("关键词:" / "Keywords:")的字符格式 | 子配置(继承 global_format 的 15 个字段) | +| label | 关键词标签("关键词:" / "Keywords:")的字符格式 | 子配置(继承 global_format 的 16 个字段) | | label.bold | 标签是否加粗 | true/false | | label.chinese_font_name | 标签中文字体 | 宋体、黑体 等 | | label.font_size | 标签字号 | 四号、小四 等 | -| count_min | 最少关键词数量 | 正整数 | -| count_max | 最多关键词数量 | 正整数 | -| trailing_punct_forbidden | 是否禁止末尾标点 | true/false | - -### 图表专用字段 +| rules.keyword_count | 关键词数量校验规则 | 子配置 | +| rules.keyword_count.enabled | 是否启用数量校验 | true/false | +| rules.keyword_count.count_min | 最少关键词数量 | 正整数 | +| rules.keyword_count.count_max | 最多关键词数量 | 正整数 | +| rules.trailing_punctuation | 末尾标点校验规则(仅中文) | 子配置 | +| rules.trailing_punctuation.enabled | 是否启用末尾标点校验 | true/false | +| rules.trailing_punctuation.forbidden_chars | 禁止出现在末尾的标点 | 字符串 | + +### 题注专用字段 | 配置项 | 说明 | 可选值 | |-------|------|--------| -| caption_position | 题注位置 | above(上方)、below(下方) | | caption_prefix | 题注前缀 | 图、表 | +| rules.caption_numbering | 题注编号校验/修正规则 | 子配置 | +| rules.caption_numbering.enabled | 是否启用编号校验 | true/false | +| rules.caption_numbering.separator | 章节号与编号间分隔符 | . - : — – | +| rules.caption_numbering.label_number_space | 标签与编号间是否加空格 | true/false | ### 参考文献专用字段 | 配置项 | 说明 | 示例 | diff --git a/docs/rule-handler-guide.md b/docs/rule-handler-guide.md new file mode 100644 index 0000000..92a9ec5 --- /dev/null +++ b/docs/rule-handler-guide.md @@ -0,0 +1,166 @@ +# 规则 Handler 开发指南 + +声明式规则引擎让开发者只需专注"判断是否有格式问题",是否生效、何时生效全部由 YAML 配置决定。 + +## 快速开始 + +### 1. 定义规则配置模型 + +```python +# datamodel.py +from pydantic import BaseModel, Field + +class BaseRuleConfig(BaseModel): + """所有规则的基类,enabled 控制开关。""" + enabled: bool = Field(default=True) + +class MyCheckRule(BaseRuleConfig): + """自定义校验规则的配置参数。""" + threshold: int = Field(default=3, description="最小数量阈值") + strict_mode: bool = Field(default=False) + + +class MyRulesConfig(BaseModel): + """规则集合。""" + my_check: MyCheckRule = Field(default_factory=MyCheckRule) +``` + +### 2. 挂到目标 Config 上 + +```python +class MyNodeConfig(GlobalFormatConfig): + # ... 原有格式字段 ... + rules: MyRulesConfig = Field(default_factory=MyRulesConfig) +``` + +### 3. 注册 Handler + +```python +class MyNode(FormatNode[MyNodeConfig]): + NODE_TYPE = "my_node" + CONFIG_MODEL = MyNodeConfig + CONFIG_PATH = "my_node" + + # 注册:规则名 → handler 方法名 + RULES = {"my_check": "_handle_my_check"} + + def _base(self, doc, p, r): + """只做格式样式检查(ParagraphStyle / CharacterStyle)。""" + ... + + def _handle_my_check(self, doc, rule_cfg: MyCheckRule, p: bool): + """业务规则:只管判断,不关心 enabled。""" + count = len(self.paragraph.text.split()) + if count < rule_cfg.threshold: + self.add_comment( + doc=doc, + runs=self.paragraph.runs, + text=f"数量不足(最少 {rule_cfg.threshold},当前 {count})", + ) +``` + +### 4. YAML 配置 + +```yaml +my_node: + <<: *global_format + rules: + my_check: + enabled: true # false 则整个 handler 不执行 + threshold: 5 + strict_mode: true +``` + +--- + +## Handler 签名 + +``` +handler(self, doc: Document, rule_cfg: RuleConfig, p: bool) -> None +``` + +| 参数 | 说明 | +|------|------| +| `doc` | python-docx 的 `Document` 对象,用于 `add_comment` | +| `rule_cfg` | 规则对应的 Pydantic 配置对象,`enabled` 已被框架检查过 | +| `p` | `True` = 检查模式(diff),`False` = 应用模式(apply) | + +**进入 handler 时 `enabled` 已为 `True`**,不需要在 handler 里再判断。 + +--- + +## 示例 + +### 示例 1:纯检查型规则(关键词数量) + +不需要区分 check/apply 模式,只做计数 + 报警。 + +```python +RULES = {"keyword_count": "_check_keyword_count"} + +def _check_keyword_count(self, doc, rule_cfg: KeywordCountRule, p: bool = False): + keyword_text = "".join(run.text for run in self.paragraph.runs) + keyword_list = [ + k.strip() for k in re.split(r"[;,]", keyword_text) if k.strip() + ] + if len(keyword_list) < rule_cfg.count_min: + self.add_comment( + doc=doc, runs=self.paragraph.runs, + text=f"数量不足(最少 {rule_cfg.count_min},当前 {len(keyword_list)})", + ) +``` + +### 示例 2:区分 check/apply 的规则(题注编号) + +check 模式加批注,apply 模式直接改文本。 + +```python +RULES = {"caption_numbering": "_handle_caption_numbering"} + +def _handle_caption_numbering(self, doc, rule_cfg: CaptionNumberingConfig, p: bool): + prefix = self.pydantic_config.caption_prefix or "图" + if p: + _check_caption_numbering(self, doc, prefix, rule_cfg) # 加批注 + else: + _apply_caption_numbering(self, prefix, rule_cfg) # 直接改 +``` + +### 示例 3:注册多个规则 + +```python +RULES = { + "keyword_count": "_check_keyword_count", + "trailing_punctuation": "_check_trailing_punctuation", +} + +def _check_keyword_count(self, doc, rule_cfg: KeywordCountRule, p: bool = False): + ... + +def _check_trailing_punctuation(self, doc, rule_cfg: TrailingPunctRule, p: bool = False): + text = "".join(r.text for r in self.paragraph.runs).strip() + if text and text[-1] in rule_cfg.forbidden_chars: + self.add_comment(doc=doc, runs=self.paragraph.runs, text="末尾禁止标点") +``` + +--- + +## 执行流程 + +``` +check_format(doc) + ├── _base(doc, p=True, r=True) ← 格式样式(自动) + └── _run_rules(doc, p=True) ← 业务规则(自动) + ├── 读 config.rules + ├── 比对 RULES ↔ config(不匹配则 warning) + └── 遍历 RULES: + enabled=True → handler(doc, rule_cfg, p) + enabled=False → 跳过 +``` + +## 注意事项 + +- **`_base()` 只放格式样式检查**(`ParagraphStyle` / `CharacterStyle`),不要在里面直接写业务判断 +- **Handler 里不要检查 `enabled`**——框架已过滤,能进来说明已启用 +- **`p` 参数默认值设为 `False`**(`p: bool = False`),兼容不需要区分模式的 handler +- **Handler 不应有返回值**——结果全部通过 `self.add_comment()` 上报 +- **新增配置模型记得在 `LEAF_TYPES` 注册**(`cli.py:58`),否则 `wordf config` 会把它当容器继续往下展开而非打印字段 diff --git a/example/undergrad_thesis.yaml b/example/undergrad_thesis.yaml index d7f321b..f5e1765 100644 --- a/example/undergrad_thesis.yaml +++ b/example/undergrad_thesis.yaml @@ -14,25 +14,27 @@ # 对齐:左对齐 / 居中对齐 / 右对齐 / 两端对齐 / 分散对齐 # =========================================================================== +template_name: "山西晋中理工学院(毕业设计)" + # --------------------------------------------------------------------------- # 预警开关:控制各字段差异是否在批注中显示(false=不显示该类型差异) # --------------------------------------------------------------------------- style_checks_warning: - bold: false + bold: true italic: false underline: false - font_size: false - font_name: false + font_size: true + font_name: true font_color: false - alignment: false - space_before: false - space_after: false - line_spacing: false - line_spacingrule: false - left_indent: false - right_indent: false - first_line_indent: false - builtin_style_name: false + alignment: true + space_before: true + space_after: true + line_spacing: true + line_spacingrule: true + left_indent: true + right_indent: true + first_line_indent: true + builtin_style_name: true # --------------------------------------------------------------------------- # 全局基础格式(其他节通过 <<: *global_format 继承后再覆写) @@ -71,7 +73,7 @@ abstract: alignment: '居中对齐' first_line_indent: '0字符' chinese_font_name: '黑体' - font_size: '小二' + font_size: '四号' bold: false # -- 中文摘要正文 -- @@ -88,8 +90,8 @@ abstract: <<: *global_format alignment: '居中对齐' first_line_indent: '0字符' - font_size: '小四' - bold: true + font_size: '四号' + bold: false # -- 英文摘要正文 -- english_content: @@ -103,32 +105,39 @@ abstract: chinese: # 从 global_format 继承,再覆写关键词特有字段 <<: *global_format - alignment: '左对齐' - first_line_indent: '0字符' - font_size: '四号' + alignment: '两端对齐' + first_line_indent: '2字符' + font_size: '小四' # -- 关键词标签("关键词:")的字符格式 -- label: <<: *global_format chinese_font_name: '黑体' font_size: '四号' - bold: true - # -- 关键词数量和标点校验 -- - count_min: 3 # 最少关键词数 - count_max: 5 # 最多关键词数 - trailing_punct_forbidden: true # 中文关键词末尾是否禁止标点 + bold: false + # -- 关键词业务规则(均通过 enabled 开关控制) -- + rules: + keyword_count: + enabled: true + count_min: 3 # 最少关键词数 + count_max: 5 # 最多关键词数 + trailing_punctuation: + enabled: true + forbidden_chars: ";,。、" # 中文关键词末尾禁止出现的标点 english: <<: *global_format - alignment: '左对齐' - first_line_indent: '0字符' - font_size: '四号' + alignment: '两端对齐' + first_line_indent: '2字符' + font_size: '小四' label: <<: *global_format font_size: '四号' - bold: true - count_min: 3 - count_max: 5 - trailing_punct_forbidden: true + bold: false + rules: + keyword_count: + enabled: true + count_min: 3 + count_max: 5 # =========================================================================== # 各级标题(章、节、小节) @@ -154,8 +163,8 @@ headings: chinese_font_name: '黑体' font_size: '三号' bold: false - space_before: "0.5行" - space_after: "0.5行" + space_before: "0行" + space_after: "0行" builtin_style_name: 'Heading 2' # -- 三级标题(1.1.1)-- @@ -166,8 +175,8 @@ headings: chinese_font_name: '黑体' font_size: '小四' bold: false - space_before: "0.5行" - space_after: "0.5行" + space_before: "0行" + space_after: "0行" builtin_style_name: 'Heading 3' # =========================================================================== @@ -175,6 +184,9 @@ headings: # =========================================================================== body_text: <<: *global_format + rules: + punctuation: + enabled: true # =========================================================================== # 插图题注(Figure) @@ -187,9 +199,19 @@ figures: first_line_indent: '0字符' # -- 插图特有字段 -- caption_prefix: '图' # 图注编号前缀 + # -- 图片段落格式(包含内联图片的段落)-- + image: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false # =========================================================================== -# 表格(题注 + 表格内容) +# 表格(题注 + 表格对象 + 表格内容) # =========================================================================== tables: <<: *global_format @@ -199,6 +221,11 @@ tables: first_line_indent: '0字符' # -- 表格题注特有字段 -- caption_prefix: '表' # 表注编号前缀 + # -- 表格对象格式(表格整体对齐、环绕)-- + object: + <<: *global_format + alignment: '居中对齐' + first_line_indent: '0字符' # -- 表格内容格式(单元格内文字)-- content: <<: *global_format @@ -210,6 +237,11 @@ tables: first_line_indent: '0字符' space_before: "0行" space_after: "0行" + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false # =========================================================================== # 参考文献 diff --git a/pyproject.toml b/pyproject.toml index 64b59b0..602251a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "wordformat" -version = "1.3.2" +version = "1.4.0" description = "论文格式自动化处理工具" readme = "README.md" license = "Apache-2.0" diff --git a/src/wordformat/_version.py b/src/wordformat/_version.py index 0ba3485..b3d780d 100644 --- a/src/wordformat/_version.py +++ b/src/wordformat/_version.py @@ -1,3 +1,3 @@ # 此文件由 scripts/sync_version.py 自动生成,请勿手动编辑。 # 版本号唯一来源为 pyproject.toml。 -__version__ = "1.3.2" +__version__ = "1.4.0" diff --git a/src/wordformat/api/__init__.py b/src/wordformat/api/__init__.py index 65304a8..07bf362 100644 --- a/src/wordformat/api/__init__.py +++ b/src/wordformat/api/__init__.py @@ -274,6 +274,55 @@ def download_file(filename: str): raise HTTPException(status_code=500, detail=f"文件下载失败:{str(e)}") from e +# ---------------------- 配置文件管理 ---------------------- +CONFIGS_DIR = BASE_DIR / "configs" +CONFIGS_DIR.mkdir(parents=True, exist_ok=True) + + +@app.get("/configs", summary="获取可用配置文件列表") +def list_configs(): + """返回 configs 目录下的所有 YAML 文件名。""" + try: + files = [f.name for f in CONFIGS_DIR.glob("*.yaml") if f.is_file()] + [ + f.name for f in CONFIGS_DIR.glob("*.yml") if f.is_file() + ] + return {"code": 200, "data": sorted(set(files))} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + + +@app.get("/configs/{filename}", summary="读取指定配置文件内容") +def read_config(filename: str): + """返回配置文件 YAML 内容。""" + file_path = CONFIGS_DIR / filename + if not file_path.is_file(): + raise HTTPException(status_code=404, detail=f"配置文件 {filename} 不存在") + try: + with open(file_path, encoding="utf-8") as f: + return {"code": 200, "data": f.read()} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + + +class SaveConfigRequest(BaseModel): + filename: str + content: str + + +@app.post("/configs/save", summary="保存配置文件到 configs 目录") +def save_config(req: SaveConfigRequest): + """将 YAML 内容保存到 configs 目录。""" + if not req.filename.endswith((".yaml", ".yml")): + req.filename += ".yaml" + file_path = CONFIGS_DIR / req.filename + try: + with open(file_path, "w", encoding="utf-8") as f: + f.write(req.content) + return {"code": 200, "msg": f"配置已保存到 configs/{req.filename}"} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + + # ---------------------- 前端静态文件(Vue SPA)--------------------- # 路由优先级:API 路由(已定义)> 静态文件 # html=True 会自动将 / 映射到 index.html diff --git a/src/wordformat/api/static/assets/index-BBrpGIev.js b/src/wordformat/api/static/assets/index-BBrpGIev.js deleted file mode 100644 index f25e3f4..0000000 --- a/src/wordformat/api/static/assets/index-BBrpGIev.js +++ /dev/null @@ -1,60 +0,0 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))i(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const s of o.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&i(s)}).observe(document,{childList:!0,subtree:!0});function n(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function i(r){if(r.ep)return;r.ep=!0;const o=n(r);fetch(r.href,o)}})();/** -* @vue/shared v3.5.34 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/function fo(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const he={},Cn=[],Tt=()=>{},al=()=>!1,Qi=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Zi=e=>e.startsWith("onUpdate:"),Ne=Object.assign,po=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},Zc=Object.prototype.hasOwnProperty,ce=(e,t)=>Zc.call(e,t),W=Array.isArray,Sn=e=>hi(e)==="[object Map]",$n=e=>hi(e)==="[object Set]",Ko=e=>hi(e)==="[object Date]",Q=e=>typeof e=="function",ye=e=>typeof e=="string",ut=e=>typeof e=="symbol",ue=e=>e!==null&&typeof e=="object",cl=e=>(ue(e)||Q(e))&&Q(e.then)&&Q(e.catch),ul=Object.prototype.toString,hi=e=>ul.call(e),eu=e=>hi(e).slice(8,-1),fl=e=>hi(e)==="[object Object]",ho=e=>ye(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,zn=fo(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),er=e=>{const t=Object.create(null);return(n=>t[n]||(t[n]=e(n)))},tu=/-\w/g,at=er(e=>e.replace(tu,t=>t.slice(1).toUpperCase())),nu=/\B([A-Z])/g,gn=er(e=>e.replace(nu,"-$1").toLowerCase()),dl=er(e=>e.charAt(0).toUpperCase()+e.slice(1)),yr=er(e=>e?`on${dl(e)}`:""),Et=(e,t)=>!Object.is(e,t),Ti=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:i,value:n})},tr=e=>{const t=parseFloat(e);return isNaN(t)?e:t},iu=e=>{const t=ye(e)?Number(e):NaN;return isNaN(t)?e:t};let Wo;const nr=()=>Wo||(Wo=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Rn(e){if(W(e)){const t={};for(let n=0;n{if(n){const i=n.split(ou);i.length>1&&(t[i[0].trim()]=i[1].trim())}}),t}function ve(e){let t="";if(ye(e))t=e;else if(W(e))for(let n=0;nPn(n,t))}const gl=e=>!!(e&&e.__v_isRef===!0),ee=e=>ye(e)?e:e==null?"":W(e)||ue(e)&&(e.toString===ul||!Q(e.toString))?gl(e)?ee(e.value):JSON.stringify(e,ml,2):String(e),ml=(e,t)=>gl(t)?ml(e,t.value):Sn(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[i,r],o)=>(n[vr(i,o)+" =>"]=r,n),{})}:$n(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>vr(n))}:ut(t)?vr(t):ue(t)&&!W(t)&&!fl(t)?String(t):t,vr=(e,t="")=>{var n;return ut(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** -* @vue/reactivity v3.5.34 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/let $e;class fu{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&$e&&($e.active?(this.parent=$e,this.index=($e.scopes||($e.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t0&&--this._on===0){if($e===this)$e=this.prevScope;else{let t=$e;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let n,i;for(n=0,i=this.effects.length;n0)return;if(Xn){let t=Xn;for(Xn=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;Gn;){let t=Gn;for(Gn=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(i){e||(e=i)}t=n}}if(e)throw e}function _l(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function xl(e){let t,n=e.depsTail,i=n;for(;i;){const r=i.prevDep;i.version===-1?(i===n&&(n=r),yo(i),pu(i)):t=i,i.dep.activeLink=i.prevActiveLink,i.prevActiveLink=void 0,i=r}e.deps=t,e.depsTail=n}function jr(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(wl(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function wl(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===ti)||(e.globalVersion=ti,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!jr(e))))return;e.flags|=2;const t=e.dep,n=me,i=ct;me=e,ct=!0;try{_l(e);const r=e.fn(e._value);(t.version===0||Et(r,e._value))&&(e.flags|=128,e._value=r,t.version++)}catch(r){throw t.version++,r}finally{me=n,ct=i,xl(e),e.flags&=-3}}function yo(e,t=!1){const{dep:n,prevSub:i,nextSub:r}=e;if(i&&(i.nextSub=r,e.prevSub=void 0),r&&(r.prevSub=i,e.nextSub=void 0),n.subs===e&&(n.subs=i,!i&&n.computed)){n.computed.flags&=-5;for(let o=n.computed.deps;o;o=o.nextDep)yo(o,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function pu(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let ct=!0;const Al=[];function Ut(){Al.push(ct),ct=!1}function jt(){const e=Al.pop();ct=e===void 0?!0:e}function Yo(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=me;me=void 0;try{t()}finally{me=n}}}let ti=0;class hu{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class vo{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!me||!ct||me===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==me)n=this.activeLink=new hu(me,this),me.deps?(n.prevDep=me.depsTail,me.depsTail.nextDep=n,me.depsTail=n):me.deps=me.depsTail=n,Cl(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const i=n.nextDep;i.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=i),n.prevDep=me.depsTail,n.nextDep=void 0,me.depsTail.nextDep=n,me.depsTail=n,me.deps===n&&(me.deps=i)}return n}trigger(t){this.version++,ti++,this.notify(t)}notify(t){mo();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{bo()}}}function Cl(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let i=t.deps;i;i=i.nextDep)Cl(i)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const Br=new WeakMap,an=Symbol(""),Hr=Symbol(""),ni=Symbol("");function Me(e,t,n){if(ct&&me){let i=Br.get(e);i||Br.set(e,i=new Map);let r=i.get(n);r||(i.set(n,r=new vo),r.map=i,r.key=n),r.track()}}function Pt(e,t,n,i,r,o){const s=Br.get(e);if(!s){ti++;return}const l=a=>{a&&a.trigger()};if(mo(),t==="clear")s.forEach(l);else{const a=W(e),c=a&&ho(n);if(a&&n==="length"){const u=Number(i);s.forEach((d,h)=>{(h==="length"||h===ni||!ut(h)&&h>=u)&&l(d)})}else switch((n!==void 0||s.has(void 0))&&l(s.get(n)),c&&l(s.get(ni)),t){case"add":a?c&&l(s.get("length")):(l(s.get(an)),Sn(e)&&l(s.get(Hr)));break;case"delete":a||(l(s.get(an)),Sn(e)&&l(s.get(Hr)));break;case"set":Sn(e)&&l(s.get(an));break}}bo()}function mn(e){const t=le(e);return t===e?t:(Me(t,"iterate",ni),lt(e)?t:t.map(ft))}function ir(e){return Me(e=le(e),"iterate",ni),e}function Ct(e,t){return Bt(e)?Fn(cn(e)?ft(t):t):ft(t)}const gu={__proto__:null,[Symbol.iterator](){return xr(this,Symbol.iterator,e=>Ct(this,e))},concat(...e){return mn(this).concat(...e.map(t=>W(t)?mn(t):t))},entries(){return xr(this,"entries",e=>(e[1]=Ct(this,e[1]),e))},every(e,t){return Lt(this,"every",e,t,void 0,arguments)},filter(e,t){return Lt(this,"filter",e,t,n=>n.map(i=>Ct(this,i)),arguments)},find(e,t){return Lt(this,"find",e,t,n=>Ct(this,n),arguments)},findIndex(e,t){return Lt(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return Lt(this,"findLast",e,t,n=>Ct(this,n),arguments)},findLastIndex(e,t){return Lt(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return Lt(this,"forEach",e,t,void 0,arguments)},includes(...e){return wr(this,"includes",e)},indexOf(...e){return wr(this,"indexOf",e)},join(e){return mn(this).join(e)},lastIndexOf(...e){return wr(this,"lastIndexOf",e)},map(e,t){return Lt(this,"map",e,t,void 0,arguments)},pop(){return jn(this,"pop")},push(...e){return jn(this,"push",e)},reduce(e,...t){return Jo(this,"reduce",e,t)},reduceRight(e,...t){return Jo(this,"reduceRight",e,t)},shift(){return jn(this,"shift")},some(e,t){return Lt(this,"some",e,t,void 0,arguments)},splice(...e){return jn(this,"splice",e)},toReversed(){return mn(this).toReversed()},toSorted(e){return mn(this).toSorted(e)},toSpliced(...e){return mn(this).toSpliced(...e)},unshift(...e){return jn(this,"unshift",e)},values(){return xr(this,"values",e=>Ct(this,e))}};function xr(e,t,n){const i=ir(e),r=i[t]();return i!==e&&!lt(e)&&(r._next=r.next,r.next=()=>{const o=r._next();return o.done||(o.value=n(o.value)),o}),r}const mu=Array.prototype;function Lt(e,t,n,i,r,o){const s=ir(e),l=s!==e&&!lt(e),a=s[t];if(a!==mu[t]){const d=a.apply(e,o);return l?ft(d):d}let c=n;s!==e&&(l?c=function(d,h){return n.call(this,Ct(e,d),h,e)}:n.length>2&&(c=function(d,h){return n.call(this,d,h,e)}));const u=a.call(s,c,i);return l&&r?r(u):u}function Jo(e,t,n,i){const r=ir(e),o=r!==e&&!lt(e);let s=n,l=!1;r!==e&&(o?(l=i.length===0,s=function(c,u,d){return l&&(l=!1,c=Ct(e,c)),n.call(this,c,Ct(e,u),d,e)}):n.length>3&&(s=function(c,u,d){return n.call(this,c,u,d,e)}));const a=r[t](s,...i);return l?Ct(e,a):a}function wr(e,t,n){const i=le(e);Me(i,"iterate",ni);const r=i[t](...n);return(r===-1||r===!1)&&wo(n[0])?(n[0]=le(n[0]),i[t](...n)):r}function jn(e,t,n=[]){Ut(),mo();const i=le(e)[t].apply(e,n);return bo(),jt(),i}const bu=fo("__proto__,__v_isRef,__isVue"),Sl=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(ut));function yu(e){ut(e)||(e=String(e));const t=le(this);return Me(t,"has",e),t.hasOwnProperty(e)}class El{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,i){if(n==="__v_skip")return t.__v_skip;const r=this._isReadonly,o=this._isShallow;if(n==="__v_isReactive")return!r;if(n==="__v_isReadonly")return r;if(n==="__v_isShallow")return o;if(n==="__v_raw")return i===(r?o?Tu:Fl:o?Rl:Tl).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(i)?t:void 0;const s=W(t);if(!r){let a;if(s&&(a=gu[n]))return a;if(n==="hasOwnProperty")return yu}const l=Reflect.get(t,n,Be(t)?t:i);if((ut(n)?Sl.has(n):bu(n))||(r||Me(t,"get",n),o))return l;if(Be(l)){const a=s&&ho(n)?l:l.value;return r&&ue(a)?qr(a):a}return ue(l)?r?qr(l):rr(l):l}}class Ol extends El{constructor(t=!1){super(!1,t)}set(t,n,i,r){let o=t[n];const s=W(t)&&ho(n);if(!this._isShallow){const c=Bt(o);if(!lt(i)&&!Bt(i)&&(o=le(o),i=le(i)),!s&&Be(o)&&!Be(i))return c||(o.value=i),!0}const l=s?Number(n)e,Ai=e=>Reflect.getPrototypeOf(e);function Au(e,t,n){return function(...i){const r=this.__v_raw,o=le(r),s=Sn(o),l=e==="entries"||e===Symbol.iterator&&s,a=e==="keys"&&s,c=r[e](...i),u=n?Vr:t?Fn:ft;return!t&&Me(o,"iterate",a?Hr:an),Ne(Object.create(c),{next(){const{value:d,done:h}=c.next();return h?{value:d,done:h}:{value:l?[u(d[0]),u(d[1])]:u(d),done:h}}})}}function Ci(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function Cu(e,t){const n={get(r){const o=this.__v_raw,s=le(o),l=le(r);e||(Et(r,l)&&Me(s,"get",r),Me(s,"get",l));const{has:a}=Ai(s),c=t?Vr:e?Fn:ft;if(a.call(s,r))return c(o.get(r));if(a.call(s,l))return c(o.get(l));o!==s&&o.get(r)},get size(){const r=this.__v_raw;return!e&&Me(le(r),"iterate",an),r.size},has(r){const o=this.__v_raw,s=le(o),l=le(r);return e||(Et(r,l)&&Me(s,"has",r),Me(s,"has",l)),r===l?o.has(r):o.has(r)||o.has(l)},forEach(r,o){const s=this,l=s.__v_raw,a=le(l),c=t?Vr:e?Fn:ft;return!e&&Me(a,"iterate",an),l.forEach((u,d)=>r.call(o,c(u),c(d),s))}};return Ne(n,e?{add:Ci("add"),set:Ci("set"),delete:Ci("delete"),clear:Ci("clear")}:{add(r){const o=le(this),s=Ai(o),l=le(r),a=!t&&!lt(r)&&!Bt(r)?l:r;return s.has.call(o,a)||Et(r,a)&&s.has.call(o,r)||Et(l,a)&&s.has.call(o,l)||(o.add(a),Pt(o,"add",a,a)),this},set(r,o){!t&&!lt(o)&&!Bt(o)&&(o=le(o));const s=le(this),{has:l,get:a}=Ai(s);let c=l.call(s,r);c||(r=le(r),c=l.call(s,r));const u=a.call(s,r);return s.set(r,o),c?Et(o,u)&&Pt(s,"set",r,o):Pt(s,"add",r,o),this},delete(r){const o=le(this),{has:s,get:l}=Ai(o);let a=s.call(o,r);a||(r=le(r),a=s.call(o,r)),l&&l.call(o,r);const c=o.delete(r);return a&&Pt(o,"delete",r,void 0),c},clear(){const r=le(this),o=r.size!==0,s=r.clear();return o&&Pt(r,"clear",void 0,void 0),s}}),["keys","values","entries",Symbol.iterator].forEach(r=>{n[r]=Au(r,e,t)}),n}function _o(e,t){const n=Cu(e,t);return(i,r,o)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?i:Reflect.get(ce(n,r)&&r in i?n:i,r,o)}const Su={get:_o(!1,!1)},Eu={get:_o(!1,!0)},Ou={get:_o(!0,!1)};const Tl=new WeakMap,Rl=new WeakMap,Fl=new WeakMap,Tu=new WeakMap;function Ru(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Fu(e){return e.__v_skip||!Object.isExtensible(e)?0:Ru(eu(e))}function rr(e){return Bt(e)?e:xo(e,!1,_u,Su,Tl)}function Nu(e){return xo(e,!1,wu,Eu,Rl)}function qr(e){return xo(e,!0,xu,Ou,Fl)}function xo(e,t,n,i,r){if(!ue(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const o=Fu(e);if(o===0)return e;const s=r.get(e);if(s)return s;const l=new Proxy(e,o===2?i:n);return r.set(e,l),l}function cn(e){return Bt(e)?cn(e.__v_raw):!!(e&&e.__v_isReactive)}function Bt(e){return!!(e&&e.__v_isReadonly)}function lt(e){return!!(e&&e.__v_isShallow)}function wo(e){return e?!!e.__v_raw:!1}function le(e){const t=e&&e.__v_raw;return t?le(t):e}function ku(e){return!ce(e,"__v_skip")&&Object.isExtensible(e)&&pl(e,"__v_skip",!0),e}const ft=e=>ue(e)?rr(e):e,Fn=e=>ue(e)?qr(e):e;function Be(e){return e?e.__v_isRef===!0:!1}function be(e){return Lu(e,!1)}function Lu(e,t){return Be(e)?e:new Iu(e,t)}class Iu{constructor(t,n){this.dep=new vo,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:le(t),this._value=n?t:ft(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,i=this.__v_isShallow||lt(t)||Bt(t);t=i?t:le(t),Et(t,n)&&(this._rawValue=t,this._value=i?t:ft(t),this.dep.trigger())}}function Ye(e){return Be(e)?e.value:e}const $u={get:(e,t,n)=>t==="__v_raw"?e:Ye(Reflect.get(e,t,n)),set:(e,t,n,i)=>{const r=e[t];return Be(r)&&!Be(n)?(r.value=n,!0):Reflect.set(e,t,n,i)}};function Nl(e){return cn(e)?e:new Proxy(e,$u)}class Pu{constructor(t,n,i){this.fn=t,this.setter=n,this._value=void 0,this.dep=new vo(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=ti-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=i}notify(){if(this.flags|=16,!(this.flags&8)&&me!==this)return vl(this,!0),!0}get value(){const t=this.dep.track();return wl(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function Du(e,t,n=!1){let i,r;return Q(e)?i=e:(i=e.get,r=e.set),new Pu(i,r,n)}const Si={},$i=new WeakMap;let rn;function Mu(e,t=!1,n=rn){if(n){let i=$i.get(n);i||$i.set(n,i=[]),i.push(e)}}function Uu(e,t,n=he){const{immediate:i,deep:r,once:o,scheduler:s,augmentJob:l,call:a}=n,c=R=>r?R:lt(R)||r===!1||r===0?Dt(R,1):Dt(R);let u,d,h,b,v=!1,g=!1;if(Be(e)?(d=()=>e.value,v=lt(e)):cn(e)?(d=()=>c(e),v=!0):W(e)?(g=!0,v=e.some(R=>cn(R)||lt(R)),d=()=>e.map(R=>{if(Be(R))return R.value;if(cn(R))return c(R);if(Q(R))return a?a(R,2):R()})):Q(e)?t?d=a?()=>a(e,2):e:d=()=>{if(h){Ut();try{h()}finally{jt()}}const R=rn;rn=u;try{return a?a(e,3,[b]):e(b)}finally{rn=R}}:d=Tt,t&&r){const R=d,G=r===!0?1/0:r;d=()=>Dt(R(),G)}const _=du(),A=()=>{u.stop(),_&&_.active&&po(_.effects,u)};if(o&&t){const R=t;t=(...G)=>{R(...G),A()}}let C=g?new Array(e.length).fill(Si):Si;const $=R=>{if(!(!(u.flags&1)||!u.dirty&&!R))if(t){const G=u.run();if(r||v||(g?G.some((re,J)=>Et(re,C[J])):Et(G,C))){h&&h();const re=rn;rn=u;try{const J=[G,C===Si?void 0:g&&C[0]===Si?[]:C,b];C=G,a?a(t,3,J):t(...J)}finally{rn=re}}}else u.run()};return l&&l($),u=new bl(d),u.scheduler=s?()=>s($,!1):$,b=R=>Mu(R,!1,u),h=u.onStop=()=>{const R=$i.get(u);if(R){if(a)a(R,4);else for(const G of R)G();$i.delete(u)}},t?i?$(!0):C=u.run():s?s($.bind(null,!0),!0):u.run(),A.pause=u.pause.bind(u),A.resume=u.resume.bind(u),A.stop=A,A}function Dt(e,t=1/0,n){if(t<=0||!ue(e)||e.__v_skip||(n=n||new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,Be(e))Dt(e.value,t,n);else if(W(e))for(let i=0;i{Dt(i,t,n)});else if(fl(e)){for(const i in e)Dt(e[i],t,n);for(const i of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,i)&&Dt(e[i],t,n)}return e}/** -* @vue/runtime-core v3.5.34 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/function gi(e,t,n,i){try{return i?e(...i):e()}catch(r){or(r,t,n)}}function dt(e,t,n,i){if(Q(e)){const r=gi(e,t,n,i);return r&&cl(r)&&r.catch(o=>{or(o,t,n)}),r}if(W(e)){const r=[];for(let o=0;o>>1,r=We[i],o=ii(r);o=ii(n)?We.push(e):We.splice(Bu(t),0,e),e.flags|=1,Il()}}function Il(){Pi||(Pi=kl.then(Pl))}function Hu(e){W(e)?En.push(...e):Jt&&e.id===-1?Jt.splice(vn+1,0,e):e.flags&1||(En.push(e),e.flags|=1),Il()}function zo(e,t,n=At+1){for(;nii(n)-ii(i));if(En.length=0,Jt){Jt.push(...t);return}for(Jt=t,vn=0;vne.id==null?e.flags&2?-1:1/0:e.id;function Pl(e){try{for(At=0;At{i._d&&as(-1);const o=Di(t);let s;try{s=e(...r)}finally{Di(o),i._d&&as(1)}return s};return i._n=!0,i._c=!0,i._d=!0,i}function M(e,t){if(je===null)return e;const n=cr(je),i=e.dirs||(e.dirs=[]);for(let r=0;r1)return n&&Q(t)?t.call(i&&i.proxy):t}}const qu=Symbol.for("v-scx"),Ku=()=>Ri(qu);function un(e,t,n){return Ml(e,t,n)}function Ml(e,t,n=he){const{immediate:i,deep:r,flush:o,once:s}=n,l=Ne({},n),a=t&&i||!t&&o!=="post";let c;if(li){if(o==="sync"){const b=Ku();c=b.__watcherHandles||(b.__watcherHandles=[])}else if(!a){const b=()=>{};return b.stop=Tt,b.resume=Tt,b.pause=Tt,b}}const u=Je;l.call=(b,v,g)=>dt(b,u,v,g);let d=!1;o==="post"?l.scheduler=b=>{Ke(b,u&&u.suspense)}:o!=="sync"&&(d=!0,l.scheduler=(b,v)=>{v?b():Ao(b)}),l.augmentJob=b=>{t&&(b.flags|=4),d&&(b.flags|=2,u&&(b.id=u.uid,b.i=u))};const h=Uu(e,t,l);return li&&(c?c.push(h):a&&h()),h}function Wu(e,t,n){const i=this.proxy,r=ye(e)?e.includes(".")?Ul(i,e):()=>i[e]:e.bind(i,i);let o;Q(t)?o=t:(o=t.handler,n=t);const s=bi(this),l=Ml(r,o.bind(i),n);return s(),l}function Ul(e,t){const n=t.split(".");return()=>{let i=e;for(let r=0;re.__isTeleport,on=e=>e&&(e.disabled||e.disabled===""),Ju=e=>e&&(e.defer||e.defer===""),Go=e=>typeof SVGElement<"u"&&e instanceof SVGElement,Xo=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,Kr=(e,t)=>{const n=e&&e.to;return ye(n)?t?t(n):null:n},zu={name:"Teleport",__isTeleport:!0,process(e,t,n,i,r,o,s,l,a,c){const{mc:u,pc:d,pbc:h,o:{insert:b,querySelector:v,createText:g,createComment:_,parentNode:A}}=c,C=on(t.props);let{dynamicChildren:$}=t;const R=(J,ne,U)=>{J.shapeFlag&16&&u(J.children,ne,U,r,o,s,l,a)},G=(J=t)=>{const ne=on(J.props),U=J.target=Kr(J.props,v),X=Wr(U,J,g,b);U&&(s!=="svg"&&Go(U)?s="svg":s!=="mathml"&&Xo(U)&&(s="mathml"),r&&r.isCE&&(r.ce._teleportTargets||(r.ce._teleportTargets=new Set)).add(U),ne||(R(J,U,X),Kn(J,!1)))},re=J=>{const ne=()=>{if(Kt.get(J)===ne){if(Kt.delete(J),on(J.props)){const U=A(J.el)||n;R(J,U,J.anchor),Kn(J,!0)}G(J)}};Kt.set(J,ne),Ke(ne,o)};if(e==null){const J=t.el=g(""),ne=t.anchor=g("");if(b(J,n,i),b(ne,n,i),Ju(t.props)||o&&o.pendingBranch){re(t);return}C&&(R(t,n,ne),Kn(t,!0)),G()}else{t.el=e.el;const J=t.anchor=e.anchor,ne=Kt.get(e);if(ne){ne.flags|=8,Kt.delete(e),re(t);return}t.targetStart=e.targetStart;const U=t.target=e.target,X=t.targetAnchor=e.targetAnchor,F=on(e.props),w=F?n:U,j=F?J:X;if(s==="svg"||Go(U)?s="svg":(s==="mathml"||Xo(U))&&(s="mathml"),$?(h(e.dynamicChildren,$,w,r,o,s,l),Eo(e,t,!0)):a||d(e,t,w,j,r,o,s,l,!1),C)F?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):Ei(t,n,J,c,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const D=t.target=Kr(t.props,v);D&&Ei(t,D,null,c,0)}else F&&Ei(t,U,X,c,1);Kn(t,C)}},remove(e,t,n,{um:i,o:{remove:r}},o){const{shapeFlag:s,children:l,anchor:a,targetStart:c,targetAnchor:u,target:d,props:h}=e;let b=o||!on(h);const v=Kt.get(e);if(v&&(v.flags|=8,Kt.delete(e),b=!1),d&&(r(c),r(u)),o&&r(a),s&16)for(let g=0;g{e.isMounted=!0}),Wl(()=>{e.isUnmounting=!0}),e}const rt=[Function,Array],Zu={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:rt,onEnter:rt,onAfterEnter:rt,onEnterCancelled:rt,onBeforeLeave:rt,onLeave:rt,onAfterLeave:rt,onLeaveCancelled:rt,onBeforeAppear:rt,onAppear:rt,onAfterAppear:rt,onAppearCancelled:rt};function ef(e,t){const{leavingVNodes:n}=e;let i=n.get(t.type);return i||(i=Object.create(null),n.set(t.type,i)),i}function Yr(e,t,n,i,r){const{appear:o,mode:s,persisted:l=!1,onBeforeEnter:a,onEnter:c,onAfterEnter:u,onEnterCancelled:d,onBeforeLeave:h,onLeave:b,onAfterLeave:v,onLeaveCancelled:g,onBeforeAppear:_,onAppear:A,onAfterAppear:C,onAppearCancelled:$}=t,R=String(e.key),G=ef(n,e),re=(U,X)=>{U&&dt(U,i,9,X)},J=(U,X)=>{const F=X[1];re(U,X),W(U)?U.every(w=>w.length<=1)&&F():U.length<=1&&F()},ne={mode:s,persisted:l,beforeEnter(U){let X=a;if(!n.isMounted)if(o)X=_||a;else return;U[Wt]&&U[Wt](!0);const F=G[R];F&&_n(e,F)&&F.el[Wt]&&F.el[Wt](),re(X,[U])},enter(U){if(G[R]===e)return;let X=c,F=u,w=d;if(!n.isMounted)if(o)X=A||c,F=C||u,w=$||d;else return;let j=!1;U[Bn]=se=>{j||(j=!0,se?re(w,[U]):re(F,[U]),ne.delayedLeave&&ne.delayedLeave(),U[Bn]=void 0)};const D=U[Bn].bind(null,!1);X?J(X,[U,D]):D()},leave(U,X){const F=String(e.key);if(U[Bn]&&U[Bn](!0),n.isUnmounting)return X();re(h,[U]);let w=!1;U[Wt]=D=>{w||(w=!0,X(),D?re(g,[U]):re(v,[U]),U[Wt]=void 0,G[F]===e&&delete G[F])};const j=U[Wt].bind(null,!1);G[F]=e,b?J(b,[U,j]):j()},clone(U){return Yr(U,t,n,i)}};return ne}function ri(e,t){e.shapeFlag&6&&e.component?(e.transition=t,ri(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Bl(e,t=!1,n){let i=[],r=0;for(let o=0;o1)for(let o=0;oQn(g,t&&(W(t)?t[_]:t),n,i,r));return}if(On(i)&&!r){i.shapeFlag&512&&i.type.__asyncResolved&&i.component.subTree.component&&Qn(e,t,n,i.component.subTree);return}const o=i.shapeFlag&4?cr(i.component):i.el,s=r?null:o,{i:l,r:a}=e,c=t&&t.r,u=l.refs===he?l.refs={}:l.refs,d=l.setupState,h=le(d),b=d===he?al:g=>Qo(u,g)?!1:ce(h,g),v=(g,_)=>!(_&&Qo(u,_));if(c!=null&&c!==a){if(Zo(t),ye(c))u[c]=null,b(c)&&(d[c]=null);else if(Be(c)){const g=t;v(c,g.k)&&(c.value=null),g.k&&(u[g.k]=null)}}if(Q(a))gi(a,l,12,[s,u]);else{const g=ye(a),_=Be(a);if(g||_){const A=()=>{if(e.f){const C=g?b(a)?d[a]:u[a]:v()||!e.k?a.value:u[e.k];if(r)W(C)&&po(C,o);else if(W(C))C.includes(o)||C.push(o);else if(g)u[a]=[o],b(a)&&(d[a]=u[a]);else{const $=[o];v(a,e.k)&&(a.value=$),e.k&&(u[e.k]=$)}}else g?(u[a]=s,b(a)&&(d[a]=s)):_&&(v(a,e.k)&&(a.value=s),e.k&&(u[e.k]=s))};if(s){const C=()=>{A(),Mi.delete(e)};C.id=-1,Mi.set(e,C),Ke(C,n)}else Zo(e),A()}}}function Zo(e){const t=Mi.get(e);t&&(t.flags|=8,Mi.delete(e))}nr().requestIdleCallback;nr().cancelIdleCallback;const On=e=>!!e.type.__asyncLoader,Vl=e=>e.type.__isKeepAlive;function tf(e,t){ql(e,"a",t)}function nf(e,t){ql(e,"da",t)}function ql(e,t,n=Je){const i=e.__wdc||(e.__wdc=()=>{let r=n;for(;r;){if(r.isDeactivated)return;r=r.parent}return e()});if(sr(t,i,n),n){let r=n.parent;for(;r&&r.parent;)Vl(r.parent.vnode)&&rf(i,t,n,r),r=r.parent}}function rf(e,t,n,i){const r=sr(t,e,i,!0);Yl(()=>{po(i[t],r)},n)}function sr(e,t,n=Je,i=!1){if(n){const r=n[e]||(n[e]=[]),o=t.__weh||(t.__weh=(...s)=>{Ut();const l=bi(n),a=dt(t,n,e,s);return l(),jt(),a});return i?r.unshift(o):r.push(o),o}}const Vt=e=>(t,n=Je)=>{(!li||e==="sp")&&sr(e,(...i)=>t(...i),n)},of=Vt("bm"),mi=Vt("m"),sf=Vt("bu"),Kl=Vt("u"),Wl=Vt("bum"),Yl=Vt("um"),lf=Vt("sp"),af=Vt("rtg"),cf=Vt("rtc");function uf(e,t=Je){sr("ec",e,t)}const ff=Symbol.for("v-ndc");function Gt(e,t,n,i){let r;const o=n,s=W(e);if(s||ye(e)){const l=s&&cn(e);let a=!1,c=!1;l&&(a=!lt(e),c=Bt(e),e=ir(e)),r=new Array(e.length);for(let u=0,d=e.length;ut(l,a,void 0,o));else{const l=Object.keys(e);r=new Array(l.length);for(let a=0,c=l.length;a0;return H(),si(_e,null,[B("slot",n,i)],c?-2:64)}let o=e[t];o&&o._c&&(o._d=!1),H();const s=o&&Jl(o(n)),l=n.key||s&&s.key,a=si(_e,{key:(l&&!ut(l)?l:`_${t}`)+(!s&&i?"_fb":"")},s||[],s&&e._===1?64:-2);return o&&o._c&&(o._d=!0),a}function Jl(e){return e.some(t=>Oo(t)?!(t.type===Ft||t.type===_e&&!Jl(t.children)):!0)?e:null}const Jr=e=>e?ha(e)?cr(e):Jr(e.parent):null,Zn=Ne(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Jr(e.parent),$root:e=>Jr(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Gl(e),$forceUpdate:e=>e.f||(e.f=()=>{Ao(e.update)}),$nextTick:e=>e.n||(e.n=Ll.bind(e.proxy)),$watch:e=>Wu.bind(e)}),Ar=(e,t)=>e!==he&&!e.__isScriptSetup&&ce(e,t),pf={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:n,setupState:i,data:r,props:o,accessCache:s,type:l,appContext:a}=e;if(t[0]!=="$"){const h=s[t];if(h!==void 0)switch(h){case 1:return i[t];case 2:return r[t];case 4:return n[t];case 3:return o[t]}else{if(Ar(i,t))return s[t]=1,i[t];if(r!==he&&ce(r,t))return s[t]=2,r[t];if(ce(o,t))return s[t]=3,o[t];if(n!==he&&ce(n,t))return s[t]=4,n[t];zr&&(s[t]=0)}}const c=Zn[t];let u,d;if(c)return t==="$attrs"&&Me(e.attrs,"get",""),c(e);if((u=l.__cssModules)&&(u=u[t]))return u;if(n!==he&&ce(n,t))return s[t]=4,n[t];if(d=a.config.globalProperties,ce(d,t))return d[t]},set({_:e},t,n){const{data:i,setupState:r,ctx:o}=e;return Ar(r,t)?(r[t]=n,!0):i!==he&&ce(i,t)?(i[t]=n,!0):ce(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(o[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:i,appContext:r,props:o,type:s}},l){let a;return!!(n[l]||e!==he&&l[0]!=="$"&&ce(e,l)||Ar(t,l)||ce(o,l)||ce(i,l)||ce(Zn,l)||ce(r.config.globalProperties,l)||(a=s.__cssModules)&&a[l])},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:ce(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function es(e){return W(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let zr=!0;function hf(e){const t=Gl(e),n=e.proxy,i=e.ctx;zr=!1,t.beforeCreate&&ts(t.beforeCreate,e,"bc");const{data:r,computed:o,methods:s,watch:l,provide:a,inject:c,created:u,beforeMount:d,mounted:h,beforeUpdate:b,updated:v,activated:g,deactivated:_,beforeDestroy:A,beforeUnmount:C,destroyed:$,unmounted:R,render:G,renderTracked:re,renderTriggered:J,errorCaptured:ne,serverPrefetch:U,expose:X,inheritAttrs:F,components:w,directives:j,filters:D}=t;if(c&&gf(c,i,null),s)for(const te in s){const ie=s[te];Q(ie)&&(i[te]=ie.bind(n))}if(r){const te=r.call(n,n);ue(te)&&(e.data=rr(te))}if(zr=!0,o)for(const te in o){const ie=o[te],xe=Q(ie)?ie.bind(n,n):Q(ie.get)?ie.get.bind(n,n):Tt,Le=!Q(ie)&&Q(ie.set)?ie.set.bind(n):Tt,Ve=Ee({get:xe,set:Le});Object.defineProperty(i,te,{enumerable:!0,configurable:!0,get:()=>Ve.value,set:et=>Ve.value=et})}if(l)for(const te in l)zl(l[te],i,n,te);if(a){const te=Q(a)?a.call(n):a;Reflect.ownKeys(te).forEach(ie=>{Vu(ie,te[ie])})}u&&ts(u,e,"c");function Z(te,ie){W(ie)?ie.forEach(xe=>te(xe.bind(n))):ie&&te(ie.bind(n))}if(Z(of,d),Z(mi,h),Z(sf,b),Z(Kl,v),Z(tf,g),Z(nf,_),Z(uf,ne),Z(cf,re),Z(af,J),Z(Wl,C),Z(Yl,R),Z(lf,U),W(X))if(X.length){const te=e.exposed||(e.exposed={});X.forEach(ie=>{Object.defineProperty(te,ie,{get:()=>n[ie],set:xe=>n[ie]=xe,enumerable:!0})})}else e.exposed||(e.exposed={});G&&e.render===Tt&&(e.render=G),F!=null&&(e.inheritAttrs=F),w&&(e.components=w),j&&(e.directives=j),U&&Hl(e)}function gf(e,t,n=Tt){W(e)&&(e=Gr(e));for(const i in e){const r=e[i];let o;ue(r)?"default"in r?o=Ri(r.from||i,r.default,!0):o=Ri(r.from||i):o=Ri(r),Be(o)?Object.defineProperty(t,i,{enumerable:!0,configurable:!0,get:()=>o.value,set:s=>o.value=s}):t[i]=o}}function ts(e,t,n){dt(W(e)?e.map(i=>i.bind(t.proxy)):e.bind(t.proxy),t,n)}function zl(e,t,n,i){let r=i.includes(".")?Ul(n,i):()=>n[i];if(ye(e)){const o=t[e];Q(o)&&un(r,o)}else if(Q(e))un(r,e.bind(n));else if(ue(e))if(W(e))e.forEach(o=>zl(o,t,n,i));else{const o=Q(e.handler)?e.handler.bind(n):t[e.handler];Q(o)&&un(r,o,e)}}function Gl(e){const t=e.type,{mixins:n,extends:i}=t,{mixins:r,optionsCache:o,config:{optionMergeStrategies:s}}=e.appContext,l=o.get(t);let a;return l?a=l:!r.length&&!n&&!i?a=t:(a={},r.length&&r.forEach(c=>Ui(a,c,s,!0)),Ui(a,t,s)),ue(t)&&o.set(t,a),a}function Ui(e,t,n,i=!1){const{mixins:r,extends:o}=t;o&&Ui(e,o,n,!0),r&&r.forEach(s=>Ui(e,s,n,!0));for(const s in t)if(!(i&&s==="expose")){const l=mf[s]||n&&n[s];e[s]=l?l(e[s],t[s]):t[s]}return e}const mf={data:ns,props:is,emits:is,methods:Wn,computed:Wn,beforeCreate:qe,created:qe,beforeMount:qe,mounted:qe,beforeUpdate:qe,updated:qe,beforeDestroy:qe,beforeUnmount:qe,destroyed:qe,unmounted:qe,activated:qe,deactivated:qe,errorCaptured:qe,serverPrefetch:qe,components:Wn,directives:Wn,watch:yf,provide:ns,inject:bf};function ns(e,t){return t?e?function(){return Ne(Q(e)?e.call(this,this):e,Q(t)?t.call(this,this):t)}:t:e}function bf(e,t){return Wn(Gr(e),Gr(t))}function Gr(e){if(W(e)){const t={};for(let n=0;nt==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${at(t)}Modifiers`]||e[`${gn(t)}Modifiers`];function wf(e,t,...n){if(e.isUnmounted)return;const i=e.vnode.props||he;let r=n;const o=t.startsWith("update:"),s=o&&xf(i,t.slice(7));s&&(s.trim&&(r=n.map(u=>ye(u)?u.trim():u)),s.number&&(r=n.map(tr)));let l,a=i[l=yr(t)]||i[l=yr(at(t))];!a&&o&&(a=i[l=yr(gn(t))]),a&&dt(a,e,6,r);const c=i[l+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,dt(c,e,6,r)}}const Af=new WeakMap;function Ql(e,t,n=!1){const i=n?Af:t.emitsCache,r=i.get(e);if(r!==void 0)return r;const o=e.emits;let s={},l=!1;if(!Q(e)){const a=c=>{const u=Ql(c,t,!0);u&&(l=!0,Ne(s,u))};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!o&&!l?(ue(e)&&i.set(e,null),null):(W(o)?o.forEach(a=>s[a]=null):Ne(s,o),ue(e)&&i.set(e,s),s)}function lr(e,t){return!e||!Qi(t)?!1:(t=t.slice(2).replace(/Once$/,""),ce(e,t[0].toLowerCase()+t.slice(1))||ce(e,gn(t))||ce(e,t))}function rs(e){const{type:t,vnode:n,proxy:i,withProxy:r,propsOptions:[o],slots:s,attrs:l,emit:a,render:c,renderCache:u,props:d,data:h,setupState:b,ctx:v,inheritAttrs:g}=e,_=Di(e);let A,C;try{if(n.shapeFlag&4){const R=r||i,G=R;A=St(c.call(G,R,u,d,b,h,v)),C=l}else{const R=t;A=St(R.length>1?R(d,{attrs:l,slots:s,emit:a}):R(d,null)),C=t.props?l:Cf(l)}}catch(R){ei.length=0,or(R,e,1),A=B(Ft)}let $=A;if(C&&g!==!1){const R=Object.keys(C),{shapeFlag:G}=$;R.length&&G&7&&(o&&R.some(Zi)&&(C=Sf(C,o)),$=pn($,C,!1,!0))}return n.dirs&&($=pn($,null,!1,!0),$.dirs=$.dirs?$.dirs.concat(n.dirs):n.dirs),n.transition&&ri($,n.transition),A=$,Di(_),A}const Cf=e=>{let t;for(const n in e)(n==="class"||n==="style"||Qi(n))&&((t||(t={}))[n]=e[n]);return t},Sf=(e,t)=>{const n={};for(const i in e)(!Zi(i)||!(i.slice(9)in t))&&(n[i]=e[i]);return n};function Ef(e,t,n){const{props:i,children:r,component:o}=e,{props:s,children:l,patchFlag:a}=t,c=o.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&a>=0){if(a&1024)return!0;if(a&16)return i?os(i,s,c):!!s;if(a&8){const u=t.dynamicProps;for(let d=0;dObject.create(ea),na=e=>Object.getPrototypeOf(e)===ea;function Tf(e,t,n,i=!1){const r={},o=ta();e.propsDefaults=Object.create(null),ia(e,t,r,o);for(const s in e.propsOptions[0])s in r||(r[s]=void 0);n?e.props=i?r:Nu(r):e.type.props?e.props=r:e.props=o,e.attrs=o}function Rf(e,t,n,i){const{props:r,attrs:o,vnode:{patchFlag:s}}=e,l=le(r),[a]=e.propsOptions;let c=!1;if((i||s>0)&&!(s&16)){if(s&8){const u=e.vnode.dynamicProps;for(let d=0;d{a=!0;const[h,b]=ra(d,t,!0);Ne(s,h),b&&l.push(...b)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!o&&!a)return ue(e)&&i.set(e,Cn),Cn;if(W(o))for(let u=0;ue==="_"||e==="_ctx"||e==="$stable",So=e=>W(e)?e.map(St):[St(e)],Nf=(e,t,n)=>{if(t._n)return t;const i=st((...r)=>So(t(...r)),n);return i._c=!1,i},oa=(e,t,n)=>{const i=e._ctx;for(const r in e){if(Co(r))continue;const o=e[r];if(Q(o))t[r]=Nf(r,o,i);else if(o!=null){const s=So(o);t[r]=()=>s}}},sa=(e,t)=>{const n=So(t);e.slots.default=()=>n},la=(e,t,n)=>{for(const i in t)(n||!Co(i))&&(e[i]=t[i])},kf=(e,t,n)=>{const i=e.slots=ta();if(e.vnode.shapeFlag&32){const r=t._;r?(la(i,t,n),n&&pl(i,"_",r,!0)):oa(t,i)}else t&&sa(e,t)},Lf=(e,t,n)=>{const{vnode:i,slots:r}=e;let o=!0,s=he;if(i.shapeFlag&32){const l=t._;l?n&&l===1?o=!1:la(r,t,n):(o=!t.$stable,oa(t,r)),s=t}else t&&(sa(e,t),s={default:1});if(o)for(const l in r)!Co(l)&&s[l]==null&&delete r[l]},Ke=Mf;function If(e){return $f(e)}function $f(e,t){const n=nr();n.__VUE__=!0;const{insert:i,remove:r,patchProp:o,createElement:s,createText:l,createComment:a,setText:c,setElementText:u,parentNode:d,nextSibling:h,setScopeId:b=Tt,insertStaticContent:v}=e,g=(p,m,x,T=null,S=null,E=null,L=void 0,k=null,N=!!m.dynamicChildren)=>{if(p===m)return;p&&!_n(p,m)&&(T=Xe(p),et(p,S,E,!0),p=null),m.patchFlag===-2&&(N=!1,m.dynamicChildren=null);const{type:O,ref:Y,shapeFlag:I}=m;switch(O){case ar:_(p,m,x,T);break;case Ft:A(p,m,x,T);break;case Sr:p==null&&C(m,x,T,L);break;case _e:w(p,m,x,T,S,E,L,k,N);break;default:I&1?G(p,m,x,T,S,E,L,k,N):I&6?j(p,m,x,T,S,E,L,k,N):(I&64||I&128)&&O.process(p,m,x,T,S,E,L,k,N,mt)}Y!=null&&S?Qn(Y,p&&p.ref,E,m||p,!m):Y==null&&p&&p.ref!=null&&Qn(p.ref,null,E,p,!0)},_=(p,m,x,T)=>{if(p==null)i(m.el=l(m.children),x,T);else{const S=m.el=p.el;m.children!==p.children&&c(S,m.children)}},A=(p,m,x,T)=>{p==null?i(m.el=a(m.children||""),x,T):m.el=p.el},C=(p,m,x,T)=>{[p.el,p.anchor]=v(p.children,m,x,T,p.el,p.anchor)},$=({el:p,anchor:m},x,T)=>{let S;for(;p&&p!==m;)S=h(p),i(p,x,T),p=S;i(m,x,T)},R=({el:p,anchor:m})=>{let x;for(;p&&p!==m;)x=h(p),r(p),p=x;r(m)},G=(p,m,x,T,S,E,L,k,N)=>{if(m.type==="svg"?L="svg":m.type==="math"&&(L="mathml"),p==null)re(m,x,T,S,E,L,k,N);else{const O=p.el&&p.el._isVueCE?p.el:null;try{O&&O._beginPatch(),U(p,m,S,E,L,k,N)}finally{O&&O._endPatch()}}},re=(p,m,x,T,S,E,L,k)=>{let N,O;const{props:Y,shapeFlag:I,transition:q,dirs:z}=p;if(N=p.el=s(p.type,E,Y&&Y.is,Y),I&8?u(N,p.children):I&16&&ne(p.children,N,null,T,S,Cr(p,E),L,k),z&&en(p,null,T,"created"),J(N,p,p.scopeId,L,T),Y){for(const fe in Y)fe!=="value"&&!zn(fe)&&o(N,fe,null,Y[fe],E,T);"value"in Y&&o(N,"value",null,Y.value,E),(O=Y.onVnodeBeforeMount)&&_t(O,T,p)}z&&en(p,null,T,"beforeMount");const oe=Pf(S,q);oe&&q.beforeEnter(N),i(N,m,x),((O=Y&&Y.onVnodeMounted)||oe||z)&&Ke(()=>{try{O&&_t(O,T,p),oe&&q.enter(N),z&&en(p,null,T,"mounted")}finally{}},S)},J=(p,m,x,T,S)=>{if(x&&b(p,x),T)for(let E=0;E{for(let O=N;O{const k=m.el=p.el;let{patchFlag:N,dynamicChildren:O,dirs:Y}=m;N|=p.patchFlag&16;const I=p.props||he,q=m.props||he;let z;if(x&&tn(x,!1),(z=q.onVnodeBeforeUpdate)&&_t(z,x,m,p),Y&&en(m,p,x,"beforeUpdate"),x&&tn(x,!0),(I.innerHTML&&q.innerHTML==null||I.textContent&&q.textContent==null)&&u(k,""),O?X(p.dynamicChildren,O,k,x,T,Cr(m,S),E):L||ie(p,m,k,null,x,T,Cr(m,S),E,!1),N>0){if(N&16)F(k,I,q,x,S);else if(N&2&&I.class!==q.class&&o(k,"class",null,q.class,S),N&4&&o(k,"style",I.style,q.style,S),N&8){const oe=m.dynamicProps;for(let fe=0;fe{z&&_t(z,x,m,p),Y&&en(m,p,x,"updated")},T)},X=(p,m,x,T,S,E,L)=>{for(let k=0;k{if(m!==x){if(m!==he)for(const E in m)!zn(E)&&!(E in x)&&o(p,E,m[E],null,S,T);for(const E in x){if(zn(E))continue;const L=x[E],k=m[E];L!==k&&E!=="value"&&o(p,E,k,L,S,T)}"value"in x&&o(p,"value",m.value,x.value,S)}},w=(p,m,x,T,S,E,L,k,N)=>{const O=m.el=p?p.el:l(""),Y=m.anchor=p?p.anchor:l("");let{patchFlag:I,dynamicChildren:q,slotScopeIds:z}=m;z&&(k=k?k.concat(z):z),p==null?(i(O,x,T),i(Y,x,T),ne(m.children||[],x,Y,S,E,L,k,N)):I>0&&I&64&&q&&p.dynamicChildren&&p.dynamicChildren.length===q.length?(X(p.dynamicChildren,q,x,S,E,L,k),(m.key!=null||S&&m===S.subTree)&&Eo(p,m,!0)):ie(p,m,x,Y,S,E,L,k,N)},j=(p,m,x,T,S,E,L,k,N)=>{m.slotScopeIds=k,p==null?m.shapeFlag&512?S.ctx.activate(m,x,T,L,N):D(m,x,T,S,E,L,N):se(p,m,N)},D=(p,m,x,T,S,E,L)=>{const k=p.component=Kf(p,T,S);if(Vl(p)&&(k.ctx.renderer=mt),Wf(k,!1,L),k.asyncDep){if(S&&S.registerDep(k,Z,L),!p.el){const N=k.subTree=B(Ft);A(null,N,m,x),p.placeholder=N.el}}else Z(k,p,m,x,S,E,L)},se=(p,m,x)=>{const T=m.component=p.component;if(Ef(p,m,x))if(T.asyncDep&&!T.asyncResolved){te(T,m,x);return}else T.next=m,T.update();else m.el=p.el,T.vnode=m},Z=(p,m,x,T,S,E,L)=>{const k=()=>{if(p.isMounted){let{next:I,bu:q,u:z,parent:oe,vnode:fe}=p;{const yt=aa(p);if(yt){I&&(I.el=fe.el,te(p,I,L)),yt.asyncDep.then(()=>{Ke(()=>{p.isUnmounted||O()},S)});return}}let ge=I,Ce;tn(p,!1),I?(I.el=fe.el,te(p,I,L)):I=fe,q&&Ti(q),(Ce=I.props&&I.props.onVnodeBeforeUpdate)&&_t(Ce,oe,I,fe),tn(p,!0);const Ie=rs(p),bt=p.subTree;p.subTree=Ie,g(bt,Ie,d(bt.el),Xe(bt),p,S,E),I.el=Ie.el,ge===null&&Of(p,Ie.el),z&&Ke(z,S),(Ce=I.props&&I.props.onVnodeUpdated)&&Ke(()=>_t(Ce,oe,I,fe),S)}else{let I;const{el:q,props:z}=m,{bm:oe,m:fe,parent:ge,root:Ce,type:Ie}=p,bt=On(m);tn(p,!1),oe&&Ti(oe),!bt&&(I=z&&z.onVnodeBeforeMount)&&_t(I,ge,m),tn(p,!0);{Ce.ce&&Ce.ce._hasShadowRoot()&&Ce.ce._injectChildStyle(Ie,p.parent?p.parent.type:void 0);const yt=p.subTree=rs(p);g(null,yt,x,T,p,S,E),m.el=yt.el}if(fe&&Ke(fe,S),!bt&&(I=z&&z.onVnodeMounted)){const yt=m;Ke(()=>_t(I,ge,yt),S)}(m.shapeFlag&256||ge&&On(ge.vnode)&&ge.vnode.shapeFlag&256)&&p.a&&Ke(p.a,S),p.isMounted=!0,m=x=T=null}};p.scope.on();const N=p.effect=new bl(k);p.scope.off();const O=p.update=N.run.bind(N),Y=p.job=N.runIfDirty.bind(N);Y.i=p,Y.id=p.uid,N.scheduler=()=>Ao(Y),tn(p,!0),O()},te=(p,m,x)=>{m.component=p;const T=p.vnode.props;p.vnode=m,p.next=null,Rf(p,m.props,T,x),Lf(p,m.children,x),Ut(),zo(p),jt()},ie=(p,m,x,T,S,E,L,k,N=!1)=>{const O=p&&p.children,Y=p?p.shapeFlag:0,I=m.children,{patchFlag:q,shapeFlag:z}=m;if(q>0){if(q&128){Le(O,I,x,T,S,E,L,k,N);return}else if(q&256){xe(O,I,x,T,S,E,L,k,N);return}}z&8?(Y&16&&Nt(O,S,E),I!==O&&u(x,I)):Y&16?z&16?Le(O,I,x,T,S,E,L,k,N):Nt(O,S,E,!0):(Y&8&&u(x,""),z&16&&ne(I,x,T,S,E,L,k,N))},xe=(p,m,x,T,S,E,L,k,N)=>{p=p||Cn,m=m||Cn;const O=p.length,Y=m.length,I=Math.min(O,Y);let q;for(q=0;qY?Nt(p,S,E,!0,!1,I):ne(m,x,T,S,E,L,k,N,I)},Le=(p,m,x,T,S,E,L,k,N)=>{let O=0;const Y=m.length;let I=p.length-1,q=Y-1;for(;O<=I&&O<=q;){const z=p[O],oe=m[O]=N?$t(m[O]):St(m[O]);if(_n(z,oe))g(z,oe,x,null,S,E,L,k,N);else break;O++}for(;O<=I&&O<=q;){const z=p[I],oe=m[q]=N?$t(m[q]):St(m[q]);if(_n(z,oe))g(z,oe,x,null,S,E,L,k,N);else break;I--,q--}if(O>I){if(O<=q){const z=q+1,oe=zq)for(;O<=I;)et(p[O],S,E,!0),O++;else{const z=O,oe=O,fe=new Map;for(O=oe;O<=q;O++){const tt=m[O]=N?$t(m[O]):St(m[O]);tt.key!=null&&fe.set(tt.key,O)}let ge,Ce=0;const Ie=q-oe+1;let bt=!1,yt=0;const Un=new Array(Ie);for(O=0;O=Ie){et(tt,S,E,!0);continue}let vt;if(tt.key!=null)vt=fe.get(tt.key);else for(ge=oe;ge<=q;ge++)if(Un[ge-oe]===0&&_n(tt,m[ge])){vt=ge;break}vt===void 0?et(tt,S,E,!0):(Un[vt-oe]=O+1,vt>=yt?yt=vt:bt=!0,g(tt,m[vt],x,null,S,E,L,k,N),Ce++)}const Ho=bt?Df(Un):Cn;for(ge=Ho.length-1,O=Ie-1;O>=0;O--){const tt=oe+O,vt=m[tt],Vo=m[tt+1],qo=tt+1{const{el:E,type:L,transition:k,children:N,shapeFlag:O}=p;if(O&6){Ve(p.component.subTree,m,x,T);return}if(O&128){p.suspense.move(m,x,T);return}if(O&64){L.move(p,m,x,mt);return}if(L===_e){i(E,m,x);for(let I=0;Ik.enter(E),S);else{const{leave:I,delayLeave:q,afterLeave:z}=k,oe=()=>{p.ctx.isUnmounted?r(E):i(E,m,x)},fe=()=>{E._isLeaving&&E[Wt](!0),I(E,()=>{oe(),z&&z()})};q?q(E,oe,fe):fe()}else i(E,m,x)},et=(p,m,x,T=!1,S=!1)=>{const{type:E,props:L,ref:k,children:N,dynamicChildren:O,shapeFlag:Y,patchFlag:I,dirs:q,cacheIndex:z,memo:oe}=p;if(I===-2&&(S=!1),k!=null&&(Ut(),Qn(k,null,x,p,!0),jt()),z!=null&&(m.renderCache[z]=void 0),Y&256){m.ctx.deactivate(p);return}const fe=Y&1&&q,ge=!On(p);let Ce;if(ge&&(Ce=L&&L.onVnodeBeforeUnmount)&&_t(Ce,m,p),Y&6)it(p.component,x,T);else{if(Y&128){p.suspense.unmount(x,T);return}fe&&en(p,null,m,"beforeUnmount"),Y&64?p.type.remove(p,m,x,mt,T):O&&!O.hasOnce&&(E!==_e||I>0&&I&64)?Nt(O,m,x,!1,!0):(E===_e&&I&384||!S&&Y&16)&&Nt(N,m,x),T&&Te(p)}const Ie=oe!=null&&z==null;(ge&&(Ce=L&&L.onVnodeUnmounted)||fe||Ie)&&Ke(()=>{Ce&&_t(Ce,m,p),fe&&en(p,null,m,"unmounted"),Ie&&(p.el=null)},x)},Te=p=>{const{type:m,el:x,anchor:T,transition:S}=p;if(m===_e){gt(x,T);return}if(m===Sr){R(p);return}const E=()=>{r(x),S&&!S.persisted&&S.afterLeave&&S.afterLeave()};if(p.shapeFlag&1&&S&&!S.persisted){const{leave:L,delayLeave:k}=S,N=()=>L(x,E);k?k(p.el,E,N):N()}else E()},gt=(p,m)=>{let x;for(;p!==m;)x=h(p),r(p),p=x;r(m)},it=(p,m,x)=>{const{bum:T,scope:S,job:E,subTree:L,um:k,m:N,a:O}=p;ls(N),ls(O),T&&Ti(T),S.stop(),E&&(E.flags|=8,et(L,p,m,x)),k&&Ke(k,m),Ke(()=>{p.isUnmounted=!0},m)},Nt=(p,m,x,T=!1,S=!1,E=0)=>{for(let L=E;L{if(p.shapeFlag&6)return Xe(p.component.subTree);if(p.shapeFlag&128)return p.suspense.next();const m=h(p.anchor||p.el),x=m&&m[jl];return x?h(x):m};let ae=!1;const kt=(p,m,x)=>{let T;p==null?m._vnode&&(et(m._vnode,null,null,!0),T=m._vnode.component):g(m._vnode||null,p,m,null,null,null,x),m._vnode=p,ae||(ae=!0,zo(T),$l(),ae=!1)},mt={p:g,um:et,m:Ve,r:Te,mt:D,mc:ne,pc:ie,pbc:X,n:Xe,o:e};return{render:kt,hydrate:void 0,createApp:_f(kt)}}function Cr({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function tn({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Pf(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Eo(e,t,n=!1){const i=e.children,r=t.children;if(W(i)&&W(r))for(let o=0;o>1,e[n[l]]0&&(t[i]=n[o-1]),n[o]=i)}}for(o=n.length,s=n[o-1];o-- >0;)n[o]=s,s=t[s];return n}function aa(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:aa(t)}function ls(e){if(e)for(let t=0;te.__isSuspense;function Mf(e,t){t&&t.pendingBranch?W(e)?t.effects.push(...e):t.effects.push(e):Hu(e)}const _e=Symbol.for("v-fgt"),ar=Symbol.for("v-txt"),Ft=Symbol.for("v-cmt"),Sr=Symbol.for("v-stc"),ei=[];let nt=null;function H(e=!1){ei.push(nt=e?null:[])}function Uf(){ei.pop(),nt=ei[ei.length-1]||null}let oi=1;function as(e,t=!1){oi+=e,e<0&&nt&&t&&(nt.hasOnce=!0)}function fa(e){return e.dynamicChildren=oi>0?nt||Cn:null,Uf(),oi>0&&nt&&nt.push(e),e}function K(e,t,n,i,r,o){return fa(f(e,t,n,i,r,o,!0))}function si(e,t,n,i,r){return fa(B(e,t,n,i,r,!0))}function Oo(e){return e?e.__v_isVNode===!0:!1}function _n(e,t){return e.type===t.type&&e.key===t.key}const da=({key:e})=>e??null,Fi=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?ye(e)||Be(e)||Q(e)?{i:je,r:e,k:t,f:!!n}:e:null);function f(e,t=null,n=null,i=0,r=null,o=e===_e?0:1,s=!1,l=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&da(t),ref:t&&Fi(t),scopeId:Dl,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:i,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:je};return l?(To(a,n),o&128&&e.normalize(a)):n&&(a.shapeFlag|=ye(n)?8:16),oi>0&&!s&&nt&&(a.patchFlag>0||o&6)&&a.patchFlag!==32&&nt.push(a),a}const B=jf;function jf(e,t=null,n=null,i=0,r=null,o=!1){if((!e||e===ff)&&(e=Ft),Oo(e)){const l=pn(e,t,!0);return n&&To(l,n),oi>0&&!o&&nt&&(l.shapeFlag&6?nt[nt.indexOf(e)]=l:nt.push(l)),l.patchFlag=-2,l}if(Gf(e)&&(e=e.__vccOpts),t){t=Bf(t);let{class:l,style:a}=t;l&&!ye(l)&&(t.class=ve(l)),ue(a)&&(wo(a)&&!W(a)&&(a=Ne({},a)),t.style=Rn(a))}const s=ye(e)?1:ua(e)?128:Yu(e)?64:ue(e)?4:Q(e)?2:0;return f(e,t,n,i,r,s,o,!0)}function Bf(e){return e?wo(e)||na(e)?Ne({},e):e:null}function pn(e,t,n=!1,i=!1){const{props:r,ref:o,patchFlag:s,children:l,transition:a}=e,c=t?Hf(r||{},t):r,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&da(c),ref:t&&t.ref?n&&o?W(o)?o.concat(Fi(t)):[o,Fi(t)]:Fi(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==_e?s===-1?16:s|16:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:a,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&pn(e.ssContent),ssFallback:e.ssFallback&&pn(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return a&&i&&ri(u,a.clone(u)),u}function de(e=" ",t=0){return B(ar,null,e,t)}function pt(e="",t=!1){return t?(H(),si(Ft,null,e)):B(Ft,null,e)}function St(e){return e==null||typeof e=="boolean"?B(Ft):W(e)?B(_e,null,e.slice()):Oo(e)?$t(e):B(ar,null,String(e))}function $t(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:pn(e)}function To(e,t){let n=0;const{shapeFlag:i}=e;if(t==null)t=null;else if(W(t))n=16;else if(typeof t=="object")if(i&65){const r=t.default;r&&(r._c&&(r._d=!1),To(e,r()),r._c&&(r._d=!0));return}else{n=32;const r=t._;!r&&!na(t)?t._ctx=je:r===3&&je&&(je.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else Q(t)?(t={default:t,_ctx:je},n=32):(t=String(t),i&64?(n=16,t=[de(t)]):n=8);e.children=t,e.shapeFlag|=n}function Hf(...e){const t={};for(let n=0;nJe||je;let ji,Qr;{const e=nr(),t=(n,i)=>{let r;return(r=e[n])||(r=e[n]=[]),r.push(i),o=>{r.length>1?r.forEach(s=>s(o)):r[0](o)}};ji=t("__VUE_INSTANCE_SETTERS__",n=>Je=n),Qr=t("__VUE_SSR_SETTERS__",n=>li=n)}const bi=e=>{const t=Je;return ji(e),e.scope.on(),()=>{e.scope.off(),ji(t)}},cs=()=>{Je&&Je.scope.off(),ji(null)};function ha(e){return e.vnode.shapeFlag&4}let li=!1;function Wf(e,t=!1,n=!1){t&&Qr(t);const{props:i,children:r}=e.vnode,o=ha(e);Tf(e,i,o,t),kf(e,r,n||t);const s=o?Yf(e,t):void 0;return t&&Qr(!1),s}function Yf(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,pf);const{setup:i}=n;if(i){Ut();const r=e.setupContext=i.length>1?zf(e):null,o=bi(e),s=gi(i,e,0,[e.props,r]),l=cl(s);if(jt(),o(),(l||e.sp)&&!On(e)&&Hl(e),l){if(s.then(cs,cs),t)return s.then(a=>{us(e,a)}).catch(a=>{or(a,e,0)});e.asyncDep=s}else us(e,s)}else ga(e)}function us(e,t,n){Q(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:ue(t)&&(e.setupState=Nl(t)),ga(e)}function ga(e,t,n){const i=e.type;e.render||(e.render=i.render||Tt);{const r=bi(e);Ut();try{hf(e)}finally{jt(),r()}}}const Jf={get(e,t){return Me(e,"get",""),e[t]}};function zf(e){const t=n=>{e.exposed=n||{}};return{attrs:new Proxy(e.attrs,Jf),slots:e.slots,emit:e.emit,expose:t}}function cr(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(Nl(ku(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Zn)return Zn[n](e)},has(t,n){return n in t||n in Zn}})):e.proxy}function Gf(e){return Q(e)&&"__vccOpts"in e}const Ee=(e,t)=>Du(e,t,li),Xf="3.5.34";/** -* @vue/runtime-dom v3.5.34 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/let Zr;const fs=typeof window<"u"&&window.trustedTypes;if(fs)try{Zr=fs.createPolicy("vue",{createHTML:e=>e})}catch{}const ma=Zr?e=>Zr.createHTML(e):e=>e,Qf="http://www.w3.org/2000/svg",Zf="http://www.w3.org/1998/Math/MathML",It=typeof document<"u"?document:null,ds=It&&It.createElement("template"),ed={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,i)=>{const r=t==="svg"?It.createElementNS(Qf,e):t==="mathml"?It.createElementNS(Zf,e):n?It.createElement(e,{is:n}):It.createElement(e);return e==="select"&&i&&i.multiple!=null&&r.setAttribute("multiple",i.multiple),r},createText:e=>It.createTextNode(e),createComment:e=>It.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>It.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,i,r,o){const s=n?n.previousSibling:t.lastChild;if(r&&(r===o||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===o||!(r=r.nextSibling)););else{ds.innerHTML=ma(i==="svg"?`${e}`:i==="mathml"?`${e}`:e);const l=ds.content;if(i==="svg"||i==="mathml"){const a=l.firstChild;for(;a.firstChild;)l.appendChild(a.firstChild);l.removeChild(a)}t.insertBefore(l,n)}return[s?s.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},qt="transition",Hn="animation",Nn=Symbol("_vtc"),ba={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},td=Ne({},Zu,ba),nn=(e,t=[])=>{W(e)?e.forEach(n=>n(...t)):e&&e(...t)},ps=e=>e?W(e)?e.some(t=>t.length>1):e.length>1:!1;function nd(e){const t={};for(const w in e)w in ba||(t[w]=e[w]);if(e.css===!1)return t;const{name:n="v",type:i,duration:r,enterFromClass:o=`${n}-enter-from`,enterActiveClass:s=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:a=o,appearActiveClass:c=s,appearToClass:u=l,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:h=`${n}-leave-active`,leaveToClass:b=`${n}-leave-to`}=e,v=id(r),g=v&&v[0],_=v&&v[1],{onBeforeEnter:A,onEnter:C,onEnterCancelled:$,onLeave:R,onLeaveCancelled:G,onBeforeAppear:re=A,onAppear:J=C,onAppearCancelled:ne=$}=t,U=(w,j,D,se)=>{w._enterCancelled=se,Yt(w,j?u:l),Yt(w,j?c:s),D&&D()},X=(w,j)=>{w._isLeaving=!1,Yt(w,d),Yt(w,b),Yt(w,h),j&&j()},F=w=>(j,D)=>{const se=w?J:C,Z=()=>U(j,w,D);nn(se,[j,Z]),hs(()=>{Yt(j,w?a:o),wt(j,w?u:l),ps(se)||gs(j,i,g,Z)})};return Ne(t,{onBeforeEnter(w){nn(A,[w]),wt(w,o),wt(w,s)},onBeforeAppear(w){nn(re,[w]),wt(w,a),wt(w,c)},onEnter:F(!1),onAppear:F(!0),onLeave(w,j){w._isLeaving=!0;const D=()=>X(w,j);wt(w,d),w._enterCancelled?(wt(w,h),eo(w)):(eo(w),wt(w,h)),hs(()=>{w._isLeaving&&(Yt(w,d),wt(w,b),ps(R)||gs(w,i,_,D))}),nn(R,[w,D])},onEnterCancelled(w){U(w,!1,void 0,!0),nn($,[w])},onAppearCancelled(w){U(w,!0,void 0,!0),nn(ne,[w])},onLeaveCancelled(w){X(w),nn(G,[w])}})}function id(e){if(e==null)return null;if(ue(e))return[Er(e.enter),Er(e.leave)];{const t=Er(e);return[t,t]}}function Er(e){return iu(e)}function wt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Nn]||(e[Nn]=new Set)).add(t)}function Yt(e,t){t.split(/\s+/).forEach(i=>i&&e.classList.remove(i));const n=e[Nn];n&&(n.delete(t),n.size||(e[Nn]=void 0))}function hs(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let rd=0;function gs(e,t,n,i){const r=e._endId=++rd,o=()=>{r===e._endId&&i()};if(n!=null)return setTimeout(o,n);const{type:s,timeout:l,propCount:a}=ya(e,t);if(!s)return i();const c=s+"end";let u=0;const d=()=>{e.removeEventListener(c,h),o()},h=b=>{b.target===e&&++u>=a&&d()};setTimeout(()=>{u(n[v]||"").split(", "),r=i(`${qt}Delay`),o=i(`${qt}Duration`),s=ms(r,o),l=i(`${Hn}Delay`),a=i(`${Hn}Duration`),c=ms(l,a);let u=null,d=0,h=0;t===qt?s>0&&(u=qt,d=s,h=o.length):t===Hn?c>0&&(u=Hn,d=c,h=a.length):(d=Math.max(s,c),u=d>0?s>c?qt:Hn:null,h=u?u===qt?o.length:a.length:0);const b=u===qt&&/\b(?:transform|all)(?:,|$)/.test(i(`${qt}Property`).toString());return{type:u,timeout:d,propCount:h,hasTransform:b}}function ms(e,t){for(;e.lengthbs(n)+bs(e[i])))}function bs(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function eo(e){return(e?e.ownerDocument:document).body.offsetHeight}function od(e,t,n){const i=e[Nn];i&&(t=(t?[t,...i]:[...i]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const Bi=Symbol("_vod"),va=Symbol("_vsh"),Or={name:"show",beforeMount(e,{value:t},{transition:n}){e[Bi]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):Vn(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:i}){!t!=!n&&(i?t?(i.beforeEnter(e),Vn(e,!0),i.enter(e)):i.leave(e,()=>{Vn(e,!1)}):Vn(e,t))},beforeUnmount(e,{value:t}){Vn(e,t)}};function Vn(e,t){e.style.display=t?e[Bi]:"none",e[va]=!t}const sd=Symbol(""),ld=/(?:^|;)\s*display\s*:/;function ad(e,t,n){const i=e.style,r=ye(n);let o=!1;if(n&&!r){if(t)if(ye(t))for(const s of t.split(";")){const l=s.slice(0,s.indexOf(":")).trim();n[l]==null&&Yn(i,l,"")}else for(const s in t)n[s]==null&&Yn(i,s,"");for(const s in n){s==="display"&&(o=!0);const l=n[s];l!=null?ud(e,s,!ye(t)&&t?t[s]:void 0,l)||Yn(i,s,l):Yn(i,s,"")}}else if(r){if(t!==n){const s=i[sd];s&&(n+=";"+s),i.cssText=n,o=ld.test(n)}}else t&&e.removeAttribute("style");Bi in e&&(e[Bi]=o?i.display:"",e[va]&&(i.display="none"))}const ys=/\s*!important$/;function Yn(e,t,n){if(W(n))n.forEach(i=>Yn(e,t,i));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const i=cd(e,t);ys.test(n)?e.setProperty(gn(i),n.replace(ys,""),"important"):e[i]=n}}const vs=["Webkit","Moz","ms"],Tr={};function cd(e,t){const n=Tr[t];if(n)return n;let i=at(t);if(i!=="filter"&&i in e)return Tr[t]=i;i=dl(i);for(let r=0;rRr||(hd.then(()=>Rr=0),Rr=Date.now());function md(e,t){const n=i=>{if(!i._vts)i._vts=Date.now();else if(i._vts<=n.attached)return;dt(bd(i,n.value),t,5,[i])};return n.value=e,n.attached=gd(),n}function bd(e,t){if(W(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(i=>r=>!r._stopped&&i&&i(r))}else return t}const Ss=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,yd=(e,t,n,i,r,o)=>{const s=r==="svg";t==="class"?od(e,i,s):t==="style"?ad(e,n,i):Qi(t)?Zi(t)||dd(e,t,n,i,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):vd(e,t,i,s))?(ws(e,t,i),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&xs(e,t,i,s,o,t!=="value")):e._isVueCE&&(_d(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!ye(i)))?ws(e,at(t),i,o,t):(t==="true-value"?e._trueValue=i:t==="false-value"&&(e._falseValue=i),xs(e,t,i,s))};function vd(e,t,n,i){if(i)return!!(t==="innerHTML"||t==="textContent"||t in e&&Ss(t)&&Q(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const r=e.tagName;if(r==="IMG"||r==="VIDEO"||r==="CANVAS"||r==="SOURCE")return!1}return Ss(t)&&ye(n)?!1:t in e}function _d(e,t){const n=e._def.props;if(!n)return!1;const i=at(t);return Array.isArray(n)?n.some(r=>at(r)===i):Object.keys(n).some(r=>at(r)===i)}const _a=new WeakMap,xa=new WeakMap,Hi=Symbol("_moveCb"),Es=Symbol("_enterCb"),xd=e=>(delete e.props.mode,e),wd=xd({name:"TransitionGroup",props:Ne({},td,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=pa(),i=Qu();let r,o;return Kl(()=>{if(!r.length)return;const s=e.moveClass||`${e.name||"v"}-move`;if(!Od(r[0].el,n.vnode.el,s)){r=[];return}r.forEach(Cd),r.forEach(Sd);const l=r.filter(Ed);eo(n.vnode.el),l.forEach(a=>{const c=a.el,u=c.style;wt(c,s),u.transform=u.webkitTransform=u.transitionDuration="";const d=c[Hi]=h=>{h&&h.target!==c||(!h||h.propertyName.endsWith("transform"))&&(c.removeEventListener("transitionend",d),c[Hi]=null,Yt(c,s))};c.addEventListener("transitionend",d)}),r=[]}),()=>{const s=le(e),l=nd(s);let a=s.tag||_e;if(r=[],o)for(let c=0;c{l.split(/\s+/).forEach(a=>a&&i.classList.remove(a))}),n.split(/\s+/).forEach(l=>l&&i.classList.add(l)),i.style.display="none";const o=t.nodeType===1?t:t.parentNode;o.appendChild(i);const{hasTransform:s}=ya(i);return o.removeChild(i),s}const kn=e=>{const t=e.props["onUpdate:modelValue"]||!1;return W(t)?n=>Ti(t,n):t};function Td(e){e.target.composing=!0}function Os(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Mt=Symbol("_assign");function Ts(e,t,n){return t&&(e=e.trim()),n&&(e=tr(e)),e}const we={created(e,{modifiers:{lazy:t,trim:n,number:i}},r){e[Mt]=kn(r);const o=i||r.props&&r.props.type==="number";Xt(e,t?"change":"input",s=>{s.target.composing||e[Mt](Ts(e.value,n,o))}),(n||o)&&Xt(e,"change",()=>{e.value=Ts(e.value,n,o)}),t||(Xt(e,"compositionstart",Td),Xt(e,"compositionend",Os),Xt(e,"change",Os))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:i,trim:r,number:o}},s){if(e[Mt]=kn(s),e.composing)return;const l=(o||e.type==="number")&&!/^0\d/.test(e.value)?tr(e.value):e.value,a=t??"";if(l===a)return;const c=e.getRootNode();(c instanceof Document||c instanceof ShadowRoot)&&c.activeElement===e&&e.type!=="range"&&(i&&t===n||r&&e.value.trim()===a)||(e.value=a)}},pe={deep:!0,created(e,t,n){e[Mt]=kn(n),Xt(e,"change",()=>{const i=e._modelValue,r=ai(e),o=e.checked,s=e[Mt];if(W(i)){const l=go(i,r),a=l!==-1;if(o&&!a)s(i.concat(r));else if(!o&&a){const c=[...i];c.splice(l,1),s(c)}}else if($n(i)){const l=new Set(i);o?l.add(r):l.delete(r),s(l)}else s(Aa(e,o))})},mounted:Rs,beforeUpdate(e,t,n){e[Mt]=kn(n),Rs(e,t,n)}};function Rs(e,{value:t,oldValue:n},i){e._modelValue=t;let r;if(W(t))r=go(t,i.props.value)>-1;else if($n(t))r=t.has(i.props.value);else{if(t===n)return;r=Pn(t,Aa(e,!0))}e.checked!==r&&(e.checked=r)}const Ot={deep:!0,created(e,{value:t,modifiers:{number:n}},i){const r=$n(t);Xt(e,"change",()=>{const o=Array.prototype.filter.call(e.options,s=>s.selected).map(s=>n?tr(ai(s)):ai(s));e[Mt](e.multiple?r?new Set(o):o:o[0]),e._assigning=!0,Ll(()=>{e._assigning=!1})}),e[Mt]=kn(i)},mounted(e,{value:t}){Fs(e,t)},beforeUpdate(e,t,n){e[Mt]=kn(n)},updated(e,{value:t}){e._assigning||Fs(e,t)}};function Fs(e,t){const n=e.multiple,i=W(t);if(!(n&&!i&&!$n(t))){for(let r=0,o=e.options.length;rString(c)===String(l)):s.selected=go(t,l)>-1}else s.selected=t.has(l);else if(Pn(ai(s),t)){e.selectedIndex!==r&&(e.selectedIndex=r);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function ai(e){return"_value"in e?e._value:e.value}function Aa(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const Rd=Ne({patchProp:yd},ed);let Ns;function Fd(){return Ns||(Ns=If(Rd))}const Nd=((...e)=>{const t=Fd().createApp(...e),{mount:n}=t;return t.mount=i=>{const r=Ld(i);if(!r)return;const o=t._component;!Q(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.nodeType===1&&(r.textContent="");const s=n(r,!1,kd(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},t});function kd(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Ld(e){return ye(e)?document.querySelector(e):e}const Id={class:"toast-container"},$d={class:"toast-msg"},Pd=["onClick"],Dd={__name:"GlobalToast",setup(e,{expose:t}){const n=be([]);let i=0;function r(l,a,c=4e3){const u=++i;n.value.push({id:u,type:l,message:a}),c>0&&setTimeout(()=>o(u),c)}function o(l){const a=n.value.findIndex(c=>c.id===l);a>=0&&n.value.splice(a,1)}return t({toast:{info:(l,a)=>r("info",l,a),success:(l,a)=>r("success",l,a),warn:(l,a)=>r("warn",l,a),error:(l,a)=>r("error",l,a??8e3)}}),(l,a)=>(H(),si(Xu,{to:"body"},[f("div",Id,[B(Ad,{name:"toast"},{default:st(()=>[(H(!0),K(_e,null,Gt(n.value,c=>(H(),K("div",{key:c.id,class:ve(["toast-item",`toast-${c.type}`])},[f("span",$d,ee(c.message),1),f("button",{class:"toast-close",onClick:u=>o(c.id)},"×",8,Pd)],2))),128))]),_:1})])]))}},Md="modulepreload",Ud=function(e,t){return new URL(e,t).href},ks={},Fr=function(t,n,i){let r=Promise.resolve();if(n&&n.length>0){let s=function(u){return Promise.all(u.map(d=>Promise.resolve(d).then(h=>({status:"fulfilled",value:h}),h=>({status:"rejected",reason:h}))))};const l=document.getElementsByTagName("link"),a=document.querySelector("meta[property=csp-nonce]"),c=(a==null?void 0:a.nonce)||(a==null?void 0:a.getAttribute("nonce"));r=s(n.map(u=>{if(u=Ud(u,i),u in ks)return;ks[u]=!0;const d=u.endsWith(".css"),h=d?'[rel="stylesheet"]':"";if(!!i)for(let g=l.length-1;g>=0;g--){const _=l[g];if(_.href===u&&(!d||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${h}`))return;const v=document.createElement("link");if(v.rel=d?"stylesheet":Md,d||(v.as="script"),v.crossOrigin="",v.href=u,c&&v.setAttribute("nonce",c),document.head.appendChild(v),d)return new Promise((g,_)=>{v.addEventListener("load",g),v.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(s){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=s,window.dispatchEvent(l),!l.defaultPrevented)throw s}return r.then(s=>{for(const l of s||[])l.status==="rejected"&&o(l.reason);return t().catch(o)})},ke=(e,t)=>{const n=e.__vccOpts||e;for(const[i,r]of t)n[i]=r;return n},jd={class:"upload-group"},Bd={class:"file-tip"},Hd={class:"file-tip"},Vd=["disabled"],qd={__name:"FileUploadPanel",props:{docxFile:File,yamlFile:File,generatedConfig:Object,isLoading:Boolean},emits:["update:docxFile","update:yamlFile","generate-json"],setup(e,{emit:t}){const n=e,i=t,r=Ee(()=>n.docxFile?`已选择:${n.docxFile.name}`:"未选择"),o=Ee(()=>n.yamlFile?`已选择:${n.yamlFile.name}`:"未选择"),s=a=>i("update:docxFile",a.target.files[0]),l=a=>i("update:yamlFile",a.target.files[0]);return(a,c)=>(H(),K("div",jd,[c[2]||(c[2]=f("label",{for:"docx-file",class:"upload-btn"},"选择 docx",-1)),f("input",{type:"file",id:"docx-file",accept:".docx",class:"file-hidden",onChange:s},null,32),f("span",Bd,ee(r.value),1),e.generatedConfig?pt("",!0):(H(),K(_e,{key:0},[c[1]||(c[1]=f("label",{for:"yaml-file",class:"upload-btn"},"选择 yaml",-1)),f("input",{type:"file",id:"yaml-file",accept:".yaml,.yml",class:"file-hidden",onChange:l},null,32),f("span",Hd,ee(o.value),1)],64)),f("button",{class:"go-btn",disabled:!e.docxFile||!e.yamlFile&&!e.generatedConfig||e.isLoading,onClick:c[0]||(c[0]=u=>a.$emit("generate-json"))}," 生成节点 ",8,Vd)]))}},Kd=ke(qd,[["__scopeId","data-v-6d870395"]]),Wd={class:"format-btn-group"},Yd=["disabled"],Jd=["disabled"],zd={__name:"FormatActionPanel",props:{isLoading:Boolean},emits:["check-format","apply-format"],setup(e){return(t,n)=>(H(),K("div",Wd,[f("button",{class:"btn btn-amber",disabled:e.isLoading,onClick:n[0]||(n[0]=i=>t.$emit("check-format"))},"格式校验",8,Yd),f("button",{class:"btn btn-green",disabled:e.isLoading,onClick:n[1]||(n[1]=i=>t.$emit("apply-format"))},"自动格式化",8,Jd)]))}},Gd=ke(zd,[["__scopeId","data-v-99eed13a"]]),Ca={abstract_chinese_title:"仅当段落是“摘要”或“摘 要”(允许尾随空格或冒号)",abstract_chinese_title_content:"当且仅当摘要和正文在一个段落中",abstract_english_title:"仅当段落是“Abstract”(大小写不敏感,允许尾随空格或冒号)",abstract_english_title_content:"当且仅当摘要和正文在一个段落中",keywords_chinese:"包含“关键词”或“关键字”,后面跟着术语列表",keywords_english:"包含“Keywords”(大小写不敏感),后面跟着英文术语",chinese_title:"论文中文题目(通常简短且无编号)",english_title:"论文英文题目(通常简短且无编号)",heading_level_1:"段落必须以“第X章”或单个阿拉伯数字(如“1”“2”)开头,后接空格和标题文字;仅为名词短语",heading_level_2:"段落必须以“X.Y”格式开头(如“1.1”),仅含一个“.”;后接标题文字无完整句子",heading_level_3:"段落必须以“X.Y.Z”格式开头(如“1.1.1”),仅含两个“.”;后接标题文字无完整句子",heading_mulu:"目录标题:段落等于“目录”或“目 录”(含空格变体)",heading_fulu:"段落等于“附录”",references_title:"段落等于“参考文献”或“References”",acknowledgements_title:"段落和“致谢”或“Acknowledgements”等词意思相近",caption_figure:"以“图 X.Y”或“Figure X.Y”开头的图注",caption_table:"以“表 X.Y”或“Table X.Y”开头的表注",body_text:"包含完整句子、谓语动词/句号;或含“本章/本文”等明确论述的内容",other:"标记跳过:后端处理时直接忽略该节点(防止误删,仅标记)"},Ro={chinese_title:1,english_title:1,abstract_chinese_title:1,abstract_english_title:1,keywords_chinese:2,keywords_english:2,references_title:1,acknowledgements_title:1,heading_fulu:1,heading_mulu:1,heading_level_1:1,heading_level_2:2,heading_level_3:3,abstract_chinese_title_content:1,abstract_english_title_content:1,caption_figure:5,caption_table:5,body_text:5,other:5},Xd=["#1e40af","#2563eb","#3b82f6","#60a5fa","#93c5fd","#9ca3af"],Ni=.8;function Vi(e,t=Ni){return(e==null?void 0:e.score)r.toLowerCase()===n?`${r}`:r).join("")}const ep={class:"node-list-section"},tp={class:"card"},np={key:0,class:"loading-tip"},ip={key:1,class:"init-tip"},rp={key:2,class:"node-list"},op={key:0,class:"empty-tip"},sp=["onClick"],lp=["title"],ap={class:"node-score"},cp=["innerHTML"],up={key:0,class:"replace-badge",title:"有替换内容"},fp={class:"node-meta"},dp={class:"node-comment"},pp={class:"node-fingerprint"},hp={__name:"NodeListPanel",props:{nodeData:Array,selectedIndex:Number,isFileLoaded:Boolean,isLoading:Boolean,loadingText:String,globalSearchTerm:String},emits:["select-node"],setup(e){return(t,n)=>(H(),K("div",ep,[f("div",tp,[e.isLoading?(H(),K("div",np,[n[0]||(n[0]=f("div",{class:"loading-spinner"},null,-1)),f("p",null,ee(e.loadingText),1)])):e.isFileLoaded?(H(),K("div",rp,[e.nodeData.length===0?(H(),K("div",op,"无匹配的节点")):pt("",!0),(H(!0),K(_e,null,Gt(e.nodeData,(i,r)=>{var o;return H(),K("div",{key:r,class:ve(["node-item",{error:Ye(Vi)(i),other:i.category==="other",selected:e.selectedIndex===r}]),style:Rn({marginLeft:Ye(Qd)(i)}),onClick:s=>t.$emit("select-node",r)},[f("div",{class:"level-dot",style:Rn({backgroundColor:Ye(Sa)(i)})},null,4),f("div",{class:ve(["node-tag",i.category]),title:Ye(Ca)[i.category]||""},ee(i.category.replace(/_/g," ")),11,lp),f("div",ap,ee(i.score.toFixed(4)),1),f("div",{class:"node-content",innerHTML:Ye(Zd)(i.paragraph,e.globalSearchTerm)},null,8,cp),i.replace?(H(),K("span",up,"R")):pt("",!0),f("div",fp,[f("span",dp,ee(i.comment||"无注释"),1),f("span",pp,ee(((o=i.fingerprint)==null?void 0:o.slice(0,8))||"无"),1)])],14,sp)}),128))])):(H(),K("div",ip,[...n[1]||(n[1]=[f("svg",{class:"init-icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[f("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9m-5 13h14a2 2 0 002-2V9a2 2 0 00-2-2h-2.586a1 1 0 01-.707-.293l-2.414-2.414a1 1 0 00-.707-.293H11a2 2 0 00-2 2v1m2 13a2 2 0 01-2-2V7m2 13c3.314 0 6-2.686 6-6V9a6 6 0 00-6-6H9a6 6 0 00-6 6v8a6 6 0 006 6z"})],-1),f("p",null,"请上传docx+yaml配置文件,点击「生成节点JSON」获取节点数据",-1),f("p",{class:"init-sub-tip"},"生成后可修改标签,再执行「格式校验」或「自动格式化」,支持直接下载结果文件",-1)])]))])]))}},gp=ke(hp,[["__scopeId","data-v-d86ce66e"]]),mp={class:"node-detail-section"},bp={class:"card detail-card"},yp={key:0,class:"no-select-tip"},vp={key:1,class:"node-detail-content"},_p={class:"property-card"},xp={class:"property-card-body"},wp={class:"property-item"},Ap={class:"property-value"},Cp={class:"property-item"},Sp={class:"property-item"},Ep={class:"property-value flex items-center"},Op={class:"property-item"},Tp={class:"property-value content-value"},Rp={key:0,class:"property-item"},Fp={class:"property-value content-value replace-value"},Np={class:"property-item"},kp={class:"property-value"},Lp={class:"property-item"},Ip={class:"property-value fingerprint-value"},$p={class:"property-item"},Pp={class:"property-value"},Dp={class:"property-card mt-4"},Mp={class:"property-card-body"},Up={class:"property-item"},jp=["value","title"],Bp={class:"category-desc"},Hp={__name:"NodeDetailPanel",props:{currentNode:Object,categoryConfig:Object,scoreThreshold:Number,totalNodes:Number,nodeIndex:Number},emits:["update-category"],setup(e,{emit:t}){var b;const n=e,i=t,r=be(((b=n.currentNode)==null?void 0:b.category)||"");un(()=>n.currentNode,v=>{v&&(r.value=v.category)});const o=()=>{i("update-category",r.value)},s=Ee(()=>Vi(n.currentNode,n.scoreThreshold)),l=Ee(()=>{var v;return((v=n.currentNode)==null?void 0:v.category)==="other"}),a=Ee(()=>l.value?"status-other":s.value?"status-error":"status-normal"),c=Ee(()=>l.value?"🔖 标记跳过(后端将忽略)":s.value?"❌ 疑似标签错误(得分低于阈值)":"✅ 正常节点(得分高于阈值)"),u=Ee(()=>l.value?"标记层级(无缩进)":`层级 ${Ro[n.currentNode.category]||6} (配置映射)`),d=Ee(()=>l.value?"result-other":s.value?"result-error":"result-normal"),h=Ee(()=>{if(l.value)return"📌 已标记为跳过:后端处理时直接忽略该节点(防止误删)";const v=n.currentNode.score.toFixed(4);return s.value?`❌ 疑似标签错误:得分(${v}) < 阈值(${n.scoreThreshold})`:`✅ 标签匹配正常:得分(${v}) ≥ 阈值(${n.scoreThreshold})`});return(v,g)=>(H(),K("div",mp,[f("div",bp,[g[13]||(g[13]=f("h2",{class:"detail-title"},"节点详情",-1)),e.currentNode?(H(),K("div",vp,[f("div",_p,[g[10]||(g[10]=f("div",{class:"property-card-header"},"固定信息(不可修改)",-1)),f("div",xp,[f("div",wp,[g[2]||(g[2]=f("div",{class:"property-label"},"节点序号",-1)),f("div",Ap,ee(e.nodeIndex)+"/"+ee(e.totalNodes),1)]),f("div",Cp,[g[3]||(g[3]=f("div",{class:"property-label"},"节点状态",-1)),f("div",{class:ve(["property-value status-value",a.value])},ee(c.value),3)]),f("div",Sp,[g[4]||(g[4]=f("div",{class:"property-label"},"节点层级",-1)),f("div",Ep,[f("div",{class:"level-dot mr-2",style:Rn({backgroundColor:Ye(Sa)(e.currentNode)})},null,4),de(" "+ee(u.value),1)])]),f("div",Op,[g[5]||(g[5]=f("div",{class:"property-label"},"节点内容",-1)),f("div",Tp,ee(e.currentNode.paragraph),1)]),e.currentNode.replace?(H(),K("div",Rp,[g[6]||(g[6]=f("div",{class:"property-label replace-label"},"替换内容",-1)),f("div",Fp,ee(e.currentNode.replace),1)])):pt("",!0),f("div",Np,[g[7]||(g[7]=f("div",{class:"property-label"},"置信度得分",-1)),f("div",kp,ee(e.currentNode.score.toFixed(4))+"(判定阈值:"+ee(e.scoreThreshold)+")",1)]),f("div",Lp,[g[8]||(g[8]=f("div",{class:"property-label"},"节点指纹",-1)),f("div",Ip,ee(e.currentNode.fingerprint||"[无指纹]"),1)]),f("div",$p,[g[9]||(g[9]=f("div",{class:"property-label"},"节点注释",-1)),f("div",Pp,ee(e.currentNode.comment||"[无注释]"),1)])])]),f("div",Dp,[g[12]||(g[12]=f("div",{class:"property-card-header"},"可变信息(仅标签可修改)",-1)),f("div",Mp,[f("div",Up,[g[11]||(g[11]=f("div",{class:"property-label"},[de(" 当前分类标签 "),f("span",{class:"label-tip"},"(hover查看标签说明)")],-1)),M(f("select",{class:"category-select","onUpdate:modelValue":g[0]||(g[0]=_=>r.value=_),onChange:o},[(H(!0),K(_e,null,Gt(e.categoryConfig,(_,A)=>(H(),K("option",{key:A,value:A,title:_},ee(A.replace(/_/g," ")),9,jp))),128))],544),[[Ot,r.value]]),f("div",Bp,ee(e.categoryConfig[r.value]||""),1)]),f("div",{class:ve(["check-result",d.value])},ee(h.value),3)])])])):(H(),K("div",yp,[...g[1]||(g[1]=[f("svg",{class:"no-select-icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[f("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})],-1),f("p",null,"生成节点数据后,点击左侧节点查看/修改详情",-1)])]))])]))}},Vp=ke(Hp,[["__scopeId","data-v-caa1c263"]]);function Ea(e,t){return function(){return e.apply(t,arguments)}}const{toString:qp}=Object.prototype,{getPrototypeOf:ur}=Object,{iterator:fr,toStringTag:Oa}=Symbol,dr=(e=>t=>{const n=qp.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),ht=e=>(e=e.toLowerCase(),t=>dr(t)===e),pr=e=>t=>typeof t===e,{isArray:Dn}=Array,Ln=pr("undefined");function yi(e){return e!==null&&!Ln(e)&&e.constructor!==null&&!Ln(e.constructor)&&Ze(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const Ta=ht("ArrayBuffer");function Kp(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&Ta(e.buffer),t}const Wp=pr("string"),Ze=pr("function"),Ra=pr("number"),vi=e=>e!==null&&typeof e=="object",Yp=e=>e===!0||e===!1,ki=e=>{if(dr(e)!=="object")return!1;const t=ur(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Oa in e)&&!(fr in e)},Jp=e=>{if(!vi(e)||yi(e))return!1;try{return Object.keys(e).length===0&&Object.getPrototypeOf(e)===Object.prototype}catch{return!1}},zp=ht("Date"),Gp=ht("File"),Xp=e=>!!(e&&typeof e.uri<"u"),Qp=e=>e&&typeof e.getParts<"u",Zp=ht("Blob"),eh=ht("FileList"),th=e=>vi(e)&&Ze(e.pipe);function nh(){return typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}}const Ls=nh(),Is=typeof Ls.FormData<"u"?Ls.FormData:void 0,ih=e=>{if(!e)return!1;if(Is&&e instanceof Is)return!0;const t=ur(e);if(!t||t===Object.prototype||!Ze(e.append))return!1;const n=dr(e);return n==="formdata"||n==="object"&&Ze(e.toString)&&e.toString()==="[object FormData]"},rh=ht("URLSearchParams"),[oh,sh,lh,ah]=["ReadableStream","Request","Response","Headers"].map(ht),ch=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function _i(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let i,r;if(typeof e!="object"&&(e=[e]),Dn(e))for(i=0,r=e.length;i0;)if(r=n[i],t===r.toLowerCase())return r;return null}const sn=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,Na=e=>!Ln(e)&&e!==sn;function to(...e){const{caseless:t,skipUndefined:n}=Na(this)&&this||{},i={},r=(o,s)=>{if(s==="__proto__"||s==="constructor"||s==="prototype")return;const l=t&&Fa(i,s)||s,a=no(i,l)?i[l]:void 0;ki(a)&&ki(o)?i[l]=to(a,o):ki(o)?i[l]=to({},o):Dn(o)?i[l]=o.slice():(!n||!Ln(o))&&(i[l]=o)};for(let o=0,s=e.length;o(_i(t,(r,o)=>{n&&Ze(r)?Object.defineProperty(e,o,{__proto__:null,value:Ea(r,n),writable:!0,enumerable:!0,configurable:!0}):Object.defineProperty(e,o,{__proto__:null,value:r,writable:!0,enumerable:!0,configurable:!0})},{allOwnKeys:i}),e),fh=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),dh=(e,t,n,i)=>{e.prototype=Object.create(t.prototype,i),Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{__proto__:null,value:t.prototype}),n&&Object.assign(e.prototype,n)},ph=(e,t,n,i)=>{let r,o,s;const l={};if(t=t||{},e==null)return t;do{for(r=Object.getOwnPropertyNames(e),o=r.length;o-- >0;)s=r[o],(!i||i(s,e,t))&&!l[s]&&(t[s]=e[s],l[s]=!0);e=n!==!1&&ur(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},hh=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const i=e.indexOf(t,n);return i!==-1&&i===n},gh=e=>{if(!e)return null;if(Dn(e))return e;let t=e.length;if(!Ra(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},mh=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&ur(Uint8Array)),bh=(e,t)=>{const i=(e&&e[fr]).call(e);let r;for(;(r=i.next())&&!r.done;){const o=r.value;t.call(e,o[0],o[1])}},yh=(e,t)=>{let n;const i=[];for(;(n=e.exec(t))!==null;)i.push(n);return i},vh=ht("HTMLFormElement"),_h=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,i,r){return i.toUpperCase()+r}),no=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),xh=ht("RegExp"),ka=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),i={};_i(n,(r,o)=>{let s;(s=t(r,o,e))!==!1&&(i[o]=s||r)}),Object.defineProperties(e,i)},wh=e=>{ka(e,(t,n)=>{if(Ze(e)&&["arguments","caller","callee"].includes(n))return!1;const i=e[n];if(Ze(i)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},Ah=(e,t)=>{const n={},i=r=>{r.forEach(o=>{n[o]=!0})};return Dn(e)?i(e):i(String(e).split(t)),n},Ch=()=>{},Sh=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function Eh(e){return!!(e&&Ze(e.append)&&e[Oa]==="FormData"&&e[fr])}const Oh=e=>{const t=new Array(10),n=(i,r)=>{if(vi(i)){if(t.indexOf(i)>=0)return;if(yi(i))return i;if(!("toJSON"in i)){t[r]=i;const o=Dn(i)?[]:{};return _i(i,(s,l)=>{const a=n(s,r+1);!Ln(a)&&(o[l]=a)}),t[r]=void 0,o}}return i};return n(e,0)},Th=ht("AsyncFunction"),Rh=e=>e&&(vi(e)||Ze(e))&&Ze(e.then)&&Ze(e.catch),La=((e,t)=>e?setImmediate:t?((n,i)=>(sn.addEventListener("message",({source:r,data:o})=>{r===sn&&o===n&&i.length&&i.shift()()},!1),r=>{i.push(r),sn.postMessage(n,"*")}))(`axios@${Math.random()}`,[]):n=>setTimeout(n))(typeof setImmediate=="function",Ze(sn.postMessage)),Fh=typeof queueMicrotask<"u"?queueMicrotask.bind(sn):typeof process<"u"&&process.nextTick||La,Nh=e=>e!=null&&Ze(e[fr]),y={isArray:Dn,isArrayBuffer:Ta,isBuffer:yi,isFormData:ih,isArrayBufferView:Kp,isString:Wp,isNumber:Ra,isBoolean:Yp,isObject:vi,isPlainObject:ki,isEmptyObject:Jp,isReadableStream:oh,isRequest:sh,isResponse:lh,isHeaders:ah,isUndefined:Ln,isDate:zp,isFile:Gp,isReactNativeBlob:Xp,isReactNative:Qp,isBlob:Zp,isRegExp:xh,isFunction:Ze,isStream:th,isURLSearchParams:rh,isTypedArray:mh,isFileList:eh,forEach:_i,merge:to,extend:uh,trim:ch,stripBOM:fh,inherits:dh,toFlatObject:ph,kindOf:dr,kindOfTest:ht,endsWith:hh,toArray:gh,forEachEntry:bh,matchAll:yh,isHTMLForm:vh,hasOwnProperty:no,hasOwnProp:no,reduceDescriptors:ka,freezeMethods:wh,toObjectSet:Ah,toCamelCase:_h,noop:Ch,toFiniteNumber:Sh,findKey:Fa,global:sn,isContextDefined:Na,isSpecCompliantForm:Eh,toJSONObject:Oh,isAsyncFn:Th,isThenable:Rh,setImmediate:La,asap:Fh,isIterable:Nh},kh=y.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Lh=e=>{const t={};let n,i,r;return e&&e.split(` -`).forEach(function(s){r=s.indexOf(":"),n=s.substring(0,r).trim().toLowerCase(),i=s.substring(r+1).trim(),!(!n||t[n]&&kh[n])&&(n==="set-cookie"?t[n]?t[n].push(i):t[n]=[i]:t[n]=t[n]?t[n]+", "+i:i)}),t},$s=Symbol("internals"),Ih=/[^\x09\x20-\x7E\x80-\xFF]/g;function $h(e){let t=0,n=e.length;for(;tt;){const i=e.charCodeAt(n-1);if(i!==9&&i!==32)break;n-=1}return t===0&&n===e.length?e:e.slice(t,n)}function qn(e){return e&&String(e).trim().toLowerCase()}function Ph(e){return $h(e.replace(Ih,""))}function Li(e){return e===!1||e==null?e:y.isArray(e)?e.map(Li):Ph(String(e))}function Dh(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let i;for(;i=n.exec(e);)t[i[1]]=i[2];return t}const Mh=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function Nr(e,t,n,i,r){if(y.isFunction(i))return i.call(this,t,n);if(r&&(t=n),!!y.isString(t)){if(y.isString(i))return t.indexOf(i)!==-1;if(y.isRegExp(i))return i.test(t)}}function Uh(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,i)=>n.toUpperCase()+i)}function jh(e,t){const n=y.toCamelCase(" "+t);["get","set","has"].forEach(i=>{Object.defineProperty(e,i+n,{__proto__:null,value:function(r,o,s){return this[i].call(this,t,r,o,s)},configurable:!0})})}let Ge=class{constructor(t){t&&this.set(t)}set(t,n,i){const r=this;function o(l,a,c){const u=qn(a);if(!u)throw new Error("header name must be a non-empty string");const d=y.findKey(r,u);(!d||r[d]===void 0||c===!0||c===void 0&&r[d]!==!1)&&(r[d||a]=Li(l))}const s=(l,a)=>y.forEach(l,(c,u)=>o(c,u,a));if(y.isPlainObject(t)||t instanceof this.constructor)s(t,n);else if(y.isString(t)&&(t=t.trim())&&!Mh(t))s(Lh(t),n);else if(y.isObject(t)&&y.isIterable(t)){let l={},a,c;for(const u of t){if(!y.isArray(u))throw TypeError("Object iterator must return a key-value pair");l[c=u[0]]=(a=l[c])?y.isArray(a)?[...a,u[1]]:[a,u[1]]:u[1]}s(l,n)}else t!=null&&o(n,t,i);return this}get(t,n){if(t=qn(t),t){const i=y.findKey(this,t);if(i){const r=this[i];if(!n)return r;if(n===!0)return Dh(r);if(y.isFunction(n))return n.call(this,r,i);if(y.isRegExp(n))return n.exec(r);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=qn(t),t){const i=y.findKey(this,t);return!!(i&&this[i]!==void 0&&(!n||Nr(this,this[i],i,n)))}return!1}delete(t,n){const i=this;let r=!1;function o(s){if(s=qn(s),s){const l=y.findKey(i,s);l&&(!n||Nr(i,i[l],l,n))&&(delete i[l],r=!0)}}return y.isArray(t)?t.forEach(o):o(t),r}clear(t){const n=Object.keys(this);let i=n.length,r=!1;for(;i--;){const o=n[i];(!t||Nr(this,this[o],o,t,!0))&&(delete this[o],r=!0)}return r}normalize(t){const n=this,i={};return y.forEach(this,(r,o)=>{const s=y.findKey(i,o);if(s){n[s]=Li(r),delete n[o];return}const l=t?Uh(o):String(o).trim();l!==o&&delete n[o],n[l]=Li(r),i[l]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return y.forEach(this,(i,r)=>{i!=null&&i!==!1&&(n[r]=t&&y.isArray(i)?i.join(", "):i)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` -`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const i=new this(t);return n.forEach(r=>i.set(r)),i}static accessor(t){const i=(this[$s]=this[$s]={accessors:{}}).accessors,r=this.prototype;function o(s){const l=qn(s);i[l]||(jh(r,s),i[l]=!0)}return y.isArray(t)?t.forEach(o):o(t),this}};Ge.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);y.reduceDescriptors(Ge.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(i){this[n]=i}}});y.freezeMethods(Ge);const Bh="[REDACTED ****]";function Hh(e){if(y.hasOwnProp(e,"toJSON"))return!0;let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;){if(y.hasOwnProp(t,"toJSON"))return!0;t=Object.getPrototypeOf(t)}return!1}function Vh(e,t){const n=new Set(t.map(o=>String(o).toLowerCase())),i=[],r=o=>{if(o===null||typeof o!="object"||y.isBuffer(o))return o;if(i.indexOf(o)!==-1)return;o instanceof Ge&&(o=o.toJSON()),i.push(o);let s;if(y.isArray(o))s=[],o.forEach((l,a)=>{const c=r(l);y.isUndefined(c)||(s[a]=c)});else{if(!y.isPlainObject(o)&&Hh(o))return i.pop(),o;s=Object.create(null);for(const[l,a]of Object.entries(o)){const c=n.has(l.toLowerCase())?Bh:r(a);y.isUndefined(c)||(s[l]=c)}}return i.pop(),s};return r(e)}let P=class Ia extends Error{static from(t,n,i,r,o,s){const l=new Ia(t.message,n||t.code,i,r,o);return l.cause=t,l.name=t.name,t.status!=null&&l.status==null&&(l.status=t.status),s&&Object.assign(l,s),l}constructor(t,n,i,r,o){super(t),Object.defineProperty(this,"message",{__proto__:null,value:t,enumerable:!0,writable:!0,configurable:!0}),this.name="AxiosError",this.isAxiosError=!0,n&&(this.code=n),i&&(this.config=i),r&&(this.request=r),o&&(this.response=o,this.status=o.status)}toJSON(){const t=this.config,n=t&&y.hasOwnProp(t,"redact")?t.redact:void 0,i=y.isArray(n)&&n.length>0?Vh(t,n):y.toJSONObject(t);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:i,code:this.code,status:this.status}}};P.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";P.ERR_BAD_OPTION="ERR_BAD_OPTION";P.ECONNABORTED="ECONNABORTED";P.ETIMEDOUT="ETIMEDOUT";P.ECONNREFUSED="ECONNREFUSED";P.ERR_NETWORK="ERR_NETWORK";P.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";P.ERR_DEPRECATED="ERR_DEPRECATED";P.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";P.ERR_BAD_REQUEST="ERR_BAD_REQUEST";P.ERR_CANCELED="ERR_CANCELED";P.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";P.ERR_INVALID_URL="ERR_INVALID_URL";P.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";const qh=null;function io(e){return y.isPlainObject(e)||y.isArray(e)}function $a(e){return y.endsWith(e,"[]")?e.slice(0,-2):e}function kr(e,t,n){return e?e.concat(t).map(function(r,o){return r=$a(r),!n&&o?"["+r+"]":r}).join(n?".":""):t}function Kh(e){return y.isArray(e)&&!e.some(io)}const Wh=y.toFlatObject(y,{},null,function(t){return/^is[A-Z]/.test(t)});function hr(e,t,n){if(!y.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=y.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(_,A){return!y.isUndefined(A[_])});const i=n.metaTokens,r=n.visitor||d,o=n.dots,s=n.indexes,l=n.Blob||typeof Blob<"u"&&Blob,a=n.maxDepth===void 0?100:n.maxDepth,c=l&&y.isSpecCompliantForm(t);if(!y.isFunction(r))throw new TypeError("visitor must be a function");function u(g){if(g===null)return"";if(y.isDate(g))return g.toISOString();if(y.isBoolean(g))return g.toString();if(!c&&y.isBlob(g))throw new P("Blob is not supported. Use a Buffer instead.");return y.isArrayBuffer(g)||y.isTypedArray(g)?c&&typeof Blob=="function"?new Blob([g]):Buffer.from(g):g}function d(g,_,A){let C=g;if(y.isReactNative(t)&&y.isReactNativeBlob(g))return t.append(kr(A,_,o),u(g)),!1;if(g&&!A&&typeof g=="object"){if(y.endsWith(_,"{}"))_=i?_:_.slice(0,-2),g=JSON.stringify(g);else if(y.isArray(g)&&Kh(g)||(y.isFileList(g)||y.endsWith(_,"[]"))&&(C=y.toArray(g)))return _=$a(_),C.forEach(function(R,G){!(y.isUndefined(R)||R===null)&&t.append(s===!0?kr([_],G,o):s===null?_:_+"[]",u(R))}),!1}return io(g)?!0:(t.append(kr(A,_,o),u(g)),!1)}const h=[],b=Object.assign(Wh,{defaultVisitor:d,convertValue:u,isVisitable:io});function v(g,_,A=0){if(!y.isUndefined(g)){if(A>a)throw new P("Object is too deeply nested ("+A+" levels). Max depth: "+a,P.ERR_FORM_DATA_DEPTH_EXCEEDED);if(h.indexOf(g)!==-1)throw Error("Circular reference detected in "+_.join("."));h.push(g),y.forEach(g,function($,R){(!(y.isUndefined($)||$===null)&&r.call(t,$,y.isString(R)?R.trim():R,_,b))===!0&&v($,_?_.concat(R):[R],A+1)}),h.pop()}}if(!y.isObject(e))throw new TypeError("data must be an object");return v(e),t}function Ps(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(e).replace(/[!'()~]|%20/g,function(i){return t[i]})}function Fo(e,t){this._pairs=[],e&&hr(e,this,t)}const Pa=Fo.prototype;Pa.append=function(t,n){this._pairs.push([t,n])};Pa.toString=function(t){const n=t?function(i){return t.call(this,i,Ps)}:Ps;return this._pairs.map(function(r){return n(r[0])+"="+n(r[1])},"").join("&")};function Yh(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function Da(e,t,n){if(!t)return e;const i=n&&n.encode||Yh,r=y.isFunction(n)?{serialize:n}:n,o=r&&r.serialize;let s;if(o?s=o(t,r):s=y.isURLSearchParams(t)?t.toString():new Fo(t,r).toString(i),s){const l=e.indexOf("#");l!==-1&&(e=e.slice(0,l)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}class Ds{constructor(){this.handlers=[]}use(t,n,i){return this.handlers.push({fulfilled:t,rejected:n,synchronous:i?i.synchronous:!1,runWhen:i?i.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){y.forEach(this.handlers,function(i){i!==null&&t(i)})}}const No={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1,legacyInterceptorReqResOrdering:!0},Jh=typeof URLSearchParams<"u"?URLSearchParams:Fo,zh=typeof FormData<"u"?FormData:null,Gh=typeof Blob<"u"?Blob:null,Xh={isBrowser:!0,classes:{URLSearchParams:Jh,FormData:zh,Blob:Gh},protocols:["http","https","file","blob","url","data"]},ko=typeof window<"u"&&typeof document<"u",ro=typeof navigator=="object"&&navigator||void 0,Qh=ko&&(!ro||["ReactNative","NativeScript","NS"].indexOf(ro.product)<0),Zh=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",eg=ko&&window.location.href||"http://localhost",tg=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:ko,hasStandardBrowserEnv:Qh,hasStandardBrowserWebWorkerEnv:Zh,navigator:ro,origin:eg},Symbol.toStringTag,{value:"Module"})),Ue={...tg,...Xh};function ng(e,t){return hr(e,new Ue.classes.URLSearchParams,{visitor:function(n,i,r,o){return Ue.isNode&&y.isBuffer(n)?(this.append(i,n.toString("base64")),!1):o.defaultVisitor.apply(this,arguments)},...t})}function ig(e){return y.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function rg(e){const t={},n=Object.keys(e);let i;const r=n.length;let o;for(i=0;i=n.length;return s=!s&&y.isArray(r)?r.length:s,a?(y.hasOwnProp(r,s)?r[s]=y.isArray(r[s])?r[s].concat(i):[r[s],i]:r[s]=i,!l):((!r[s]||!y.isObject(r[s]))&&(r[s]=[]),t(n,i,r[s],o)&&y.isArray(r[s])&&(r[s]=rg(r[s])),!l)}if(y.isFormData(e)&&y.isFunction(e.entries)){const n={};return y.forEachEntry(e,(i,r)=>{t(ig(i),r,n,0)}),n}return null}const bn=(e,t)=>e!=null&&y.hasOwnProp(e,t)?e[t]:void 0;function og(e,t,n){if(y.isString(e))try{return(t||JSON.parse)(e),y.trim(e)}catch(i){if(i.name!=="SyntaxError")throw i}return(n||JSON.stringify)(e)}const xi={transitional:No,adapter:["xhr","http","fetch"],transformRequest:[function(t,n){const i=n.getContentType()||"",r=i.indexOf("application/json")>-1,o=y.isObject(t);if(o&&y.isHTMLForm(t)&&(t=new FormData(t)),y.isFormData(t))return r?JSON.stringify(Ma(t)):t;if(y.isArrayBuffer(t)||y.isBuffer(t)||y.isStream(t)||y.isFile(t)||y.isBlob(t)||y.isReadableStream(t))return t;if(y.isArrayBufferView(t))return t.buffer;if(y.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let l;if(o){const a=bn(this,"formSerializer");if(i.indexOf("application/x-www-form-urlencoded")>-1)return ng(t,a).toString();if((l=y.isFileList(t))||i.indexOf("multipart/form-data")>-1){const c=bn(this,"env"),u=c&&c.FormData;return hr(l?{"files[]":t}:t,u&&new u,a)}}return o||r?(n.setContentType("application/json",!1),og(t)):t}],transformResponse:[function(t){const n=bn(this,"transitional")||xi.transitional,i=n&&n.forcedJSONParsing,r=bn(this,"responseType"),o=r==="json";if(y.isResponse(t)||y.isReadableStream(t))return t;if(t&&y.isString(t)&&(i&&!r||o)){const l=!(n&&n.silentJSONParsing)&&o;try{return JSON.parse(t,bn(this,"parseReviver"))}catch(a){if(l)throw a.name==="SyntaxError"?P.from(a,P.ERR_BAD_RESPONSE,this,null,bn(this,"response")):a}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:Ue.classes.FormData,Blob:Ue.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};y.forEach(["delete","get","head","post","put","patch","query"],e=>{xi.headers[e]={}});function Lr(e,t){const n=this||xi,i=t||n,r=Ge.from(i.headers);let o=i.data;return y.forEach(e,function(l){o=l.call(n,o,r.normalize(),t?t.status:void 0)}),r.normalize(),o}function Ua(e){return!!(e&&e.__CANCEL__)}let wi=class extends P{constructor(t,n,i){super(t??"canceled",P.ERR_CANCELED,n,i),this.name="CanceledError",this.__CANCEL__=!0}};function ja(e,t,n){const i=n.config.validateStatus;!n.status||!i||i(n.status)?e(n):t(new P("Request failed with status code "+n.status,n.status>=400&&n.status<500?P.ERR_BAD_REQUEST:P.ERR_BAD_RESPONSE,n.config,n.request,n))}function sg(e){const t=/^([-+\w]{1,25}):(?:\/\/)?/.exec(e);return t&&t[1]||""}function lg(e,t){e=e||10;const n=new Array(e),i=new Array(e);let r=0,o=0,s;return t=t!==void 0?t:1e3,function(a){const c=Date.now(),u=i[o];s||(s=c),n[r]=a,i[r]=c;let d=o,h=0;for(;d!==r;)h+=n[d++],d=d%e;if(r=(r+1)%e,r===o&&(o=(o+1)%e),c-s{n=u,r=null,o&&(clearTimeout(o),o=null),e(...c)};return[(...c)=>{const u=Date.now(),d=u-n;d>=i?s(c,u):(r=c,o||(o=setTimeout(()=>{o=null,s(r)},i-d)))},()=>r&&s(r)]}const qi=(e,t,n=3)=>{let i=0;const r=lg(50,250);return ag(o=>{const s=o.loaded,l=o.lengthComputable?o.total:void 0,a=l!=null?Math.min(s,l):s,c=Math.max(0,a-i),u=r(c);i=Math.max(i,a);const d={loaded:a,total:l,progress:l?a/l:void 0,bytes:c,rate:u||void 0,estimated:u&&l?(l-a)/u:void 0,event:o,lengthComputable:l!=null,[t?"download":"upload"]:!0};e(d)},n)},Ms=(e,t)=>{const n=e!=null;return[i=>t[0]({lengthComputable:n,total:e,loaded:i}),t[1]]},Us=e=>(...t)=>y.asap(()=>e(...t)),cg=Ue.hasStandardBrowserEnv?((e,t)=>n=>(n=new URL(n,Ue.origin),e.protocol===n.protocol&&e.host===n.host&&(t||e.port===n.port)))(new URL(Ue.origin),Ue.navigator&&/(msie|trident)/i.test(Ue.navigator.userAgent)):()=>!0,ug=Ue.hasStandardBrowserEnv?{write(e,t,n,i,r,o,s){if(typeof document>"u")return;const l=[`${e}=${encodeURIComponent(t)}`];y.isNumber(n)&&l.push(`expires=${new Date(n).toUTCString()}`),y.isString(i)&&l.push(`path=${i}`),y.isString(r)&&l.push(`domain=${r}`),o===!0&&l.push("secure"),y.isString(s)&&l.push(`SameSite=${s}`),document.cookie=l.join("; ")},read(e){if(typeof document>"u")return null;const t=document.cookie.split(";");for(let n=0;ne instanceof Ge?{...e}:e;function hn(e,t){t=t||{};const n=Object.create(null);Object.defineProperty(n,"hasOwnProperty",{__proto__:null,value:Object.prototype.hasOwnProperty,enumerable:!1,writable:!0,configurable:!0});function i(c,u,d,h){return y.isPlainObject(c)&&y.isPlainObject(u)?y.merge.call({caseless:h},c,u):y.isPlainObject(u)?y.merge({},u):y.isArray(u)?u.slice():u}function r(c,u,d,h){if(y.isUndefined(u)){if(!y.isUndefined(c))return i(void 0,c,d,h)}else return i(c,u,d,h)}function o(c,u){if(!y.isUndefined(u))return i(void 0,u)}function s(c,u){if(y.isUndefined(u)){if(!y.isUndefined(c))return i(void 0,c)}else return i(void 0,u)}function l(c,u,d){if(y.hasOwnProp(t,d))return i(c,u);if(y.hasOwnProp(e,d))return i(void 0,c)}const a={url:o,method:o,data:o,baseURL:s,transformRequest:s,transformResponse:s,paramsSerializer:s,timeout:s,timeoutMessage:s,withCredentials:s,withXSRFToken:s,adapter:s,responseType:s,xsrfCookieName:s,xsrfHeaderName:s,onUploadProgress:s,onDownloadProgress:s,decompress:s,maxContentLength:s,maxBodyLength:s,beforeRedirect:s,transport:s,httpAgent:s,httpsAgent:s,cancelToken:s,socketPath:s,allowedSocketPaths:s,responseEncoding:s,validateStatus:l,headers:(c,u,d)=>r(js(c),js(u),d,!0)};return y.forEach(Object.keys({...e,...t}),function(u){if(u==="__proto__"||u==="constructor"||u==="prototype")return;const d=y.hasOwnProp(a,u)?a[u]:r,h=y.hasOwnProp(e,u)?e[u]:void 0,b=y.hasOwnProp(t,u)?t[u]:void 0,v=d(h,b,u);y.isUndefined(v)&&d!==l||(n[u]=v)}),n}const pg=["content-type","content-length"];function hg(e,t,n){if(n!=="content-only"){e.set(t);return}Object.entries(t).forEach(([i,r])=>{pg.includes(i.toLowerCase())&&e.set(i,r)})}const gg=e=>encodeURIComponent(e).replace(/%([0-9A-F]{2})/gi,(t,n)=>String.fromCharCode(parseInt(n,16))),Ha=e=>{const t=hn({},e),n=h=>y.hasOwnProp(t,h)?t[h]:void 0,i=n("data");let r=n("withXSRFToken");const o=n("xsrfHeaderName"),s=n("xsrfCookieName");let l=n("headers");const a=n("auth"),c=n("baseURL"),u=n("allowAbsoluteUrls"),d=n("url");if(t.headers=l=Ge.from(l),t.url=Da(Ba(c,d,u),e.params,e.paramsSerializer),a&&l.set("Authorization","Basic "+btoa((a.username||"")+":"+(a.password?gg(a.password):""))),y.isFormData(i)&&(Ue.hasStandardBrowserEnv||Ue.hasStandardBrowserWebWorkerEnv?l.setContentType(void 0):y.isFunction(i.getHeaders)&&hg(l,i.getHeaders(),n("formDataHeaderPolicy"))),Ue.hasStandardBrowserEnv&&(y.isFunction(r)&&(r=r(t)),r===!0||r==null&&cg(t.url))){const b=o&&s&&ug.read(s);b&&l.set(o,b)}return t},mg=typeof XMLHttpRequest<"u",bg=mg&&function(e){return new Promise(function(n,i){const r=Ha(e);let o=r.data;const s=Ge.from(r.headers).normalize();let{responseType:l,onUploadProgress:a,onDownloadProgress:c}=r,u,d,h,b,v;function g(){b&&b(),v&&v(),r.cancelToken&&r.cancelToken.unsubscribe(u),r.signal&&r.signal.removeEventListener("abort",u)}let _=new XMLHttpRequest;_.open(r.method.toUpperCase(),r.url,!0),_.timeout=r.timeout;function A(){if(!_)return;const $=Ge.from("getAllResponseHeaders"in _&&_.getAllResponseHeaders()),G={data:!l||l==="text"||l==="json"?_.responseText:_.response,status:_.status,statusText:_.statusText,headers:$,config:e,request:_};ja(function(J){n(J),g()},function(J){i(J),g()},G),_=null}"onloadend"in _?_.onloadend=A:_.onreadystatechange=function(){!_||_.readyState!==4||_.status===0&&!(_.responseURL&&_.responseURL.startsWith("file:"))||setTimeout(A)},_.onabort=function(){_&&(i(new P("Request aborted",P.ECONNABORTED,e,_)),g(),_=null)},_.onerror=function(R){const G=R&&R.message?R.message:"Network Error",re=new P(G,P.ERR_NETWORK,e,_);re.event=R||null,i(re),g(),_=null},_.ontimeout=function(){let R=r.timeout?"timeout of "+r.timeout+"ms exceeded":"timeout exceeded";const G=r.transitional||No;r.timeoutErrorMessage&&(R=r.timeoutErrorMessage),i(new P(R,G.clarifyTimeoutError?P.ETIMEDOUT:P.ECONNABORTED,e,_)),g(),_=null},o===void 0&&s.setContentType(null),"setRequestHeader"in _&&y.forEach(s.toJSON(),function(R,G){_.setRequestHeader(G,R)}),y.isUndefined(r.withCredentials)||(_.withCredentials=!!r.withCredentials),l&&l!=="json"&&(_.responseType=r.responseType),c&&([h,v]=qi(c,!0),_.addEventListener("progress",h)),a&&_.upload&&([d,b]=qi(a),_.upload.addEventListener("progress",d),_.upload.addEventListener("loadend",b)),(r.cancelToken||r.signal)&&(u=$=>{_&&(i(!$||$.type?new wi(null,e,_):$),_.abort(),g(),_=null)},r.cancelToken&&r.cancelToken.subscribe(u),r.signal&&(r.signal.aborted?u():r.signal.addEventListener("abort",u)));const C=sg(r.url);if(C&&!Ue.protocols.includes(C)){i(new P("Unsupported protocol "+C+":",P.ERR_BAD_REQUEST,e));return}_.send(o||null)})},yg=(e,t)=>{const{length:n}=e=e?e.filter(Boolean):[];if(t||n){let i=new AbortController,r;const o=function(c){if(!r){r=!0,l();const u=c instanceof Error?c:this.reason;i.abort(u instanceof P?u:new wi(u instanceof Error?u.message:u))}};let s=t&&setTimeout(()=>{s=null,o(new P(`timeout of ${t}ms exceeded`,P.ETIMEDOUT))},t);const l=()=>{e&&(s&&clearTimeout(s),s=null,e.forEach(c=>{c.unsubscribe?c.unsubscribe(o):c.removeEventListener("abort",o)}),e=null)};e.forEach(c=>c.addEventListener("abort",o));const{signal:a}=i;return a.unsubscribe=()=>y.asap(l),a}},vg=function*(e,t){let n=e.byteLength;if(n{const r=_g(e,t);let o=0,s,l=a=>{s||(s=!0,i&&i(a))};return new ReadableStream({async pull(a){try{const{done:c,value:u}=await r.next();if(c){l(),a.close();return}let d=u.byteLength;if(n){let h=o+=d;n(h)}a.enqueue(new Uint8Array(u))}catch(c){throw l(c),c}},cancel(a){return l(a),r.return()}},{highWaterMark:2})};function wg(e){if(!e||typeof e!="string"||!e.startsWith("data:"))return 0;const t=e.indexOf(",");if(t<0)return 0;const n=e.slice(5,t),i=e.slice(t+1);if(/;base64/i.test(n)){let s=i.length;const l=i.length;for(let b=0;b=48&&v<=57||v>=65&&v<=70||v>=97&&v<=102)&&(g>=48&&g<=57||g>=65&&g<=70||g>=97&&g<=102)&&(s-=2,b+=2)}let a=0,c=l-1;const u=b=>b>=2&&i.charCodeAt(b-2)===37&&i.charCodeAt(b-1)===51&&(i.charCodeAt(b)===68||i.charCodeAt(b)===100);c>=0&&(i.charCodeAt(c)===61?(a++,c--):u(c)&&(a++,c-=3)),a===1&&c>=0&&(i.charCodeAt(c)===61||u(c))&&a++;const h=Math.floor(s/4)*3-(a||0);return h>0?h:0}if(typeof Buffer<"u"&&typeof Buffer.byteLength=="function")return Buffer.byteLength(i,"utf8");let o=0;for(let s=0,l=i.length;s=55296&&a<=56319&&s+1=56320&&c<=57343?(o+=4,s++):o+=3}else o+=3}return o}const Lo="1.16.0",Hs=64*1024,{isFunction:Oi}=y,Vs=(e,...t)=>{try{return!!e(...t)}catch{return!1}},Ag=e=>{const t=y.global??globalThis,{ReadableStream:n,TextEncoder:i}=t;e=y.merge.call({skipUndefined:!0},{Request:t.Request,Response:t.Response},e);const{fetch:r,Request:o,Response:s}=e,l=r?Oi(r):typeof fetch=="function",a=Oi(o),c=Oi(s);if(!l)return!1;const u=l&&Oi(n),d=l&&(typeof i=="function"?(A=>C=>A.encode(C))(new i):async A=>new Uint8Array(await new o(A).arrayBuffer())),h=a&&u&&Vs(()=>{let A=!1;const C=new o(Ue.origin,{body:new n,method:"POST",get duplex(){return A=!0,"half"}}),$=C.headers.has("Content-Type");return C.body!=null&&C.body.cancel(),A&&!$}),b=c&&u&&Vs(()=>y.isReadableStream(new s("").body)),v={stream:b&&(A=>A.body)};l&&["text","arrayBuffer","blob","formData","stream"].forEach(A=>{!v[A]&&(v[A]=(C,$)=>{let R=C&&C[A];if(R)return R.call(C);throw new P(`Response type '${A}' is not supported`,P.ERR_NOT_SUPPORT,$)})});const g=async A=>{if(A==null)return 0;if(y.isBlob(A))return A.size;if(y.isSpecCompliantForm(A))return(await new o(Ue.origin,{method:"POST",body:A}).arrayBuffer()).byteLength;if(y.isArrayBufferView(A)||y.isArrayBuffer(A))return A.byteLength;if(y.isURLSearchParams(A)&&(A=A+""),y.isString(A))return(await d(A)).byteLength},_=async(A,C)=>{const $=y.toFiniteNumber(A.getContentLength());return $??g(C)};return async A=>{let{url:C,method:$,data:R,signal:G,cancelToken:re,timeout:J,onDownloadProgress:ne,onUploadProgress:U,responseType:X,headers:F,withCredentials:w="same-origin",fetchOptions:j,maxContentLength:D,maxBodyLength:se}=Ha(A);const Z=y.isNumber(D)&&D>-1,te=y.isNumber(se)&&se>-1;let ie=r||fetch;X=X?(X+"").toLowerCase():"text";let xe=yg([G,re&&re.toAbortSignal()],J),Le=null;const Ve=xe&&xe.unsubscribe&&(()=>{xe.unsubscribe()});let et;try{if(Z&&typeof C=="string"&&C.startsWith("data:")&&wg(C)>D)throw new P("maxContentLength size of "+D+" exceeded",P.ERR_BAD_RESPONSE,A,Le);if(te&&$!=="get"&&$!=="head"){const ae=await _(F,R);if(typeof ae=="number"&&isFinite(ae)&&ae>se)throw new P("Request body larger than maxBodyLength limit",P.ERR_BAD_REQUEST,A,Le)}if(U&&h&&$!=="get"&&$!=="head"&&(et=await _(F,R))!==0){let ae=new o(C,{method:"POST",body:R,duplex:"half"}),kt;if(y.isFormData(R)&&(kt=ae.headers.get("content-type"))&&F.setContentType(kt),ae.body){const[mt,Mn]=Ms(et,qi(Us(U)));R=Bs(ae.body,Hs,mt,Mn)}}y.isString(w)||(w=w?"include":"omit");const Te=a&&"credentials"in o.prototype;if(y.isFormData(R)){const ae=F.getContentType();ae&&/^multipart\/form-data/i.test(ae)&&!/boundary=/i.test(ae)&&F.delete("content-type")}F.set("User-Agent","axios/"+Lo,!1);const gt={...j,signal:xe,method:$.toUpperCase(),headers:F.normalize().toJSON(),body:R,duplex:"half",credentials:Te?w:void 0};Le=a&&new o(C,gt);let it=await(a?ie(Le,j):ie(C,gt));if(Z){const ae=y.toFiniteNumber(it.headers.get("content-length"));if(ae!=null&&ae>D)throw new P("maxContentLength size of "+D+" exceeded",P.ERR_BAD_RESPONSE,A,Le)}const Nt=b&&(X==="stream"||X==="response");if(b&&it.body&&(ne||Z||Nt&&Ve)){const ae={};["status","statusText","headers"].forEach(x=>{ae[x]=it[x]});const kt=y.toFiniteNumber(it.headers.get("content-length")),[mt,Mn]=ne&&Ms(kt,qi(Us(ne),!0))||[];let p=0;const m=x=>{if(Z&&(p=x,p>D))throw new P("maxContentLength size of "+D+" exceeded",P.ERR_BAD_RESPONSE,A,Le);mt&&mt(x)};it=new s(Bs(it.body,Hs,m,()=>{Mn&&Mn(),Ve&&Ve()}),ae)}X=X||"text";let Xe=await v[y.findKey(v,X)||"text"](it,A);if(Z&&!b&&!Nt){let ae;if(Xe!=null&&(typeof Xe.byteLength=="number"?ae=Xe.byteLength:typeof Xe.size=="number"?ae=Xe.size:typeof Xe=="string"&&(ae=typeof i=="function"?new i().encode(Xe).byteLength:Xe.length)),typeof ae=="number"&&ae>D)throw new P("maxContentLength size of "+D+" exceeded",P.ERR_BAD_RESPONSE,A,Le)}return!Nt&&Ve&&Ve(),await new Promise((ae,kt)=>{ja(ae,kt,{data:Xe,headers:Ge.from(it.headers),status:it.status,statusText:it.statusText,config:A,request:Le})})}catch(Te){if(Ve&&Ve(),xe&&xe.aborted&&xe.reason instanceof P){const gt=xe.reason;throw gt.config=A,Le&&(gt.request=Le),Te!==gt&&(gt.cause=Te),gt}throw Te&&Te.name==="TypeError"&&/Load failed|fetch/i.test(Te.message)?Object.assign(new P("Network Error",P.ERR_NETWORK,A,Le,Te&&Te.response),{cause:Te.cause||Te}):P.from(Te,Te&&Te.code,A,Le,Te&&Te.response)}}},Cg=new Map,Va=e=>{let t=e&&e.env||{};const{fetch:n,Request:i,Response:r}=t,o=[i,r,n];let s=o.length,l=s,a,c,u=Cg;for(;l--;)a=o[l],c=u.get(a),c===void 0&&u.set(a,c=l?new Map:Ag(t)),u=c;return c};Va();const Io={http:qh,xhr:bg,fetch:{get:Va}};y.forEach(Io,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{__proto__:null,value:t})}catch{}Object.defineProperty(e,"adapterName",{__proto__:null,value:t})}});const qs=e=>`- ${e}`,Sg=e=>y.isFunction(e)||e===null||e===!1;function Eg(e,t){e=y.isArray(e)?e:[e];const{length:n}=e;let i,r;const o={};for(let s=0;s`adapter ${a} `+(c===!1?"is not supported by the environment":"is not available in the build"));let l=n?s.length>1?`since : -`+s.map(qs).join(` -`):" "+qs(s[0]):"as no adapter specified";throw new P("There is no suitable adapter to dispatch the request "+l,"ERR_NOT_SUPPORT")}return r}const qa={getAdapter:Eg,adapters:Io};function Ir(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new wi(null,e)}function Ks(e){return Ir(e),e.headers=Ge.from(e.headers),e.data=Lr.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),qa.getAdapter(e.adapter||xi.adapter,e)(e).then(function(i){Ir(e),e.response=i;try{i.data=Lr.call(e,e.transformResponse,i)}finally{delete e.response}return i.headers=Ge.from(i.headers),i},function(i){if(!Ua(i)&&(Ir(e),i&&i.response)){e.response=i.response;try{i.response.data=Lr.call(e,e.transformResponse,i.response)}finally{delete e.response}i.response.headers=Ge.from(i.response.headers)}return Promise.reject(i)})}const gr={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{gr[e]=function(i){return typeof i===e||"a"+(t<1?"n ":" ")+e}});const Ws={};gr.transitional=function(t,n,i){function r(o,s){return"[Axios v"+Lo+"] Transitional option '"+o+"'"+s+(i?". "+i:"")}return(o,s,l)=>{if(t===!1)throw new P(r(s," has been removed"+(n?" in "+n:"")),P.ERR_DEPRECATED);return n&&!Ws[s]&&(Ws[s]=!0,console.warn(r(s," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(o,s,l):!0}};gr.spelling=function(t){return(n,i)=>(console.warn(`${i} is likely a misspelling of ${t}`),!0)};function Og(e,t,n){if(typeof e!="object")throw new P("options must be an object",P.ERR_BAD_OPTION_VALUE);const i=Object.keys(e);let r=i.length;for(;r-- >0;){const o=i[r],s=Object.prototype.hasOwnProperty.call(t,o)?t[o]:void 0;if(s){const l=e[o],a=l===void 0||s(l,o,e);if(a!==!0)throw new P("option "+o+" must be "+a,P.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new P("Unknown option "+o,P.ERR_BAD_OPTION)}}const Ii={assertOptions:Og,validators:gr},ot=Ii.validators;let fn=class{constructor(t){this.defaults=t||{},this.interceptors={request:new Ds,response:new Ds}}async request(t,n){try{return await this._request(t,n)}catch(i){if(i instanceof Error){let r={};Error.captureStackTrace?Error.captureStackTrace(r):r=new Error;const o=(()=>{if(!r.stack)return"";const s=r.stack.indexOf(` -`);return s===-1?"":r.stack.slice(s+1)})();try{if(!i.stack)i.stack=o;else if(o){const s=o.indexOf(` -`),l=s===-1?-1:o.indexOf(` -`,s+1),a=l===-1?"":o.slice(l+1);String(i.stack).endsWith(a)||(i.stack+=` -`+o)}}catch{}}throw i}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=hn(this.defaults,n);const{transitional:i,paramsSerializer:r,headers:o}=n;i!==void 0&&Ii.assertOptions(i,{silentJSONParsing:ot.transitional(ot.boolean),forcedJSONParsing:ot.transitional(ot.boolean),clarifyTimeoutError:ot.transitional(ot.boolean),legacyInterceptorReqResOrdering:ot.transitional(ot.boolean)},!1),r!=null&&(y.isFunction(r)?n.paramsSerializer={serialize:r}:Ii.assertOptions(r,{encode:ot.function,serialize:ot.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),Ii.assertOptions(n,{baseUrl:ot.spelling("baseURL"),withXsrfToken:ot.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let s=o&&y.merge(o.common,o[n.method]);o&&y.forEach(["delete","get","head","post","put","patch","query","common"],v=>{delete o[v]}),n.headers=Ge.concat(s,o);const l=[];let a=!0;this.interceptors.request.forEach(function(g){if(typeof g.runWhen=="function"&&g.runWhen(n)===!1)return;a=a&&g.synchronous;const _=n.transitional||No;_&&_.legacyInterceptorReqResOrdering?l.unshift(g.fulfilled,g.rejected):l.push(g.fulfilled,g.rejected)});const c=[];this.interceptors.response.forEach(function(g){c.push(g.fulfilled,g.rejected)});let u,d=0,h;if(!a){const v=[Ks.bind(this),void 0];for(v.unshift(...l),v.push(...c),h=v.length,u=Promise.resolve(n);d{if(!i._listeners)return;let o=i._listeners.length;for(;o-- >0;)i._listeners[o](r);i._listeners=null}),this.promise.then=r=>{let o;const s=new Promise(l=>{i.subscribe(l),o=l}).then(r);return s.cancel=function(){i.unsubscribe(o)},s},t(function(o,s,l){i.reason||(i.reason=new wi(o,s,l),n(i.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=i=>{t.abort(i)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new Ka(function(r){t=r}),cancel:t}}};function Rg(e){return function(n){return e.apply(null,n)}}function Fg(e){return y.isObject(e)&&e.isAxiosError===!0}const oo={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(oo).forEach(([e,t])=>{oo[t]=e});function Wa(e){const t=new fn(e),n=Ea(fn.prototype.request,t);return y.extend(n,fn.prototype,t,{allOwnKeys:!0}),y.extend(n,t,null,{allOwnKeys:!0}),n.create=function(r){return Wa(hn(e,r))},n}const Ae=Wa(xi);Ae.Axios=fn;Ae.CanceledError=wi;Ae.CancelToken=Tg;Ae.isCancel=Ua;Ae.VERSION=Lo;Ae.toFormData=hr;Ae.AxiosError=P;Ae.Cancel=Ae.CanceledError;Ae.all=function(t){return Promise.all(t)};Ae.spread=Rg;Ae.isAxiosError=Fg;Ae.mergeConfig=hn;Ae.AxiosHeaders=Ge;Ae.formToJSON=e=>Ma(y.isHTMLForm(e)?new FormData(e):e);Ae.getAdapter=qa.getAdapter;Ae.HttpStatusCode=oo;Ae.default=Ae;const{Axios:B1,AxiosError:H1,CanceledError:V1,isCancel:q1,CancelToken:K1,VERSION:W1,all:Y1,Cancel:J1,isAxiosError:z1,spread:G1,toFormData:X1,AxiosHeaders:Q1,HttpStatusCode:Z1,formToJSON:ev,getAdapter:tv,mergeConfig:nv,create:iv}=Ae,Ya="wordformat-settings",De=rr({host:"127.0.0.1",port:8e3}),Ki=Ee(()=>{const e=De.host||"127.0.0.1",t=De.port||8e3;return`http://${e}:${t}`});function Ja(){try{const e=localStorage.getItem(Ya);if(e){const t=JSON.parse(e);t.host&&(De.host=t.host),t.port!=null&&(De.port=t.port)}}catch{}}function za(){localStorage.setItem(Ya,JSON.stringify({host:De.host,port:De.port}))}function Ng(){De.host="127.0.0.1",De.port=8e3,za()}const zt=Ae.create({timeout:12e4,headers:{"Content-Type":"application/json;charset=UTF-8"}});zt.interceptors.request.use(e=>(e.baseURL=Ki.value,e.method==="get"&&(e.params={...e.params,_t:Date.now()}),e),e=>Promise.reject(e));zt.interceptors.response.use(e=>{const t=e.data;return t.code!==void 0&&(t.code<200||t.code>=300)?Promise.reject(new Error(t.msg||"Error")):t.success===!1?Promise.reject(new Error(t.msg||"操作失败")):t},e=>{let t="请求失败";if(e.response)switch(e.response.status){case 400:t="请求错误";break;case 404:t="请求地址不存在";break;case 500:t="服务器内部错误";break;default:t=`连接错误 ${e.response.status}`}else e.request?t="网络连接异常,请检查后端服务是否启动":t=e.message;return Promise.reject(new Error(t))});class kg{get(t,n={},i={}){return zt({method:"get",url:t,params:n,...i})}post(t,n={},i={}){return zt({method:"post",url:t,data:n,...i})}put(t,n={},i={}){return zt({method:"put",url:t,data:n,...i})}patch(t,n={},i={}){return zt({method:"patch",url:t,data:n,...i})}delete(t,n={},i={}){return zt({method:"delete",url:t,params:n,...i})}upload(t,n,i=null){return zt.post(t,n,{headers:{"Content-Type":"multipart/form-data"},onUploadProgress:r=>{i&&r.total&&i(Math.round(r.loaded*100/r.total))}})}}const $r=new kg,Lg={class:"doc-tag-check-container"},Ig={class:"header-bar"},$g={class:"header-content"},Pg={class:"header-left"},Dg={key:0,class:"stats-info"},Mg={class:"header-right"},Ug={class:"search-box"},jg=["disabled"],Bg=["disabled"],Hg=["disabled"],Vg={class:"main-content"},qg={__name:"DocTagChecker",props:{generatedConfig:{type:Object,default:null}},setup(e){const t=e,n=be(t.generatedConfig);un(()=>t.generatedConfig,F=>{n.value=F},{deep:!0});const i=be(null),r=be(null),o=be([]),s=be(!1),l=be(!1),a=be(""),c=be(-1),u=be(""),d=be(null),h=Ee(()=>c.value>=0?o.value[c.value]:null),b=Ee(()=>o.value.length),v=Ee(()=>o.value.filter(F=>Vi(F,Ni)).length),g=Ee(()=>o.value.filter(F=>F.category==="other").length),_=Ee(()=>{const F=u.value.trim().toLowerCase();return F?o.value.filter(w=>w.paragraph.toLowerCase().includes(F)):o.value}),A=F=>{c.value=F},C=F=>{h.value&&(o.value[c.value].category=F)},$=async()=>{var w,j;if(!i.value)return;const F=new FormData;if(F.append("docx_file",i.value),n.value){const se=(await Fr(()=>Promise.resolve().then(()=>Ur),void 0,import.meta.url)).dump(n.value,{indent:2,skipInvalid:!0}),Z=new Blob([se],{type:"application/yaml"}),te=new File([Z],"generated-config.yaml",{type:"application/yaml"});F.append("config_file",te)}else if(r.value)F.append("config_file",r.value);else return;l.value=!0,a.value="正在解析文档并生成节点...";try{const D=await $r.post("/generate-json",F,{timeout:3e5,headers:{"Content-Type":"multipart/form-data"}});D.data&&Array.isArray(D.data.json_data)?(o.value=D.data.json_data.map((se,Z)=>({...se,id:Z})),s.value=!0,c.value=-1):alert("❌ 后端返回数据格式异常")}catch(D){console.error("生成JSON失败:",D),alert("❌ 生成节点失败:"+(((j=(w=D.response)==null?void 0:w.data)==null?void 0:j.detail)||D.message))}finally{l.value=!1}},R=async()=>{var w,j;if(!s.value||(l.value=!0,a.value="正在执行格式校验...",!i.value))return;const F=new FormData;if(F.append("docx_file",i.value),n.value){const se=(await Fr(()=>Promise.resolve().then(()=>Ur),void 0,import.meta.url)).dump(n.value,{indent:2,skipInvalid:!0}),Z=new Blob([se],{type:"application/yaml"}),te=new File([Z],"generated-config.yaml",{type:"application/yaml"});F.append("config_file",te)}else if(r.value)F.append("config_file",r.value);else{l.value=!1;return}F.append("json_data",JSON.stringify(o.value));try{const D=await $r.post("/check-format",F,{headers:{Accept:"application/json","Content-Type":void 0}});re(D)}catch(D){console.error("格式校验失败:",D),alert("❌ 格式校验失败:"+(((j=(w=D.response)==null?void 0:w.data)==null?void 0:j.detail)||D.message))}finally{l.value=!1}},G=async()=>{var j,D;if(!s.value||!window.confirm("此操作将根据当前标签生成新文档,是否继续?")||(l.value=!0,a.value="正在生成格式化后的文档...",!i.value))return;const w=new FormData;if(w.append("docx_file",i.value),n.value){const Z=(await Fr(()=>Promise.resolve().then(()=>Ur),void 0,import.meta.url)).dump(n.value,{indent:2,skipInvalid:!0}),te=new Blob([Z],{type:"application/yaml"}),ie=new File([te],"generated-config.yaml",{type:"application/yaml"});w.append("config_file",ie)}else if(r.value)w.append("config_file",r.value);else{l.value=!1;return}w.append("json_data",JSON.stringify(o.value));try{const se=await $r.post("/apply-format",w,{headers:{Accept:"application/json","Content-Type":void 0}});re(se)}catch(se){console.error("格式化失败:",se),alert("❌ 文档格式化失败:"+(((D=(j=se.response)==null?void 0:j.data)==null?void 0:D.detail)||se.message))}finally{l.value=!1}};async function re(F){try{l.value=!1;const w=(F==null?void 0:F.data)??F;if(!(w!=null&&w.download_url)){alert("操作完成!");return}const{download_url:j,final_filename:D}=w,se=j.startsWith("http")?j:`${Ki.value}${j}`,Z=await fetch(se);if(!Z.ok)throw new Error(`下载失败: ${Z.status}`);const te=await Z.blob(),ie=URL.createObjectURL(te),xe=document.createElement("a");xe.href=ie,xe.download=D||"document.docx",document.body.appendChild(xe),xe.click(),URL.revokeObjectURL(ie),document.body.removeChild(xe)}catch(w){console.error("下载失败",w),alert("处理完成!文件下载失败:"+w.message)}}const J=()=>{if(!s.value)return;const F=o.value.map((w,j)=>({...w,idx:j})).filter(w=>Vi(w,Ni)||w.category==="other");if(F.length===0)alert("✅ 所有节点标签均通过阈值校验!");else{let w=`🔍 发现 ${F.length} 个需关注的节点: - -`;w+=F.slice(0,10).map(j=>`• [${j.idx+1}] ${j.category}: ${j.paragraph.substring(0,50)}...`).join(` -`),F.length>10&&(w+=` -... 还有 ${F.length-10} 个`),alert(w)}},ne=()=>{if(!s.value)return;const F=JSON.stringify(o.value,null,2),w=new Blob([F],{type:"application/json;charset=utf-8"}),j=URL.createObjectURL(w),D=document.createElement("a");D.href=j,D.download="modified_nodes.json",document.body.appendChild(D),D.click(),URL.revokeObjectURL(j),document.body.removeChild(D)},U=()=>{var F;(F=d.value)==null||F.click()},X=async F=>{var j;const w=(j=F.target.files)==null?void 0:j[0];if(w)try{const D=await w.text(),se=JSON.parse(D);if(!Array.isArray(se)){alert("JSON 格式错误:期望一个节点数组");return}o.value=se.map((Z,te)=>({...Z,id:Z.id??te})),s.value=!0,c.value=-1,alert(`导入成功:${o.value.length} 个节点`)}catch(D){console.error("导入 JSON 失败:",D),alert("导入失败:"+D.message)}finally{F.target.value=""}};return un(s,F=>{F||(c.value=-1)}),(F,w)=>(H(),K("div",Lg,[f("div",Ig,[f("div",$g,[f("div",Pg,[w[7]||(w[7]=f("h1",{class:"tool-title"},"文档标签核对工具",-1)),s.value?(H(),K("div",Dg,[w[3]||(w[3]=de(" 共 ",-1)),f("span",null,ee(b.value),1),w[4]||(w[4]=de(" 个节点 | 疑似错误 ",-1)),f("span",null,ee(v.value),1),w[5]||(w[5]=de(" 个 | 标记跳过 ",-1)),f("span",null,ee(g.value),1),w[6]||(w[6]=de(" 个 ",-1))])):pt("",!0)]),f("div",Mg,[B(Kd,{"docx-file":i.value,"onUpdate:docxFile":w[0]||(w[0]=j=>i.value=j),"yaml-file":r.value,"onUpdate:yamlFile":w[1]||(w[1]=j=>r.value=j),"generated-config":e.generatedConfig,"is-loading":l.value,onGenerateJson:$},null,8,["docx-file","yaml-file","generated-config","is-loading"]),s.value?(H(),si(Gd,{key:0,"is-loading":l.value,onCheckFormat:R,onApplyFormat:G},null,8,["is-loading"])):pt("",!0),f("div",Ug,[M(f("input",{type:"text","onUpdate:modelValue":w[2]||(w[2]=j=>u.value=j),placeholder:"搜索段落内容...",class:"search-input"},null,512),[[we,u.value]]),w[8]||(w[8]=f("svg",{class:"search-icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[f("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})],-1))]),f("button",{class:"btn secondary-btn",onClick:J,disabled:!s.value||l.value}," 核对所有标签 ",8,jg),f("button",{class:"btn secondary-btn",onClick:U,disabled:!s.value||l.value}," 导入JSON ",8,Bg),f("button",{class:"btn primary-btn",onClick:ne,disabled:!s.value}," 导出JSON ",8,Hg)])])]),f("input",{ref_key:"jsonFileInput",ref:d,type:"file",accept:".json",style:{display:"none"},onChange:X},null,544),f("div",Vg,[B(gp,{"node-data":_.value,"selected-index":c.value,"is-file-loaded":s.value,"is-loading":l.value,"loading-text":a.value,"global-search-term":u.value,onSelectNode:A},null,8,["node-data","selected-index","is-file-loaded","is-loading","loading-text","global-search-term"]),B(Vp,{"current-node":h.value,"category-config":Ye(Ca),"score-threshold":Ye(Ni),"total-nodes":o.value.length,"node-index":c.value+1,onUpdateCategory:C},null,8,["current-node","category-config","score-threshold","total-nodes","node-index"])])]))}},Kg=ke(qg,[["__scopeId","data-v-bd52c815"]]);/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */function Ga(e){return typeof e>"u"||e===null}function Wg(e){return typeof e=="object"&&e!==null}function Yg(e){return Array.isArray(e)?e:Ga(e)?[]:[e]}function Jg(e,t){var n,i,r,o;if(t)for(o=Object.keys(t),n=0,i=o.length;nl&&(o=" ... ",t=i-l+o.length),n-i>l&&(s=" ...",n=i+l-s.length),{str:o+e.slice(t,n).replace(/\t/g,"→")+s,pos:i-t+o.length}}function Dr(e,t){return Fe.repeat(" ",t-e.length)+e}function im(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),typeof t.indent!="number"&&(t.indent=1),typeof t.linesBefore!="number"&&(t.linesBefore=3),typeof t.linesAfter!="number"&&(t.linesAfter=2);for(var n=/\r?\n|\r|\0/g,i=[0],r=[],o,s=-1;o=n.exec(e.buffer);)r.push(o.index),i.push(o.index+o[0].length),e.position<=o.index&&s<0&&(s=i.length-2);s<0&&(s=i.length-1);var l="",a,c,u=Math.min(e.line+t.linesAfter,r.length).toString().length,d=t.maxLength-(t.indent+u+3);for(a=1;a<=t.linesBefore&&!(s-a<0);a++)c=Pr(e.buffer,i[s-a],r[s-a],e.position-(i[s]-i[s-a]),d),l=Fe.repeat(" ",t.indent)+Dr((e.line-a+1).toString(),u)+" | "+c.str+` -`+l;for(c=Pr(e.buffer,i[s],r[s],e.position,d),l+=Fe.repeat(" ",t.indent)+Dr((e.line+1).toString(),u)+" | "+c.str+` -`,l+=Fe.repeat("-",t.indent+u+3+c.pos)+`^ -`,a=1;a<=t.linesAfter&&!(s+a>=r.length);a++)c=Pr(e.buffer,i[s+a],r[s+a],e.position-(i[s]-i[s+a]),d),l+=Fe.repeat(" ",t.indent)+Dr((e.line+a+1).toString(),u)+" | "+c.str+` -`;return l.replace(/\n$/,"")}var rm=im,om=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],sm=["scalar","sequence","mapping"];function lm(e){var t={};return e!==null&&Object.keys(e).forEach(function(n){e[n].forEach(function(i){t[String(i)]=n})}),t}function am(e,t){if(t=t||{},Object.keys(t).forEach(function(n){if(om.indexOf(n)===-1)throw new ze('Unknown option "'+n+'" is met in definition of "'+e+'" YAML type.')}),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(n){return n},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=lm(t.styleAliases||null),sm.indexOf(this.kind)===-1)throw new ze('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}var Pe=am;function Ys(e,t){var n=[];return e[t].forEach(function(i){var r=n.length;n.forEach(function(o,s){o.tag===i.tag&&o.kind===i.kind&&o.multi===i.multi&&(r=s)}),n[r]=i}),n}function cm(){var e={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}},t,n;function i(r){r.multi?(e.multi[r.kind].push(r),e.multi.fallback.push(r)):e[r.kind][r.tag]=e.fallback[r.tag]=r}for(t=0,n=arguments.length;t=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),wm=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function Am(e){return!(e===null||!wm.test(e)||e[e.length-1]==="_")}function Cm(e){var t,n;return t=e.replace(/_/g,"").toLowerCase(),n=t[0]==="-"?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),t===".inf"?n===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:t===".nan"?NaN:n*parseFloat(t,10)}var Sm=/^[-+]?[0-9]+e/;function Em(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(Fe.isNegativeZero(e))return"-0.0";return n=e.toString(10),Sm.test(n)?n.replace("e",".e"):n}function Om(e){return Object.prototype.toString.call(e)==="[object Number]"&&(e%1!==0||Fe.isNegativeZero(e))}var sc=new Pe("tag:yaml.org,2002:float",{kind:"scalar",resolve:Am,construct:Cm,predicate:Om,represent:Em,defaultStyle:"lowercase"}),lc=nc.extend({implicit:[ic,rc,oc,sc]}),ac=lc,cc=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),uc=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function Tm(e){return e===null?!1:cc.exec(e)!==null||uc.exec(e)!==null}function Rm(e){var t,n,i,r,o,s,l,a=0,c=null,u,d,h;if(t=cc.exec(e),t===null&&(t=uc.exec(e)),t===null)throw new Error("Date resolve error");if(n=+t[1],i=+t[2]-1,r=+t[3],!t[4])return new Date(Date.UTC(n,i,r));if(o=+t[4],s=+t[5],l=+t[6],t[7]){for(a=t[7].slice(0,3);a.length<3;)a+="0";a=+a}return t[9]&&(u=+t[10],d=+(t[11]||0),c=(u*60+d)*6e4,t[9]==="-"&&(c=-c)),h=new Date(Date.UTC(n,i,r,o,s,l,a)),c&&h.setTime(h.getTime()-c),h}function Fm(e){return e.toISOString()}var fc=new Pe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:Tm,construct:Rm,instanceOf:Date,represent:Fm});function Nm(e){return e==="<<"||e===null}var dc=new Pe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:Nm}),$o=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= -\r`;function km(e){if(e===null)return!1;var t,n,i=0,r=e.length,o=$o;for(n=0;n64)){if(t<0)return!1;i+=6}return i%8===0}function Lm(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=$o,s=0,l=[];for(t=0;t>16&255),l.push(s>>8&255),l.push(s&255)),s=s<<6|o.indexOf(i.charAt(t));return n=r%4*6,n===0?(l.push(s>>16&255),l.push(s>>8&255),l.push(s&255)):n===18?(l.push(s>>10&255),l.push(s>>2&255)):n===12&&l.push(s>>4&255),new Uint8Array(l)}function Im(e){var t="",n=0,i,r,o=e.length,s=$o;for(i=0;i>18&63],t+=s[n>>12&63],t+=s[n>>6&63],t+=s[n&63]),n=(n<<8)+e[i];return r=o%3,r===0?(t+=s[n>>18&63],t+=s[n>>12&63],t+=s[n>>6&63],t+=s[n&63]):r===2?(t+=s[n>>10&63],t+=s[n>>4&63],t+=s[n<<2&63],t+=s[64]):r===1&&(t+=s[n>>2&63],t+=s[n<<4&63],t+=s[64],t+=s[64]),t}function $m(e){return Object.prototype.toString.call(e)==="[object Uint8Array]"}var pc=new Pe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:km,construct:Lm,predicate:$m,represent:Im}),Pm=Object.prototype.hasOwnProperty,Dm=Object.prototype.toString;function Mm(e){if(e===null)return!0;var t=[],n,i,r,o,s,l=e;for(n=0,i=l.length;n>10)+55296,(e-65536&1023)+56320)}function xc(e,t,n){t==="__proto__"?Object.defineProperty(e,t,{configurable:!0,enumerable:!0,writable:!0,value:n}):e[t]=n}var wc=new Array(256),Ac=new Array(256);for(var yn=0;yn<256;yn++)wc[yn]=Gs(yn)?1:0,Ac[yn]=Gs(yn);function e0(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||Po,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function Cc(e,t){var n={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return n.snippet=rm(n),new ze(t,n)}function V(e,t){throw Cc(e,t)}function Ji(e,t){e.onWarning&&e.onWarning.call(null,Cc(e,t))}var Xs={YAML:function(t,n,i){var r,o,s;t.version!==null&&V(t,"duplication of %YAML directive"),i.length!==1&&V(t,"YAML directive accepts exactly one argument"),r=/^([0-9]+)\.([0-9]+)$/.exec(i[0]),r===null&&V(t,"ill-formed argument of the YAML directive"),o=parseInt(r[1],10),s=parseInt(r[2],10),o!==1&&V(t,"unacceptable YAML version of the document"),t.version=i[0],t.checkLineBreaks=s<2,s!==1&&s!==2&&Ji(t,"unsupported YAML version of the document")},TAG:function(t,n,i){var r,o;i.length!==2&&V(t,"TAG directive accepts exactly two arguments"),r=i[0],o=i[1],vc.test(r)||V(t,"ill-formed tag handle (first argument) of the TAG directive"),Zt.call(t.tagMap,r)&&V(t,'there is a previously declared suffix for "'+r+'" tag handle'),_c.test(o)||V(t,"ill-formed tag prefix (second argument) of the TAG directive");try{o=decodeURIComponent(o)}catch{V(t,"tag prefix is malformed: "+o)}t.tagMap[r]=o}};function Qt(e,t,n,i){var r,o,s,l;if(t1&&(e.result+=Fe.repeat(` -`,t-1))}function t0(e,t,n){var i,r,o,s,l,a,c,u,d=e.kind,h=e.result,b;if(b=e.input.charCodeAt(e.position),Qe(b)||wn(b)||b===35||b===38||b===42||b===33||b===124||b===62||b===39||b===34||b===37||b===64||b===96||(b===63||b===45)&&(r=e.input.charCodeAt(e.position+1),Qe(r)||n&&wn(r)))return!1;for(e.kind="scalar",e.result="",o=s=e.position,l=!1;b!==0;){if(b===58){if(r=e.input.charCodeAt(e.position+1),Qe(r)||n&&wn(r))break}else if(b===35){if(i=e.input.charCodeAt(e.position-1),Qe(i))break}else{if(e.position===e.lineStart&&mr(e)||n&&wn(b))break;if(Rt(b))if(a=e.line,c=e.lineStart,u=e.lineIndent,Oe(e,!1,-1),e.lineIndent>=t){l=!0,b=e.input.charCodeAt(e.position);continue}else{e.position=s,e.line=a,e.lineStart=c,e.lineIndent=u;break}}l&&(Qt(e,o,s,!1),Mo(e,e.line-a),o=s=e.position,l=!1),dn(b)||(s=e.position+1),b=e.input.charCodeAt(++e.position)}return Qt(e,o,s,!1),e.result?!0:(e.kind=d,e.result=h,!1)}function n0(e,t){var n,i,r;if(n=e.input.charCodeAt(e.position),n!==39)return!1;for(e.kind="scalar",e.result="",e.position++,i=r=e.position;(n=e.input.charCodeAt(e.position))!==0;)if(n===39)if(Qt(e,i,e.position,!0),n=e.input.charCodeAt(++e.position),n===39)i=e.position,e.position++,r=e.position;else return!0;else Rt(n)?(Qt(e,i,r,!0),Mo(e,Oe(e,!1,t)),i=r=e.position):e.position===e.lineStart&&mr(e)?V(e,"unexpected end of the document within a single quoted scalar"):(e.position++,r=e.position);V(e,"unexpected end of the stream within a single quoted scalar")}function i0(e,t){var n,i,r,o,s,l;if(l=e.input.charCodeAt(e.position),l!==34)return!1;for(e.kind="scalar",e.result="",e.position++,n=i=e.position;(l=e.input.charCodeAt(e.position))!==0;){if(l===34)return Qt(e,n,e.position,!0),e.position++,!0;if(l===92){if(Qt(e,n,e.position,!0),l=e.input.charCodeAt(++e.position),Rt(l))Oe(e,!1,t);else if(l<256&&wc[l])e.result+=Ac[l],e.position++;else if((s=Xm(l))>0){for(r=s,o=0;r>0;r--)l=e.input.charCodeAt(++e.position),(s=Gm(l))>=0?o=(o<<4)+s:V(e,"expected hexadecimal character");e.result+=Zm(o),e.position++}else V(e,"unknown escape sequence");n=i=e.position}else Rt(l)?(Qt(e,n,i,!0),Mo(e,Oe(e,!1,t)),n=i=e.position):e.position===e.lineStart&&mr(e)?V(e,"unexpected end of the document within a double quoted scalar"):(e.position++,i=e.position)}V(e,"unexpected end of the stream within a double quoted scalar")}function r0(e,t){var n=!0,i,r,o,s=e.tag,l,a=e.anchor,c,u,d,h,b,v=Object.create(null),g,_,A,C;if(C=e.input.charCodeAt(e.position),C===91)u=93,b=!1,l=[];else if(C===123)u=125,b=!0,l={};else return!1;for(e.anchor!==null&&(e.anchorMap[e.anchor]=l),C=e.input.charCodeAt(++e.position);C!==0;){if(Oe(e,!0,t),C=e.input.charCodeAt(e.position),C===u)return e.position++,e.tag=s,e.anchor=a,e.kind=b?"mapping":"sequence",e.result=l,!0;n?C===44&&V(e,"expected the node content, but found ','"):V(e,"missed comma between flow collection entries"),_=g=A=null,d=h=!1,C===63&&(c=e.input.charCodeAt(e.position+1),Qe(c)&&(d=h=!0,e.position++,Oe(e,!0,t))),i=e.line,r=e.lineStart,o=e.position,In(e,t,Wi,!1,!0),_=e.tag,g=e.result,Oe(e,!0,t),C=e.input.charCodeAt(e.position),(h||e.line===i)&&C===58&&(d=!0,C=e.input.charCodeAt(++e.position),Oe(e,!0,t),In(e,t,Wi,!1,!0),A=e.result),b?An(e,l,v,_,g,A,i,r,o):d?l.push(An(e,null,v,_,g,A,i,r,o)):l.push(g),Oe(e,!0,t),C=e.input.charCodeAt(e.position),C===44?(n=!0,C=e.input.charCodeAt(++e.position)):n=!1}V(e,"unexpected end of the stream within a flow collection")}function o0(e,t){var n,i,r=Mr,o=!1,s=!1,l=t,a=0,c=!1,u,d;if(d=e.input.charCodeAt(e.position),d===124)i=!1;else if(d===62)i=!0;else return!1;for(e.kind="scalar",e.result="";d!==0;)if(d=e.input.charCodeAt(++e.position),d===43||d===45)Mr===r?r=d===43?Js:Wm:V(e,"repeat of a chomping mode identifier");else if((u=Qm(d))>=0)u===0?V(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):s?V(e,"repeat of an indentation width identifier"):(l=t+u-1,s=!0);else break;if(dn(d)){do d=e.input.charCodeAt(++e.position);while(dn(d));if(d===35)do d=e.input.charCodeAt(++e.position);while(!Rt(d)&&d!==0)}for(;d!==0;){for(Do(e),e.lineIndent=0,d=e.input.charCodeAt(e.position);(!s||e.lineIndentl&&(l=e.lineIndent),Rt(d)){a++;continue}if(e.lineIndentt)&&a!==0)V(e,"bad indentation of a sequence entry");else if(e.lineIndentt)&&(_&&(s=e.line,l=e.lineStart,a=e.position),In(e,t,Yi,!0,r)&&(_?v=e.result:g=e.result),_||(An(e,d,h,b,v,g,s,l,a),b=v=g=null),Oe(e,!0,-1),C=e.input.charCodeAt(e.position)),(e.line===o||e.lineIndent>t)&&C!==0)V(e,"bad indentation of a mapping entry");else if(e.lineIndentt?a=1:e.lineIndent===t?a=0:e.lineIndentt?a=1:e.lineIndent===t?a=0:e.lineIndent tag; it should be "scalar", not "'+e.kind+'"'),d=0,h=e.implicitTypes.length;d"),e.result!==null&&v.kind!==e.kind&&V(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+v.kind+'", not "'+e.kind+'"'),v.resolve(e.result,e.tag)?(e.result=v.construct(e.result,e.tag),e.anchor!==null&&(e.anchorMap[e.anchor]=e.result)):V(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return e.listener!==null&&e.listener("close",e),e.tag!==null||e.anchor!==null||u}function u0(e){var t=e.position,n,i,r,o=!1,s;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);(s=e.input.charCodeAt(e.position))!==0&&(Oe(e,!0,-1),s=e.input.charCodeAt(e.position),!(e.lineIndent>0||s!==37));){for(o=!0,s=e.input.charCodeAt(++e.position),n=e.position;s!==0&&!Qe(s);)s=e.input.charCodeAt(++e.position);for(i=e.input.slice(n,e.position),r=[],i.length<1&&V(e,"directive name must not be less than one character in length");s!==0;){for(;dn(s);)s=e.input.charCodeAt(++e.position);if(s===35){do s=e.input.charCodeAt(++e.position);while(s!==0&&!Rt(s));break}if(Rt(s))break;for(n=e.position;s!==0&&!Qe(s);)s=e.input.charCodeAt(++e.position);r.push(e.input.slice(n,e.position))}s!==0&&Do(e),Zt.call(Xs,i)?Xs[i](e,i,r):Ji(e,'unknown document directive "'+i+'"')}if(Oe(e,!0,-1),e.lineIndent===0&&e.input.charCodeAt(e.position)===45&&e.input.charCodeAt(e.position+1)===45&&e.input.charCodeAt(e.position+2)===45?(e.position+=3,Oe(e,!0,-1)):o&&V(e,"directives end mark is expected"),In(e,e.lineIndent-1,Yi,!1,!0),Oe(e,!0,-1),e.checkLineBreaks&&Jm.test(e.input.slice(t,e.position))&&Ji(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&mr(e)){e.input.charCodeAt(e.position)===46&&(e.position+=3,Oe(e,!0,-1));return}if(e.position"u"&&(n=t,t=null);var i=Sc(e,n);if(typeof t!="function")return i;for(var r=0,o=i.length;r=55296&&n<=56319&&t+1=56320&&i<=57343)?(n-55296)*1024+i-56320+65536:n}function Ic(e){var t=/^\n* /;return t.test(e)}var $c=1,co=2,Pc=3,Dc=4,xn=5;function j0(e,t,n,i,r,o,s,l){var a,c=0,u=null,d=!1,h=!1,b=i!==-1,v=-1,g=M0(Jn(e,0))&&U0(Jn(e,e.length-1));if(t||s)for(a=0;a=65536?a+=2:a++){if(c=Jn(e,a),!di(c))return xn;g=g&&nl(c,u,l),u=c}else{for(a=0;a=65536?a+=2:a++){if(c=Jn(e,a),c===ui)d=!0,b&&(h=h||a-v-1>i&&e[v+1]!==" ",v=a);else if(!di(c))return xn;g=g&&nl(c,u,l),u=c}h=h||b&&a-v-1>i&&e[v+1]!==" "}return!d&&!h?g&&!s&&!r(e)?$c:o===fi?xn:co:n>9&&Ic(e)?xn:s?o===fi?xn:co:h?Dc:Pc}function B0(e,t,n,i,r){e.dump=(function(){if(t.length===0)return e.quotingType===fi?'""':"''";if(!e.noCompatMode&&(N0.indexOf(t)!==-1||k0.test(t)))return e.quotingType===fi?'"'+t+'"':"'"+t+"'";var o=e.indent*Math.max(1,n),s=e.lineWidth===-1?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o),l=i||e.flowLevel>-1&&n>=e.flowLevel;function a(c){return D0(e,c)}switch(j0(t,l,e.indent,s,a,e.quotingType,e.forceQuotes&&!i,r)){case $c:return t;case co:return"'"+t.replace(/'/g,"''")+"'";case Pc:return"|"+il(t,e.indent)+rl(el(t,o));case Dc:return">"+il(t,e.indent)+rl(el(H0(t,s),o));case xn:return'"'+V0(t)+'"';default:throw new ze("impossible error: invalid scalar style")}})()}function il(e,t){var n=Ic(e)?String(t):"",i=e[e.length-1]===` -`,r=i&&(e[e.length-2]===` -`||e===` -`),o=r?"+":i?"":"-";return n+o+` -`}function rl(e){return e[e.length-1]===` -`?e.slice(0,-1):e}function H0(e,t){for(var n=/(\n+)([^\n]*)/g,i=(function(){var c=e.indexOf(` -`);return c=c!==-1?c:e.length,n.lastIndex=c,ol(e.slice(0,c),t)})(),r=e[0]===` -`||e[0]===" ",o,s;s=n.exec(e);){var l=s[1],a=s[2];o=a[0]===" ",i+=l+(!r&&!o&&a!==""?` -`:"")+ol(a,t),r=o}return i}function ol(e,t){if(e===""||e[0]===" ")return e;for(var n=/ [^ ]/g,i,r=0,o,s=0,l=0,a="";i=n.exec(e);)l=i.index,l-r>t&&(o=s>r?s:l,a+=` -`+e.slice(r,o),r=o+1),s=l;return a+=` -`,e.length-r>t&&s>r?a+=e.slice(r,s)+` -`+e.slice(s+1):a+=e.slice(r),a.slice(1)}function V0(e){for(var t="",n=0,i,r=0;r=65536?r+=2:r++)n=Jn(e,r),i=He[n],!i&&di(n)?(t+=e[r],n>=65536&&(t+=e[r+1])):t+=i||I0(n);return t}function q0(e,t,n){var i="",r=e.tag,o,s,l;for(o=0,s=n.length;o"u"&&Ht(e,t,null,!1,!1))&&(i!==""&&(i+=","+(e.condenseFlow?"":" ")),i+=e.dump);e.tag=r,e.dump="["+i+"]"}function sl(e,t,n,i){var r="",o=e.tag,s,l,a;for(s=0,l=n.length;s"u"&&Ht(e,t+1,null,!0,!0,!1,!0))&&((!i||r!=="")&&(r+=ao(e,t)),e.dump&&ui===e.dump.charCodeAt(0)?r+="-":r+="- ",r+=e.dump);e.tag=o,e.dump=r||"[]"}function K0(e,t,n){var i="",r=e.tag,o=Object.keys(n),s,l,a,c,u;for(s=0,l=o.length;s1024&&(u+="? "),u+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Ht(e,t,c,!1,!1)&&(u+=e.dump,i+=u));e.tag=r,e.dump="{"+i+"}"}function W0(e,t,n,i){var r="",o=e.tag,s=Object.keys(n),l,a,c,u,d,h;if(e.sortKeys===!0)s.sort();else if(typeof e.sortKeys=="function")s.sort(e.sortKeys);else if(e.sortKeys)throw new ze("sortKeys must be a boolean or a function");for(l=0,a=s.length;l1024,d&&(e.dump&&ui===e.dump.charCodeAt(0)?h+="?":h+="? "),h+=e.dump,d&&(h+=ao(e,t)),Ht(e,t+1,u,!0,d)&&(e.dump&&ui===e.dump.charCodeAt(0)?h+=":":h+=": ",h+=e.dump,r+=h));e.tag=o,e.dump=r||"{}"}function ll(e,t,n){var i,r,o,s,l,a;for(r=n?e.explicitTypes:e.implicitTypes,o=0,s=r.length;o tag resolver accepts not "'+a+'" style');e.dump=i}return!0}return!1}function Ht(e,t,n,i,r,o,s){e.tag=null,e.dump=n,ll(e,n,!1)||ll(e,n,!0);var l=Oc.call(e.dump),a=i,c;i&&(i=e.flowLevel<0||e.flowLevel>t);var u=l==="[object Object]"||l==="[object Array]",d,h;if(u&&(d=e.duplicates.indexOf(n),h=d!==-1),(e.tag!==null&&e.tag!=="?"||h||e.indent!==2&&t>0)&&(r=!1),h&&e.usedDuplicates[d])e.dump="*ref_"+d;else{if(u&&h&&!e.usedDuplicates[d]&&(e.usedDuplicates[d]=!0),l==="[object Object]")i&&Object.keys(e.dump).length!==0?(W0(e,t,e.dump,r),h&&(e.dump="&ref_"+d+e.dump)):(K0(e,t,e.dump),h&&(e.dump="&ref_"+d+" "+e.dump));else if(l==="[object Array]")i&&e.dump.length!==0?(e.noArrayIndent&&!s&&t>0?sl(e,t-1,e.dump,r):sl(e,t,e.dump,r),h&&(e.dump="&ref_"+d+e.dump)):(q0(e,t,e.dump),h&&(e.dump="&ref_"+d+" "+e.dump));else if(l==="[object String]")e.tag!=="?"&&B0(e,e.dump,t,o,a);else{if(l==="[object Undefined]")return!1;if(e.skipInvalid)return!1;throw new ze("unacceptable kind of an object to dump "+l)}e.tag!==null&&e.tag!=="?"&&(c=encodeURI(e.tag[0]==="!"?e.tag.slice(1):e.tag).replace(/!/g,"%21"),e.tag[0]==="!"?c="!"+c:c.slice(0,18)==="tag:yaml.org,2002:"?c="!!"+c.slice(18):c="!<"+c+">",e.dump=c+" "+e.dump)}return!0}function Y0(e,t){var n=[],i=[],r,o;for(uo(e,n,i),r=0,o=i.length;r({...Qc,...e}),ln={style_checks_warning:{bold:!1,italic:!1,underline:!1,font_size:!1,font_name:!1,font_color:!1,alignment:!1,space_before:!1,space_after:!1,line_spacing:!1,line_spacingrule:!1,left_indent:!1,right_indent:!1,first_line_indent:!1,builtin_style_name:!1},global_format:{...Qc},abstract:{chinese:{chinese_title:Re({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"四号"}),chinese_content:Re({alignment:"两端对齐"})},english:{english_title:Re({alignment:"居中对齐",first_line_indent:"0字符",font_size:"四号"}),english_content:Re({alignment:"两端对齐"})},keywords:{chinese:Re({label:Re({chinese_font_name:"黑体",font_size:"四号",bold:!1}),count_min:3,count_max:5,trailing_punct_forbidden:!0}),english:Re({label:Re({font_size:"四号",bold:!1}),count_min:3,count_max:5,trailing_punct_forbidden:!0})}},headings:{level_1:Re({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"小二",space_before:"0.5行",space_after:"0.5行",builtin_style_name:"Heading 1"}),level_2:Re({alignment:"左对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"三号",space_before:"0行",space_after:"0行",builtin_style_name:"Heading 2"}),level_3:Re({alignment:"左对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"小四",space_before:"0行",space_after:"0行",builtin_style_name:"Heading 3"})},body_text:Re(),figures:Re({alignment:"居中对齐",first_line_indent:"0字符",font_size:"五号",builtin_style_name:"题注",caption_prefix:"图"}),tables:Re({alignment:"居中对齐",first_line_indent:"0字符",font_size:"五号",builtin_style_name:"题注",caption_prefix:"表",content:Re({chinese_font_name:"宋体",english_font_name:"Times New Roman",font_size:"五号",line_spacingrule:"1.5倍行距",alignment:"居中对齐",first_line_indent:"0字符",space_before:"0行",space_after:"0行"})}),references:{title:Re({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"三号"}),content:Re({alignment:"两端对齐",first_line_indent:"-2.2字符",left_indent:"0.26字符",chinese_font_name:"宋体",font_size:"五号"})},acknowledgements:{title:Re({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"小二"}),content:Re({alignment:"两端对齐",font_size:"五号"})},numbering:{enabled:!0,level_1:{enabled:!0,template:"%1",suffix:"space"},level_2:{enabled:!0,template:"%1.%2",suffix:"space"},level_3:{enabled:!0,template:"%1.%2.%3",suffix:"space"},references:{enabled:!0,template:"[%1]",suffix:"space"},captions:{enabled:!1,separator:".",label_number_space:!1}}},X0=["左对齐","居中对齐","右对齐","两端对齐","分散对齐"],Q0=["单倍行距","1.5倍行距","2倍行距","最小值","固定值","多倍行距"],Z0=["宋体","黑体","楷体","仿宋","微软雅黑","汉仪小标宋"],eb=["Times New Roman","Arial","Calibri","Courier New","Helvetica"],tb=["一号","小一","二号","小二","三号","小三","四号","小四","五号","小五","六号","七号"],Xi=(e,t)=>{const n={...e};for(const i of Object.keys(t))i in n?typeof t[i]=="object"&&t[i]!==null&&!Array.isArray(t[i])&&(n[i]=Xi(n[i],t[i])):n[i]=JSON.parse(JSON.stringify(t[i]));return n},nb=e=>{e.abstract.chinese.chinese_title={...e.global_format},e.abstract.chinese.chinese_content={...e.global_format},e.abstract.english.english_title={...e.global_format},e.abstract.english.english_content={...e.global_format},e.abstract.keywords.english={...e.global_format,label:e.abstract.keywords.english.label,count_min:e.abstract.keywords.english.count_min,count_max:e.abstract.keywords.english.count_max,trailing_punct_forbidden:e.abstract.keywords.english.trailing_punct_forbidden},e.abstract.keywords.chinese={...e.global_format,label:e.abstract.keywords.chinese.label,count_min:e.abstract.keywords.chinese.count_min,count_max:e.abstract.keywords.chinese.count_max,trailing_punct_forbidden:e.abstract.keywords.chinese.trailing_punct_forbidden},e.headings.level_1={...e.global_format},e.headings.level_2={...e.global_format},e.headings.level_3={...e.global_format},e.body_text={...e.global_format},e.figures={...e.global_format,caption_prefix:e.figures.caption_prefix},e.tables={...e.global_format,caption_prefix:e.tables.caption_prefix,content:e.tables.content},e.references.title={...e.global_format},e.references.content={...e.global_format},e.acknowledgements.title={...e.global_format},e.acknowledgements.content={...e.global_format}},ib={class:"config-section"},rb={key:0,class:"section-content"},ob={__name:"ConfigSection",props:{title:{type:String,required:!0},initialExpanded:{type:Boolean,default:!0}},setup(e){const n=be(e.initialExpanded),i=()=>{n.value=!n.value};return(r,o)=>(H(),K("div",ib,[f("div",{class:"section-header",onClick:i},[f("h2",null,ee(e.title),1),(H(),K("svg",{class:ve(["toggle-arrow",{expanded:n.value}]),width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[...o[0]||(o[0]=[f("polyline",{points:"6 9 12 15 18 9"},null,-1)])],2))]),n.value?(H(),K("div",rb,[df(r.$slots,"default",{},void 0)])):pt("",!0)]))}},xt=ke(ob,[["__scopeId","data-v-88bb2378"]]),sb={class:"warning-fields-config"},lb={class:"select-all-bar"},ab={class:"select-all-label"},cb=["checked"],ub={class:"grid grid-cols-3 gap-2"},fb={class:"form-item"},db={class:"form-item"},pb={class:"form-item"},hb={class:"form-item"},gb={class:"form-item"},mb={class:"form-item"},bb={class:"form-item"},yb={class:"form-item"},vb={class:"form-item"},_b={class:"form-item"},xb={class:"form-item"},wb={class:"form-item"},Ab={class:"form-item"},Cb={class:"form-item"},Sb={class:"form-item"},Eb={__name:"WarningFieldsConfig",props:{config:{type:Object,required:!0}},setup(e){const t=e,n=["bold","italic","underline","font_size","font_name","font_color","alignment","space_before","space_after","line_spacing","line_spacingrule","left_indent","right_indent","first_line_indent","builtin_style_name"],i=Ee(()=>n.every(o=>t.config[o]));function r(){const o=!i.value;n.forEach(s=>{t.config[s]=o})}return(o,s)=>(H(),K("div",sb,[f("div",lb,[f("label",ab,[f("input",{type:"checkbox",checked:i.value,onChange:r},null,40,cb),f("span",null,ee(i.value?"取消全选":"全选"),1)])]),f("div",ub,[f("div",fb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[0]||(s[0]=l=>e.config.bold=l)},null,512),[[pe,e.config.bold]]),s[15]||(s[15]=de(" 加粗",-1))])]),f("div",db,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[1]||(s[1]=l=>e.config.italic=l)},null,512),[[pe,e.config.italic]]),s[16]||(s[16]=de(" 斜体",-1))])]),f("div",pb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[2]||(s[2]=l=>e.config.underline=l)},null,512),[[pe,e.config.underline]]),s[17]||(s[17]=de(" 下划线",-1))])]),f("div",hb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[3]||(s[3]=l=>e.config.font_size=l)},null,512),[[pe,e.config.font_size]]),s[18]||(s[18]=de(" 字号",-1))])]),f("div",gb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[4]||(s[4]=l=>e.config.font_name=l)},null,512),[[pe,e.config.font_name]]),s[19]||(s[19]=de(" 字体名称",-1))])]),f("div",mb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[5]||(s[5]=l=>e.config.font_color=l)},null,512),[[pe,e.config.font_color]]),s[20]||(s[20]=de(" 字体颜色",-1))])]),f("div",bb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[6]||(s[6]=l=>e.config.alignment=l)},null,512),[[pe,e.config.alignment]]),s[21]||(s[21]=de(" 对齐方式",-1))])]),f("div",yb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[7]||(s[7]=l=>e.config.space_before=l)},null,512),[[pe,e.config.space_before]]),s[22]||(s[22]=de(" 段前间距",-1))])]),f("div",vb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[8]||(s[8]=l=>e.config.space_after=l)},null,512),[[pe,e.config.space_after]]),s[23]||(s[23]=de(" 段后间距",-1))])]),f("div",_b,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[9]||(s[9]=l=>e.config.line_spacing=l)},null,512),[[pe,e.config.line_spacing]]),s[24]||(s[24]=de(" 行距",-1))])]),f("div",xb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[10]||(s[10]=l=>e.config.line_spacingrule=l)},null,512),[[pe,e.config.line_spacingrule]]),s[25]||(s[25]=de(" 行距类型",-1))])]),f("div",wb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[11]||(s[11]=l=>e.config.left_indent=l)},null,512),[[pe,e.config.left_indent]]),s[26]||(s[26]=de(" 文本之前",-1))])]),f("div",Ab,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[12]||(s[12]=l=>e.config.right_indent=l)},null,512),[[pe,e.config.right_indent]]),s[27]||(s[27]=de(" 文本之后",-1))])]),f("div",Cb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[13]||(s[13]=l=>e.config.first_line_indent=l)},null,512),[[pe,e.config.first_line_indent]]),s[28]||(s[28]=de(" 段落首行缩进",-1))])]),f("div",Sb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":s[14]||(s[14]=l=>e.config.builtin_style_name=l)},null,512),[[pe,e.config.builtin_style_name]]),s[29]||(s[29]=de(" 内置样式名称",-1))])])])]))}},Ob=ke(Eb,[["__scopeId","data-v-315bca75"]]),Tb={class:"format-config"},Rb={class:"grid grid-cols-2 gap-4"},Fb={class:"form-item"},Nb=["value"],kb={class:"form-item"},Lb={class:"form-item"},Ib={class:"form-item"},$b=["value"],Pb={class:"form-item"},Db={class:"form-item"},Mb={class:"form-item"},Ub={class:"form-item"},jb={class:"form-item"},Bb={class:"form-item"},Hb=["value"],Vb={class:"form-item"},qb=["value"],Kb={class:"form-item"},Wb=["value"],Yb={class:"form-item"},Jb={class:"form-item"},zb={class:"form-item"},Gb={class:"form-item"},Xb={__name:"FormatConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",Tb,[f("div",Rb,[f("div",Fb,[n[16]||(n[16]=f("label",null,"对齐方式:",-1)),M(f("select",{"onUpdate:modelValue":n[0]||(n[0]=i=>e.config.alignment=i)},[(H(!0),K(_e,null,Gt(Ye(X0),i=>(H(),K("option",{key:i,value:i},ee(i),9,Nb))),128))],512),[[Ot,e.config.alignment]])]),f("div",kb,[n[17]||(n[17]=f("label",null,"段前间距:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.space_before=i)},null,512),[[we,e.config.space_before]])]),f("div",Lb,[n[18]||(n[18]=f("label",null,"段后间距:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[2]||(n[2]=i=>e.config.space_after=i)},null,512),[[we,e.config.space_after]])]),f("div",Ib,[n[19]||(n[19]=f("label",null,"行距类型:",-1)),M(f("select",{"onUpdate:modelValue":n[3]||(n[3]=i=>e.config.line_spacingrule=i)},[(H(!0),K(_e,null,Gt(Ye(Q0),i=>(H(),K("option",{key:i,value:i},ee(i),9,$b))),128))],512),[[Ot,e.config.line_spacingrule]])]),f("div",Pb,[n[20]||(n[20]=f("label",null,"行距参数:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[4]||(n[4]=i=>e.config.line_spacing=i)},null,512),[[we,e.config.line_spacing]])]),f("div",Db,[n[21]||(n[21]=f("label",null,"文本之前:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[5]||(n[5]=i=>e.config.left_indent=i)},null,512),[[we,e.config.left_indent]])]),f("div",Mb,[n[22]||(n[22]=f("label",null,"文本之后:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[6]||(n[6]=i=>e.config.right_indent=i)},null,512),[[we,e.config.right_indent]])]),f("div",Ub,[n[23]||(n[23]=f("label",null,"段落首行缩进:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[7]||(n[7]=i=>e.config.first_line_indent=i)},null,512),[[we,e.config.first_line_indent]])]),f("div",jb,[n[24]||(n[24]=f("label",null,"内置样式名称:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[8]||(n[8]=i=>e.config.builtin_style_name=i)},null,512),[[we,e.config.builtin_style_name]])]),f("div",Bb,[n[25]||(n[25]=f("label",null,"中文字体名称:",-1)),M(f("select",{"onUpdate:modelValue":n[9]||(n[9]=i=>e.config.chinese_font_name=i)},[(H(!0),K(_e,null,Gt(Ye(Z0),i=>(H(),K("option",{key:i,value:i},ee(i),9,Hb))),128))],512),[[Ot,e.config.chinese_font_name]])]),f("div",Vb,[n[26]||(n[26]=f("label",null,"英文字体名称:",-1)),M(f("select",{"onUpdate:modelValue":n[10]||(n[10]=i=>e.config.english_font_name=i)},[(H(!0),K(_e,null,Gt(Ye(eb),i=>(H(),K("option",{key:i,value:i},ee(i),9,qb))),128))],512),[[Ot,e.config.english_font_name]])]),f("div",Kb,[n[27]||(n[27]=f("label",null,"字号:",-1)),M(f("select",{"onUpdate:modelValue":n[11]||(n[11]=i=>e.config.font_size=i)},[(H(!0),K(_e,null,Gt(Ye(tb),i=>(H(),K("option",{key:i,value:i},ee(i),9,Wb))),128))],512),[[Ot,e.config.font_size]])]),f("div",Yb,[n[28]||(n[28]=f("label",null,"字体颜色:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[12]||(n[12]=i=>e.config.font_color=i)},null,512),[[we,e.config.font_color]])]),f("div",Jb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[13]||(n[13]=i=>e.config.bold=i)},null,512),[[pe,e.config.bold]]),n[29]||(n[29]=de(" 加粗",-1))])]),f("div",zb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[14]||(n[14]=i=>e.config.italic=i)},null,512),[[pe,e.config.italic]]),n[30]||(n[30]=de(" 斜体",-1))])]),f("div",Gb,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[15]||(n[15]=i=>e.config.underline=i)},null,512),[[pe,e.config.underline]]),n[31]||(n[31]=de(" 下划线",-1))])])])]))}},Se=ke(Xb,[["__scopeId","data-v-5177a808"]]),Qb={class:"global-format-config"},Zb={key:0,class:"mt-4"},ey={__name:"GlobalFormatConfig",props:{config:{type:Object,required:!0},showApplyButton:{type:Boolean,default:!1}},emits:["apply-to-all"],setup(e){return(t,n)=>(H(),K("div",Qb,[B(Se,{config:e.config},null,8,["config"]),e.showApplyButton?(H(),K("div",Zb,[f("button",{onClick:n[0]||(n[0]=i=>t.$emit("apply-to-all")),class:"btn btn-green"},"应用到所有配置")])):pt("",!0)]))}},ty=ke(ey,[["__scopeId","data-v-98ee8f2a"]]),ny={class:"abstract-config"},iy={class:"grid grid-cols-2 gap-4 mb-4"},ry={class:"form-item"},oy={class:"form-item"},sy={class:"form-item"},ly={class:"grid grid-cols-2 gap-4 mb-4"},ay={class:"form-item"},cy={class:"form-item"},uy={class:"form-item"},fy={__name:"AbstractConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",ny,[n[12]||(n[12]=f("h3",null,"中文摘要",-1)),n[13]||(n[13]=f("h4",null,"中文标题",-1)),n[14]||(n[14]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),B(Se,{config:e.config.chinese.chinese_title},null,8,["config"]),n[15]||(n[15]=f("h4",{class:"mt-4"},"中文内容",-1)),B(Se,{config:e.config.chinese.chinese_content},null,8,["config"]),n[16]||(n[16]=f("h3",{class:"mt-4"},"英文摘要",-1)),n[17]||(n[17]=f("h4",null,"英文标题",-1)),n[18]||(n[18]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),B(Se,{config:e.config.english.english_title},null,8,["config"]),n[19]||(n[19]=f("h4",{class:"mt-4"},"英文内容",-1)),B(Se,{config:e.config.english.english_content},null,8,["config"]),n[20]||(n[20]=f("h3",{class:"mt-4"},"关键词配置",-1)),n[21]||(n[21]=f("h4",null,"中文关键词",-1)),f("div",iy,[f("div",ry,[n[6]||(n[6]=f("label",null,"最少数量:",-1)),M(f("input",{type:"number","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.keywords.chinese.count_min=i)},null,512),[[we,e.config.keywords.chinese.count_min,void 0,{number:!0}]])]),f("div",oy,[n[7]||(n[7]=f("label",null,"最大数量:",-1)),M(f("input",{type:"number","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.keywords.chinese.count_max=i)},null,512),[[we,e.config.keywords.chinese.count_max,void 0,{number:!0}]])]),f("div",sy,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[2]||(n[2]=i=>e.config.keywords.chinese.trailing_punct_forbidden=i)},null,512),[[pe,e.config.keywords.chinese.trailing_punct_forbidden]]),n[8]||(n[8]=de(" 禁止末尾标点",-1))])])]),n[22]||(n[22]=f("h5",{class:"subsection-title"},"中文关键词内容格式",-1)),B(Se,{config:e.config.keywords.chinese},null,8,["config"]),n[23]||(n[23]=f("h5",{class:"subsection-title mt-3"},'中文关键词标签格式("关键词:")',-1)),B(Se,{config:e.config.keywords.chinese.label},null,8,["config"]),n[24]||(n[24]=f("h4",{class:"mt-4"},"英文关键词",-1)),f("div",ly,[f("div",ay,[n[9]||(n[9]=f("label",null,"最少数量:",-1)),M(f("input",{type:"number","onUpdate:modelValue":n[3]||(n[3]=i=>e.config.keywords.english.count_min=i)},null,512),[[we,e.config.keywords.english.count_min,void 0,{number:!0}]])]),f("div",cy,[n[10]||(n[10]=f("label",null,"最大数量:",-1)),M(f("input",{type:"number","onUpdate:modelValue":n[4]||(n[4]=i=>e.config.keywords.english.count_max=i)},null,512),[[we,e.config.keywords.english.count_max,void 0,{number:!0}]])]),f("div",uy,[f("label",null,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[5]||(n[5]=i=>e.config.keywords.english.trailing_punct_forbidden=i)},null,512),[[pe,e.config.keywords.english.trailing_punct_forbidden]]),n[11]||(n[11]=de(" 禁止末尾标点",-1))])])]),n[25]||(n[25]=f("h5",{class:"subsection-title"},"英文关键词内容格式",-1)),B(Se,{config:e.config.keywords.english},null,8,["config"]),n[26]||(n[26]=f("h5",{class:"subsection-title mt-3"},'英文关键词标签格式("Keywords:")',-1)),B(Se,{config:e.config.keywords.english.label},null,8,["config"])]))}},dy=ke(fy,[["__scopeId","data-v-f954f4ba"]]),py={class:"headings-config"},hy={__name:"HeadingsConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",py,[n[0]||(n[0]=f("h3",null,"一级标题",-1)),n[1]||(n[1]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),B(Se,{config:e.config.level_1},null,8,["config"]),n[2]||(n[2]=f("h3",{class:"mt-4"},"二级标题",-1)),n[3]||(n[3]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),B(Se,{config:e.config.level_2},null,8,["config"]),n[4]||(n[4]=f("h3",{class:"mt-4"},"三级标题",-1)),n[5]||(n[5]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),B(Se,{config:e.config.level_3},null,8,["config"])]))}},gy=ke(hy,[["__scopeId","data-v-82e39cec"]]),my={class:"figures-config"},by={class:"grid grid-cols-2 gap-4 mb-4"},yy={class:"form-item"},vy={__name:"FiguresConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",my,[f("div",by,[f("div",yy,[n[1]||(n[1]=f("label",null,"图注编号前缀:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.caption_prefix=i)},null,512),[[we,e.config.caption_prefix]])])]),B(Se,{config:e.config},null,8,["config"])]))}},_y=ke(vy,[["__scopeId","data-v-30153421"]]),xy={class:"tables-config"},wy={class:"grid grid-cols-2 gap-4 mb-4"},Ay={class:"form-item"},Cy={__name:"TablesConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",xy,[f("div",wy,[f("div",Ay,[n[1]||(n[1]=f("label",null,"表注编号前缀:",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.caption_prefix=i)},null,512),[[we,e.config.caption_prefix]])])]),B(Se,{config:e.config},null,8,["config"]),n[2]||(n[2]=f("h3",{class:"mt-4"},"表格内容格式(单元格内文字)",-1)),B(Se,{config:e.config.content},null,8,["config"])]))}},Sy=ke(Cy,[["__scopeId","data-v-c29e0042"]]),Ey={class:"references-config"},Oy={__name:"ReferencesConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",Ey,[n[0]||(n[0]=f("h3",null,"参考文献标题",-1)),B(Se,{config:e.config.title},null,8,["config"]),n[1]||(n[1]=f("h3",{class:"mt-4"},"参考文献内容",-1)),B(Se,{config:e.config.content},null,8,["config"])]))}},Ty=ke(Oy,[["__scopeId","data-v-ef2c2d78"]]),Ry={class:"acknowledgements-config"},Fy={__name:"AcknowledgementsConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",Ry,[n[0]||(n[0]=f("h3",null,"致谢标题",-1)),n[1]||(n[1]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),B(Se,{config:e.config.title},null,8,["config"]),n[2]||(n[2]=f("h3",{class:"mt-4"},"致谢内容",-1)),B(Se,{config:e.config.content},null,8,["config"])]))}},Ny=ke(Fy,[["__scopeId","data-v-31b00dfd"]]),ky={class:"numbering-config"},Ly={class:"master-switch"},Iy={class:"switch-label"},$y={key:0,class:"levels-config"},Py={class:"level-item"},Dy={class:"level-controls"},My={class:"inline-check"},Uy=["disabled"],jy=["disabled"],By={class:"level-item"},Hy={class:"level-controls"},Vy={class:"inline-check"},qy=["disabled"],Ky=["disabled"],Wy={class:"level-item"},Yy={class:"level-controls"},Jy={class:"inline-check"},zy=["disabled"],Gy=["disabled"],Xy={class:"level-item"},Qy={class:"level-controls"},Zy={class:"inline-check"},e1=["disabled"],t1=["disabled"],n1={class:"level-item"},i1={class:"level-controls"},r1={class:"inline-check"},o1=["disabled"],s1=["disabled"],l1={__name:"NumberingConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(H(),K("div",ky,[f("div",Ly,[f("label",Iy,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.enabled=i)},null,512),[[pe,e.config.enabled]]),n[16]||(n[16]=f("span",null,"启用标题自动编号",-1))])]),e.config.enabled?(H(),K("div",$y,[f("div",Py,[n[22]||(n[22]=f("h4",null,"一级标题",-1)),f("div",Dy,[f("label",My,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.level_1.enabled=i)},null,512),[[pe,e.config.level_1.enabled]]),n[17]||(n[17]=f("span",null,"启用",-1))]),f("div",{class:ve(["field",{disabled:!e.config.level_1.enabled}])},[n[18]||(n[18]=f("label",null,"编号模板",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[2]||(n[2]=i=>e.config.level_1.template=i),disabled:!e.config.level_1.enabled},null,8,Uy),[[we,e.config.level_1.template]]),n[19]||(n[19]=f("span",{class:"hint"},"如 %1",-1))],2),f("div",{class:ve(["field",{disabled:!e.config.level_1.enabled}])},[n[21]||(n[21]=f("label",null,"后缀",-1)),M(f("select",{"onUpdate:modelValue":n[3]||(n[3]=i=>e.config.level_1.suffix=i),disabled:!e.config.level_1.enabled},[...n[20]||(n[20]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,jy),[[Ot,e.config.level_1.suffix]])],2)])]),f("div",By,[n[28]||(n[28]=f("h4",null,"二级标题",-1)),f("div",Hy,[f("label",Vy,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[4]||(n[4]=i=>e.config.level_2.enabled=i)},null,512),[[pe,e.config.level_2.enabled]]),n[23]||(n[23]=f("span",null,"启用",-1))]),f("div",{class:ve(["field",{disabled:!e.config.level_2.enabled}])},[n[24]||(n[24]=f("label",null,"编号模板",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[5]||(n[5]=i=>e.config.level_2.template=i),disabled:!e.config.level_2.enabled},null,8,qy),[[we,e.config.level_2.template]]),n[25]||(n[25]=f("span",{class:"hint"},"如 %1.%2",-1))],2),f("div",{class:ve(["field",{disabled:!e.config.level_2.enabled}])},[n[27]||(n[27]=f("label",null,"后缀",-1)),M(f("select",{"onUpdate:modelValue":n[6]||(n[6]=i=>e.config.level_2.suffix=i),disabled:!e.config.level_2.enabled},[...n[26]||(n[26]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,Ky),[[Ot,e.config.level_2.suffix]])],2)])]),f("div",Wy,[n[34]||(n[34]=f("h4",null,"三级标题",-1)),f("div",Yy,[f("label",Jy,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[7]||(n[7]=i=>e.config.level_3.enabled=i)},null,512),[[pe,e.config.level_3.enabled]]),n[29]||(n[29]=f("span",null,"启用",-1))]),f("div",{class:ve(["field",{disabled:!e.config.level_3.enabled}])},[n[30]||(n[30]=f("label",null,"编号模板",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[8]||(n[8]=i=>e.config.level_3.template=i),disabled:!e.config.level_3.enabled},null,8,zy),[[we,e.config.level_3.template]]),n[31]||(n[31]=f("span",{class:"hint"},"如 %1.%2.%3",-1))],2),f("div",{class:ve(["field",{disabled:!e.config.level_3.enabled}])},[n[33]||(n[33]=f("label",null,"后缀",-1)),M(f("select",{"onUpdate:modelValue":n[9]||(n[9]=i=>e.config.level_3.suffix=i),disabled:!e.config.level_3.enabled},[...n[32]||(n[32]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,Gy),[[Ot,e.config.level_3.suffix]])],2)])]),f("div",Xy,[n[40]||(n[40]=f("h4",null,"参考文献",-1)),f("div",Qy,[f("label",Zy,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[10]||(n[10]=i=>e.config.references.enabled=i)},null,512),[[pe,e.config.references.enabled]]),n[35]||(n[35]=f("span",null,"启用",-1))]),f("div",{class:ve(["field",{disabled:!e.config.references.enabled}])},[n[36]||(n[36]=f("label",null,"编号模板",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[11]||(n[11]=i=>e.config.references.template=i),disabled:!e.config.references.enabled},null,8,e1),[[we,e.config.references.template]]),n[37]||(n[37]=f("span",{class:"hint"},"如 [%1]",-1))],2),f("div",{class:ve(["field",{disabled:!e.config.references.enabled}])},[n[39]||(n[39]=f("label",null,"后缀",-1)),M(f("select",{"onUpdate:modelValue":n[12]||(n[12]=i=>e.config.references.suffix=i),disabled:!e.config.references.enabled},[...n[38]||(n[38]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,t1),[[Ot,e.config.references.suffix]])],2)])]),f("div",n1,[n[45]||(n[45]=f("h4",null,"题注编号",-1)),f("div",i1,[f("label",r1,[M(f("input",{type:"checkbox","onUpdate:modelValue":n[13]||(n[13]=i=>e.config.captions.enabled=i)},null,512),[[pe,e.config.captions.enabled]]),n[41]||(n[41]=f("span",null,"启用",-1))]),f("div",{class:ve(["field",{disabled:!e.config.captions.enabled}])},[n[42]||(n[42]=f("label",null,"分隔符",-1)),M(f("input",{type:"text","onUpdate:modelValue":n[14]||(n[14]=i=>e.config.captions.separator=i),disabled:!e.config.captions.enabled},null,8,o1),[[we,e.config.captions.separator]]),n[43]||(n[43]=f("span",{class:"hint"},"章节号与编号间的分隔符,如 . - :",-1))],2),f("label",{class:ve(["inline-check",{disabled:!e.config.captions.enabled}])},[M(f("input",{type:"checkbox","onUpdate:modelValue":n[15]||(n[15]=i=>e.config.captions.label_number_space=i),disabled:!e.config.captions.enabled},null,8,s1),[[pe,e.config.captions.label_number_space]]),n[44]||(n[44]=f("span",null,"标签与编号间加空格",-1))],2)])])])):pt("",!0)]))}},a1=ke(l1,[["__scopeId","data-v-21ca7315"]]),c1={class:"yaml-output"},u1={class:"yaml-content"},f1={class:"yaml-actions"},d1={__name:"YamlOutput",props:{yamlContent:{type:String,required:!0}},emits:["reset-to-default","import-yaml"],setup(e,{emit:t}){const n=e,i=t,r=be(null),o=()=>{navigator.clipboard.writeText(n.yamlContent)},s=()=>{r.value.click()},l=a=>{const c=a.target.files[0];if(!c)return;const u=new FileReader;u.onload=d=>{try{i("import-yaml",pi.load(d.target.result))}catch(h){alert("导入失败: "+h.message)}},u.onerror=()=>{alert("文件读取失败")},u.readAsText(c,"utf-8"),a.target.value=""};return(a,c)=>(H(),K("div",c1,[c[1]||(c[1]=f("div",{class:"yaml-header"},"生成的 YAML 配置",-1)),f("div",u1,[f("pre",null,ee(e.yamlContent),1)]),f("div",f1,[f("button",{onClick:o,class:"btn btn-green"},"复制"),f("button",{onClick:s,class:"btn btn-ghost"},"导入 YAML"),f("button",{onClick:c[0]||(c[0]=u=>a.$emit("reset-to-default")),class:"btn btn-ghost"},"重置")]),f("input",{type:"file",ref_key:"fileInput",ref:r,style:{display:"none"},accept:".yaml,.yml",onChange:l},null,544)]))}},p1=ke(d1,[["__scopeId","data-v-235091b7"]]),h1={class:"config-generator"},g1={class:"app-content"},m1={class:"config-sections"},b1={class:"yaml-preview"},y1={__name:"ConfigGenerator",emits:["config-updated"],setup(e,{expose:t,emit:n}){const i=be(JSON.parse(JSON.stringify(ln))),r=Ee(()=>pi.dump(i.value,{indent:2,skipInvalid:!0})),o=()=>{i.value=JSON.parse(JSON.stringify(ln))},s=()=>{nb(i.value)},l=d=>{i.value=Xi(d,ln)},a=()=>JSON.parse(JSON.stringify(i.value)),c=d=>{i.value=Xi(JSON.parse(JSON.stringify(d)),ln)},u=n;return un(i,d=>{u("config-updated",JSON.parse(JSON.stringify(d)))},{deep:!0}),mi(()=>{u("config-updated",JSON.parse(JSON.stringify(i.value)))}),t({exportConfig:a,importConfig:c,resetToDefault:o,handleApplyGlobalFormat:s}),(d,h)=>(H(),K("div",h1,[f("div",g1,[f("div",m1,[B(xt,{title:"警告字段配置"},{default:st(()=>[B(Ob,{config:i.value.style_checks_warning},null,8,["config"])]),_:1}),B(xt,{title:"全局基础格式配置"},{default:st(()=>[B(ty,{config:i.value.global_format,"show-apply-button":!0,onApplyToAll:s},null,8,["config"])]),_:1}),B(xt,{title:"摘要配置"},{default:st(()=>[B(dy,{config:i.value.abstract},null,8,["config"])]),_:1}),B(xt,{title:"标题配置"},{default:st(()=>[B(gy,{config:i.value.headings},null,8,["config"])]),_:1}),B(xt,{title:"正文配置"},{default:st(()=>[B(Se,{config:i.value.body_text},null,8,["config"])]),_:1}),B(xt,{title:"插图配置"},{default:st(()=>[B(_y,{config:i.value.figures},null,8,["config"])]),_:1}),B(xt,{title:"表格配置"},{default:st(()=>[B(Sy,{config:i.value.tables},null,8,["config"])]),_:1}),B(xt,{title:"参考文献配置"},{default:st(()=>[B(Ty,{config:i.value.references},null,8,["config"])]),_:1}),B(xt,{title:"致谢配置"},{default:st(()=>[B(Ny,{config:i.value.acknowledgements},null,8,["config"])]),_:1}),B(xt,{title:"标题自动编号"},{default:st(()=>[B(a1,{config:i.value.numbering},null,8,["config"])]),_:1})]),f("div",b1,[B(p1,{"yaml-content":r.value,onResetToDefault:o,onImportYaml:l},null,8,["yaml-content"])])])]))}},v1=ke(y1,[["__scopeId","data-v-c1c26bc8"]]),_1={class:"settings-page"},x1={class:"settings-card"},w1={key:0,class:"connection-url"},A1={class:"form-group"},C1={class:"form-group"},S1={class:"form-actions"},E1=["disabled"],O1={__name:"SettingsPage",setup(e){const t=be(De.host),n=be(De.port),i=be(!1),r=be(null);mi(()=>{Ja(),t.value=De.host,n.value=De.port});const o=Ee(()=>r.value===null?"bar-untested":r.value?"bar-ok":"bar-fail"),s=Ee(()=>r.value===null?"未测试连接":r.value?"连接成功":"连接失败");function l(){De.host=t.value,De.port=n.value,za(),r.value=null}async function a(){i.value=!0,r.value=null;try{const u=await fetch(`${Ki.value}/openapi.json`,{signal:AbortSignal.timeout(5e3)});r.value=u.ok}catch{r.value=!1}finally{i.value=!1}}function c(){Ng(),t.value=De.host,n.value=De.port,r.value=null}return(u,d)=>(H(),K("div",_1,[f("div",x1,[d[5]||(d[5]=f("h2",{class:"settings-title"},"后端连接设置",-1)),d[6]||(d[6]=f("p",{class:"settings-desc"},"配置后端 API 服务的地址和端口,修改后自动保存。",-1)),f("div",{class:ve(["connection-bar",o.value])},[d[2]||(d[2]=f("span",{class:"connection-dot"},null,-1)),f("span",null,ee(s.value),1),r.value?(H(),K("span",w1,ee(Ye(Ki)),1)):pt("",!0)],2),f("div",A1,[d[3]||(d[3]=f("label",{class:"form-label"},"后端 IP 地址",-1)),M(f("input",{"onUpdate:modelValue":d[0]||(d[0]=h=>t.value=h),class:"form-input",placeholder:"127.0.0.1",onInput:l},null,544),[[we,t.value]])]),f("div",C1,[d[4]||(d[4]=f("label",{class:"form-label"},"后端端口",-1)),M(f("input",{"onUpdate:modelValue":d[1]||(d[1]=h=>n.value=h),type:"number",class:"form-input",placeholder:"8000",min:"1",max:"65535",onInput:l},null,544),[[we,n.value,void 0,{number:!0}]])]),f("div",S1,[f("button",{class:"btn btn-green",onClick:a,disabled:i.value},ee(i.value?"测试中...":"测试连接"),9,E1),f("button",{class:"btn btn-ghost",onClick:c},"恢复默认")])])]))}},T1=ke(O1,[["__scopeId","data-v-835f1297"]]),R1={class:"app-container"},F1={class:"nav-bar"},N1={class:"nav-content"},k1={class:"nav-actions"},L1={key:0,class:"config-actions"},I1=["disabled"],$1={class:"nav-tabs"},P1={class:"content-area"},D1={__name:"App",setup(e){const t=be(null),n=be("config"),i=be(JSON.parse(JSON.stringify(ln))),r=be(null),o=be(null),s=u=>{i.value=u};mi(()=>{Ja(),i.value=JSON.parse(JSON.stringify(ln)),t.value&&(window.__toast=t.value.toast)});const l=()=>{var u,d;if(i.value)try{const h=pi.dump(i.value,{indent:2,skipInvalid:!0}),b=new Blob([h],{type:"application/x-yaml"}),v=URL.createObjectURL(b),g=document.createElement("a");g.href=v,g.download="wordformat-config.yaml",document.body.appendChild(g),g.click(),URL.revokeObjectURL(v),document.body.removeChild(g),(u=t.value)==null||u.toast.success("配置已下载!")}catch(h){console.error("保存配置失败:",h),(d=t.value)==null||d.toast.error("保存配置失败:"+h.message)}},a=()=>{var u;(u=o.value)==null||u.click()},c=async u=>{var h,b,v;const d=(h=u.target.files)==null?void 0:h[0];if(d)try{const g=await d.text(),_=pi.load(g),A=Xi(_,ln);i.value=A,r.value&&r.value.importConfig(A),(b=t.value)==null||b.toast.success("配置加载成功!")}catch(g){console.error("加载配置失败:",g),(v=t.value)==null||v.toast.error("加载配置失败:"+g.message)}finally{u.target.value=""}};return(u,d)=>(H(),K("div",R1,[B(Dd,{ref_key:"toastRef",ref:t},null,512),f("div",F1,[f("div",N1,[d[3]||(d[3]=f("h1",{class:"app-title"},"WordFormat 工具",-1)),f("div",k1,[n.value==="config"?(H(),K("div",L1,[f("button",{class:"btn secondary-btn",onClick:l,disabled:!i.value}," 保存配置 ",8,I1),f("button",{class:"btn secondary-btn",onClick:a}," 加载配置 ")])):pt("",!0),f("div",$1,[f("button",{class:ve(["nav-tab",{active:n.value==="config"}]),onClick:d[0]||(d[0]=h=>n.value="config")}," 配置生成器 ",2),f("button",{class:ve(["nav-tab",{active:n.value==="checker"}]),onClick:d[1]||(d[1]=h=>n.value="checker")}," 文档标签核对 ",2),f("button",{class:ve(["nav-tab",{active:n.value==="settings"}]),onClick:d[2]||(d[2]=h=>n.value="settings")}," 设置 ",2)])])])]),f("div",P1,[M(B(v1,{ref_key:"configGeneratorRef",ref:r,onConfigUpdated:s},null,512),[[Or,n.value==="config"]]),M(B(Kg,{"generated-config":i.value},null,8,["generated-config"]),[[Or,n.value==="checker"]]),M(B(T1,null,null,512),[[Or,n.value==="settings"]])]),f("input",{ref_key:"fileInputRef",ref:o,type:"file",accept:".yaml,.yml",style:{display:"none"},onChange:c},null,544)]))}},Bo=Nd(D1),br={info:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.info(e,t)},success:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.success(e,t)},warn:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.warn(e,t)},error:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.error(e,t)}};Bo.config.globalProperties.$toast=br;Bo.config.errorHandler=(e,t,n)=>{console.error("[Vue Error]",e,n),br.error(`[${n}] ${e.message||e}`)};window.addEventListener("error",e=>{var t;console.error("[Global Error]",e.error),br.error(((t=e.error)==null?void 0:t.message)||e.message)});window.addEventListener("unhandledrejection",e=>{var t;console.error("[Unhandled Rejection]",e.reason),br.error(((t=e.reason)==null?void 0:t.message)||String(e.reason))});Bo.mount("#app"); diff --git a/src/wordformat/api/static/assets/index-BI1_kgRW.css b/src/wordformat/api/static/assets/index-BI1_kgRW.css deleted file mode 100644 index 1c2931c..0000000 --- a/src/wordformat/api/static/assets/index-BI1_kgRW.css +++ /dev/null @@ -1 +0,0 @@ -.toast-container{position:fixed;top:16px;right:16px;z-index:99999;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast-item{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:10px;background:#1e293b;box-shadow:0 8px 32px #00000059;min-width:280px;max-width:480px;pointer-events:auto;font-size:14px;border:1px solid #334155}.toast-msg{flex:1;color:#e2e8f0}.toast-close{background:none;border:none;font-size:22px;cursor:pointer;color:#64748b;padding:0 4px;line-height:1}.toast-close:hover{color:#e2e8f0}.toast-info{border-left:4px solid #3b82f6}.toast-success{border-left:4px solid #22c55e}.toast-warn{border-left:4px solid #f59e0b}.toast-error{border-left:4px solid #ef4444}.toast-enter-active{transition:all .3s ease}.toast-leave-active{transition:all .2s ease}.toast-enter-from,.toast-leave-to{opacity:0;transform:translate(40px)}.upload-group[data-v-6d870395]{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.upload-btn[data-v-6d870395]{padding:6px 12px;font-size:12px;font-weight:500;border:1px solid #475569;border-radius:6px;background:#1e293b;color:#cbd5e1;cursor:pointer;transition:all .2s;font-family:inherit}.upload-btn[data-v-6d870395]:hover{background:#334155;border-color:#64748b;color:#e2e8f0}.file-hidden[data-v-6d870395]{display:none}.file-tip[data-v-6d870395]{font-size:11px;color:#64748b;white-space:nowrap}.go-btn[data-v-6d870395]{padding:6px 14px;font-size:12px;font-weight:600;border:none;border-radius:6px;background:#22c55e;color:#052e16;cursor:pointer;transition:all .2s;font-family:inherit}.go-btn[data-v-6d870395]:hover:not(:disabled){background:#16a34a}.go-btn[data-v-6d870395]:disabled{opacity:.4;cursor:not-allowed}.format-btn-group[data-v-99eed13a]{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.btn[data-v-99eed13a]{padding:6px 12px;font-size:12px;font-weight:500;border:none;border-radius:6px;cursor:pointer;transition:all .2s;font-family:inherit}.btn[data-v-99eed13a]:disabled{opacity:.4;cursor:not-allowed}.btn-amber[data-v-99eed13a]{background:#d97706;color:#fef3c7}.btn-amber[data-v-99eed13a]:hover:not(:disabled){background:#b45309}.btn-green[data-v-99eed13a]{background:#22c55e;color:#052e16}.btn-green[data-v-99eed13a]:hover:not(:disabled){background:#16a34a}.node-list-section[data-v-d86ce66e]{width:100%;flex:1}.card[data-v-d86ce66e]{background-color:#1e293b;border:1px solid #334155;border-radius:10px;padding:1rem;display:flex;flex-direction:column;height:100%}.node-list[data-v-d86ce66e]{display:flex;flex-direction:column;gap:.125rem;overflow-y:auto;flex:1;min-height:calc(100vh - 110px)}.node-item[data-v-d86ce66e]{position:relative;margin:2px 0;border-radius:6px;transition:background-color .2s ease;display:flex;align-items:center;min-height:36px;padding:4px 8px;cursor:pointer;gap:.5rem;flex-wrap:wrap}.node-item[data-v-d86ce66e]:hover{background-color:#334155}.node-item.error[data-v-d86ce66e]{background-color:#450a0a;border-left:3px solid #ef4444}.node-item.other[data-v-d86ce66e]{background-color:#1e293b;border-left:3px solid #475569;opacity:.7}.node-item.selected[data-v-d86ce66e]{background-color:#1e3a5f;border-left:3px solid #3b82f6;opacity:1}.level-dot[data-v-d86ce66e]{width:8px;height:8px;border-radius:50%;flex-shrink:0}.node-tag[data-v-d86ce66e]{min-width:140px;font-size:12px;padding:2px 6px;border-radius:3px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:0}.node-score[data-v-d86ce66e]{min-width:60px;font-size:12px;padding:2px 6px;border-radius:3px;background:#064e3b;color:#6ee7b7;text-align:center;flex-shrink:0}.node-content[data-v-d86ce66e]{flex:1;font-size:13px;color:#e2e8f0;word-break:break-all;line-height:1.4}.node-meta[data-v-d86ce66e]{font-size:11px;color:#64748b;display:flex;gap:10px;align-items:center;flex-shrink:0;white-space:nowrap}.node-fingerprint[data-v-d86ce66e]{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace}.init-tip[data-v-d86ce66e],.loading-tip[data-v-d86ce66e],.empty-tip[data-v-d86ce66e]{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;color:#64748b;gap:.75rem;padding:6rem 0}.init-icon[data-v-d86ce66e]{width:48px;height:48px;color:#334155}.init-sub-tip[data-v-d86ce66e]{font-size:12px;color:#475569;margin-top:.25rem;text-align:center;line-height:1.5}.loading-spinner[data-v-d86ce66e]{width:20px;height:20px;border:3px solid #334155;border-radius:50%;border-top-color:#22c55e;animation:spin-d86ce66e 1s ease-in-out infinite}.empty-tip[data-v-d86ce66e]{font-size:13px}@keyframes spin-d86ce66e{to{transform:rotate(360deg)}}.node-tag.other[data-v-d86ce66e]{background:#334155;color:#94a3b8;font-weight:500}.node-tag.abstract_chinese_title[data-v-d86ce66e]{background:#064e3b;color:#6ee7b7}.node-tag.abstract_chinese_title_content[data-v-d86ce66e]{background:#0c4a6e;color:#7dd3fc}.node-tag.abstract_english_title[data-v-d86ce66e]{background:#4c1d95;color:#c4b5fd}.node-tag.abstract_english_title_content[data-v-d86ce66e]{background:#581c87;color:#d8b4fe}.node-tag.keywords_chinese[data-v-d86ce66e]{background:#713f12;color:#fde68a}.node-tag.keywords_english[data-v-d86ce66e]{background:#7f1d1d;color:#fecaca}.node-tag.chinese_title[data-v-d86ce66e]{background:#0c4a6e;color:#7dd3fc}.node-tag.english_title[data-v-d86ce66e]{background:#064e3b;color:#6ee7b7}.node-tag.heading_level_1[data-v-d86ce66e]{background:#312e81;color:#c7d2fe}.node-tag.heading_level_2[data-v-d86ce66e]{background:#4c1d95;color:#d8b4fe}.node-tag.heading_level_3[data-v-d86ce66e]{background:#581c87;color:#e9d5ff}.node-tag.heading_mulu[data-v-d86ce66e]{background:#713f12;color:#fde68a}.node-tag.heading_fulu[data-v-d86ce66e]{background:#1e293b;color:#94a3b8}.node-tag.references_title[data-v-d86ce66e]{background:#164e63;color:#67e8f9}.node-tag.acknowledgements_title[data-v-d86ce66e]{background:#064e3b;color:#6ee7b7}.node-tag.caption_figure[data-v-d86ce66e],.node-tag.caption_table[data-v-d86ce66e]{background:#1e293b;color:#94a3b8}.node-tag.body_text[data-v-d86ce66e]{background:#0f172a;color:#94a3b8}.search-highlight[data-v-d86ce66e]{background-color:#713f12;color:#fde68a;padding:0 2px;border-radius:2px}.replace-badge[data-v-d86ce66e]{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:#22c55e;color:#052e16;font-size:11px;font-weight:700;flex-shrink:0;cursor:default}.node-detail-section[data-v-caa1c263]{margin-left:auto}.detail-card[data-v-caa1c263]{position:sticky;top:84px;max-height:calc(100vh - 120px);min-height:auto;overflow-y:auto;display:flex;flex-direction:column;background-color:#1e293b;border:1px solid #334155;border-radius:10px;padding:1rem}.detail-title[data-v-caa1c263]{font-size:14px;font-weight:600;color:#e2e8f0;padding-bottom:.5rem;border-bottom:1px solid #334155;margin-bottom:1rem}.no-select-tip[data-v-caa1c263]{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;color:#64748b;gap:.75rem;padding:6rem 0}.no-select-icon[data-v-caa1c263]{width:48px;height:48px;color:#334155}.property-card[data-v-caa1c263]{border:1px solid #334155;border-radius:6px;overflow:hidden;margin-bottom:8px}.property-card-header[data-v-caa1c263]{padding:6px 8px;font-size:12px;font-weight:500;background-color:#0f172a;color:#94a3b8;border-bottom:1px solid #334155}.property-card-body[data-v-caa1c263]{padding:8px;display:flex;flex-direction:column;gap:.75rem}.property-item[data-v-caa1c263]{display:flex;flex-direction:column;gap:2px}.property-label[data-v-caa1c263]{font-size:12px;font-weight:500;color:#64748b}.label-tip[data-v-caa1c263]{font-size:11px;font-weight:400;color:#475569}.property-value[data-v-caa1c263]{font-size:13px;color:#e2e8f0;padding:6px 8px;border-radius:6px;border:1px solid #334155;background-color:#0f172a;line-height:1.4;word-break:break-all}.content-value[data-v-caa1c263]{max-height:8rem;overflow-y:auto}.replace-label[data-v-caa1c263]{color:#4ade80;font-weight:600}.replace-value[data-v-caa1c263]{border-color:#166534;background-color:#052e16;color:#6ee7b7}.status-value[data-v-caa1c263]{border:none;padding:6px 8px}.status-normal[data-v-caa1c263]{background-color:#052e16;color:#4ade80}.status-error[data-v-caa1c263]{background-color:#450a0a;color:#fca5a5}.status-other[data-v-caa1c263]{background-color:#1e293b;color:#94a3b8}.category-select[data-v-caa1c263]{width:100%;font-size:13px;padding:6px 8px;border-radius:6px;border:1px solid #475569;background:#0f172a;color:#e2e8f0;cursor:pointer;margin:4px 0;box-sizing:border-box}.category-select[data-v-caa1c263]:focus{outline:1px solid #22c55e;border-color:#22c55e}.category-desc[data-v-caa1c263]{font-size:11px;color:#64748b;line-height:1.4;padding:4px 0 0}.check-result[data-v-caa1c263]{padding:6px 8px;border-radius:6px;font-size:13px;text-align:center;margin-top:8px}.result-normal[data-v-caa1c263]{background-color:#052e16;color:#4ade80}.result-error[data-v-caa1c263]{background-color:#450a0a;color:#fca5a5}.result-other[data-v-caa1c263]{background-color:#1e293b;color:#94a3b8}.flex[data-v-caa1c263]{display:flex}.items-center[data-v-caa1c263]{align-items:center}.mr-2[data-v-caa1c263]{margin-right:.5rem}.mt-4[data-v-caa1c263]{margin-top:1rem}.fingerprint-value[data-v-caa1c263]{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px}.doc-tag-check-container[data-v-bd52c815]{width:100%;min-height:100vh;display:flex;flex-direction:column;background-color:#0f172a}.header-bar[data-v-bd52c815]{background-color:#1e293b;border-bottom:1px solid #334155;padding:.75rem 1.5rem}.header-content[data-v-bd52c815]{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:1rem;max-width:1280px;margin:0 auto;width:100%}.header-left[data-v-bd52c815]{display:flex;flex-direction:column;gap:.25rem}.tool-title[data-v-bd52c815]{font-size:1.15rem;font-weight:600;color:#f1f5f9;margin:0;font-family:Crimson Pro,serif}.stats-info[data-v-bd52c815]{font-size:.8125rem;color:#64748b}.stats-info span[data-v-bd52c815]{font-weight:600;color:#22c55e}.header-right[data-v-bd52c815]{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.search-box[data-v-bd52c815]{position:relative;display:flex;align-items:center}.search-input[data-v-bd52c815]{padding:6px 28px 6px 10px;font-size:13px;border:1px solid #475569;border-radius:6px;width:180px;outline:none;background:#0f172a;color:#e2e8f0;font-family:inherit}.search-input[data-v-bd52c815]:focus{border-color:#22c55e;box-shadow:0 0 0 2px #22c55e26}.search-icon[data-v-bd52c815]{position:absolute;right:8px;width:16px;height:16px;color:#64748b;pointer-events:none}.btn[data-v-bd52c815]{padding:6px 12px;font-size:12px;border-radius:6px;border:1px solid transparent;cursor:pointer;transition:all .2s;white-space:nowrap;font-family:inherit}.btn[data-v-bd52c815]:disabled{opacity:.4;cursor:not-allowed}.primary-btn[data-v-bd52c815]{background-color:#22c55e;color:#052e16}.primary-btn[data-v-bd52c815]:hover:not(:disabled){background-color:#16a34a}.secondary-btn[data-v-bd52c815]{background-color:#334155;color:#cbd5e1;border:1px solid #475569}.secondary-btn[data-v-bd52c815]:hover:not(:disabled){background-color:#475569;border-color:#64748b}.main-content[data-v-bd52c815]{flex:1;display:grid;grid-template-columns:1fr 400px;gap:1.5rem;padding:1.5rem;width:100%;max-width:1280px;margin:0 auto}@media(max-width:992px){.main-content[data-v-bd52c815]{grid-template-columns:1fr}}.config-section[data-v-88bb2378]{margin-bottom:18px;border:1px solid #334155;border-radius:10px;overflow:hidden;background-color:#1e293b;transition:border-color .2s}.config-section[data-v-88bb2378]:hover{border-color:#475569}.section-header[data-v-88bb2378]{display:flex;justify-content:space-between;align-items:center;padding:14px 20px;background-color:#0f172a;cursor:pointer;transition:background-color .2s}.section-header[data-v-88bb2378]:hover{background-color:#1e293b}.section-header h2[data-v-88bb2378]{margin:0;font-size:15px;font-weight:600;color:#e2e8f0}.toggle-arrow[data-v-88bb2378]{color:#64748b;transition:transform .2s;flex-shrink:0}.toggle-arrow.expanded[data-v-88bb2378]{transform:rotate(180deg)}.section-content[data-v-88bb2378]{padding:18px 20px;border-top:1px solid #334155}.section-content h3[data-v-88bb2378]{margin-top:0;margin-bottom:14px;font-size:14px;color:#94a3b8}.select-all-bar[data-v-315bca75]{margin-bottom:12px;padding-bottom:10px;border-bottom:1px solid #334155}.select-all-label[data-v-315bca75]{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-weight:600;font-size:13px;color:#22c55e}.select-all-label input[type=checkbox][data-v-315bca75]{width:16px;height:16px;cursor:pointer;accent-color:#22c55e}.form-item[data-v-315bca75]{margin-bottom:8px;display:flex;flex-direction:row;align-items:center;gap:4px}.form-item label[data-v-315bca75]{font-weight:500;color:#94a3b8;font-size:13px;white-space:nowrap;cursor:pointer}.form-item input[type=checkbox][data-v-315bca75]{margin-right:6px;accent-color:#22c55e}.grid[data-v-315bca75]{display:grid}.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(6,1fr)}.gap-2[data-v-315bca75]{gap:6px}@media(min-width:1024px){.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(7,1fr)}}@media(min-width:1200px){.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(8,1fr)}}@media(max-width:768px){.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(2,1fr)}}.form-item[data-v-5177a808]{margin-bottom:6px;display:flex;align-items:center;gap:8px}.form-item label[data-v-5177a808]{font-weight:500;color:#94a3b8;font-size:13px;white-space:nowrap;min-width:80px}.form-item input[type=text][data-v-5177a808],.form-item input[type=number][data-v-5177a808],.form-item select[data-v-5177a808]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #475569;border-radius:6px;font-size:13px;background:#0f172a;color:#e2e8f0;outline:none;transition:border-color .2s}.form-item input[data-v-5177a808]:focus,.form-item select[data-v-5177a808]:focus{border-color:#22c55e;box-shadow:0 0 0 2px #22c55e26}.form-item input[type=text][data-v-5177a808]:disabled,.form-item select[data-v-5177a808]:disabled{opacity:.4}.form-item[data-v-5177a808]:has(input[type=checkbox]){width:auto}.form-item:has(input[type=checkbox]) label[data-v-5177a808]{min-width:auto}.form-item input[type=checkbox][data-v-5177a808]{margin-right:5px;accent-color:#22c55e}.grid[data-v-5177a808]{display:grid}.grid-cols-2[data-v-5177a808]{grid-template-columns:repeat(4,1fr)}.gap-4[data-v-5177a808]{gap:10px}@media(min-width:1200px){.grid-cols-2[data-v-5177a808]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1600px){.grid-cols-2[data-v-5177a808]{grid-template-columns:repeat(6,1fr)}}@media(max-width:768px){.grid-cols-2[data-v-5177a808]{grid-template-columns:1fr}.form-item[data-v-5177a808]{flex-direction:column;align-items:flex-start}.form-item label[data-v-5177a808]{min-width:auto}.form-item input[type=text][data-v-5177a808],.form-item input[type=number][data-v-5177a808],.form-item select[data-v-5177a808]{width:120px}}.btn-green[data-v-98ee8f2a]{padding:8px 16px;border:none;border-radius:6px;font-size:13px;cursor:pointer;background:#22c55e;color:#052e16;font-family:inherit;transition:background .2s}.btn-green[data-v-98ee8f2a]:hover{background:#16a34a}.mt-4[data-v-98ee8f2a]{margin-top:14px}.form-item[data-v-f954f4ba]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-f954f4ba]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:120px}.form-item input[type=text][data-v-f954f4ba],.form-item input[type=number][data-v-f954f4ba],.form-item select[data-v-f954f4ba]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-f954f4ba]{margin-right:5px}.form-item[data-v-f954f4ba]:has(input[type=checkbox]){width:auto}.form-item:has(input[type=checkbox]) label[data-v-f954f4ba]{min-width:auto}.grid[data-v-f954f4ba]{display:grid}.grid-cols-2[data-v-f954f4ba]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-f954f4ba]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-f954f4ba]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-f954f4ba]{gap:10px}.mb-4[data-v-f954f4ba]{margin-bottom:12px}.subsection-title[data-v-f954f4ba]{font-size:12px;font-weight:600;color:#94a3b8;margin-bottom:4px}.mt-3[data-v-f954f4ba]{margin-top:8px}.mt-4[data-v-f954f4ba]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-f954f4ba]{grid-template-columns:1fr}.form-item[data-v-f954f4ba]{flex-direction:column;align-items:flex-start}.form-item label[data-v-f954f4ba]{min-width:auto}.form-item input[type=text][data-v-f954f4ba],.form-item input[type=number][data-v-f954f4ba],.form-item select[data-v-f954f4ba]{width:120px}}.form-item[data-v-82e39cec]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-82e39cec]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:80px}.form-item input[type=text][data-v-82e39cec],.form-item input[type=number][data-v-82e39cec],.form-item select[data-v-82e39cec]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-82e39cec]{margin-right:5px}.grid[data-v-82e39cec]{display:grid}.grid-cols-2[data-v-82e39cec]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-82e39cec]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-82e39cec]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-82e39cec]{gap:10px}.mb-4[data-v-82e39cec]{margin-bottom:12px}.mt-4[data-v-82e39cec]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-82e39cec]{grid-template-columns:1fr}.form-item[data-v-82e39cec]{flex-direction:column;align-items:flex-start}.form-item label[data-v-82e39cec]{min-width:auto}.form-item input[type=text][data-v-82e39cec],.form-item input[type=number][data-v-82e39cec],.form-item select[data-v-82e39cec]{width:120px}}.form-item[data-v-30153421]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-30153421]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:100px}.form-item input[type=text][data-v-30153421],.form-item input[type=number][data-v-30153421],.form-item select[data-v-30153421]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.grid[data-v-30153421]{display:grid}.grid-cols-2[data-v-30153421]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-30153421]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-30153421]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-30153421]{gap:10px}.mb-4[data-v-30153421]{margin-bottom:12px}@media(max-width:768px){.grid-cols-2[data-v-30153421]{grid-template-columns:1fr}.form-item[data-v-30153421]{flex-direction:column;align-items:flex-start}.form-item label[data-v-30153421]{min-width:auto}.form-item input[type=text][data-v-30153421],.form-item input[type=number][data-v-30153421],.form-item select[data-v-30153421]{width:120px}}.form-item[data-v-c29e0042]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-c29e0042]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:100px}.form-item input[type=text][data-v-c29e0042],.form-item input[type=number][data-v-c29e0042],.form-item select[data-v-c29e0042]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.grid[data-v-c29e0042]{display:grid}.grid-cols-2[data-v-c29e0042]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-c29e0042]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-c29e0042]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-c29e0042]{gap:10px}.mb-4[data-v-c29e0042]{margin-bottom:12px}.mt-4[data-v-c29e0042]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-c29e0042]{grid-template-columns:1fr}.form-item[data-v-c29e0042]{flex-direction:column;align-items:flex-start}.form-item label[data-v-c29e0042]{min-width:auto}.form-item input[type=text][data-v-c29e0042],.form-item input[type=number][data-v-c29e0042],.form-item select[data-v-c29e0042]{width:120px}}.form-item[data-v-ef2c2d78]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-ef2c2d78]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:100px}.form-item input[type=text][data-v-ef2c2d78],.form-item input[type=number][data-v-ef2c2d78],.form-item select[data-v-ef2c2d78]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-ef2c2d78]{margin-right:5px}.form-item[data-v-ef2c2d78]:has(input[type=checkbox]){width:auto}.form-item:has(input[type=checkbox]) label[data-v-ef2c2d78]{min-width:auto}.grid[data-v-ef2c2d78]{display:grid}.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-ef2c2d78]{gap:10px}.mb-4[data-v-ef2c2d78]{margin-bottom:12px}.mt-4[data-v-ef2c2d78]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:1fr}.form-item[data-v-ef2c2d78]{flex-direction:column;align-items:flex-start}.form-item label[data-v-ef2c2d78]{min-width:auto}.form-item input[type=text][data-v-ef2c2d78],.form-item input[type=number][data-v-ef2c2d78],.form-item select[data-v-ef2c2d78]{width:120px}}.form-item[data-v-31b00dfd]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-31b00dfd]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:80px}.form-item input[type=text][data-v-31b00dfd],.form-item input[type=number][data-v-31b00dfd],.form-item select[data-v-31b00dfd]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-31b00dfd]{margin-right:5px}.grid[data-v-31b00dfd]{display:grid}.grid-cols-2[data-v-31b00dfd]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-31b00dfd]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-31b00dfd]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-31b00dfd]{gap:10px}.mb-4[data-v-31b00dfd]{margin-bottom:12px}.mt-4[data-v-31b00dfd]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-31b00dfd]{grid-template-columns:1fr}.form-item[data-v-31b00dfd]{flex-direction:column;align-items:flex-start}.form-item label[data-v-31b00dfd]{min-width:auto}.form-item input[type=text][data-v-31b00dfd],.form-item input[type=number][data-v-31b00dfd],.form-item select[data-v-31b00dfd]{width:120px}}.master-switch[data-v-21ca7315]{margin-bottom:16px}.switch-label[data-v-21ca7315]{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-weight:600;font-size:13px;color:#22c55e}.switch-label input[type=checkbox][data-v-21ca7315]{width:16px;height:16px;cursor:pointer;accent-color:#22c55e}.levels-config[data-v-21ca7315]{display:flex;flex-direction:column;gap:12px}.level-item[data-v-21ca7315]{border:1px solid #334155;border-radius:8px;padding:12px;background:#0f172a}.level-item h4[data-v-21ca7315]{margin:0 0 10px;font-size:13px;font-weight:600;color:#e2e8f0}.level-controls[data-v-21ca7315]{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.inline-check[data-v-21ca7315]{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-size:13px;color:#cbd5e1;white-space:nowrap}.inline-check input[type=checkbox][data-v-21ca7315]{width:14px;height:14px;cursor:pointer;accent-color:#22c55e}.field[data-v-21ca7315]{display:flex;align-items:center;gap:6px}.field.disabled[data-v-21ca7315]{opacity:.4;pointer-events:none}.field label[data-v-21ca7315]{font-size:12px;color:#64748b;white-space:nowrap}.field input[type=text][data-v-21ca7315]{width:80px;padding:4px 8px;border:1px solid #475569;border-radius:5px;font-size:13px;font-family:monospace;background:#1e293b;color:#e2e8f0;outline:none}.field input[type=text][data-v-21ca7315]:focus{border-color:#22c55e;box-shadow:0 0 0 2px #22c55e26}.field select[data-v-21ca7315]{padding:4px 8px;border:1px solid #475569;border-radius:5px;font-size:13px;background:#1e293b;color:#e2e8f0;outline:none}.hint[data-v-21ca7315]{font-size:11px;color:#64748b;white-space:nowrap}.yaml-output[data-v-235091b7]{border:1px solid #334155;border-radius:10px;overflow:hidden}.yaml-header[data-v-235091b7]{padding:12px 18px;background:#0f172a;font-size:14px;font-weight:600;color:#e2e8f0}.yaml-content[data-v-235091b7]{padding:16px 18px;background:#020617;max-height:360px;overflow-y:auto}.yaml-content pre[data-v-235091b7]{margin:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.6;color:#94a3b8;white-space:pre;word-wrap:break-word;-moz-tab-size:2;tab-size:2}.yaml-actions[data-v-235091b7]{padding:10px 18px;background:#0f172a;border-top:1px solid #334155;display:flex;gap:8px}.btn[data-v-235091b7]{padding:6px 14px;border:none;border-radius:6px;font-size:12px;cursor:pointer;font-family:inherit;transition:all .2s}.btn-green[data-v-235091b7]{background:#22c55e;color:#052e16}.btn-green[data-v-235091b7]:hover{background:#16a34a}.btn-ghost[data-v-235091b7]{background:transparent;color:#94a3b8;border:1px solid #475569}.btn-ghost[data-v-235091b7]:hover{background:#1e293b;color:#e2e8f0}.config-generator[data-v-c1c26bc8]{width:100%}.app-content[data-v-c1c26bc8]{display:flex;gap:20px;width:100%}.config-sections[data-v-c1c26bc8]{flex:1;min-width:0}.yaml-preview[data-v-c1c26bc8]{width:380px;min-width:280px;position:sticky;top:84px;align-self:flex-start;max-height:calc(100vh - 110px);overflow-y:auto}@media(max-width:1200px){.app-content[data-v-c1c26bc8]{flex-direction:column}.yaml-preview[data-v-c1c26bc8]{width:100%;position:static;max-height:none}}@media(max-width:768px){.app-content[data-v-c1c26bc8]{gap:10px}}.settings-page[data-v-835f1297]{max-width:520px;margin:0 auto}.settings-card[data-v-835f1297]{background:#1e293b;border:1px solid #334155;border-radius:12px;padding:2rem}.settings-title[data-v-835f1297]{font-size:1.15rem;font-weight:600;color:#f1f5f9;margin-bottom:.35rem;font-family:Crimson Pro,serif}.settings-desc[data-v-835f1297]{font-size:.8125rem;color:#64748b;margin-bottom:1.5rem}.connection-bar[data-v-835f1297]{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-radius:8px;font-size:.8125rem;margin-bottom:1.5rem}.connection-dot[data-v-835f1297]{width:8px;height:8px;border-radius:50%;flex-shrink:0}.bar-untested[data-v-835f1297]{background:#0f172a;border:1px solid #334155;color:#64748b}.bar-untested .connection-dot[data-v-835f1297]{background:#64748b}.bar-ok[data-v-835f1297]{background:#052e16;border:1px solid #166534;color:#4ade80}.bar-ok .connection-dot[data-v-835f1297]{background:#22c55e}.bar-fail[data-v-835f1297]{background:#450a0a;border:1px solid #7f1d1d;color:#fca5a5}.bar-fail .connection-dot[data-v-835f1297]{background:#ef4444}.connection-url[data-v-835f1297]{margin-left:auto;font-family:monospace;font-size:.75rem;opacity:.8}.form-group[data-v-835f1297]{margin-bottom:1rem}.form-label[data-v-835f1297]{display:block;font-size:.8125rem;font-weight:500;color:#94a3b8;margin-bottom:.375rem}.form-input[data-v-835f1297]{width:100%;padding:.625rem .75rem;font-size:.875rem;border:1px solid #475569;border-radius:8px;outline:none;background:#0f172a;color:#e2e8f0;transition:border-color .2s;font-family:inherit;box-sizing:border-box}.form-input[data-v-835f1297]:focus{border-color:#22c55e;box-shadow:0 0 0 3px #22c55e26}.form-actions[data-v-835f1297]{display:flex;gap:.75rem;margin-top:1.5rem}.btn[data-v-835f1297]{padding:.5rem 1rem;font-size:.8125rem;font-weight:500;border:none;border-radius:6px;cursor:pointer;transition:all .2s;font-family:inherit}.btn[data-v-835f1297]:disabled{opacity:.4;cursor:not-allowed}.btn-green[data-v-835f1297]{background:#22c55e;color:#052e16}.btn-green[data-v-835f1297]:hover:not(:disabled){background:#16a34a}.btn-ghost[data-v-835f1297]{background:transparent;color:#94a3b8;border:1px solid #475569}.btn-ghost[data-v-835f1297]:hover{background:#1e293b;color:#e2e8f0}*{margin:0;padding:0;box-sizing:border-box}body{background-color:#0f172a;color:#e2e8f0;font-family:Atkinson Hyperlegible,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;-webkit-font-smoothing:antialiased}.app-container{width:100%;min-height:100vh;display:flex;flex-direction:column}.nav-bar{background-color:#1e293b;border-bottom:1px solid #334155;padding:0 2rem;position:sticky;top:0;z-index:100;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.nav-content{max-width:1400px;margin:0 auto;width:100%;display:flex;justify-content:space-between;align-items:center;height:64px}.app-title{font-family:Crimson Pro,serif;font-size:1.4rem;font-weight:600;color:#f1f5f9;margin:0;letter-spacing:-.02em}.nav-actions{display:flex;align-items:center;gap:.75rem}.config-actions{display:flex;gap:.5rem}.nav-tabs{display:flex;gap:.25rem;background:#0f172a;border-radius:8px;padding:3px}.btn{padding:.5rem 1rem;font-size:.8125rem;font-weight:500;border:none;border-radius:6px;cursor:pointer;transition:all .2s ease;font-family:inherit}.btn:disabled{opacity:.4;cursor:not-allowed}.primary-btn{background-color:#22c55e;color:#052e16}.primary-btn:hover:not(:disabled){background-color:#16a34a}.secondary-btn{background-color:#334155;color:#cbd5e1;border:1px solid #475569}.secondary-btn:hover:not(:disabled){background-color:#475569;border-color:#64748b}.nav-tab{padding:.45rem 1.25rem;font-size:.875rem;font-weight:500;border:none;border-radius:6px;background-color:transparent;color:#94a3b8;cursor:pointer;transition:all .2s ease;font-family:inherit}.nav-tab:hover{background-color:#1e293b;color:#e2e8f0}.nav-tab.active{background-color:#22c55e;color:#052e16}.content-area{flex:1;padding:1.5rem 2rem;max-width:1400px;margin:0 auto;width:100%}@media(max-width:768px){.nav-content{flex-direction:column;height:auto;padding:1rem 0;gap:.75rem}.nav-tabs{width:100%;justify-content:center}.content-area{padding:1rem}} diff --git a/src/wordformat/api/static/assets/index-CkR2UYnL.js b/src/wordformat/api/static/assets/index-CkR2UYnL.js new file mode 100644 index 0000000..3b42d73 --- /dev/null +++ b/src/wordformat/api/static/assets/index-CkR2UYnL.js @@ -0,0 +1,60 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))i(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const s of o.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&i(s)}).observe(document,{childList:!0,subtree:!0});function n(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function i(r){if(r.ep)return;r.ep=!0;const o=n(r);fetch(r.href,o)}})();/** +* @vue/shared v3.5.34 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function fo(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const ge={},Sn=[],Ot=()=>{},al=()=>!1,Qi=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Zi=e=>e.startsWith("onUpdate:"),Ne=Object.assign,po=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},Zc=Object.prototype.hasOwnProperty,fe=(e,t)=>Zc.call(e,t),W=Array.isArray,En=e=>mi(e)==="[object Map]",Dn=e=>mi(e)==="[object Set]",Ko=e=>mi(e)==="[object Date]",Q=e=>typeof e=="function",_e=e=>typeof e=="string",dt=e=>typeof e=="symbol",de=e=>e!==null&&typeof e=="object",cl=e=>(de(e)||Q(e))&&Q(e.then)&&Q(e.catch),ul=Object.prototype.toString,mi=e=>ul.call(e),eu=e=>mi(e).slice(8,-1),fl=e=>mi(e)==="[object Object]",ho=e=>_e(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Qn=fo(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),er=e=>{const t=Object.create(null);return(n=>t[n]||(t[n]=e(n)))},tu=/-\w/g,ut=er(e=>e.replace(tu,t=>t.slice(1).toUpperCase())),nu=/\B([A-Z])/g,mn=er(e=>e.replace(nu,"-$1").toLowerCase()),dl=er(e=>e.charAt(0).toUpperCase()+e.slice(1)),yr=er(e=>e?`on${dl(e)}`:""),Et=(e,t)=>!Object.is(e,t),Ri=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:i,value:n})},tr=e=>{const t=parseFloat(e);return isNaN(t)?e:t},iu=e=>{const t=_e(e)?Number(e):NaN;return isNaN(t)?e:t};let Wo;const nr=()=>Wo||(Wo=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Fn(e){if(W(e)){const t={};for(let n=0;n{if(n){const i=n.split(ou);i.length>1&&(t[i[0].trim()]=i[1].trim())}}),t}function ye(e){let t="";if(_e(e))t=e;else if(W(e))for(let n=0;nUn(n,t))}const gl=e=>!!(e&&e.__v_isRef===!0),ee=e=>_e(e)?e:e==null?"":W(e)||de(e)&&(e.toString===ul||!Q(e.toString))?gl(e)?ee(e.value):JSON.stringify(e,ml,2):String(e),ml=(e,t)=>gl(t)?ml(e,t.value):En(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[i,r],o)=>(n[vr(i,o)+" =>"]=r,n),{})}:Dn(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>vr(n))}:dt(t)?vr(t):de(t)&&!W(t)&&!fl(t)?String(t):t,vr=(e,t="")=>{var n;return dt(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** +* @vue/reactivity v3.5.34 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let Ie;class fu{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&Ie&&(Ie.active?(this.parent=Ie,this.index=(Ie.scopes||(Ie.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t0&&--this._on===0){if(Ie===this)Ie=this.prevScope;else{let t=Ie;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let n,i;for(n=0,i=this.effects.length;n0)return;if(ei){let t=ei;for(ei=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;Zn;){let t=Zn;for(Zn=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(i){e||(e=i)}t=n}}if(e)throw e}function _l(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function xl(e){let t,n=e.depsTail,i=n;for(;i;){const r=i.prevDep;i.version===-1?(i===n&&(n=r),yo(i),pu(i)):t=i,i.dep.activeLink=i.prevActiveLink,i.prevActiveLink=void 0,i=r}e.deps=t,e.depsTail=n}function jr(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(wl(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function wl(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===ri)||(e.globalVersion=ri,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!jr(e))))return;e.flags|=2;const t=e.dep,n=be,i=ft;be=e,ft=!0;try{_l(e);const r=e.fn(e._value);(t.version===0||Et(r,e._value))&&(e.flags|=128,e._value=r,t.version++)}catch(r){throw t.version++,r}finally{be=n,ft=i,xl(e),e.flags&=-3}}function yo(e,t=!1){const{dep:n,prevSub:i,nextSub:r}=e;if(i&&(i.nextSub=r,e.prevSub=void 0),r&&(r.prevSub=i,e.nextSub=void 0),n.subs===e&&(n.subs=i,!i&&n.computed)){n.computed.flags&=-5;for(let o=n.computed.deps;o;o=o.nextDep)yo(o,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function pu(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let ft=!0;const Al=[];function jt(){Al.push(ft),ft=!1}function Bt(){const e=Al.pop();ft=e===void 0?!0:e}function Yo(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=be;be=void 0;try{t()}finally{be=n}}}let ri=0;class hu{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class vo{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!be||!ft||be===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==be)n=this.activeLink=new hu(be,this),be.deps?(n.prevDep=be.depsTail,be.depsTail.nextDep=n,be.depsTail=n):be.deps=be.depsTail=n,Cl(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const i=n.nextDep;i.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=i),n.prevDep=be.depsTail,n.nextDep=void 0,be.depsTail.nextDep=n,be.depsTail=n,be.deps===n&&(be.deps=i)}return n}trigger(t){this.version++,ri++,this.notify(t)}notify(t){mo();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{bo()}}}function Cl(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let i=t.deps;i;i=i.nextDep)Cl(i)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const Br=new WeakMap,cn=Symbol(""),Hr=Symbol(""),oi=Symbol("");function Ue(e,t,n){if(ft&&be){let i=Br.get(e);i||Br.set(e,i=new Map);let r=i.get(n);r||(i.set(n,r=new vo),r.map=i,r.key=n),r.track()}}function Pt(e,t,n,i,r,o){const s=Br.get(e);if(!s){ri++;return}const l=a=>{a&&a.trigger()};if(mo(),t==="clear")s.forEach(l);else{const a=W(e),c=a&&ho(n);if(a&&n==="length"){const u=Number(i);s.forEach((d,g)=>{(g==="length"||g===oi||!dt(g)&&g>=u)&&l(d)})}else switch((n!==void 0||s.has(void 0))&&l(s.get(n)),c&&l(s.get(oi)),t){case"add":a?c&&l(s.get("length")):(l(s.get(cn)),En(e)&&l(s.get(Hr)));break;case"delete":a||(l(s.get(cn)),En(e)&&l(s.get(Hr)));break;case"set":En(e)&&l(s.get(cn));break}}bo()}function bn(e){const t=ae(e);return t===e?t:(Ue(t,"iterate",oi),at(e)?t:t.map(pt))}function ir(e){return Ue(e=ae(e),"iterate",oi),e}function Ct(e,t){return Ht(e)?kn(un(e)?pt(t):t):pt(t)}const gu={__proto__:null,[Symbol.iterator](){return xr(this,Symbol.iterator,e=>Ct(this,e))},concat(...e){return bn(this).concat(...e.map(t=>W(t)?bn(t):t))},entries(){return xr(this,"entries",e=>(e[1]=Ct(this,e[1]),e))},every(e,t){return Lt(this,"every",e,t,void 0,arguments)},filter(e,t){return Lt(this,"filter",e,t,n=>n.map(i=>Ct(this,i)),arguments)},find(e,t){return Lt(this,"find",e,t,n=>Ct(this,n),arguments)},findIndex(e,t){return Lt(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return Lt(this,"findLast",e,t,n=>Ct(this,n),arguments)},findLastIndex(e,t){return Lt(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return Lt(this,"forEach",e,t,void 0,arguments)},includes(...e){return wr(this,"includes",e)},indexOf(...e){return wr(this,"indexOf",e)},join(e){return bn(this).join(e)},lastIndexOf(...e){return wr(this,"lastIndexOf",e)},map(e,t){return Lt(this,"map",e,t,void 0,arguments)},pop(){return Vn(this,"pop")},push(...e){return Vn(this,"push",e)},reduce(e,...t){return Jo(this,"reduce",e,t)},reduceRight(e,...t){return Jo(this,"reduceRight",e,t)},shift(){return Vn(this,"shift")},some(e,t){return Lt(this,"some",e,t,void 0,arguments)},splice(...e){return Vn(this,"splice",e)},toReversed(){return bn(this).toReversed()},toSorted(e){return bn(this).toSorted(e)},toSpliced(...e){return bn(this).toSpliced(...e)},unshift(...e){return Vn(this,"unshift",e)},values(){return xr(this,"values",e=>Ct(this,e))}};function xr(e,t,n){const i=ir(e),r=i[t]();return i!==e&&!at(e)&&(r._next=r.next,r.next=()=>{const o=r._next();return o.done||(o.value=n(o.value)),o}),r}const mu=Array.prototype;function Lt(e,t,n,i,r,o){const s=ir(e),l=s!==e&&!at(e),a=s[t];if(a!==mu[t]){const d=a.apply(e,o);return l?pt(d):d}let c=n;s!==e&&(l?c=function(d,g){return n.call(this,Ct(e,d),g,e)}:n.length>2&&(c=function(d,g){return n.call(this,d,g,e)}));const u=a.call(s,c,i);return l&&r?r(u):u}function Jo(e,t,n,i){const r=ir(e),o=r!==e&&!at(e);let s=n,l=!1;r!==e&&(o?(l=i.length===0,s=function(c,u,d){return l&&(l=!1,c=Ct(e,c)),n.call(this,c,Ct(e,u),d,e)}):n.length>3&&(s=function(c,u,d){return n.call(this,c,u,d,e)}));const a=r[t](s,...i);return l?Ct(e,a):a}function wr(e,t,n){const i=ae(e);Ue(i,"iterate",oi);const r=i[t](...n);return(r===-1||r===!1)&&wo(n[0])?(n[0]=ae(n[0]),i[t](...n)):r}function Vn(e,t,n=[]){jt(),mo();const i=ae(e)[t].apply(e,n);return bo(),Bt(),i}const bu=fo("__proto__,__v_isRef,__isVue"),Sl=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(dt));function yu(e){dt(e)||(e=String(e));const t=ae(this);return Ue(t,"has",e),t.hasOwnProperty(e)}class El{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,i){if(n==="__v_skip")return t.__v_skip;const r=this._isReadonly,o=this._isShallow;if(n==="__v_isReactive")return!r;if(n==="__v_isReadonly")return r;if(n==="__v_isShallow")return o;if(n==="__v_raw")return i===(r?o?Ou:Fl:o?Rl:Ol).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(i)?t:void 0;const s=W(t);if(!r){let a;if(s&&(a=gu[n]))return a;if(n==="hasOwnProperty")return yu}const l=Reflect.get(t,n,Be(t)?t:i);if((dt(n)?Sl.has(n):bu(n))||(r||Ue(t,"get",n),o))return l;if(Be(l)){const a=s&&ho(n)?l:l.value;return r&&de(a)?qr(a):a}return de(l)?r?qr(l):rr(l):l}}class Tl extends El{constructor(t=!1){super(!1,t)}set(t,n,i,r){let o=t[n];const s=W(t)&&ho(n);if(!this._isShallow){const c=Ht(o);if(!at(i)&&!Ht(i)&&(o=ae(o),i=ae(i)),!s&&Be(o)&&!Be(i))return c||(o.value=i),!0}const l=s?Number(n)e,Ci=e=>Reflect.getPrototypeOf(e);function Au(e,t,n){return function(...i){const r=this.__v_raw,o=ae(r),s=En(o),l=e==="entries"||e===Symbol.iterator&&s,a=e==="keys"&&s,c=r[e](...i),u=n?Vr:t?kn:pt;return!t&&Ue(o,"iterate",a?Hr:cn),Ne(Object.create(c),{next(){const{value:d,done:g}=c.next();return g?{value:d,done:g}:{value:l?[u(d[0]),u(d[1])]:u(d),done:g}}})}}function Si(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function Cu(e,t){const n={get(r){const o=this.__v_raw,s=ae(o),l=ae(r);e||(Et(r,l)&&Ue(s,"get",r),Ue(s,"get",l));const{has:a}=Ci(s),c=t?Vr:e?kn:pt;if(a.call(s,r))return c(o.get(r));if(a.call(s,l))return c(o.get(l));o!==s&&o.get(r)},get size(){const r=this.__v_raw;return!e&&Ue(ae(r),"iterate",cn),r.size},has(r){const o=this.__v_raw,s=ae(o),l=ae(r);return e||(Et(r,l)&&Ue(s,"has",r),Ue(s,"has",l)),r===l?o.has(r):o.has(r)||o.has(l)},forEach(r,o){const s=this,l=s.__v_raw,a=ae(l),c=t?Vr:e?kn:pt;return!e&&Ue(a,"iterate",cn),l.forEach((u,d)=>r.call(o,c(u),c(d),s))}};return Ne(n,e?{add:Si("add"),set:Si("set"),delete:Si("delete"),clear:Si("clear")}:{add(r){const o=ae(this),s=Ci(o),l=ae(r),a=!t&&!at(r)&&!Ht(r)?l:r;return s.has.call(o,a)||Et(r,a)&&s.has.call(o,r)||Et(l,a)&&s.has.call(o,l)||(o.add(a),Pt(o,"add",a,a)),this},set(r,o){!t&&!at(o)&&!Ht(o)&&(o=ae(o));const s=ae(this),{has:l,get:a}=Ci(s);let c=l.call(s,r);c||(r=ae(r),c=l.call(s,r));const u=a.call(s,r);return s.set(r,o),c?Et(o,u)&&Pt(s,"set",r,o):Pt(s,"add",r,o),this},delete(r){const o=ae(this),{has:s,get:l}=Ci(o);let a=s.call(o,r);a||(r=ae(r),a=s.call(o,r)),l&&l.call(o,r);const c=o.delete(r);return a&&Pt(o,"delete",r,void 0),c},clear(){const r=ae(this),o=r.size!==0,s=r.clear();return o&&Pt(r,"clear",void 0,void 0),s}}),["keys","values","entries",Symbol.iterator].forEach(r=>{n[r]=Au(r,e,t)}),n}function _o(e,t){const n=Cu(e,t);return(i,r,o)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?i:Reflect.get(fe(n,r)&&r in i?n:i,r,o)}const Su={get:_o(!1,!1)},Eu={get:_o(!1,!0)},Tu={get:_o(!0,!1)};const Ol=new WeakMap,Rl=new WeakMap,Fl=new WeakMap,Ou=new WeakMap;function Ru(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Fu(e){return e.__v_skip||!Object.isExtensible(e)?0:Ru(eu(e))}function rr(e){return Ht(e)?e:xo(e,!1,_u,Su,Ol)}function ku(e){return xo(e,!1,wu,Eu,Rl)}function qr(e){return xo(e,!0,xu,Tu,Fl)}function xo(e,t,n,i,r){if(!de(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const o=Fu(e);if(o===0)return e;const s=r.get(e);if(s)return s;const l=new Proxy(e,o===2?i:n);return r.set(e,l),l}function un(e){return Ht(e)?un(e.__v_raw):!!(e&&e.__v_isReactive)}function Ht(e){return!!(e&&e.__v_isReadonly)}function at(e){return!!(e&&e.__v_isShallow)}function wo(e){return e?!!e.__v_raw:!1}function ae(e){const t=e&&e.__v_raw;return t?ae(t):e}function Nu(e){return!fe(e,"__v_skip")&&Object.isExtensible(e)&&pl(e,"__v_skip",!0),e}const pt=e=>de(e)?rr(e):e,kn=e=>de(e)?qr(e):e;function Be(e){return e?e.__v_isRef===!0:!1}function he(e){return Lu(e,!1)}function Lu(e,t){return Be(e)?e:new $u(e,t)}class $u{constructor(t,n){this.dep=new vo,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:ae(t),this._value=n?t:pt(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,i=this.__v_isShallow||at(t)||Ht(t);t=i?t:ae(t),Et(t,n)&&(this._rawValue=t,this._value=i?t:pt(t),this.dep.trigger())}}function Ye(e){return Be(e)?e.value:e}const Iu={get:(e,t,n)=>t==="__v_raw"?e:Ye(Reflect.get(e,t,n)),set:(e,t,n,i)=>{const r=e[t];return Be(r)&&!Be(n)?(r.value=n,!0):Reflect.set(e,t,n,i)}};function kl(e){return un(e)?e:new Proxy(e,Iu)}class Pu{constructor(t,n,i){this.fn=t,this.setter=n,this._value=void 0,this.dep=new vo(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=ri-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=i}notify(){if(this.flags|=16,!(this.flags&8)&&be!==this)return vl(this,!0),!0}get value(){const t=this.dep.track();return wl(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function Du(e,t,n=!1){let i,r;return Q(e)?i=e:(i=e.get,r=e.set),new Pu(i,r,n)}const Ei={},Pi=new WeakMap;let on;function Uu(e,t=!1,n=on){if(n){let i=Pi.get(n);i||Pi.set(n,i=[]),i.push(e)}}function Mu(e,t,n=ge){const{immediate:i,deep:r,once:o,scheduler:s,augmentJob:l,call:a}=n,c=R=>r?R:at(R)||r===!1||r===0?Dt(R,1):Dt(R);let u,d,g,m,y=!1,h=!1;if(Be(e)?(d=()=>e.value,y=at(e)):un(e)?(d=()=>c(e),y=!0):W(e)?(h=!0,y=e.some(R=>un(R)||at(R)),d=()=>e.map(R=>{if(Be(R))return R.value;if(un(R))return c(R);if(Q(R))return a?a(R,2):R()})):Q(e)?t?d=a?()=>a(e,2):e:d=()=>{if(g){jt();try{g()}finally{Bt()}}const R=on;on=u;try{return a?a(e,3,[m]):e(m)}finally{on=R}}:d=Ot,t&&r){const R=d,G=r===!0?1/0:r;d=()=>Dt(R(),G)}const _=du(),C=()=>{u.stop(),_&&_.active&&po(_.effects,u)};if(o&&t){const R=t;t=(...G)=>{R(...G),C()}}let w=h?new Array(e.length).fill(Ei):Ei;const $=R=>{if(!(!(u.flags&1)||!u.dirty&&!R))if(t){const G=u.run();if(r||y||(h?G.some((re,J)=>Et(re,w[J])):Et(G,w))){g&&g();const re=on;on=u;try{const J=[G,w===Ei?void 0:h&&w[0]===Ei?[]:w,m];w=G,a?a(t,3,J):t(...J)}finally{on=re}}}else u.run()};return l&&l($),u=new bl(d),u.scheduler=s?()=>s($,!1):$,m=R=>Uu(R,!1,u),g=u.onStop=()=>{const R=Pi.get(u);if(R){if(a)a(R,4);else for(const G of R)G();Pi.delete(u)}},t?i?$(!0):w=u.run():s?s($.bind(null,!0),!0):u.run(),C.pause=u.pause.bind(u),C.resume=u.resume.bind(u),C.stop=C,C}function Dt(e,t=1/0,n){if(t<=0||!de(e)||e.__v_skip||(n=n||new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,Be(e))Dt(e.value,t,n);else if(W(e))for(let i=0;i{Dt(i,t,n)});else if(fl(e)){for(const i in e)Dt(e[i],t,n);for(const i of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,i)&&Dt(e[i],t,n)}return e}/** +* @vue/runtime-core v3.5.34 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function bi(e,t,n,i){try{return i?e(...i):e()}catch(r){or(r,t,n)}}function ht(e,t,n,i){if(Q(e)){const r=bi(e,t,n,i);return r&&cl(r)&&r.catch(o=>{or(o,t,n)}),r}if(W(e)){const r=[];for(let o=0;o>>1,r=We[i],o=si(r);o=si(n)?We.push(e):We.splice(Bu(t),0,e),e.flags|=1,$l()}}function $l(){Di||(Di=Nl.then(Pl))}function Hu(e){W(e)?Tn.push(...e):zt&&e.id===-1?zt.splice(_n+1,0,e):e.flags&1||(Tn.push(e),e.flags|=1),$l()}function zo(e,t,n=At+1){for(;nsi(n)-si(i));if(Tn.length=0,zt){zt.push(...t);return}for(zt=t,_n=0;_ne.id==null?e.flags&2?-1:1/0:e.id;function Pl(e){try{for(At=0;At{i._d&&as(-1);const o=Ui(t);let s;try{s=e(...r)}finally{Ui(o),i._d&&as(1)}return s};return i._n=!0,i._c=!0,i._d=!0,i}function P(e,t){if(je===null)return e;const n=cr(je),i=e.dirs||(e.dirs=[]);for(let r=0;r1)return n&&Q(t)?t.call(i&&i.proxy):t}}const qu=Symbol.for("v-scx"),Ku=()=>Fi(qu);function fn(e,t,n){return Ul(e,t,n)}function Ul(e,t,n=ge){const{immediate:i,deep:r,flush:o,once:s}=n,l=Ne({},n),a=t&&i||!t&&o!=="post";let c;if(ci){if(o==="sync"){const m=Ku();c=m.__watcherHandles||(m.__watcherHandles=[])}else if(!a){const m=()=>{};return m.stop=Ot,m.resume=Ot,m.pause=Ot,m}}const u=Je;l.call=(m,y,h)=>ht(m,u,y,h);let d=!1;o==="post"?l.scheduler=m=>{Ke(m,u&&u.suspense)}:o!=="sync"&&(d=!0,l.scheduler=(m,y)=>{y?m():Ao(m)}),l.augmentJob=m=>{t&&(m.flags|=4),d&&(m.flags|=2,u&&(m.id=u.uid,m.i=u))};const g=Mu(e,t,l);return ci&&(c?c.push(g):a&&g()),g}function Wu(e,t,n){const i=this.proxy,r=_e(e)?e.includes(".")?Ml(i,e):()=>i[e]:e.bind(i,i);let o;Q(t)?o=t:(o=t.handler,n=t);const s=yi(this),l=Ul(r,o.bind(i),n);return s(),l}function Ml(e,t){const n=t.split(".");return()=>{let i=e;for(let r=0;re.__isTeleport,sn=e=>e&&(e.disabled||e.disabled===""),Ju=e=>e&&(e.defer||e.defer===""),Go=e=>typeof SVGElement<"u"&&e instanceof SVGElement,Xo=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,Kr=(e,t)=>{const n=e&&e.to;return _e(n)?t?t(n):null:n},zu={name:"Teleport",__isTeleport:!0,process(e,t,n,i,r,o,s,l,a,c){const{mc:u,pc:d,pbc:g,o:{insert:m,querySelector:y,createText:h,createComment:_,parentNode:C}}=c,w=sn(t.props);let{dynamicChildren:$}=t;const R=(J,ne,B)=>{J.shapeFlag&16&&u(J.children,ne,B,r,o,s,l,a)},G=(J=t)=>{const ne=sn(J.props),B=J.target=Kr(J.props,y),X=Wr(B,J,h,m);B&&(s!=="svg"&&Go(B)?s="svg":s!=="mathml"&&Xo(B)&&(s="mathml"),r&&r.isCE&&(r.ce._teleportTargets||(r.ce._teleportTargets=new Set)).add(B),ne||(R(J,B,X),Jn(J,!1)))},re=J=>{const ne=()=>{if(Wt.get(J)===ne){if(Wt.delete(J),sn(J.props)){const B=C(J.el)||n;R(J,B,J.anchor),Jn(J,!0)}G(J)}};Wt.set(J,ne),Ke(ne,o)};if(e==null){const J=t.el=h(""),ne=t.anchor=h("");if(m(J,n,i),m(ne,n,i),Ju(t.props)||o&&o.pendingBranch){re(t);return}w&&(R(t,n,ne),Jn(t,!0)),G()}else{t.el=e.el;const J=t.anchor=e.anchor,ne=Wt.get(e);if(ne){ne.flags|=8,Wt.delete(e),re(t);return}t.targetStart=e.targetStart;const B=t.target=e.target,X=t.targetAnchor=e.targetAnchor,F=sn(e.props),A=F?n:B,H=F?J:X;if(s==="svg"||Go(B)?s="svg":(s==="mathml"||Xo(B))&&(s="mathml"),$?(g(e.dynamicChildren,$,A,r,o,s,l),Eo(e,t,!0)):a||d(e,t,A,H,r,o,s,l,!1),w)F?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):Ti(t,n,J,c,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const M=t.target=Kr(t.props,y);M&&Ti(t,M,null,c,0)}else F&&Ti(t,B,X,c,1);Jn(t,w)}},remove(e,t,n,{um:i,o:{remove:r}},o){const{shapeFlag:s,children:l,anchor:a,targetStart:c,targetAnchor:u,target:d,props:g}=e;let m=o||!sn(g);const y=Wt.get(e);if(y&&(y.flags|=8,Wt.delete(e),m=!1),d&&(r(c),r(u)),o&&r(a),s&16)for(let h=0;h{e.isMounted=!0}),Wl(()=>{e.isUnmounting=!0}),e}const st=[Function,Array],Zu={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:st,onEnter:st,onAfterEnter:st,onEnterCancelled:st,onBeforeLeave:st,onLeave:st,onAfterLeave:st,onLeaveCancelled:st,onBeforeAppear:st,onAppear:st,onAfterAppear:st,onAppearCancelled:st};function ef(e,t){const{leavingVNodes:n}=e;let i=n.get(t.type);return i||(i=Object.create(null),n.set(t.type,i)),i}function Yr(e,t,n,i,r){const{appear:o,mode:s,persisted:l=!1,onBeforeEnter:a,onEnter:c,onAfterEnter:u,onEnterCancelled:d,onBeforeLeave:g,onLeave:m,onAfterLeave:y,onLeaveCancelled:h,onBeforeAppear:_,onAppear:C,onAfterAppear:w,onAppearCancelled:$}=t,R=String(e.key),G=ef(n,e),re=(B,X)=>{B&&ht(B,i,9,X)},J=(B,X)=>{const F=X[1];re(B,X),W(B)?B.every(A=>A.length<=1)&&F():B.length<=1&&F()},ne={mode:s,persisted:l,beforeEnter(B){let X=a;if(!n.isMounted)if(o)X=_||a;else return;B[Yt]&&B[Yt](!0);const F=G[R];F&&xn(e,F)&&F.el[Yt]&&F.el[Yt](),re(X,[B])},enter(B){if(G[R]===e)return;let X=c,F=u,A=d;if(!n.isMounted)if(o)X=C||c,F=w||u,A=$||d;else return;let H=!1;B[qn]=le=>{H||(H=!0,le?re(A,[B]):re(F,[B]),ne.delayedLeave&&ne.delayedLeave(),B[qn]=void 0)};const M=B[qn].bind(null,!1);X?J(X,[B,M]):M()},leave(B,X){const F=String(e.key);if(B[qn]&&B[qn](!0),n.isUnmounting)return X();re(g,[B]);let A=!1;B[Yt]=M=>{A||(A=!0,X(),M?re(h,[B]):re(y,[B]),B[Yt]=void 0,G[F]===e&&delete G[F])};const H=B[Yt].bind(null,!1);G[F]=e,m?J(m,[B,H]):H()},clone(B){return Yr(B,t,n,i)}};return ne}function li(e,t){e.shapeFlag&6&&e.component?(e.transition=t,li(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Bl(e,t=!1,n){let i=[],r=0;for(let o=0;o1)for(let o=0;oti(h,t&&(W(t)?t[_]:t),n,i,r));return}if(On(i)&&!r){i.shapeFlag&512&&i.type.__asyncResolved&&i.component.subTree.component&&ti(e,t,n,i.component.subTree);return}const o=i.shapeFlag&4?cr(i.component):i.el,s=r?null:o,{i:l,r:a}=e,c=t&&t.r,u=l.refs===ge?l.refs={}:l.refs,d=l.setupState,g=ae(d),m=d===ge?al:h=>Qo(u,h)?!1:fe(g,h),y=(h,_)=>!(_&&Qo(u,_));if(c!=null&&c!==a){if(Zo(t),_e(c))u[c]=null,m(c)&&(d[c]=null);else if(Be(c)){const h=t;y(c,h.k)&&(c.value=null),h.k&&(u[h.k]=null)}}if(Q(a))bi(a,l,12,[s,u]);else{const h=_e(a),_=Be(a);if(h||_){const C=()=>{if(e.f){const w=h?m(a)?d[a]:u[a]:y()||!e.k?a.value:u[e.k];if(r)W(w)&&po(w,o);else if(W(w))w.includes(o)||w.push(o);else if(h)u[a]=[o],m(a)&&(d[a]=u[a]);else{const $=[o];y(a,e.k)&&(a.value=$),e.k&&(u[e.k]=$)}}else h?(u[a]=s,m(a)&&(d[a]=s)):_&&(y(a,e.k)&&(a.value=s),e.k&&(u[e.k]=s))};if(s){const w=()=>{C(),Mi.delete(e)};w.id=-1,Mi.set(e,w),Ke(w,n)}else Zo(e),C()}}}function Zo(e){const t=Mi.get(e);t&&(t.flags|=8,Mi.delete(e))}nr().requestIdleCallback;nr().cancelIdleCallback;const On=e=>!!e.type.__asyncLoader,Vl=e=>e.type.__isKeepAlive;function tf(e,t){ql(e,"a",t)}function nf(e,t){ql(e,"da",t)}function ql(e,t,n=Je){const i=e.__wdc||(e.__wdc=()=>{let r=n;for(;r;){if(r.isDeactivated)return;r=r.parent}return e()});if(sr(t,i,n),n){let r=n.parent;for(;r&&r.parent;)Vl(r.parent.vnode)&&rf(i,t,n,r),r=r.parent}}function rf(e,t,n,i){const r=sr(t,e,i,!0);Yl(()=>{po(i[t],r)},n)}function sr(e,t,n=Je,i=!1){if(n){const r=n[e]||(n[e]=[]),o=t.__weh||(t.__weh=(...s)=>{jt();const l=yi(n),a=ht(t,n,e,s);return l(),Bt(),a});return i?r.unshift(o):r.push(o),o}}const qt=e=>(t,n=Je)=>{(!ci||e==="sp")&&sr(e,(...i)=>t(...i),n)},of=qt("bm"),Mn=qt("m"),sf=qt("bu"),Kl=qt("u"),Wl=qt("bum"),Yl=qt("um"),lf=qt("sp"),af=qt("rtg"),cf=qt("rtc");function uf(e,t=Je){sr("ec",e,t)}const ff=Symbol.for("v-ndc");function Ut(e,t,n,i){let r;const o=n,s=W(e);if(s||_e(e)){const l=s&&un(e);let a=!1,c=!1;l&&(a=!at(e),c=Ht(e),e=ir(e)),r=new Array(e.length);for(let u=0,d=e.length;ut(l,a,void 0,o));else{const l=Object.keys(e);r=new Array(l.length);for(let a=0,c=l.length;a0;return U(),Nn(ve,null,[j("slot",n,i)],c?-2:64)}let o=e[t];o&&o._c&&(o._d=!1),U();const s=o&&Jl(o(n)),l=n.key||s&&s.key,a=Nn(ve,{key:(l&&!dt(l)?l:`_${t}`)+(!s&&i?"_fb":"")},s||[],s&&e._===1?64:-2);return o&&o._c&&(o._d=!0),a}function Jl(e){return e.some(t=>To(t)?!(t.type===Ft||t.type===ve&&!Jl(t.children)):!0)?e:null}const Jr=e=>e?ha(e)?cr(e):Jr(e.parent):null,ni=Ne(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Jr(e.parent),$root:e=>Jr(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Gl(e),$forceUpdate:e=>e.f||(e.f=()=>{Ao(e.update)}),$nextTick:e=>e.n||(e.n=Ll.bind(e.proxy)),$watch:e=>Wu.bind(e)}),Ar=(e,t)=>e!==ge&&!e.__isScriptSetup&&fe(e,t),pf={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:n,setupState:i,data:r,props:o,accessCache:s,type:l,appContext:a}=e;if(t[0]!=="$"){const g=s[t];if(g!==void 0)switch(g){case 1:return i[t];case 2:return r[t];case 4:return n[t];case 3:return o[t]}else{if(Ar(i,t))return s[t]=1,i[t];if(r!==ge&&fe(r,t))return s[t]=2,r[t];if(fe(o,t))return s[t]=3,o[t];if(n!==ge&&fe(n,t))return s[t]=4,n[t];zr&&(s[t]=0)}}const c=ni[t];let u,d;if(c)return t==="$attrs"&&Ue(e.attrs,"get",""),c(e);if((u=l.__cssModules)&&(u=u[t]))return u;if(n!==ge&&fe(n,t))return s[t]=4,n[t];if(d=a.config.globalProperties,fe(d,t))return d[t]},set({_:e},t,n){const{data:i,setupState:r,ctx:o}=e;return Ar(r,t)?(r[t]=n,!0):i!==ge&&fe(i,t)?(i[t]=n,!0):fe(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(o[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:i,appContext:r,props:o,type:s}},l){let a;return!!(n[l]||e!==ge&&l[0]!=="$"&&fe(e,l)||Ar(t,l)||fe(o,l)||fe(i,l)||fe(ni,l)||fe(r.config.globalProperties,l)||(a=s.__cssModules)&&a[l])},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:fe(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function es(e){return W(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let zr=!0;function hf(e){const t=Gl(e),n=e.proxy,i=e.ctx;zr=!1,t.beforeCreate&&ts(t.beforeCreate,e,"bc");const{data:r,computed:o,methods:s,watch:l,provide:a,inject:c,created:u,beforeMount:d,mounted:g,beforeUpdate:m,updated:y,activated:h,deactivated:_,beforeDestroy:C,beforeUnmount:w,destroyed:$,unmounted:R,render:G,renderTracked:re,renderTriggered:J,errorCaptured:ne,serverPrefetch:B,expose:X,inheritAttrs:F,components:A,directives:H,filters:M}=t;if(c&&gf(c,i,null),s)for(const te in s){const ie=s[te];Q(ie)&&(i[te]=ie.bind(n))}if(r){const te=r.call(n,n);de(te)&&(e.data=rr(te))}if(zr=!0,o)for(const te in o){const ie=o[te],we=Q(ie)?ie.bind(n,n):Q(ie.get)?ie.get.bind(n,n):Ot,Le=!Q(ie)&&Q(ie.set)?ie.set.bind(n):Ot,Ve=Te({get:we,set:Le});Object.defineProperty(i,te,{enumerable:!0,configurable:!0,get:()=>Ve.value,set:tt=>Ve.value=tt})}if(l)for(const te in l)zl(l[te],i,n,te);if(a){const te=Q(a)?a.call(n):a;Reflect.ownKeys(te).forEach(ie=>{Vu(ie,te[ie])})}u&&ts(u,e,"c");function Z(te,ie){W(ie)?ie.forEach(we=>te(we.bind(n))):ie&&te(ie.bind(n))}if(Z(of,d),Z(Mn,g),Z(sf,m),Z(Kl,y),Z(tf,h),Z(nf,_),Z(uf,ne),Z(cf,re),Z(af,J),Z(Wl,w),Z(Yl,R),Z(lf,B),W(X))if(X.length){const te=e.exposed||(e.exposed={});X.forEach(ie=>{Object.defineProperty(te,ie,{get:()=>n[ie],set:we=>n[ie]=we,enumerable:!0})})}else e.exposed||(e.exposed={});G&&e.render===Ot&&(e.render=G),F!=null&&(e.inheritAttrs=F),A&&(e.components=A),H&&(e.directives=H),B&&Hl(e)}function gf(e,t,n=Ot){W(e)&&(e=Gr(e));for(const i in e){const r=e[i];let o;de(r)?"default"in r?o=Fi(r.from||i,r.default,!0):o=Fi(r.from||i):o=Fi(r),Be(o)?Object.defineProperty(t,i,{enumerable:!0,configurable:!0,get:()=>o.value,set:s=>o.value=s}):t[i]=o}}function ts(e,t,n){ht(W(e)?e.map(i=>i.bind(t.proxy)):e.bind(t.proxy),t,n)}function zl(e,t,n,i){let r=i.includes(".")?Ml(n,i):()=>n[i];if(_e(e)){const o=t[e];Q(o)&&fn(r,o)}else if(Q(e))fn(r,e.bind(n));else if(de(e))if(W(e))e.forEach(o=>zl(o,t,n,i));else{const o=Q(e.handler)?e.handler.bind(n):t[e.handler];Q(o)&&fn(r,o,e)}}function Gl(e){const t=e.type,{mixins:n,extends:i}=t,{mixins:r,optionsCache:o,config:{optionMergeStrategies:s}}=e.appContext,l=o.get(t);let a;return l?a=l:!r.length&&!n&&!i?a=t:(a={},r.length&&r.forEach(c=>ji(a,c,s,!0)),ji(a,t,s)),de(t)&&o.set(t,a),a}function ji(e,t,n,i=!1){const{mixins:r,extends:o}=t;o&&ji(e,o,n,!0),r&&r.forEach(s=>ji(e,s,n,!0));for(const s in t)if(!(i&&s==="expose")){const l=mf[s]||n&&n[s];e[s]=l?l(e[s],t[s]):t[s]}return e}const mf={data:ns,props:is,emits:is,methods:zn,computed:zn,beforeCreate:qe,created:qe,beforeMount:qe,mounted:qe,beforeUpdate:qe,updated:qe,beforeDestroy:qe,beforeUnmount:qe,destroyed:qe,unmounted:qe,activated:qe,deactivated:qe,errorCaptured:qe,serverPrefetch:qe,components:zn,directives:zn,watch:yf,provide:ns,inject:bf};function ns(e,t){return t?e?function(){return Ne(Q(e)?e.call(this,this):e,Q(t)?t.call(this,this):t)}:t:e}function bf(e,t){return zn(Gr(e),Gr(t))}function Gr(e){if(W(e)){const t={};for(let n=0;nt==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${ut(t)}Modifiers`]||e[`${mn(t)}Modifiers`];function wf(e,t,...n){if(e.isUnmounted)return;const i=e.vnode.props||ge;let r=n;const o=t.startsWith("update:"),s=o&&xf(i,t.slice(7));s&&(s.trim&&(r=n.map(u=>_e(u)?u.trim():u)),s.number&&(r=n.map(tr)));let l,a=i[l=yr(t)]||i[l=yr(ut(t))];!a&&o&&(a=i[l=yr(mn(t))]),a&&ht(a,e,6,r);const c=i[l+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,ht(c,e,6,r)}}const Af=new WeakMap;function Ql(e,t,n=!1){const i=n?Af:t.emitsCache,r=i.get(e);if(r!==void 0)return r;const o=e.emits;let s={},l=!1;if(!Q(e)){const a=c=>{const u=Ql(c,t,!0);u&&(l=!0,Ne(s,u))};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!o&&!l?(de(e)&&i.set(e,null),null):(W(o)?o.forEach(a=>s[a]=null):Ne(s,o),de(e)&&i.set(e,s),s)}function lr(e,t){return!e||!Qi(t)?!1:(t=t.slice(2).replace(/Once$/,""),fe(e,t[0].toLowerCase()+t.slice(1))||fe(e,mn(t))||fe(e,t))}function rs(e){const{type:t,vnode:n,proxy:i,withProxy:r,propsOptions:[o],slots:s,attrs:l,emit:a,render:c,renderCache:u,props:d,data:g,setupState:m,ctx:y,inheritAttrs:h}=e,_=Ui(e);let C,w;try{if(n.shapeFlag&4){const R=r||i,G=R;C=St(c.call(G,R,u,d,m,g,y)),w=l}else{const R=t;C=St(R.length>1?R(d,{attrs:l,slots:s,emit:a}):R(d,null)),w=t.props?l:Cf(l)}}catch(R){ii.length=0,or(R,e,1),C=j(Ft)}let $=C;if(w&&h!==!1){const R=Object.keys(w),{shapeFlag:G}=$;R.length&&G&7&&(o&&R.some(Zi)&&(w=Sf(w,o)),$=hn($,w,!1,!0))}return n.dirs&&($=hn($,null,!1,!0),$.dirs=$.dirs?$.dirs.concat(n.dirs):n.dirs),n.transition&&li($,n.transition),C=$,Ui(_),C}const Cf=e=>{let t;for(const n in e)(n==="class"||n==="style"||Qi(n))&&((t||(t={}))[n]=e[n]);return t},Sf=(e,t)=>{const n={};for(const i in e)(!Zi(i)||!(i.slice(9)in t))&&(n[i]=e[i]);return n};function Ef(e,t,n){const{props:i,children:r,component:o}=e,{props:s,children:l,patchFlag:a}=t,c=o.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&a>=0){if(a&1024)return!0;if(a&16)return i?os(i,s,c):!!s;if(a&8){const u=t.dynamicProps;for(let d=0;dObject.create(ea),na=e=>Object.getPrototypeOf(e)===ea;function Of(e,t,n,i=!1){const r={},o=ta();e.propsDefaults=Object.create(null),ia(e,t,r,o);for(const s in e.propsOptions[0])s in r||(r[s]=void 0);n?e.props=i?r:ku(r):e.type.props?e.props=r:e.props=o,e.attrs=o}function Rf(e,t,n,i){const{props:r,attrs:o,vnode:{patchFlag:s}}=e,l=ae(r),[a]=e.propsOptions;let c=!1;if((i||s>0)&&!(s&16)){if(s&8){const u=e.vnode.dynamicProps;for(let d=0;d{a=!0;const[g,m]=ra(d,t,!0);Ne(s,g),m&&l.push(...m)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!o&&!a)return de(e)&&i.set(e,Sn),Sn;if(W(o))for(let u=0;ue==="_"||e==="_ctx"||e==="$stable",So=e=>W(e)?e.map(St):[St(e)],kf=(e,t,n)=>{if(t._n)return t;const i=it((...r)=>So(t(...r)),n);return i._c=!1,i},oa=(e,t,n)=>{const i=e._ctx;for(const r in e){if(Co(r))continue;const o=e[r];if(Q(o))t[r]=kf(r,o,i);else if(o!=null){const s=So(o);t[r]=()=>s}}},sa=(e,t)=>{const n=So(t);e.slots.default=()=>n},la=(e,t,n)=>{for(const i in t)(n||!Co(i))&&(e[i]=t[i])},Nf=(e,t,n)=>{const i=e.slots=ta();if(e.vnode.shapeFlag&32){const r=t._;r?(la(i,t,n),n&&pl(i,"_",r,!0)):oa(t,i)}else t&&sa(e,t)},Lf=(e,t,n)=>{const{vnode:i,slots:r}=e;let o=!0,s=ge;if(i.shapeFlag&32){const l=t._;l?n&&l===1?o=!1:la(r,t,n):(o=!t.$stable,oa(t,r)),s=t}else t&&(sa(e,t),s={default:1});if(o)for(const l in r)!Co(l)&&s[l]==null&&delete r[l]},Ke=Uf;function $f(e){return If(e)}function If(e,t){const n=nr();n.__VUE__=!0;const{insert:i,remove:r,patchProp:o,createElement:s,createText:l,createComment:a,setText:c,setElementText:u,parentNode:d,nextSibling:g,setScopeId:m=Ot,insertStaticContent:y}=e,h=(p,b,x,O=null,S=null,E=null,L=void 0,N=null,k=!!b.dynamicChildren)=>{if(p===b)return;p&&!xn(p,b)&&(O=Xe(p),tt(p,S,E,!0),p=null),b.patchFlag===-2&&(k=!1,b.dynamicChildren=null);const{type:T,ref:Y,shapeFlag:I}=b;switch(T){case ar:_(p,b,x,O);break;case Ft:C(p,b,x,O);break;case Sr:p==null&&w(b,x,O,L);break;case ve:A(p,b,x,O,S,E,L,N,k);break;default:I&1?G(p,b,x,O,S,E,L,N,k):I&6?H(p,b,x,O,S,E,L,N,k):(I&64||I&128)&&T.process(p,b,x,O,S,E,L,N,k,bt)}Y!=null&&S?ti(Y,p&&p.ref,E,b||p,!b):Y==null&&p&&p.ref!=null&&ti(p.ref,null,E,p,!0)},_=(p,b,x,O)=>{if(p==null)i(b.el=l(b.children),x,O);else{const S=b.el=p.el;b.children!==p.children&&c(S,b.children)}},C=(p,b,x,O)=>{p==null?i(b.el=a(b.children||""),x,O):b.el=p.el},w=(p,b,x,O)=>{[p.el,p.anchor]=y(p.children,b,x,O,p.el,p.anchor)},$=({el:p,anchor:b},x,O)=>{let S;for(;p&&p!==b;)S=g(p),i(p,x,O),p=S;i(b,x,O)},R=({el:p,anchor:b})=>{let x;for(;p&&p!==b;)x=g(p),r(p),p=x;r(b)},G=(p,b,x,O,S,E,L,N,k)=>{if(b.type==="svg"?L="svg":b.type==="math"&&(L="mathml"),p==null)re(b,x,O,S,E,L,N,k);else{const T=p.el&&p.el._isVueCE?p.el:null;try{T&&T._beginPatch(),B(p,b,S,E,L,N,k)}finally{T&&T._endPatch()}}},re=(p,b,x,O,S,E,L,N)=>{let k,T;const{props:Y,shapeFlag:I,transition:K,dirs:z}=p;if(k=p.el=s(p.type,E,Y&&Y.is,Y),I&8?u(k,p.children):I&16&&ne(p.children,k,null,O,S,Cr(p,E),L,N),z&&tn(p,null,O,"created"),J(k,p,p.scopeId,L,O),Y){for(const pe in Y)pe!=="value"&&!Qn(pe)&&o(k,pe,null,Y[pe],E,O);"value"in Y&&o(k,"value",null,Y.value,E),(T=Y.onVnodeBeforeMount)&&xt(T,O,p)}z&&tn(p,null,O,"beforeMount");const oe=Pf(S,K);oe&&K.beforeEnter(k),i(k,b,x),((T=Y&&Y.onVnodeMounted)||oe||z)&&Ke(()=>{try{T&&xt(T,O,p),oe&&K.enter(k),z&&tn(p,null,O,"mounted")}finally{}},S)},J=(p,b,x,O,S)=>{if(x&&m(p,x),O)for(let E=0;E{for(let T=k;T{const N=b.el=p.el;let{patchFlag:k,dynamicChildren:T,dirs:Y}=b;k|=p.patchFlag&16;const I=p.props||ge,K=b.props||ge;let z;if(x&&nn(x,!1),(z=K.onVnodeBeforeUpdate)&&xt(z,x,b,p),Y&&tn(b,p,x,"beforeUpdate"),x&&nn(x,!0),(I.innerHTML&&K.innerHTML==null||I.textContent&&K.textContent==null)&&u(N,""),T?X(p.dynamicChildren,T,N,x,O,Cr(b,S),E):L||ie(p,b,N,null,x,O,Cr(b,S),E,!1),k>0){if(k&16)F(N,I,K,x,S);else if(k&2&&I.class!==K.class&&o(N,"class",null,K.class,S),k&4&&o(N,"style",I.style,K.style,S),k&8){const oe=b.dynamicProps;for(let pe=0;pe{z&&xt(z,x,b,p),Y&&tn(b,p,x,"updated")},O)},X=(p,b,x,O,S,E,L)=>{for(let N=0;N{if(b!==x){if(b!==ge)for(const E in b)!Qn(E)&&!(E in x)&&o(p,E,b[E],null,S,O);for(const E in x){if(Qn(E))continue;const L=x[E],N=b[E];L!==N&&E!=="value"&&o(p,E,N,L,S,O)}"value"in x&&o(p,"value",b.value,x.value,S)}},A=(p,b,x,O,S,E,L,N,k)=>{const T=b.el=p?p.el:l(""),Y=b.anchor=p?p.anchor:l("");let{patchFlag:I,dynamicChildren:K,slotScopeIds:z}=b;z&&(N=N?N.concat(z):z),p==null?(i(T,x,O),i(Y,x,O),ne(b.children||[],x,Y,S,E,L,N,k)):I>0&&I&64&&K&&p.dynamicChildren&&p.dynamicChildren.length===K.length?(X(p.dynamicChildren,K,x,S,E,L,N),(b.key!=null||S&&b===S.subTree)&&Eo(p,b,!0)):ie(p,b,x,Y,S,E,L,N,k)},H=(p,b,x,O,S,E,L,N,k)=>{b.slotScopeIds=N,p==null?b.shapeFlag&512?S.ctx.activate(b,x,O,L,k):M(b,x,O,S,E,L,k):le(p,b,k)},M=(p,b,x,O,S,E,L)=>{const N=p.component=Kf(p,O,S);if(Vl(p)&&(N.ctx.renderer=bt),Wf(N,!1,L),N.asyncDep){if(S&&S.registerDep(N,Z,L),!p.el){const k=N.subTree=j(Ft);C(null,k,b,x),p.placeholder=k.el}}else Z(N,p,b,x,S,E,L)},le=(p,b,x)=>{const O=b.component=p.component;if(Ef(p,b,x))if(O.asyncDep&&!O.asyncResolved){te(O,b,x);return}else O.next=b,O.update();else b.el=p.el,O.vnode=b},Z=(p,b,x,O,S,E,L)=>{const N=()=>{if(p.isMounted){let{next:I,bu:K,u:z,parent:oe,vnode:pe}=p;{const vt=aa(p);if(vt){I&&(I.el=pe.el,te(p,I,L)),vt.asyncDep.then(()=>{Ke(()=>{p.isUnmounted||T()},S)});return}}let me=I,Ee;nn(p,!1),I?(I.el=pe.el,te(p,I,L)):I=pe,K&&Ri(K),(Ee=I.props&&I.props.onVnodeBeforeUpdate)&&xt(Ee,oe,I,pe),nn(p,!0);const $e=rs(p),yt=p.subTree;p.subTree=$e,h(yt,$e,d(yt.el),Xe(yt),p,S,E),I.el=$e.el,me===null&&Tf(p,$e.el),z&&Ke(z,S),(Ee=I.props&&I.props.onVnodeUpdated)&&Ke(()=>xt(Ee,oe,I,pe),S)}else{let I;const{el:K,props:z}=b,{bm:oe,m:pe,parent:me,root:Ee,type:$e}=p,yt=On(b);nn(p,!1),oe&&Ri(oe),!yt&&(I=z&&z.onVnodeBeforeMount)&&xt(I,me,b),nn(p,!0);{Ee.ce&&Ee.ce._hasShadowRoot()&&Ee.ce._injectChildStyle($e,p.parent?p.parent.type:void 0);const vt=p.subTree=rs(p);h(null,vt,x,O,p,S,E),b.el=vt.el}if(pe&&Ke(pe,S),!yt&&(I=z&&z.onVnodeMounted)){const vt=b;Ke(()=>xt(I,me,vt),S)}(b.shapeFlag&256||me&&On(me.vnode)&&me.vnode.shapeFlag&256)&&p.a&&Ke(p.a,S),p.isMounted=!0,b=x=O=null}};p.scope.on();const k=p.effect=new bl(N);p.scope.off();const T=p.update=k.run.bind(k),Y=p.job=k.runIfDirty.bind(k);Y.i=p,Y.id=p.uid,k.scheduler=()=>Ao(Y),nn(p,!0),T()},te=(p,b,x)=>{b.component=p;const O=p.vnode.props;p.vnode=b,p.next=null,Rf(p,b.props,O,x),Lf(p,b.children,x),jt(),zo(p),Bt()},ie=(p,b,x,O,S,E,L,N,k=!1)=>{const T=p&&p.children,Y=p?p.shapeFlag:0,I=b.children,{patchFlag:K,shapeFlag:z}=b;if(K>0){if(K&128){Le(T,I,x,O,S,E,L,N,k);return}else if(K&256){we(T,I,x,O,S,E,L,N,k);return}}z&8?(Y&16&&kt(T,S,E),I!==T&&u(x,I)):Y&16?z&16?Le(T,I,x,O,S,E,L,N,k):kt(T,S,E,!0):(Y&8&&u(x,""),z&16&&ne(I,x,O,S,E,L,N,k))},we=(p,b,x,O,S,E,L,N,k)=>{p=p||Sn,b=b||Sn;const T=p.length,Y=b.length,I=Math.min(T,Y);let K;for(K=0;KY?kt(p,S,E,!0,!1,I):ne(b,x,O,S,E,L,N,k,I)},Le=(p,b,x,O,S,E,L,N,k)=>{let T=0;const Y=b.length;let I=p.length-1,K=Y-1;for(;T<=I&&T<=K;){const z=p[T],oe=b[T]=k?It(b[T]):St(b[T]);if(xn(z,oe))h(z,oe,x,null,S,E,L,N,k);else break;T++}for(;T<=I&&T<=K;){const z=p[I],oe=b[K]=k?It(b[K]):St(b[K]);if(xn(z,oe))h(z,oe,x,null,S,E,L,N,k);else break;I--,K--}if(T>I){if(T<=K){const z=K+1,oe=zK)for(;T<=I;)tt(p[T],S,E,!0),T++;else{const z=T,oe=T,pe=new Map;for(T=oe;T<=K;T++){const nt=b[T]=k?It(b[T]):St(b[T]);nt.key!=null&&pe.set(nt.key,T)}let me,Ee=0;const $e=K-oe+1;let yt=!1,vt=0;const Hn=new Array($e);for(T=0;T<$e;T++)Hn[T]=0;for(T=z;T<=I;T++){const nt=p[T];if(Ee>=$e){tt(nt,S,E,!0);continue}let _t;if(nt.key!=null)_t=pe.get(nt.key);else for(me=oe;me<=K;me++)if(Hn[me-oe]===0&&xn(nt,b[me])){_t=me;break}_t===void 0?tt(nt,S,E,!0):(Hn[_t-oe]=T+1,_t>=vt?vt=_t:yt=!0,h(nt,b[_t],x,null,S,E,L,N,k),Ee++)}const Ho=yt?Df(Hn):Sn;for(me=Ho.length-1,T=$e-1;T>=0;T--){const nt=oe+T,_t=b[nt],Vo=b[nt+1],qo=nt+1{const{el:E,type:L,transition:N,children:k,shapeFlag:T}=p;if(T&6){Ve(p.component.subTree,b,x,O);return}if(T&128){p.suspense.move(b,x,O);return}if(T&64){L.move(p,b,x,bt);return}if(L===ve){i(E,b,x);for(let I=0;IN.enter(E),S);else{const{leave:I,delayLeave:K,afterLeave:z}=N,oe=()=>{p.ctx.isUnmounted?r(E):i(E,b,x)},pe=()=>{E._isLeaving&&E[Yt](!0),I(E,()=>{oe(),z&&z()})};K?K(E,oe,pe):pe()}else i(E,b,x)},tt=(p,b,x,O=!1,S=!1)=>{const{type:E,props:L,ref:N,children:k,dynamicChildren:T,shapeFlag:Y,patchFlag:I,dirs:K,cacheIndex:z,memo:oe}=p;if(I===-2&&(S=!1),N!=null&&(jt(),ti(N,null,x,p,!0),Bt()),z!=null&&(b.renderCache[z]=void 0),Y&256){b.ctx.deactivate(p);return}const pe=Y&1&&K,me=!On(p);let Ee;if(me&&(Ee=L&&L.onVnodeBeforeUnmount)&&xt(Ee,b,p),Y&6)ot(p.component,x,O);else{if(Y&128){p.suspense.unmount(x,O);return}pe&&tn(p,null,b,"beforeUnmount"),Y&64?p.type.remove(p,b,x,bt,O):T&&!T.hasOnce&&(E!==ve||I>0&&I&64)?kt(T,b,x,!1,!0):(E===ve&&I&384||!S&&Y&16)&&kt(k,b,x),O&&Fe(p)}const $e=oe!=null&&z==null;(me&&(Ee=L&&L.onVnodeUnmounted)||pe||$e)&&Ke(()=>{Ee&&xt(Ee,b,p),pe&&tn(p,null,b,"unmounted"),$e&&(p.el=null)},x)},Fe=p=>{const{type:b,el:x,anchor:O,transition:S}=p;if(b===ve){mt(x,O);return}if(b===Sr){R(p);return}const E=()=>{r(x),S&&!S.persisted&&S.afterLeave&&S.afterLeave()};if(p.shapeFlag&1&&S&&!S.persisted){const{leave:L,delayLeave:N}=S,k=()=>L(x,E);N?N(p.el,E,k):k()}else E()},mt=(p,b)=>{let x;for(;p!==b;)x=g(p),r(p),p=x;r(b)},ot=(p,b,x)=>{const{bum:O,scope:S,job:E,subTree:L,um:N,m:k,a:T}=p;ls(k),ls(T),O&&Ri(O),S.stop(),E&&(E.flags|=8,tt(L,p,b,x)),N&&Ke(N,b),Ke(()=>{p.isUnmounted=!0},b)},kt=(p,b,x,O=!1,S=!1,E=0)=>{for(let L=E;L{if(p.shapeFlag&6)return Xe(p.component.subTree);if(p.shapeFlag&128)return p.suspense.next();const b=g(p.anchor||p.el),x=b&&b[jl];return x?g(x):b};let ce=!1;const Nt=(p,b,x)=>{let O;p==null?b._vnode&&(tt(b._vnode,null,null,!0),O=b._vnode.component):h(b._vnode||null,p,b,null,null,null,x),b._vnode=p,ce||(ce=!0,zo(O),Il(),ce=!1)},bt={p:h,um:tt,m:Ve,r:Fe,mt:M,mc:ne,pc:ie,pbc:X,n:Xe,o:e};return{render:Nt,hydrate:void 0,createApp:_f(Nt)}}function Cr({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function nn({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Pf(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Eo(e,t,n=!1){const i=e.children,r=t.children;if(W(i)&&W(r))for(let o=0;o>1,e[n[l]]0&&(t[i]=n[o-1]),n[o]=i)}}for(o=n.length,s=n[o-1];o-- >0;)n[o]=s,s=t[s];return n}function aa(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:aa(t)}function ls(e){if(e)for(let t=0;te.__isSuspense;function Uf(e,t){t&&t.pendingBranch?W(e)?t.effects.push(...e):t.effects.push(e):Hu(e)}const ve=Symbol.for("v-fgt"),ar=Symbol.for("v-txt"),Ft=Symbol.for("v-cmt"),Sr=Symbol.for("v-stc"),ii=[];let rt=null;function U(e=!1){ii.push(rt=e?null:[])}function Mf(){ii.pop(),rt=ii[ii.length-1]||null}let ai=1;function as(e,t=!1){ai+=e,e<0&&rt&&t&&(rt.hasOnce=!0)}function fa(e){return e.dynamicChildren=ai>0?rt||Sn:null,Mf(),ai>0&&rt&&rt.push(e),e}function V(e,t,n,i,r,o){return fa(f(e,t,n,i,r,o,!0))}function Nn(e,t,n,i,r){return fa(j(e,t,n,i,r,!0))}function To(e){return e?e.__v_isVNode===!0:!1}function xn(e,t){return e.type===t.type&&e.key===t.key}const da=({key:e})=>e??null,ki=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?_e(e)||Be(e)||Q(e)?{i:je,r:e,k:t,f:!!n}:e:null);function f(e,t=null,n=null,i=0,r=null,o=e===ve?0:1,s=!1,l=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&da(t),ref:t&&ki(t),scopeId:Dl,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:i,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:je};return l?(Oo(a,n),o&128&&e.normalize(a)):n&&(a.shapeFlag|=_e(n)?8:16),ai>0&&!s&&rt&&(a.patchFlag>0||o&6)&&a.patchFlag!==32&&rt.push(a),a}const j=jf;function jf(e,t=null,n=null,i=0,r=null,o=!1){if((!e||e===ff)&&(e=Ft),To(e)){const l=hn(e,t,!0);return n&&Oo(l,n),ai>0&&!o&&rt&&(l.shapeFlag&6?rt[rt.indexOf(e)]=l:rt.push(l)),l.patchFlag=-2,l}if(Gf(e)&&(e=e.__vccOpts),t){t=Bf(t);let{class:l,style:a}=t;l&&!_e(l)&&(t.class=ye(l)),de(a)&&(wo(a)&&!W(a)&&(a=Ne({},a)),t.style=Fn(a))}const s=_e(e)?1:ua(e)?128:Yu(e)?64:de(e)?4:Q(e)?2:0;return f(e,t,n,i,r,s,o,!0)}function Bf(e){return e?wo(e)||na(e)?Ne({},e):e:null}function hn(e,t,n=!1,i=!1){const{props:r,ref:o,patchFlag:s,children:l,transition:a}=e,c=t?Hf(r||{},t):r,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&da(c),ref:t&&t.ref?n&&o?W(o)?o.concat(ki(t)):[o,ki(t)]:ki(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ve?s===-1?16:s|16:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:a,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&hn(e.ssContent),ssFallback:e.ssFallback&&hn(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return a&&i&&li(u,a.clone(u)),u}function se(e=" ",t=0){return j(ar,null,e,t)}function et(e="",t=!1){return t?(U(),Nn(Ft,null,e)):j(Ft,null,e)}function St(e){return e==null||typeof e=="boolean"?j(Ft):W(e)?j(ve,null,e.slice()):To(e)?It(e):j(ar,null,String(e))}function It(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:hn(e)}function Oo(e,t){let n=0;const{shapeFlag:i}=e;if(t==null)t=null;else if(W(t))n=16;else if(typeof t=="object")if(i&65){const r=t.default;r&&(r._c&&(r._d=!1),Oo(e,r()),r._c&&(r._d=!0));return}else{n=32;const r=t._;!r&&!na(t)?t._ctx=je:r===3&&je&&(je.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else Q(t)?(t={default:t,_ctx:je},n=32):(t=String(t),i&64?(n=16,t=[se(t)]):n=8);e.children=t,e.shapeFlag|=n}function Hf(...e){const t={};for(let n=0;nJe||je;let Bi,Qr;{const e=nr(),t=(n,i)=>{let r;return(r=e[n])||(r=e[n]=[]),r.push(i),o=>{r.length>1?r.forEach(s=>s(o)):r[0](o)}};Bi=t("__VUE_INSTANCE_SETTERS__",n=>Je=n),Qr=t("__VUE_SSR_SETTERS__",n=>ci=n)}const yi=e=>{const t=Je;return Bi(e),e.scope.on(),()=>{e.scope.off(),Bi(t)}},cs=()=>{Je&&Je.scope.off(),Bi(null)};function ha(e){return e.vnode.shapeFlag&4}let ci=!1;function Wf(e,t=!1,n=!1){t&&Qr(t);const{props:i,children:r}=e.vnode,o=ha(e);Of(e,i,o,t),Nf(e,r,n||t);const s=o?Yf(e,t):void 0;return t&&Qr(!1),s}function Yf(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,pf);const{setup:i}=n;if(i){jt();const r=e.setupContext=i.length>1?zf(e):null,o=yi(e),s=bi(i,e,0,[e.props,r]),l=cl(s);if(Bt(),o(),(l||e.sp)&&!On(e)&&Hl(e),l){if(s.then(cs,cs),t)return s.then(a=>{us(e,a)}).catch(a=>{or(a,e,0)});e.asyncDep=s}else us(e,s)}else ga(e)}function us(e,t,n){Q(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:de(t)&&(e.setupState=kl(t)),ga(e)}function ga(e,t,n){const i=e.type;e.render||(e.render=i.render||Ot);{const r=yi(e);jt();try{hf(e)}finally{Bt(),r()}}}const Jf={get(e,t){return Ue(e,"get",""),e[t]}};function zf(e){const t=n=>{e.exposed=n||{}};return{attrs:new Proxy(e.attrs,Jf),slots:e.slots,emit:e.emit,expose:t}}function cr(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(kl(Nu(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in ni)return ni[n](e)},has(t,n){return n in t||n in ni}})):e.proxy}function Gf(e){return Q(e)&&"__vccOpts"in e}const Te=(e,t)=>Du(e,t,ci),Xf="3.5.34";/** +* @vue/runtime-dom v3.5.34 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let Zr;const fs=typeof window<"u"&&window.trustedTypes;if(fs)try{Zr=fs.createPolicy("vue",{createHTML:e=>e})}catch{}const ma=Zr?e=>Zr.createHTML(e):e=>e,Qf="http://www.w3.org/2000/svg",Zf="http://www.w3.org/1998/Math/MathML",$t=typeof document<"u"?document:null,ds=$t&&$t.createElement("template"),ed={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,i)=>{const r=t==="svg"?$t.createElementNS(Qf,e):t==="mathml"?$t.createElementNS(Zf,e):n?$t.createElement(e,{is:n}):$t.createElement(e);return e==="select"&&i&&i.multiple!=null&&r.setAttribute("multiple",i.multiple),r},createText:e=>$t.createTextNode(e),createComment:e=>$t.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>$t.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,i,r,o){const s=n?n.previousSibling:t.lastChild;if(r&&(r===o||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===o||!(r=r.nextSibling)););else{ds.innerHTML=ma(i==="svg"?`${e}`:i==="mathml"?`${e}`:e);const l=ds.content;if(i==="svg"||i==="mathml"){const a=l.firstChild;for(;a.firstChild;)l.appendChild(a.firstChild);l.removeChild(a)}t.insertBefore(l,n)}return[s?s.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Kt="transition",Kn="animation",Ln=Symbol("_vtc"),ba={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},td=Ne({},Zu,ba),rn=(e,t=[])=>{W(e)?e.forEach(n=>n(...t)):e&&e(...t)},ps=e=>e?W(e)?e.some(t=>t.length>1):e.length>1:!1;function nd(e){const t={};for(const A in e)A in ba||(t[A]=e[A]);if(e.css===!1)return t;const{name:n="v",type:i,duration:r,enterFromClass:o=`${n}-enter-from`,enterActiveClass:s=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:a=o,appearActiveClass:c=s,appearToClass:u=l,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:g=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=e,y=id(r),h=y&&y[0],_=y&&y[1],{onBeforeEnter:C,onEnter:w,onEnterCancelled:$,onLeave:R,onLeaveCancelled:G,onBeforeAppear:re=C,onAppear:J=w,onAppearCancelled:ne=$}=t,B=(A,H,M,le)=>{A._enterCancelled=le,Jt(A,H?u:l),Jt(A,H?c:s),M&&M()},X=(A,H)=>{A._isLeaving=!1,Jt(A,d),Jt(A,m),Jt(A,g),H&&H()},F=A=>(H,M)=>{const le=A?J:w,Z=()=>B(H,A,M);rn(le,[H,Z]),hs(()=>{Jt(H,A?a:o),wt(H,A?u:l),ps(le)||gs(H,i,h,Z)})};return Ne(t,{onBeforeEnter(A){rn(C,[A]),wt(A,o),wt(A,s)},onBeforeAppear(A){rn(re,[A]),wt(A,a),wt(A,c)},onEnter:F(!1),onAppear:F(!0),onLeave(A,H){A._isLeaving=!0;const M=()=>X(A,H);wt(A,d),A._enterCancelled?(wt(A,g),eo(A)):(eo(A),wt(A,g)),hs(()=>{A._isLeaving&&(Jt(A,d),wt(A,m),ps(R)||gs(A,i,_,M))}),rn(R,[A,M])},onEnterCancelled(A){B(A,!1,void 0,!0),rn($,[A])},onAppearCancelled(A){B(A,!0,void 0,!0),rn(ne,[A])},onLeaveCancelled(A){X(A),rn(G,[A])}})}function id(e){if(e==null)return null;if(de(e))return[Er(e.enter),Er(e.leave)];{const t=Er(e);return[t,t]}}function Er(e){return iu(e)}function wt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Ln]||(e[Ln]=new Set)).add(t)}function Jt(e,t){t.split(/\s+/).forEach(i=>i&&e.classList.remove(i));const n=e[Ln];n&&(n.delete(t),n.size||(e[Ln]=void 0))}function hs(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let rd=0;function gs(e,t,n,i){const r=e._endId=++rd,o=()=>{r===e._endId&&i()};if(n!=null)return setTimeout(o,n);const{type:s,timeout:l,propCount:a}=ya(e,t);if(!s)return i();const c=s+"end";let u=0;const d=()=>{e.removeEventListener(c,g),o()},g=m=>{m.target===e&&++u>=a&&d()};setTimeout(()=>{u(n[y]||"").split(", "),r=i(`${Kt}Delay`),o=i(`${Kt}Duration`),s=ms(r,o),l=i(`${Kn}Delay`),a=i(`${Kn}Duration`),c=ms(l,a);let u=null,d=0,g=0;t===Kt?s>0&&(u=Kt,d=s,g=o.length):t===Kn?c>0&&(u=Kn,d=c,g=a.length):(d=Math.max(s,c),u=d>0?s>c?Kt:Kn:null,g=u?u===Kt?o.length:a.length:0);const m=u===Kt&&/\b(?:transform|all)(?:,|$)/.test(i(`${Kt}Property`).toString());return{type:u,timeout:d,propCount:g,hasTransform:m}}function ms(e,t){for(;e.lengthbs(n)+bs(e[i])))}function bs(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function eo(e){return(e?e.ownerDocument:document).body.offsetHeight}function od(e,t,n){const i=e[Ln];i&&(t=(t?[t,...i]:[...i]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const Hi=Symbol("_vod"),va=Symbol("_vsh"),Tr={name:"show",beforeMount(e,{value:t},{transition:n}){e[Hi]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):Wn(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:i}){!t!=!n&&(i?t?(i.beforeEnter(e),Wn(e,!0),i.enter(e)):i.leave(e,()=>{Wn(e,!1)}):Wn(e,t))},beforeUnmount(e,{value:t}){Wn(e,t)}};function Wn(e,t){e.style.display=t?e[Hi]:"none",e[va]=!t}const sd=Symbol(""),ld=/(?:^|;)\s*display\s*:/;function ad(e,t,n){const i=e.style,r=_e(n);let o=!1;if(n&&!r){if(t)if(_e(t))for(const s of t.split(";")){const l=s.slice(0,s.indexOf(":")).trim();n[l]==null&&Gn(i,l,"")}else for(const s in t)n[s]==null&&Gn(i,s,"");for(const s in n){s==="display"&&(o=!0);const l=n[s];l!=null?ud(e,s,!_e(t)&&t?t[s]:void 0,l)||Gn(i,s,l):Gn(i,s,"")}}else if(r){if(t!==n){const s=i[sd];s&&(n+=";"+s),i.cssText=n,o=ld.test(n)}}else t&&e.removeAttribute("style");Hi in e&&(e[Hi]=o?i.display:"",e[va]&&(i.display="none"))}const ys=/\s*!important$/;function Gn(e,t,n){if(W(n))n.forEach(i=>Gn(e,t,i));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const i=cd(e,t);ys.test(n)?e.setProperty(mn(i),n.replace(ys,""),"important"):e[i]=n}}const vs=["Webkit","Moz","ms"],Or={};function cd(e,t){const n=Or[t];if(n)return n;let i=ut(t);if(i!=="filter"&&i in e)return Or[t]=i;i=dl(i);for(let r=0;rRr||(hd.then(()=>Rr=0),Rr=Date.now());function md(e,t){const n=i=>{if(!i._vts)i._vts=Date.now();else if(i._vts<=n.attached)return;ht(bd(i,n.value),t,5,[i])};return n.value=e,n.attached=gd(),n}function bd(e,t){if(W(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(i=>r=>!r._stopped&&i&&i(r))}else return t}const Ss=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,yd=(e,t,n,i,r,o)=>{const s=r==="svg";t==="class"?od(e,i,s):t==="style"?ad(e,n,i):Qi(t)?Zi(t)||dd(e,t,n,i,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):vd(e,t,i,s))?(ws(e,t,i),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&xs(e,t,i,s,o,t!=="value")):e._isVueCE&&(_d(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!_e(i)))?ws(e,ut(t),i,o,t):(t==="true-value"?e._trueValue=i:t==="false-value"&&(e._falseValue=i),xs(e,t,i,s))};function vd(e,t,n,i){if(i)return!!(t==="innerHTML"||t==="textContent"||t in e&&Ss(t)&&Q(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const r=e.tagName;if(r==="IMG"||r==="VIDEO"||r==="CANVAS"||r==="SOURCE")return!1}return Ss(t)&&_e(n)?!1:t in e}function _d(e,t){const n=e._def.props;if(!n)return!1;const i=ut(t);return Array.isArray(n)?n.some(r=>ut(r)===i):Object.keys(n).some(r=>ut(r)===i)}const _a=new WeakMap,xa=new WeakMap,Vi=Symbol("_moveCb"),Es=Symbol("_enterCb"),xd=e=>(delete e.props.mode,e),wd=xd({name:"TransitionGroup",props:Ne({},td,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=pa(),i=Qu();let r,o;return Kl(()=>{if(!r.length)return;const s=e.moveClass||`${e.name||"v"}-move`;if(!Td(r[0].el,n.vnode.el,s)){r=[];return}r.forEach(Cd),r.forEach(Sd);const l=r.filter(Ed);eo(n.vnode.el),l.forEach(a=>{const c=a.el,u=c.style;wt(c,s),u.transform=u.webkitTransform=u.transitionDuration="";const d=c[Vi]=g=>{g&&g.target!==c||(!g||g.propertyName.endsWith("transform"))&&(c.removeEventListener("transitionend",d),c[Vi]=null,Jt(c,s))};c.addEventListener("transitionend",d)}),r=[]}),()=>{const s=ae(e),l=nd(s);let a=s.tag||ve;if(r=[],o)for(let c=0;c{l.split(/\s+/).forEach(a=>a&&i.classList.remove(a))}),n.split(/\s+/).forEach(l=>l&&i.classList.add(l)),i.style.display="none";const o=t.nodeType===1?t:t.parentNode;o.appendChild(i);const{hasTransform:s}=ya(i);return o.removeChild(i),s}const $n=e=>{const t=e.props["onUpdate:modelValue"]||!1;return W(t)?n=>Ri(t,n):t};function Od(e){e.target.composing=!0}function Ts(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Mt=Symbol("_assign");function Os(e,t,n){return t&&(e=e.trim()),n&&(e=tr(e)),e}const xe={created(e,{modifiers:{lazy:t,trim:n,number:i}},r){e[Mt]=$n(r);const o=i||r.props&&r.props.type==="number";Xt(e,t?"change":"input",s=>{s.target.composing||e[Mt](Os(e.value,n,o))}),(n||o)&&Xt(e,"change",()=>{e.value=Os(e.value,n,o)}),t||(Xt(e,"compositionstart",Od),Xt(e,"compositionend",Ts),Xt(e,"change",Ts))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:i,trim:r,number:o}},s){if(e[Mt]=$n(s),e.composing)return;const l=(o||e.type==="number")&&!/^0\d/.test(e.value)?tr(e.value):e.value,a=t??"";if(l===a)return;const c=e.getRootNode();(c instanceof Document||c instanceof ShadowRoot)&&c.activeElement===e&&e.type!=="range"&&(i&&t===n||r&&e.value.trim()===a)||(e.value=a)}},ue={deep:!0,created(e,t,n){e[Mt]=$n(n),Xt(e,"change",()=>{const i=e._modelValue,r=ui(e),o=e.checked,s=e[Mt];if(W(i)){const l=go(i,r),a=l!==-1;if(o&&!a)s(i.concat(r));else if(!o&&a){const c=[...i];c.splice(l,1),s(c)}}else if(Dn(i)){const l=new Set(i);o?l.add(r):l.delete(r),s(l)}else s(Aa(e,o))})},mounted:Rs,beforeUpdate(e,t,n){e[Mt]=$n(n),Rs(e,t,n)}};function Rs(e,{value:t,oldValue:n},i){e._modelValue=t;let r;if(W(t))r=go(t,i.props.value)>-1;else if(Dn(t))r=t.has(i.props.value);else{if(t===n)return;r=Un(t,Aa(e,!0))}e.checked!==r&&(e.checked=r)}const Tt={deep:!0,created(e,{value:t,modifiers:{number:n}},i){const r=Dn(t);Xt(e,"change",()=>{const o=Array.prototype.filter.call(e.options,s=>s.selected).map(s=>n?tr(ui(s)):ui(s));e[Mt](e.multiple?r?new Set(o):o:o[0]),e._assigning=!0,Ll(()=>{e._assigning=!1})}),e[Mt]=$n(i)},mounted(e,{value:t}){Fs(e,t)},beforeUpdate(e,t,n){e[Mt]=$n(n)},updated(e,{value:t}){e._assigning||Fs(e,t)}};function Fs(e,t){const n=e.multiple,i=W(t);if(!(n&&!i&&!Dn(t))){for(let r=0,o=e.options.length;rString(c)===String(l)):s.selected=go(t,l)>-1}else s.selected=t.has(l);else if(Un(ui(s),t)){e.selectedIndex!==r&&(e.selectedIndex=r);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function ui(e){return"_value"in e?e._value:e.value}function Aa(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const Rd=Ne({patchProp:yd},ed);let ks;function Fd(){return ks||(ks=$f(Rd))}const kd=((...e)=>{const t=Fd().createApp(...e),{mount:n}=t;return t.mount=i=>{const r=Ld(i);if(!r)return;const o=t._component;!Q(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.nodeType===1&&(r.textContent="");const s=n(r,!1,Nd(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},t});function Nd(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Ld(e){return _e(e)?document.querySelector(e):e}const $d={class:"toast-container"},Id={class:"toast-msg"},Pd=["onClick"],Dd={__name:"GlobalToast",setup(e,{expose:t}){const n=he([]);let i=0;function r(l,a,c=4e3){const u=++i;n.value.push({id:u,type:l,message:a}),c>0&&setTimeout(()=>o(u),c)}function o(l){const a=n.value.findIndex(c=>c.id===l);a>=0&&n.value.splice(a,1)}return t({toast:{info:(l,a)=>r("info",l,a),success:(l,a)=>r("success",l,a),warn:(l,a)=>r("warn",l,a),error:(l,a)=>r("error",l,a??8e3)}}),(l,a)=>(U(),Nn(Xu,{to:"body"},[f("div",$d,[j(Ad,{name:"toast"},{default:it(()=>[(U(!0),V(ve,null,Ut(n.value,c=>(U(),V("div",{key:c.id,class:ye(["toast-item",`toast-${c.type}`])},[f("span",Id,ee(c.message),1),f("button",{class:"toast-close",onClick:u=>o(c.id)},"×",8,Pd)],2))),128))]),_:1})])]))}},Ud="modulepreload",Md=function(e,t){return new URL(e,t).href},Ns={},Fr=function(t,n,i){let r=Promise.resolve();if(n&&n.length>0){let s=function(u){return Promise.all(u.map(d=>Promise.resolve(d).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};const l=document.getElementsByTagName("link"),a=document.querySelector("meta[property=csp-nonce]"),c=(a==null?void 0:a.nonce)||(a==null?void 0:a.getAttribute("nonce"));r=s(n.map(u=>{if(u=Md(u,i),u in Ns)return;Ns[u]=!0;const d=u.endsWith(".css"),g=d?'[rel="stylesheet"]':"";if(!!i)for(let h=l.length-1;h>=0;h--){const _=l[h];if(_.href===u&&(!d||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${g}`))return;const y=document.createElement("link");if(y.rel=d?"stylesheet":Ud,d||(y.as="script"),y.crossOrigin="",y.href=u,c&&y.setAttribute("nonce",c),document.head.appendChild(y),d)return new Promise((h,_)=>{y.addEventListener("load",h),y.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(s){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=s,window.dispatchEvent(l),!l.defaultPrevented)throw s}return r.then(s=>{for(const l of s||[])l.status==="rejected"&&o(l.reason);return t().catch(o)})},Re=(e,t)=>{const n=e.__vccOpts||e;for(const[i,r]of t)n[i]=r;return n},jd={class:"upload-group"},Bd={class:"file-tip"},Hd={class:"file-tip"},Vd=["disabled"],qd={__name:"FileUploadPanel",props:{docxFile:File,yamlFile:File,generatedConfig:Object,isLoading:Boolean},emits:["update:docxFile","update:yamlFile","generate-json"],setup(e,{emit:t}){const n=e,i=t,r=Te(()=>n.docxFile?`已选择:${n.docxFile.name}`:"未选择"),o=Te(()=>n.yamlFile?`已选择:${n.yamlFile.name}`:"未选择"),s=a=>i("update:docxFile",a.target.files[0]),l=a=>i("update:yamlFile",a.target.files[0]);return(a,c)=>(U(),V("div",jd,[c[2]||(c[2]=f("label",{for:"docx-file",class:"upload-btn"},"选择 docx",-1)),f("input",{type:"file",id:"docx-file",accept:".docx",class:"file-hidden",onChange:s},null,32),f("span",Bd,ee(r.value),1),e.generatedConfig?et("",!0):(U(),V(ve,{key:0},[c[1]||(c[1]=f("label",{for:"yaml-file",class:"upload-btn"},"选择 yaml",-1)),f("input",{type:"file",id:"yaml-file",accept:".yaml,.yml",class:"file-hidden",onChange:l},null,32),f("span",Hd,ee(o.value),1)],64)),f("button",{class:"go-btn",disabled:!e.docxFile||!e.yamlFile&&!e.generatedConfig||e.isLoading,onClick:c[0]||(c[0]=u=>a.$emit("generate-json"))}," 生成节点 ",8,Vd)]))}},Kd=Re(qd,[["__scopeId","data-v-6d870395"]]),Wd={class:"format-btn-group"},Yd=["disabled"],Jd=["disabled"],zd={__name:"FormatActionPanel",props:{isLoading:Boolean},emits:["check-format","apply-format"],setup(e){return(t,n)=>(U(),V("div",Wd,[f("button",{class:"btn btn-amber",disabled:e.isLoading,onClick:n[0]||(n[0]=i=>t.$emit("check-format"))},"格式校验",8,Yd),f("button",{class:"btn btn-green",disabled:e.isLoading,onClick:n[1]||(n[1]=i=>t.$emit("apply-format"))},"自动格式化",8,Jd)]))}},Gd=Re(zd,[["__scopeId","data-v-99eed13a"]]),Ca={abstract_chinese_title:"仅当段落是“摘要”或“摘 要”(允许尾随空格或冒号)",abstract_chinese_title_content:"当且仅当摘要和正文在一个段落中",abstract_english_title:"仅当段落是“Abstract”(大小写不敏感,允许尾随空格或冒号)",abstract_english_title_content:"当且仅当摘要和正文在一个段落中",keywords_chinese:"包含“关键词”或“关键字”,后面跟着术语列表",keywords_english:"包含“Keywords”(大小写不敏感),后面跟着英文术语",chinese_title:"论文中文题目(通常简短且无编号)",english_title:"论文英文题目(通常简短且无编号)",heading_level_1:"段落必须以“第X章”或单个阿拉伯数字(如“1”“2”)开头,后接空格和标题文字;仅为名词短语",heading_level_2:"段落必须以“X.Y”格式开头(如“1.1”),仅含一个“.”;后接标题文字无完整句子",heading_level_3:"段落必须以“X.Y.Z”格式开头(如“1.1.1”),仅含两个“.”;后接标题文字无完整句子",heading_mulu:"目录标题:段落等于“目录”或“目 录”(含空格变体)",heading_fulu:"段落等于“附录”",references_title:"段落等于“参考文献”或“References”",acknowledgements_title:"段落和“致谢”或“Acknowledgements”等词意思相近",caption_figure:"以“图 X.Y”或“Figure X.Y”开头的图注",caption_table:"以“表 X.Y”或“Table X.Y”开头的表注",body_text:"包含完整句子、谓语动词/句号;或含“本章/本文”等明确论述的内容",other:"标记跳过:后端处理时直接忽略该节点(防止误删,仅标记)"},Ro={chinese_title:1,english_title:1,abstract_chinese_title:1,abstract_english_title:1,keywords_chinese:2,keywords_english:2,references_title:1,acknowledgements_title:1,heading_fulu:1,heading_mulu:1,heading_level_1:1,heading_level_2:2,heading_level_3:3,abstract_chinese_title_content:1,abstract_english_title_content:1,caption_figure:5,caption_table:5,body_text:5,other:5},Xd=["#1e40af","#2563eb","#3b82f6","#60a5fa","#93c5fd","#9ca3af"],Ni=.8;function qi(e,t=Ni){return(e==null?void 0:e.score)r.toLowerCase()===n?`${r}`:r).join("")}const ep={class:"node-list-section"},tp={class:"card"},np={key:0,class:"loading-tip"},ip={key:1,class:"init-tip"},rp={key:2,class:"node-list"},op={key:0,class:"empty-tip"},sp=["onClick"],lp=["title"],ap={class:"node-score"},cp=["innerHTML"],up={key:0,class:"replace-badge",title:"有替换内容"},fp={class:"node-meta"},dp={class:"node-comment"},pp={class:"node-fingerprint"},hp={__name:"NodeListPanel",props:{nodeData:Array,selectedIndex:Number,isFileLoaded:Boolean,isLoading:Boolean,loadingText:String,globalSearchTerm:String},emits:["select-node"],setup(e){return(t,n)=>(U(),V("div",ep,[f("div",tp,[e.isLoading?(U(),V("div",np,[n[0]||(n[0]=f("div",{class:"loading-spinner"},null,-1)),f("p",null,ee(e.loadingText),1)])):e.isFileLoaded?(U(),V("div",rp,[e.nodeData.length===0?(U(),V("div",op,"无匹配的节点")):et("",!0),(U(!0),V(ve,null,Ut(e.nodeData,(i,r)=>{var o;return U(),V("div",{key:r,class:ye(["node-item",{error:Ye(qi)(i),other:i.category==="other",selected:e.selectedIndex===r}]),style:Fn({marginLeft:Ye(Qd)(i)}),onClick:s=>t.$emit("select-node",r)},[f("div",{class:"level-dot",style:Fn({backgroundColor:Ye(Sa)(i)})},null,4),f("div",{class:ye(["node-tag",i.category]),title:Ye(Ca)[i.category]||""},ee(i.category.replace(/_/g," ")),11,lp),f("div",ap,ee(i.score.toFixed(4)),1),f("div",{class:"node-content",innerHTML:Ye(Zd)(i.paragraph,e.globalSearchTerm)},null,8,cp),i.replace?(U(),V("span",up,"R")):et("",!0),f("div",fp,[f("span",dp,ee(i.comment||"无注释"),1),f("span",pp,ee(((o=i.fingerprint)==null?void 0:o.slice(0,8))||"无"),1)])],14,sp)}),128))])):(U(),V("div",ip,[...n[1]||(n[1]=[f("svg",{class:"init-icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[f("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9m-5 13h14a2 2 0 002-2V9a2 2 0 00-2-2h-2.586a1 1 0 01-.707-.293l-2.414-2.414a1 1 0 00-.707-.293H11a2 2 0 00-2 2v1m2 13a2 2 0 01-2-2V7m2 13c3.314 0 6-2.686 6-6V9a6 6 0 00-6-6H9a6 6 0 00-6 6v8a6 6 0 006 6z"})],-1),f("p",null,"请上传docx+yaml配置文件,点击「生成节点JSON」获取节点数据",-1),f("p",{class:"init-sub-tip"},"生成后可修改标签,再执行「格式校验」或「自动格式化」,支持直接下载结果文件",-1)])]))])]))}},gp=Re(hp,[["__scopeId","data-v-d86ce66e"]]),mp={class:"node-detail-section"},bp={class:"card detail-card"},yp={key:0,class:"no-select-tip"},vp={key:1,class:"node-detail-content"},_p={class:"property-card"},xp={class:"property-card-body"},wp={class:"property-item"},Ap={class:"property-value"},Cp={class:"property-item"},Sp={class:"property-item"},Ep={class:"property-value flex items-center"},Tp={class:"property-item"},Op={class:"property-value content-value"},Rp={key:0,class:"property-item"},Fp={class:"property-value content-value replace-value"},kp={class:"property-item"},Np={class:"property-value"},Lp={class:"property-item"},$p={class:"property-value fingerprint-value"},Ip={class:"property-item"},Pp={class:"property-value"},Dp={class:"property-card mt-4"},Up={class:"property-card-body"},Mp={class:"property-item"},jp=["value","title"],Bp={class:"category-desc"},Hp={__name:"NodeDetailPanel",props:{currentNode:Object,categoryConfig:Object,scoreThreshold:Number,totalNodes:Number,nodeIndex:Number},emits:["update-category"],setup(e,{emit:t}){var m;const n=e,i=t,r=he(((m=n.currentNode)==null?void 0:m.category)||"");fn(()=>n.currentNode,y=>{y&&(r.value=y.category)});const o=()=>{i("update-category",r.value)},s=Te(()=>qi(n.currentNode,n.scoreThreshold)),l=Te(()=>{var y;return((y=n.currentNode)==null?void 0:y.category)==="other"}),a=Te(()=>l.value?"status-other":s.value?"status-error":"status-normal"),c=Te(()=>l.value?"🔖 标记跳过(后端将忽略)":s.value?"❌ 疑似标签错误(得分低于阈值)":"✅ 正常节点(得分高于阈值)"),u=Te(()=>l.value?"标记层级(无缩进)":`层级 ${Ro[n.currentNode.category]||6} (配置映射)`),d=Te(()=>l.value?"result-other":s.value?"result-error":"result-normal"),g=Te(()=>{if(l.value)return"📌 已标记为跳过:后端处理时直接忽略该节点(防止误删)";const y=n.currentNode.score.toFixed(4);return s.value?`❌ 疑似标签错误:得分(${y}) < 阈值(${n.scoreThreshold})`:`✅ 标签匹配正常:得分(${y}) ≥ 阈值(${n.scoreThreshold})`});return(y,h)=>(U(),V("div",mp,[f("div",bp,[h[13]||(h[13]=f("h2",{class:"detail-title"},"节点详情",-1)),e.currentNode?(U(),V("div",vp,[f("div",_p,[h[10]||(h[10]=f("div",{class:"property-card-header"},"固定信息(不可修改)",-1)),f("div",xp,[f("div",wp,[h[2]||(h[2]=f("div",{class:"property-label"},"节点序号",-1)),f("div",Ap,ee(e.nodeIndex)+"/"+ee(e.totalNodes),1)]),f("div",Cp,[h[3]||(h[3]=f("div",{class:"property-label"},"节点状态",-1)),f("div",{class:ye(["property-value status-value",a.value])},ee(c.value),3)]),f("div",Sp,[h[4]||(h[4]=f("div",{class:"property-label"},"节点层级",-1)),f("div",Ep,[f("div",{class:"level-dot mr-2",style:Fn({backgroundColor:Ye(Sa)(e.currentNode)})},null,4),se(" "+ee(u.value),1)])]),f("div",Tp,[h[5]||(h[5]=f("div",{class:"property-label"},"节点内容",-1)),f("div",Op,ee(e.currentNode.paragraph),1)]),e.currentNode.replace?(U(),V("div",Rp,[h[6]||(h[6]=f("div",{class:"property-label replace-label"},"替换内容",-1)),f("div",Fp,ee(e.currentNode.replace),1)])):et("",!0),f("div",kp,[h[7]||(h[7]=f("div",{class:"property-label"},"置信度得分",-1)),f("div",Np,ee(e.currentNode.score.toFixed(4))+"(判定阈值:"+ee(e.scoreThreshold)+")",1)]),f("div",Lp,[h[8]||(h[8]=f("div",{class:"property-label"},"节点指纹",-1)),f("div",$p,ee(e.currentNode.fingerprint||"[无指纹]"),1)]),f("div",Ip,[h[9]||(h[9]=f("div",{class:"property-label"},"节点注释",-1)),f("div",Pp,ee(e.currentNode.comment||"[无注释]"),1)])])]),f("div",Dp,[h[12]||(h[12]=f("div",{class:"property-card-header"},"可变信息(仅标签可修改)",-1)),f("div",Up,[f("div",Mp,[h[11]||(h[11]=f("div",{class:"property-label"},[se(" 当前分类标签 "),f("span",{class:"label-tip"},"(hover查看标签说明)")],-1)),P(f("select",{class:"category-select","onUpdate:modelValue":h[0]||(h[0]=_=>r.value=_),onChange:o},[(U(!0),V(ve,null,Ut(e.categoryConfig,(_,C)=>(U(),V("option",{key:C,value:C,title:_},ee(C.replace(/_/g," ")),9,jp))),128))],544),[[Tt,r.value]]),f("div",Bp,ee(e.categoryConfig[r.value]||""),1)]),f("div",{class:ye(["check-result",d.value])},ee(g.value),3)])])])):(U(),V("div",yp,[...h[1]||(h[1]=[f("svg",{class:"no-select-icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[f("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})],-1),f("p",null,"生成节点数据后,点击左侧节点查看/修改详情",-1)])]))])]))}},Vp=Re(Hp,[["__scopeId","data-v-caa1c263"]]);function Ea(e,t){return function(){return e.apply(t,arguments)}}const{toString:qp}=Object.prototype,{getPrototypeOf:ur}=Object,{iterator:fr,toStringTag:Ta}=Symbol,dr=(e=>t=>{const n=qp.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),gt=e=>(e=e.toLowerCase(),t=>dr(t)===e),pr=e=>t=>typeof t===e,{isArray:jn}=Array,In=pr("undefined");function vi(e){return e!==null&&!In(e)&&e.constructor!==null&&!In(e.constructor)&&Ze(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const Oa=gt("ArrayBuffer");function Kp(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&Oa(e.buffer),t}const Wp=pr("string"),Ze=pr("function"),Ra=pr("number"),_i=e=>e!==null&&typeof e=="object",Yp=e=>e===!0||e===!1,Li=e=>{if(dr(e)!=="object")return!1;const t=ur(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Ta in e)&&!(fr in e)},Jp=e=>{if(!_i(e)||vi(e))return!1;try{return Object.keys(e).length===0&&Object.getPrototypeOf(e)===Object.prototype}catch{return!1}},zp=gt("Date"),Gp=gt("File"),Xp=e=>!!(e&&typeof e.uri<"u"),Qp=e=>e&&typeof e.getParts<"u",Zp=gt("Blob"),eh=gt("FileList"),th=e=>_i(e)&&Ze(e.pipe);function nh(){return typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}}const Ls=nh(),$s=typeof Ls.FormData<"u"?Ls.FormData:void 0,ih=e=>{if(!e)return!1;if($s&&e instanceof $s)return!0;const t=ur(e);if(!t||t===Object.prototype||!Ze(e.append))return!1;const n=dr(e);return n==="formdata"||n==="object"&&Ze(e.toString)&&e.toString()==="[object FormData]"},rh=gt("URLSearchParams"),[oh,sh,lh,ah]=["ReadableStream","Request","Response","Headers"].map(gt),ch=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function xi(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let i,r;if(typeof e!="object"&&(e=[e]),jn(e))for(i=0,r=e.length;i0;)if(r=n[i],t===r.toLowerCase())return r;return null}const ln=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,ka=e=>!In(e)&&e!==ln;function to(...e){const{caseless:t,skipUndefined:n}=ka(this)&&this||{},i={},r=(o,s)=>{if(s==="__proto__"||s==="constructor"||s==="prototype")return;const l=t&&Fa(i,s)||s,a=no(i,l)?i[l]:void 0;Li(a)&&Li(o)?i[l]=to(a,o):Li(o)?i[l]=to({},o):jn(o)?i[l]=o.slice():(!n||!In(o))&&(i[l]=o)};for(let o=0,s=e.length;o(xi(t,(r,o)=>{n&&Ze(r)?Object.defineProperty(e,o,{__proto__:null,value:Ea(r,n),writable:!0,enumerable:!0,configurable:!0}):Object.defineProperty(e,o,{__proto__:null,value:r,writable:!0,enumerable:!0,configurable:!0})},{allOwnKeys:i}),e),fh=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),dh=(e,t,n,i)=>{e.prototype=Object.create(t.prototype,i),Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{__proto__:null,value:t.prototype}),n&&Object.assign(e.prototype,n)},ph=(e,t,n,i)=>{let r,o,s;const l={};if(t=t||{},e==null)return t;do{for(r=Object.getOwnPropertyNames(e),o=r.length;o-- >0;)s=r[o],(!i||i(s,e,t))&&!l[s]&&(t[s]=e[s],l[s]=!0);e=n!==!1&&ur(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},hh=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const i=e.indexOf(t,n);return i!==-1&&i===n},gh=e=>{if(!e)return null;if(jn(e))return e;let t=e.length;if(!Ra(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},mh=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&ur(Uint8Array)),bh=(e,t)=>{const i=(e&&e[fr]).call(e);let r;for(;(r=i.next())&&!r.done;){const o=r.value;t.call(e,o[0],o[1])}},yh=(e,t)=>{let n;const i=[];for(;(n=e.exec(t))!==null;)i.push(n);return i},vh=gt("HTMLFormElement"),_h=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,i,r){return i.toUpperCase()+r}),no=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),xh=gt("RegExp"),Na=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),i={};xi(n,(r,o)=>{let s;(s=t(r,o,e))!==!1&&(i[o]=s||r)}),Object.defineProperties(e,i)},wh=e=>{Na(e,(t,n)=>{if(Ze(e)&&["arguments","caller","callee"].includes(n))return!1;const i=e[n];if(Ze(i)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},Ah=(e,t)=>{const n={},i=r=>{r.forEach(o=>{n[o]=!0})};return jn(e)?i(e):i(String(e).split(t)),n},Ch=()=>{},Sh=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function Eh(e){return!!(e&&Ze(e.append)&&e[Ta]==="FormData"&&e[fr])}const Th=e=>{const t=new Array(10),n=(i,r)=>{if(_i(i)){if(t.indexOf(i)>=0)return;if(vi(i))return i;if(!("toJSON"in i)){t[r]=i;const o=jn(i)?[]:{};return xi(i,(s,l)=>{const a=n(s,r+1);!In(a)&&(o[l]=a)}),t[r]=void 0,o}}return i};return n(e,0)},Oh=gt("AsyncFunction"),Rh=e=>e&&(_i(e)||Ze(e))&&Ze(e.then)&&Ze(e.catch),La=((e,t)=>e?setImmediate:t?((n,i)=>(ln.addEventListener("message",({source:r,data:o})=>{r===ln&&o===n&&i.length&&i.shift()()},!1),r=>{i.push(r),ln.postMessage(n,"*")}))(`axios@${Math.random()}`,[]):n=>setTimeout(n))(typeof setImmediate=="function",Ze(ln.postMessage)),Fh=typeof queueMicrotask<"u"?queueMicrotask.bind(ln):typeof process<"u"&&process.nextTick||La,kh=e=>e!=null&&Ze(e[fr]),v={isArray:jn,isArrayBuffer:Oa,isBuffer:vi,isFormData:ih,isArrayBufferView:Kp,isString:Wp,isNumber:Ra,isBoolean:Yp,isObject:_i,isPlainObject:Li,isEmptyObject:Jp,isReadableStream:oh,isRequest:sh,isResponse:lh,isHeaders:ah,isUndefined:In,isDate:zp,isFile:Gp,isReactNativeBlob:Xp,isReactNative:Qp,isBlob:Zp,isRegExp:xh,isFunction:Ze,isStream:th,isURLSearchParams:rh,isTypedArray:mh,isFileList:eh,forEach:xi,merge:to,extend:uh,trim:ch,stripBOM:fh,inherits:dh,toFlatObject:ph,kindOf:dr,kindOfTest:gt,endsWith:hh,toArray:gh,forEachEntry:bh,matchAll:yh,isHTMLForm:vh,hasOwnProperty:no,hasOwnProp:no,reduceDescriptors:Na,freezeMethods:wh,toObjectSet:Ah,toCamelCase:_h,noop:Ch,toFiniteNumber:Sh,findKey:Fa,global:ln,isContextDefined:ka,isSpecCompliantForm:Eh,toJSONObject:Th,isAsyncFn:Oh,isThenable:Rh,setImmediate:La,asap:Fh,isIterable:kh},Nh=v.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Lh=e=>{const t={};let n,i,r;return e&&e.split(` +`).forEach(function(s){r=s.indexOf(":"),n=s.substring(0,r).trim().toLowerCase(),i=s.substring(r+1).trim(),!(!n||t[n]&&Nh[n])&&(n==="set-cookie"?t[n]?t[n].push(i):t[n]=[i]:t[n]=t[n]?t[n]+", "+i:i)}),t},Is=Symbol("internals"),$h=/[^\x09\x20-\x7E\x80-\xFF]/g;function Ih(e){let t=0,n=e.length;for(;tt;){const i=e.charCodeAt(n-1);if(i!==9&&i!==32)break;n-=1}return t===0&&n===e.length?e:e.slice(t,n)}function Yn(e){return e&&String(e).trim().toLowerCase()}function Ph(e){return Ih(e.replace($h,""))}function $i(e){return e===!1||e==null?e:v.isArray(e)?e.map($i):Ph(String(e))}function Dh(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let i;for(;i=n.exec(e);)t[i[1]]=i[2];return t}const Uh=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function kr(e,t,n,i,r){if(v.isFunction(i))return i.call(this,t,n);if(r&&(t=n),!!v.isString(t)){if(v.isString(i))return t.indexOf(i)!==-1;if(v.isRegExp(i))return i.test(t)}}function Mh(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,i)=>n.toUpperCase()+i)}function jh(e,t){const n=v.toCamelCase(" "+t);["get","set","has"].forEach(i=>{Object.defineProperty(e,i+n,{__proto__:null,value:function(r,o,s){return this[i].call(this,t,r,o,s)},configurable:!0})})}let Ge=class{constructor(t){t&&this.set(t)}set(t,n,i){const r=this;function o(l,a,c){const u=Yn(a);if(!u)throw new Error("header name must be a non-empty string");const d=v.findKey(r,u);(!d||r[d]===void 0||c===!0||c===void 0&&r[d]!==!1)&&(r[d||a]=$i(l))}const s=(l,a)=>v.forEach(l,(c,u)=>o(c,u,a));if(v.isPlainObject(t)||t instanceof this.constructor)s(t,n);else if(v.isString(t)&&(t=t.trim())&&!Uh(t))s(Lh(t),n);else if(v.isObject(t)&&v.isIterable(t)){let l={},a,c;for(const u of t){if(!v.isArray(u))throw TypeError("Object iterator must return a key-value pair");l[c=u[0]]=(a=l[c])?v.isArray(a)?[...a,u[1]]:[a,u[1]]:u[1]}s(l,n)}else t!=null&&o(n,t,i);return this}get(t,n){if(t=Yn(t),t){const i=v.findKey(this,t);if(i){const r=this[i];if(!n)return r;if(n===!0)return Dh(r);if(v.isFunction(n))return n.call(this,r,i);if(v.isRegExp(n))return n.exec(r);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=Yn(t),t){const i=v.findKey(this,t);return!!(i&&this[i]!==void 0&&(!n||kr(this,this[i],i,n)))}return!1}delete(t,n){const i=this;let r=!1;function o(s){if(s=Yn(s),s){const l=v.findKey(i,s);l&&(!n||kr(i,i[l],l,n))&&(delete i[l],r=!0)}}return v.isArray(t)?t.forEach(o):o(t),r}clear(t){const n=Object.keys(this);let i=n.length,r=!1;for(;i--;){const o=n[i];(!t||kr(this,this[o],o,t,!0))&&(delete this[o],r=!0)}return r}normalize(t){const n=this,i={};return v.forEach(this,(r,o)=>{const s=v.findKey(i,o);if(s){n[s]=$i(r),delete n[o];return}const l=t?Mh(o):String(o).trim();l!==o&&delete n[o],n[l]=$i(r),i[l]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return v.forEach(this,(i,r)=>{i!=null&&i!==!1&&(n[r]=t&&v.isArray(i)?i.join(", "):i)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` +`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const i=new this(t);return n.forEach(r=>i.set(r)),i}static accessor(t){const i=(this[Is]=this[Is]={accessors:{}}).accessors,r=this.prototype;function o(s){const l=Yn(s);i[l]||(jh(r,s),i[l]=!0)}return v.isArray(t)?t.forEach(o):o(t),this}};Ge.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);v.reduceDescriptors(Ge.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(i){this[n]=i}}});v.freezeMethods(Ge);const Bh="[REDACTED ****]";function Hh(e){if(v.hasOwnProp(e,"toJSON"))return!0;let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;){if(v.hasOwnProp(t,"toJSON"))return!0;t=Object.getPrototypeOf(t)}return!1}function Vh(e,t){const n=new Set(t.map(o=>String(o).toLowerCase())),i=[],r=o=>{if(o===null||typeof o!="object"||v.isBuffer(o))return o;if(i.indexOf(o)!==-1)return;o instanceof Ge&&(o=o.toJSON()),i.push(o);let s;if(v.isArray(o))s=[],o.forEach((l,a)=>{const c=r(l);v.isUndefined(c)||(s[a]=c)});else{if(!v.isPlainObject(o)&&Hh(o))return i.pop(),o;s=Object.create(null);for(const[l,a]of Object.entries(o)){const c=n.has(l.toLowerCase())?Bh:r(a);v.isUndefined(c)||(s[l]=c)}}return i.pop(),s};return r(e)}let D=class $a extends Error{static from(t,n,i,r,o,s){const l=new $a(t.message,n||t.code,i,r,o);return l.cause=t,l.name=t.name,t.status!=null&&l.status==null&&(l.status=t.status),s&&Object.assign(l,s),l}constructor(t,n,i,r,o){super(t),Object.defineProperty(this,"message",{__proto__:null,value:t,enumerable:!0,writable:!0,configurable:!0}),this.name="AxiosError",this.isAxiosError=!0,n&&(this.code=n),i&&(this.config=i),r&&(this.request=r),o&&(this.response=o,this.status=o.status)}toJSON(){const t=this.config,n=t&&v.hasOwnProp(t,"redact")?t.redact:void 0,i=v.isArray(n)&&n.length>0?Vh(t,n):v.toJSONObject(t);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:i,code:this.code,status:this.status}}};D.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";D.ERR_BAD_OPTION="ERR_BAD_OPTION";D.ECONNABORTED="ECONNABORTED";D.ETIMEDOUT="ETIMEDOUT";D.ECONNREFUSED="ECONNREFUSED";D.ERR_NETWORK="ERR_NETWORK";D.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";D.ERR_DEPRECATED="ERR_DEPRECATED";D.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";D.ERR_BAD_REQUEST="ERR_BAD_REQUEST";D.ERR_CANCELED="ERR_CANCELED";D.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";D.ERR_INVALID_URL="ERR_INVALID_URL";D.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";const qh=null;function io(e){return v.isPlainObject(e)||v.isArray(e)}function Ia(e){return v.endsWith(e,"[]")?e.slice(0,-2):e}function Nr(e,t,n){return e?e.concat(t).map(function(r,o){return r=Ia(r),!n&&o?"["+r+"]":r}).join(n?".":""):t}function Kh(e){return v.isArray(e)&&!e.some(io)}const Wh=v.toFlatObject(v,{},null,function(t){return/^is[A-Z]/.test(t)});function hr(e,t,n){if(!v.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=v.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(_,C){return!v.isUndefined(C[_])});const i=n.metaTokens,r=n.visitor||d,o=n.dots,s=n.indexes,l=n.Blob||typeof Blob<"u"&&Blob,a=n.maxDepth===void 0?100:n.maxDepth,c=l&&v.isSpecCompliantForm(t);if(!v.isFunction(r))throw new TypeError("visitor must be a function");function u(h){if(h===null)return"";if(v.isDate(h))return h.toISOString();if(v.isBoolean(h))return h.toString();if(!c&&v.isBlob(h))throw new D("Blob is not supported. Use a Buffer instead.");return v.isArrayBuffer(h)||v.isTypedArray(h)?c&&typeof Blob=="function"?new Blob([h]):Buffer.from(h):h}function d(h,_,C){let w=h;if(v.isReactNative(t)&&v.isReactNativeBlob(h))return t.append(Nr(C,_,o),u(h)),!1;if(h&&!C&&typeof h=="object"){if(v.endsWith(_,"{}"))_=i?_:_.slice(0,-2),h=JSON.stringify(h);else if(v.isArray(h)&&Kh(h)||(v.isFileList(h)||v.endsWith(_,"[]"))&&(w=v.toArray(h)))return _=Ia(_),w.forEach(function(R,G){!(v.isUndefined(R)||R===null)&&t.append(s===!0?Nr([_],G,o):s===null?_:_+"[]",u(R))}),!1}return io(h)?!0:(t.append(Nr(C,_,o),u(h)),!1)}const g=[],m=Object.assign(Wh,{defaultVisitor:d,convertValue:u,isVisitable:io});function y(h,_,C=0){if(!v.isUndefined(h)){if(C>a)throw new D("Object is too deeply nested ("+C+" levels). Max depth: "+a,D.ERR_FORM_DATA_DEPTH_EXCEEDED);if(g.indexOf(h)!==-1)throw Error("Circular reference detected in "+_.join("."));g.push(h),v.forEach(h,function($,R){(!(v.isUndefined($)||$===null)&&r.call(t,$,v.isString(R)?R.trim():R,_,m))===!0&&y($,_?_.concat(R):[R],C+1)}),g.pop()}}if(!v.isObject(e))throw new TypeError("data must be an object");return y(e),t}function Ps(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(e).replace(/[!'()~]|%20/g,function(i){return t[i]})}function Fo(e,t){this._pairs=[],e&&hr(e,this,t)}const Pa=Fo.prototype;Pa.append=function(t,n){this._pairs.push([t,n])};Pa.toString=function(t){const n=t?function(i){return t.call(this,i,Ps)}:Ps;return this._pairs.map(function(r){return n(r[0])+"="+n(r[1])},"").join("&")};function Yh(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function Da(e,t,n){if(!t)return e;const i=n&&n.encode||Yh,r=v.isFunction(n)?{serialize:n}:n,o=r&&r.serialize;let s;if(o?s=o(t,r):s=v.isURLSearchParams(t)?t.toString():new Fo(t,r).toString(i),s){const l=e.indexOf("#");l!==-1&&(e=e.slice(0,l)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}class Ds{constructor(){this.handlers=[]}use(t,n,i){return this.handlers.push({fulfilled:t,rejected:n,synchronous:i?i.synchronous:!1,runWhen:i?i.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){v.forEach(this.handlers,function(i){i!==null&&t(i)})}}const ko={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1,legacyInterceptorReqResOrdering:!0},Jh=typeof URLSearchParams<"u"?URLSearchParams:Fo,zh=typeof FormData<"u"?FormData:null,Gh=typeof Blob<"u"?Blob:null,Xh={isBrowser:!0,classes:{URLSearchParams:Jh,FormData:zh,Blob:Gh},protocols:["http","https","file","blob","url","data"]},No=typeof window<"u"&&typeof document<"u",ro=typeof navigator=="object"&&navigator||void 0,Qh=No&&(!ro||["ReactNative","NativeScript","NS"].indexOf(ro.product)<0),Zh=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",eg=No&&window.location.href||"http://localhost",tg=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:No,hasStandardBrowserEnv:Qh,hasStandardBrowserWebWorkerEnv:Zh,navigator:ro,origin:eg},Symbol.toStringTag,{value:"Module"})),Me={...tg,...Xh};function ng(e,t){return hr(e,new Me.classes.URLSearchParams,{visitor:function(n,i,r,o){return Me.isNode&&v.isBuffer(n)?(this.append(i,n.toString("base64")),!1):o.defaultVisitor.apply(this,arguments)},...t})}function ig(e){return v.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function rg(e){const t={},n=Object.keys(e);let i;const r=n.length;let o;for(i=0;i=n.length;return s=!s&&v.isArray(r)?r.length:s,a?(v.hasOwnProp(r,s)?r[s]=v.isArray(r[s])?r[s].concat(i):[r[s],i]:r[s]=i,!l):((!r[s]||!v.isObject(r[s]))&&(r[s]=[]),t(n,i,r[s],o)&&v.isArray(r[s])&&(r[s]=rg(r[s])),!l)}if(v.isFormData(e)&&v.isFunction(e.entries)){const n={};return v.forEachEntry(e,(i,r)=>{t(ig(i),r,n,0)}),n}return null}const yn=(e,t)=>e!=null&&v.hasOwnProp(e,t)?e[t]:void 0;function og(e,t,n){if(v.isString(e))try{return(t||JSON.parse)(e),v.trim(e)}catch(i){if(i.name!=="SyntaxError")throw i}return(n||JSON.stringify)(e)}const wi={transitional:ko,adapter:["xhr","http","fetch"],transformRequest:[function(t,n){const i=n.getContentType()||"",r=i.indexOf("application/json")>-1,o=v.isObject(t);if(o&&v.isHTMLForm(t)&&(t=new FormData(t)),v.isFormData(t))return r?JSON.stringify(Ua(t)):t;if(v.isArrayBuffer(t)||v.isBuffer(t)||v.isStream(t)||v.isFile(t)||v.isBlob(t)||v.isReadableStream(t))return t;if(v.isArrayBufferView(t))return t.buffer;if(v.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let l;if(o){const a=yn(this,"formSerializer");if(i.indexOf("application/x-www-form-urlencoded")>-1)return ng(t,a).toString();if((l=v.isFileList(t))||i.indexOf("multipart/form-data")>-1){const c=yn(this,"env"),u=c&&c.FormData;return hr(l?{"files[]":t}:t,u&&new u,a)}}return o||r?(n.setContentType("application/json",!1),og(t)):t}],transformResponse:[function(t){const n=yn(this,"transitional")||wi.transitional,i=n&&n.forcedJSONParsing,r=yn(this,"responseType"),o=r==="json";if(v.isResponse(t)||v.isReadableStream(t))return t;if(t&&v.isString(t)&&(i&&!r||o)){const l=!(n&&n.silentJSONParsing)&&o;try{return JSON.parse(t,yn(this,"parseReviver"))}catch(a){if(l)throw a.name==="SyntaxError"?D.from(a,D.ERR_BAD_RESPONSE,this,null,yn(this,"response")):a}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:Me.classes.FormData,Blob:Me.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};v.forEach(["delete","get","head","post","put","patch","query"],e=>{wi.headers[e]={}});function Lr(e,t){const n=this||wi,i=t||n,r=Ge.from(i.headers);let o=i.data;return v.forEach(e,function(l){o=l.call(n,o,r.normalize(),t?t.status:void 0)}),r.normalize(),o}function Ma(e){return!!(e&&e.__CANCEL__)}let Ai=class extends D{constructor(t,n,i){super(t??"canceled",D.ERR_CANCELED,n,i),this.name="CanceledError",this.__CANCEL__=!0}};function ja(e,t,n){const i=n.config.validateStatus;!n.status||!i||i(n.status)?e(n):t(new D("Request failed with status code "+n.status,n.status>=400&&n.status<500?D.ERR_BAD_REQUEST:D.ERR_BAD_RESPONSE,n.config,n.request,n))}function sg(e){const t=/^([-+\w]{1,25}):(?:\/\/)?/.exec(e);return t&&t[1]||""}function lg(e,t){e=e||10;const n=new Array(e),i=new Array(e);let r=0,o=0,s;return t=t!==void 0?t:1e3,function(a){const c=Date.now(),u=i[o];s||(s=c),n[r]=a,i[r]=c;let d=o,g=0;for(;d!==r;)g+=n[d++],d=d%e;if(r=(r+1)%e,r===o&&(o=(o+1)%e),c-s{n=u,r=null,o&&(clearTimeout(o),o=null),e(...c)};return[(...c)=>{const u=Date.now(),d=u-n;d>=i?s(c,u):(r=c,o||(o=setTimeout(()=>{o=null,s(r)},i-d)))},()=>r&&s(r)]}const Ki=(e,t,n=3)=>{let i=0;const r=lg(50,250);return ag(o=>{const s=o.loaded,l=o.lengthComputable?o.total:void 0,a=l!=null?Math.min(s,l):s,c=Math.max(0,a-i),u=r(c);i=Math.max(i,a);const d={loaded:a,total:l,progress:l?a/l:void 0,bytes:c,rate:u||void 0,estimated:u&&l?(l-a)/u:void 0,event:o,lengthComputable:l!=null,[t?"download":"upload"]:!0};e(d)},n)},Us=(e,t)=>{const n=e!=null;return[i=>t[0]({lengthComputable:n,total:e,loaded:i}),t[1]]},Ms=e=>(...t)=>v.asap(()=>e(...t)),cg=Me.hasStandardBrowserEnv?((e,t)=>n=>(n=new URL(n,Me.origin),e.protocol===n.protocol&&e.host===n.host&&(t||e.port===n.port)))(new URL(Me.origin),Me.navigator&&/(msie|trident)/i.test(Me.navigator.userAgent)):()=>!0,ug=Me.hasStandardBrowserEnv?{write(e,t,n,i,r,o,s){if(typeof document>"u")return;const l=[`${e}=${encodeURIComponent(t)}`];v.isNumber(n)&&l.push(`expires=${new Date(n).toUTCString()}`),v.isString(i)&&l.push(`path=${i}`),v.isString(r)&&l.push(`domain=${r}`),o===!0&&l.push("secure"),v.isString(s)&&l.push(`SameSite=${s}`),document.cookie=l.join("; ")},read(e){if(typeof document>"u")return null;const t=document.cookie.split(";");for(let n=0;ne instanceof Ge?{...e}:e;function gn(e,t){t=t||{};const n=Object.create(null);Object.defineProperty(n,"hasOwnProperty",{__proto__:null,value:Object.prototype.hasOwnProperty,enumerable:!1,writable:!0,configurable:!0});function i(c,u,d,g){return v.isPlainObject(c)&&v.isPlainObject(u)?v.merge.call({caseless:g},c,u):v.isPlainObject(u)?v.merge({},u):v.isArray(u)?u.slice():u}function r(c,u,d,g){if(v.isUndefined(u)){if(!v.isUndefined(c))return i(void 0,c,d,g)}else return i(c,u,d,g)}function o(c,u){if(!v.isUndefined(u))return i(void 0,u)}function s(c,u){if(v.isUndefined(u)){if(!v.isUndefined(c))return i(void 0,c)}else return i(void 0,u)}function l(c,u,d){if(v.hasOwnProp(t,d))return i(c,u);if(v.hasOwnProp(e,d))return i(void 0,c)}const a={url:o,method:o,data:o,baseURL:s,transformRequest:s,transformResponse:s,paramsSerializer:s,timeout:s,timeoutMessage:s,withCredentials:s,withXSRFToken:s,adapter:s,responseType:s,xsrfCookieName:s,xsrfHeaderName:s,onUploadProgress:s,onDownloadProgress:s,decompress:s,maxContentLength:s,maxBodyLength:s,beforeRedirect:s,transport:s,httpAgent:s,httpsAgent:s,cancelToken:s,socketPath:s,allowedSocketPaths:s,responseEncoding:s,validateStatus:l,headers:(c,u,d)=>r(js(c),js(u),d,!0)};return v.forEach(Object.keys({...e,...t}),function(u){if(u==="__proto__"||u==="constructor"||u==="prototype")return;const d=v.hasOwnProp(a,u)?a[u]:r,g=v.hasOwnProp(e,u)?e[u]:void 0,m=v.hasOwnProp(t,u)?t[u]:void 0,y=d(g,m,u);v.isUndefined(y)&&d!==l||(n[u]=y)}),n}const pg=["content-type","content-length"];function hg(e,t,n){if(n!=="content-only"){e.set(t);return}Object.entries(t).forEach(([i,r])=>{pg.includes(i.toLowerCase())&&e.set(i,r)})}const gg=e=>encodeURIComponent(e).replace(/%([0-9A-F]{2})/gi,(t,n)=>String.fromCharCode(parseInt(n,16))),Ha=e=>{const t=gn({},e),n=g=>v.hasOwnProp(t,g)?t[g]:void 0,i=n("data");let r=n("withXSRFToken");const o=n("xsrfHeaderName"),s=n("xsrfCookieName");let l=n("headers");const a=n("auth"),c=n("baseURL"),u=n("allowAbsoluteUrls"),d=n("url");if(t.headers=l=Ge.from(l),t.url=Da(Ba(c,d,u),e.params,e.paramsSerializer),a&&l.set("Authorization","Basic "+btoa((a.username||"")+":"+(a.password?gg(a.password):""))),v.isFormData(i)&&(Me.hasStandardBrowserEnv||Me.hasStandardBrowserWebWorkerEnv?l.setContentType(void 0):v.isFunction(i.getHeaders)&&hg(l,i.getHeaders(),n("formDataHeaderPolicy"))),Me.hasStandardBrowserEnv&&(v.isFunction(r)&&(r=r(t)),r===!0||r==null&&cg(t.url))){const m=o&&s&&ug.read(s);m&&l.set(o,m)}return t},mg=typeof XMLHttpRequest<"u",bg=mg&&function(e){return new Promise(function(n,i){const r=Ha(e);let o=r.data;const s=Ge.from(r.headers).normalize();let{responseType:l,onUploadProgress:a,onDownloadProgress:c}=r,u,d,g,m,y;function h(){m&&m(),y&&y(),r.cancelToken&&r.cancelToken.unsubscribe(u),r.signal&&r.signal.removeEventListener("abort",u)}let _=new XMLHttpRequest;_.open(r.method.toUpperCase(),r.url,!0),_.timeout=r.timeout;function C(){if(!_)return;const $=Ge.from("getAllResponseHeaders"in _&&_.getAllResponseHeaders()),G={data:!l||l==="text"||l==="json"?_.responseText:_.response,status:_.status,statusText:_.statusText,headers:$,config:e,request:_};ja(function(J){n(J),h()},function(J){i(J),h()},G),_=null}"onloadend"in _?_.onloadend=C:_.onreadystatechange=function(){!_||_.readyState!==4||_.status===0&&!(_.responseURL&&_.responseURL.startsWith("file:"))||setTimeout(C)},_.onabort=function(){_&&(i(new D("Request aborted",D.ECONNABORTED,e,_)),h(),_=null)},_.onerror=function(R){const G=R&&R.message?R.message:"Network Error",re=new D(G,D.ERR_NETWORK,e,_);re.event=R||null,i(re),h(),_=null},_.ontimeout=function(){let R=r.timeout?"timeout of "+r.timeout+"ms exceeded":"timeout exceeded";const G=r.transitional||ko;r.timeoutErrorMessage&&(R=r.timeoutErrorMessage),i(new D(R,G.clarifyTimeoutError?D.ETIMEDOUT:D.ECONNABORTED,e,_)),h(),_=null},o===void 0&&s.setContentType(null),"setRequestHeader"in _&&v.forEach(s.toJSON(),function(R,G){_.setRequestHeader(G,R)}),v.isUndefined(r.withCredentials)||(_.withCredentials=!!r.withCredentials),l&&l!=="json"&&(_.responseType=r.responseType),c&&([g,y]=Ki(c,!0),_.addEventListener("progress",g)),a&&_.upload&&([d,m]=Ki(a),_.upload.addEventListener("progress",d),_.upload.addEventListener("loadend",m)),(r.cancelToken||r.signal)&&(u=$=>{_&&(i(!$||$.type?new Ai(null,e,_):$),_.abort(),h(),_=null)},r.cancelToken&&r.cancelToken.subscribe(u),r.signal&&(r.signal.aborted?u():r.signal.addEventListener("abort",u)));const w=sg(r.url);if(w&&!Me.protocols.includes(w)){i(new D("Unsupported protocol "+w+":",D.ERR_BAD_REQUEST,e));return}_.send(o||null)})},yg=(e,t)=>{const{length:n}=e=e?e.filter(Boolean):[];if(t||n){let i=new AbortController,r;const o=function(c){if(!r){r=!0,l();const u=c instanceof Error?c:this.reason;i.abort(u instanceof D?u:new Ai(u instanceof Error?u.message:u))}};let s=t&&setTimeout(()=>{s=null,o(new D(`timeout of ${t}ms exceeded`,D.ETIMEDOUT))},t);const l=()=>{e&&(s&&clearTimeout(s),s=null,e.forEach(c=>{c.unsubscribe?c.unsubscribe(o):c.removeEventListener("abort",o)}),e=null)};e.forEach(c=>c.addEventListener("abort",o));const{signal:a}=i;return a.unsubscribe=()=>v.asap(l),a}},vg=function*(e,t){let n=e.byteLength;if(n{const r=_g(e,t);let o=0,s,l=a=>{s||(s=!0,i&&i(a))};return new ReadableStream({async pull(a){try{const{done:c,value:u}=await r.next();if(c){l(),a.close();return}let d=u.byteLength;if(n){let g=o+=d;n(g)}a.enqueue(new Uint8Array(u))}catch(c){throw l(c),c}},cancel(a){return l(a),r.return()}},{highWaterMark:2})};function wg(e){if(!e||typeof e!="string"||!e.startsWith("data:"))return 0;const t=e.indexOf(",");if(t<0)return 0;const n=e.slice(5,t),i=e.slice(t+1);if(/;base64/i.test(n)){let s=i.length;const l=i.length;for(let m=0;m=48&&y<=57||y>=65&&y<=70||y>=97&&y<=102)&&(h>=48&&h<=57||h>=65&&h<=70||h>=97&&h<=102)&&(s-=2,m+=2)}let a=0,c=l-1;const u=m=>m>=2&&i.charCodeAt(m-2)===37&&i.charCodeAt(m-1)===51&&(i.charCodeAt(m)===68||i.charCodeAt(m)===100);c>=0&&(i.charCodeAt(c)===61?(a++,c--):u(c)&&(a++,c-=3)),a===1&&c>=0&&(i.charCodeAt(c)===61||u(c))&&a++;const g=Math.floor(s/4)*3-(a||0);return g>0?g:0}if(typeof Buffer<"u"&&typeof Buffer.byteLength=="function")return Buffer.byteLength(i,"utf8");let o=0;for(let s=0,l=i.length;s=55296&&a<=56319&&s+1=56320&&c<=57343?(o+=4,s++):o+=3}else o+=3}return o}const Lo="1.16.0",Hs=64*1024,{isFunction:Oi}=v,Vs=(e,...t)=>{try{return!!e(...t)}catch{return!1}},Ag=e=>{const t=v.global??globalThis,{ReadableStream:n,TextEncoder:i}=t;e=v.merge.call({skipUndefined:!0},{Request:t.Request,Response:t.Response},e);const{fetch:r,Request:o,Response:s}=e,l=r?Oi(r):typeof fetch=="function",a=Oi(o),c=Oi(s);if(!l)return!1;const u=l&&Oi(n),d=l&&(typeof i=="function"?(C=>w=>C.encode(w))(new i):async C=>new Uint8Array(await new o(C).arrayBuffer())),g=a&&u&&Vs(()=>{let C=!1;const w=new o(Me.origin,{body:new n,method:"POST",get duplex(){return C=!0,"half"}}),$=w.headers.has("Content-Type");return w.body!=null&&w.body.cancel(),C&&!$}),m=c&&u&&Vs(()=>v.isReadableStream(new s("").body)),y={stream:m&&(C=>C.body)};l&&["text","arrayBuffer","blob","formData","stream"].forEach(C=>{!y[C]&&(y[C]=(w,$)=>{let R=w&&w[C];if(R)return R.call(w);throw new D(`Response type '${C}' is not supported`,D.ERR_NOT_SUPPORT,$)})});const h=async C=>{if(C==null)return 0;if(v.isBlob(C))return C.size;if(v.isSpecCompliantForm(C))return(await new o(Me.origin,{method:"POST",body:C}).arrayBuffer()).byteLength;if(v.isArrayBufferView(C)||v.isArrayBuffer(C))return C.byteLength;if(v.isURLSearchParams(C)&&(C=C+""),v.isString(C))return(await d(C)).byteLength},_=async(C,w)=>{const $=v.toFiniteNumber(C.getContentLength());return $??h(w)};return async C=>{let{url:w,method:$,data:R,signal:G,cancelToken:re,timeout:J,onDownloadProgress:ne,onUploadProgress:B,responseType:X,headers:F,withCredentials:A="same-origin",fetchOptions:H,maxContentLength:M,maxBodyLength:le}=Ha(C);const Z=v.isNumber(M)&&M>-1,te=v.isNumber(le)&&le>-1;let ie=r||fetch;X=X?(X+"").toLowerCase():"text";let we=yg([G,re&&re.toAbortSignal()],J),Le=null;const Ve=we&&we.unsubscribe&&(()=>{we.unsubscribe()});let tt;try{if(Z&&typeof w=="string"&&w.startsWith("data:")&&wg(w)>M)throw new D("maxContentLength size of "+M+" exceeded",D.ERR_BAD_RESPONSE,C,Le);if(te&&$!=="get"&&$!=="head"){const ce=await _(F,R);if(typeof ce=="number"&&isFinite(ce)&&ce>le)throw new D("Request body larger than maxBodyLength limit",D.ERR_BAD_REQUEST,C,Le)}if(B&&g&&$!=="get"&&$!=="head"&&(tt=await _(F,R))!==0){let ce=new o(w,{method:"POST",body:R,duplex:"half"}),Nt;if(v.isFormData(R)&&(Nt=ce.headers.get("content-type"))&&F.setContentType(Nt),ce.body){const[bt,Bn]=Us(tt,Ki(Ms(B)));R=Bs(ce.body,Hs,bt,Bn)}}v.isString(A)||(A=A?"include":"omit");const Fe=a&&"credentials"in o.prototype;if(v.isFormData(R)){const ce=F.getContentType();ce&&/^multipart\/form-data/i.test(ce)&&!/boundary=/i.test(ce)&&F.delete("content-type")}F.set("User-Agent","axios/"+Lo,!1);const mt={...H,signal:we,method:$.toUpperCase(),headers:F.normalize().toJSON(),body:R,duplex:"half",credentials:Fe?A:void 0};Le=a&&new o(w,mt);let ot=await(a?ie(Le,H):ie(w,mt));if(Z){const ce=v.toFiniteNumber(ot.headers.get("content-length"));if(ce!=null&&ce>M)throw new D("maxContentLength size of "+M+" exceeded",D.ERR_BAD_RESPONSE,C,Le)}const kt=m&&(X==="stream"||X==="response");if(m&&ot.body&&(ne||Z||kt&&Ve)){const ce={};["status","statusText","headers"].forEach(x=>{ce[x]=ot[x]});const Nt=v.toFiniteNumber(ot.headers.get("content-length")),[bt,Bn]=ne&&Us(Nt,Ki(Ms(ne),!0))||[];let p=0;const b=x=>{if(Z&&(p=x,p>M))throw new D("maxContentLength size of "+M+" exceeded",D.ERR_BAD_RESPONSE,C,Le);bt&&bt(x)};ot=new s(Bs(ot.body,Hs,b,()=>{Bn&&Bn(),Ve&&Ve()}),ce)}X=X||"text";let Xe=await y[v.findKey(y,X)||"text"](ot,C);if(Z&&!m&&!kt){let ce;if(Xe!=null&&(typeof Xe.byteLength=="number"?ce=Xe.byteLength:typeof Xe.size=="number"?ce=Xe.size:typeof Xe=="string"&&(ce=typeof i=="function"?new i().encode(Xe).byteLength:Xe.length)),typeof ce=="number"&&ce>M)throw new D("maxContentLength size of "+M+" exceeded",D.ERR_BAD_RESPONSE,C,Le)}return!kt&&Ve&&Ve(),await new Promise((ce,Nt)=>{ja(ce,Nt,{data:Xe,headers:Ge.from(ot.headers),status:ot.status,statusText:ot.statusText,config:C,request:Le})})}catch(Fe){if(Ve&&Ve(),we&&we.aborted&&we.reason instanceof D){const mt=we.reason;throw mt.config=C,Le&&(mt.request=Le),Fe!==mt&&(mt.cause=Fe),mt}throw Fe&&Fe.name==="TypeError"&&/Load failed|fetch/i.test(Fe.message)?Object.assign(new D("Network Error",D.ERR_NETWORK,C,Le,Fe&&Fe.response),{cause:Fe.cause||Fe}):D.from(Fe,Fe&&Fe.code,C,Le,Fe&&Fe.response)}}},Cg=new Map,Va=e=>{let t=e&&e.env||{};const{fetch:n,Request:i,Response:r}=t,o=[i,r,n];let s=o.length,l=s,a,c,u=Cg;for(;l--;)a=o[l],c=u.get(a),c===void 0&&u.set(a,c=l?new Map:Ag(t)),u=c;return c};Va();const $o={http:qh,xhr:bg,fetch:{get:Va}};v.forEach($o,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{__proto__:null,value:t})}catch{}Object.defineProperty(e,"adapterName",{__proto__:null,value:t})}});const qs=e=>`- ${e}`,Sg=e=>v.isFunction(e)||e===null||e===!1;function Eg(e,t){e=v.isArray(e)?e:[e];const{length:n}=e;let i,r;const o={};for(let s=0;s`adapter ${a} `+(c===!1?"is not supported by the environment":"is not available in the build"));let l=n?s.length>1?`since : +`+s.map(qs).join(` +`):" "+qs(s[0]):"as no adapter specified";throw new D("There is no suitable adapter to dispatch the request "+l,"ERR_NOT_SUPPORT")}return r}const qa={getAdapter:Eg,adapters:$o};function $r(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new Ai(null,e)}function Ks(e){return $r(e),e.headers=Ge.from(e.headers),e.data=Lr.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),qa.getAdapter(e.adapter||wi.adapter,e)(e).then(function(i){$r(e),e.response=i;try{i.data=Lr.call(e,e.transformResponse,i)}finally{delete e.response}return i.headers=Ge.from(i.headers),i},function(i){if(!Ma(i)&&($r(e),i&&i.response)){e.response=i.response;try{i.response.data=Lr.call(e,e.transformResponse,i.response)}finally{delete e.response}i.response.headers=Ge.from(i.response.headers)}return Promise.reject(i)})}const gr={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{gr[e]=function(i){return typeof i===e||"a"+(t<1?"n ":" ")+e}});const Ws={};gr.transitional=function(t,n,i){function r(o,s){return"[Axios v"+Lo+"] Transitional option '"+o+"'"+s+(i?". "+i:"")}return(o,s,l)=>{if(t===!1)throw new D(r(s," has been removed"+(n?" in "+n:"")),D.ERR_DEPRECATED);return n&&!Ws[s]&&(Ws[s]=!0,console.warn(r(s," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(o,s,l):!0}};gr.spelling=function(t){return(n,i)=>(console.warn(`${i} is likely a misspelling of ${t}`),!0)};function Tg(e,t,n){if(typeof e!="object")throw new D("options must be an object",D.ERR_BAD_OPTION_VALUE);const i=Object.keys(e);let r=i.length;for(;r-- >0;){const o=i[r],s=Object.prototype.hasOwnProperty.call(t,o)?t[o]:void 0;if(s){const l=e[o],a=l===void 0||s(l,o,e);if(a!==!0)throw new D("option "+o+" must be "+a,D.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new D("Unknown option "+o,D.ERR_BAD_OPTION)}}const Ii={assertOptions:Tg,validators:gr},lt=Ii.validators;let dn=class{constructor(t){this.defaults=t||{},this.interceptors={request:new Ds,response:new Ds}}async request(t,n){try{return await this._request(t,n)}catch(i){if(i instanceof Error){let r={};Error.captureStackTrace?Error.captureStackTrace(r):r=new Error;const o=(()=>{if(!r.stack)return"";const s=r.stack.indexOf(` +`);return s===-1?"":r.stack.slice(s+1)})();try{if(!i.stack)i.stack=o;else if(o){const s=o.indexOf(` +`),l=s===-1?-1:o.indexOf(` +`,s+1),a=l===-1?"":o.slice(l+1);String(i.stack).endsWith(a)||(i.stack+=` +`+o)}}catch{}}throw i}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=gn(this.defaults,n);const{transitional:i,paramsSerializer:r,headers:o}=n;i!==void 0&&Ii.assertOptions(i,{silentJSONParsing:lt.transitional(lt.boolean),forcedJSONParsing:lt.transitional(lt.boolean),clarifyTimeoutError:lt.transitional(lt.boolean),legacyInterceptorReqResOrdering:lt.transitional(lt.boolean)},!1),r!=null&&(v.isFunction(r)?n.paramsSerializer={serialize:r}:Ii.assertOptions(r,{encode:lt.function,serialize:lt.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),Ii.assertOptions(n,{baseUrl:lt.spelling("baseURL"),withXsrfToken:lt.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let s=o&&v.merge(o.common,o[n.method]);o&&v.forEach(["delete","get","head","post","put","patch","query","common"],y=>{delete o[y]}),n.headers=Ge.concat(s,o);const l=[];let a=!0;this.interceptors.request.forEach(function(h){if(typeof h.runWhen=="function"&&h.runWhen(n)===!1)return;a=a&&h.synchronous;const _=n.transitional||ko;_&&_.legacyInterceptorReqResOrdering?l.unshift(h.fulfilled,h.rejected):l.push(h.fulfilled,h.rejected)});const c=[];this.interceptors.response.forEach(function(h){c.push(h.fulfilled,h.rejected)});let u,d=0,g;if(!a){const y=[Ks.bind(this),void 0];for(y.unshift(...l),y.push(...c),g=y.length,u=Promise.resolve(n);d{if(!i._listeners)return;let o=i._listeners.length;for(;o-- >0;)i._listeners[o](r);i._listeners=null}),this.promise.then=r=>{let o;const s=new Promise(l=>{i.subscribe(l),o=l}).then(r);return s.cancel=function(){i.unsubscribe(o)},s},t(function(o,s,l){i.reason||(i.reason=new Ai(o,s,l),n(i.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=i=>{t.abort(i)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new Ka(function(r){t=r}),cancel:t}}};function Rg(e){return function(n){return e.apply(null,n)}}function Fg(e){return v.isObject(e)&&e.isAxiosError===!0}const oo={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(oo).forEach(([e,t])=>{oo[t]=e});function Wa(e){const t=new dn(e),n=Ea(dn.prototype.request,t);return v.extend(n,dn.prototype,t,{allOwnKeys:!0}),v.extend(n,t,null,{allOwnKeys:!0}),n.create=function(r){return Wa(gn(e,r))},n}const Se=Wa(wi);Se.Axios=dn;Se.CanceledError=Ai;Se.CancelToken=Og;Se.isCancel=Ma;Se.VERSION=Lo;Se.toFormData=hr;Se.AxiosError=D;Se.Cancel=Se.CanceledError;Se.all=function(t){return Promise.all(t)};Se.spread=Rg;Se.isAxiosError=Fg;Se.mergeConfig=gn;Se.AxiosHeaders=Ge;Se.formToJSON=e=>Ua(v.isHTMLForm(e)?new FormData(e):e);Se.getAdapter=qa.getAdapter;Se.HttpStatusCode=oo;Se.default=Se;const{Axios:tv,AxiosError:nv,CanceledError:iv,isCancel:rv,CancelToken:ov,VERSION:sv,all:lv,Cancel:av,isAxiosError:cv,spread:uv,toFormData:fv,AxiosHeaders:dv,HttpStatusCode:pv,formToJSON:hv,getAdapter:gv,mergeConfig:mv,create:bv}=Se,Ya="wordformat-settings",De=rr({host:"127.0.0.1",port:8e3}),Wi=Te(()=>{const e=De.host||"127.0.0.1",t=De.port||8e3;return`http://${e}:${t}`});function Ja(){try{const e=localStorage.getItem(Ya);if(e){const t=JSON.parse(e);t.host&&(De.host=t.host),t.port!=null&&(De.port=t.port)}}catch{}}function za(){localStorage.setItem(Ya,JSON.stringify({host:De.host,port:De.port}))}function kg(){De.host="127.0.0.1",De.port=8e3,za()}const Gt=Se.create({timeout:12e4,headers:{"Content-Type":"application/json;charset=UTF-8"}});Gt.interceptors.request.use(e=>(e.baseURL=Wi.value,e.method==="get"&&(e.params={...e.params,_t:Date.now()}),e),e=>Promise.reject(e));Gt.interceptors.response.use(e=>{const t=e.data;return t.code!==void 0&&(t.code<200||t.code>=300)?Promise.reject(new Error(t.msg||"Error")):t.success===!1?Promise.reject(new Error(t.msg||"操作失败")):t},e=>{let t="请求失败";if(e.response)switch(e.response.status){case 400:t="请求错误";break;case 404:t="请求地址不存在";break;case 500:t="服务器内部错误";break;default:t=`连接错误 ${e.response.status}`}else e.request?t="网络连接异常,请检查后端服务是否启动":t=e.message;return Promise.reject(new Error(t))});class Ng{get(t,n={},i={}){return Gt({method:"get",url:t,params:n,...i})}post(t,n={},i={}){return Gt({method:"post",url:t,data:n,...i})}put(t,n={},i={}){return Gt({method:"put",url:t,data:n,...i})}patch(t,n={},i={}){return Gt({method:"patch",url:t,data:n,...i})}delete(t,n={},i={}){return Gt({method:"delete",url:t,params:n,...i})}upload(t,n,i=null){return Gt.post(t,n,{headers:{"Content-Type":"multipart/form-data"},onUploadProgress:r=>{i&&r.total&&i(Math.round(r.loaded*100/r.total))}})}}const Ir=new Ng,Lg={class:"doc-tag-check-container"},$g={class:"header-bar"},Ig={class:"header-content"},Pg={class:"header-left"},Dg={key:0,class:"stats-info"},Ug={class:"header-right"},Mg={class:"search-box"},jg=["disabled"],Bg=["disabled"],Hg=["disabled"],Vg={class:"main-content"},qg={__name:"DocTagChecker",props:{generatedConfig:{type:Object,default:null}},setup(e){const t=e,n=he(t.generatedConfig);fn(()=>t.generatedConfig,F=>{n.value=F},{deep:!0});const i=he(null),r=he(null),o=he([]),s=he(!1),l=he(!1),a=he(""),c=he(-1),u=he(""),d=he(null),g=Te(()=>c.value>=0?o.value[c.value]:null),m=Te(()=>o.value.length),y=Te(()=>o.value.filter(F=>qi(F,Ni)).length),h=Te(()=>o.value.filter(F=>F.category==="other").length),_=Te(()=>{const F=u.value.trim().toLowerCase();return F?o.value.filter(A=>A.paragraph.toLowerCase().includes(F)):o.value}),C=F=>{c.value=F},w=F=>{g.value&&(o.value[c.value].category=F)},$=async()=>{var A,H;if(!i.value)return;const F=new FormData;if(F.append("docx_file",i.value),n.value){const le=(await Fr(()=>Promise.resolve().then(()=>Mr),void 0,import.meta.url)).dump(n.value,{indent:2,skipInvalid:!0}),Z=new Blob([le],{type:"application/yaml"}),te=new File([Z],"generated-config.yaml",{type:"application/yaml"});F.append("config_file",te)}else if(r.value)F.append("config_file",r.value);else return;l.value=!0,a.value="正在解析文档并生成节点...";try{const M=await Ir.post("/generate-json",F,{timeout:3e5,headers:{"Content-Type":"multipart/form-data"}});M.data&&Array.isArray(M.data.json_data)?(o.value=M.data.json_data.map((le,Z)=>({...le,id:Z})),s.value=!0,c.value=-1):alert("❌ 后端返回数据格式异常")}catch(M){console.error("生成JSON失败:",M),alert("❌ 生成节点失败:"+(((H=(A=M.response)==null?void 0:A.data)==null?void 0:H.detail)||M.message))}finally{l.value=!1}},R=async()=>{var A,H;if(!s.value||(l.value=!0,a.value="正在执行格式校验...",!i.value))return;const F=new FormData;if(F.append("docx_file",i.value),n.value){const le=(await Fr(()=>Promise.resolve().then(()=>Mr),void 0,import.meta.url)).dump(n.value,{indent:2,skipInvalid:!0}),Z=new Blob([le],{type:"application/yaml"}),te=new File([Z],"generated-config.yaml",{type:"application/yaml"});F.append("config_file",te)}else if(r.value)F.append("config_file",r.value);else{l.value=!1;return}F.append("json_data",JSON.stringify(o.value));try{const M=await Ir.post("/check-format",F,{headers:{Accept:"application/json","Content-Type":void 0}});re(M)}catch(M){console.error("格式校验失败:",M),alert("❌ 格式校验失败:"+(((H=(A=M.response)==null?void 0:A.data)==null?void 0:H.detail)||M.message))}finally{l.value=!1}},G=async()=>{var H,M;if(!s.value||!window.confirm("此操作将根据当前标签生成新文档,是否继续?")||(l.value=!0,a.value="正在生成格式化后的文档...",!i.value))return;const A=new FormData;if(A.append("docx_file",i.value),n.value){const Z=(await Fr(()=>Promise.resolve().then(()=>Mr),void 0,import.meta.url)).dump(n.value,{indent:2,skipInvalid:!0}),te=new Blob([Z],{type:"application/yaml"}),ie=new File([te],"generated-config.yaml",{type:"application/yaml"});A.append("config_file",ie)}else if(r.value)A.append("config_file",r.value);else{l.value=!1;return}A.append("json_data",JSON.stringify(o.value));try{const le=await Ir.post("/apply-format",A,{headers:{Accept:"application/json","Content-Type":void 0}});re(le)}catch(le){console.error("格式化失败:",le),alert("❌ 文档格式化失败:"+(((M=(H=le.response)==null?void 0:H.data)==null?void 0:M.detail)||le.message))}finally{l.value=!1}};async function re(F){try{l.value=!1;const A=(F==null?void 0:F.data)??F;if(!(A!=null&&A.download_url)){alert("操作完成!");return}const{download_url:H,final_filename:M}=A,le=H.startsWith("http")?H:`${Wi.value}${H}`,Z=await fetch(le);if(!Z.ok)throw new Error(`下载失败: ${Z.status}`);const te=await Z.blob(),ie=URL.createObjectURL(te),we=document.createElement("a");we.href=ie,we.download=M||"document.docx",document.body.appendChild(we),we.click(),URL.revokeObjectURL(ie),document.body.removeChild(we)}catch(A){console.error("下载失败",A),alert("处理完成!文件下载失败:"+A.message)}}const J=()=>{if(!s.value)return;const F=o.value.map((A,H)=>({...A,idx:H})).filter(A=>qi(A,Ni)||A.category==="other");if(F.length===0)alert("✅ 所有节点标签均通过阈值校验!");else{let A=`🔍 发现 ${F.length} 个需关注的节点: + +`;A+=F.slice(0,10).map(H=>`• [${H.idx+1}] ${H.category}: ${H.paragraph.substring(0,50)}...`).join(` +`),F.length>10&&(A+=` +... 还有 ${F.length-10} 个`),alert(A)}},ne=()=>{if(!s.value)return;const F=JSON.stringify(o.value,null,2),A=new Blob([F],{type:"application/json;charset=utf-8"}),H=URL.createObjectURL(A),M=document.createElement("a");M.href=H,M.download="modified_nodes.json",document.body.appendChild(M),M.click(),URL.revokeObjectURL(H),document.body.removeChild(M)},B=()=>{var F;(F=d.value)==null||F.click()},X=async F=>{var H;const A=(H=F.target.files)==null?void 0:H[0];if(A)try{const M=await A.text(),le=JSON.parse(M);if(!Array.isArray(le)){alert("JSON 格式错误:期望一个节点数组");return}o.value=le.map((Z,te)=>({...Z,id:Z.id??te})),s.value=!0,c.value=-1,alert(`导入成功:${o.value.length} 个节点`)}catch(M){console.error("导入 JSON 失败:",M),alert("导入失败:"+M.message)}finally{F.target.value=""}};return fn(s,F=>{F||(c.value=-1)}),(F,A)=>(U(),V("div",Lg,[f("div",$g,[f("div",Ig,[f("div",Pg,[A[7]||(A[7]=f("h1",{class:"tool-title"},"文档标签核对工具",-1)),s.value?(U(),V("div",Dg,[A[3]||(A[3]=se(" 共 ",-1)),f("span",null,ee(m.value),1),A[4]||(A[4]=se(" 个节点 | 疑似错误 ",-1)),f("span",null,ee(y.value),1),A[5]||(A[5]=se(" 个 | 标记跳过 ",-1)),f("span",null,ee(h.value),1),A[6]||(A[6]=se(" 个 ",-1))])):et("",!0)]),f("div",Ug,[j(Kd,{"docx-file":i.value,"onUpdate:docxFile":A[0]||(A[0]=H=>i.value=H),"yaml-file":r.value,"onUpdate:yamlFile":A[1]||(A[1]=H=>r.value=H),"generated-config":e.generatedConfig,"is-loading":l.value,onGenerateJson:$},null,8,["docx-file","yaml-file","generated-config","is-loading"]),s.value?(U(),Nn(Gd,{key:0,"is-loading":l.value,onCheckFormat:R,onApplyFormat:G},null,8,["is-loading"])):et("",!0),f("div",Mg,[P(f("input",{type:"text","onUpdate:modelValue":A[2]||(A[2]=H=>u.value=H),placeholder:"搜索段落内容...",class:"search-input"},null,512),[[xe,u.value]]),A[8]||(A[8]=f("svg",{class:"search-icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[f("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})],-1))]),f("button",{class:"btn secondary-btn",onClick:J,disabled:!s.value||l.value}," 核对所有标签 ",8,jg),f("button",{class:"btn secondary-btn",onClick:B,disabled:!s.value||l.value}," 导入JSON ",8,Bg),f("button",{class:"btn primary-btn",onClick:ne,disabled:!s.value}," 导出JSON ",8,Hg)])])]),f("input",{ref_key:"jsonFileInput",ref:d,type:"file",accept:".json",style:{display:"none"},onChange:X},null,544),f("div",Vg,[j(gp,{"node-data":_.value,"selected-index":c.value,"is-file-loaded":s.value,"is-loading":l.value,"loading-text":a.value,"global-search-term":u.value,onSelectNode:C},null,8,["node-data","selected-index","is-file-loaded","is-loading","loading-text","global-search-term"]),j(Vp,{"current-node":g.value,"category-config":Ye(Ca),"score-threshold":Ye(Ni),"total-nodes":o.value.length,"node-index":c.value+1,onUpdateCategory:w},null,8,["current-node","category-config","score-threshold","total-nodes","node-index"])])]))}},Kg=Re(qg,[["__scopeId","data-v-e6786e76"]]);/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */function Ga(e){return typeof e>"u"||e===null}function Wg(e){return typeof e=="object"&&e!==null}function Yg(e){return Array.isArray(e)?e:Ga(e)?[]:[e]}function Jg(e,t){var n,i,r,o;if(t)for(o=Object.keys(t),n=0,i=o.length;nl&&(o=" ... ",t=i-l+o.length),n-i>l&&(s=" ...",n=i+l-s.length),{str:o+e.slice(t,n).replace(/\t/g,"→")+s,pos:i-t+o.length}}function Dr(e,t){return ke.repeat(" ",t-e.length)+e}function im(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),typeof t.indent!="number"&&(t.indent=1),typeof t.linesBefore!="number"&&(t.linesBefore=3),typeof t.linesAfter!="number"&&(t.linesAfter=2);for(var n=/\r?\n|\r|\0/g,i=[0],r=[],o,s=-1;o=n.exec(e.buffer);)r.push(o.index),i.push(o.index+o[0].length),e.position<=o.index&&s<0&&(s=i.length-2);s<0&&(s=i.length-1);var l="",a,c,u=Math.min(e.line+t.linesAfter,r.length).toString().length,d=t.maxLength-(t.indent+u+3);for(a=1;a<=t.linesBefore&&!(s-a<0);a++)c=Pr(e.buffer,i[s-a],r[s-a],e.position-(i[s]-i[s-a]),d),l=ke.repeat(" ",t.indent)+Dr((e.line-a+1).toString(),u)+" | "+c.str+` +`+l;for(c=Pr(e.buffer,i[s],r[s],e.position,d),l+=ke.repeat(" ",t.indent)+Dr((e.line+1).toString(),u)+" | "+c.str+` +`,l+=ke.repeat("-",t.indent+u+3+c.pos)+`^ +`,a=1;a<=t.linesAfter&&!(s+a>=r.length);a++)c=Pr(e.buffer,i[s+a],r[s+a],e.position-(i[s]-i[s+a]),d),l+=ke.repeat(" ",t.indent)+Dr((e.line+a+1).toString(),u)+" | "+c.str+` +`;return l.replace(/\n$/,"")}var rm=im,om=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],sm=["scalar","sequence","mapping"];function lm(e){var t={};return e!==null&&Object.keys(e).forEach(function(n){e[n].forEach(function(i){t[String(i)]=n})}),t}function am(e,t){if(t=t||{},Object.keys(t).forEach(function(n){if(om.indexOf(n)===-1)throw new ze('Unknown option "'+n+'" is met in definition of "'+e+'" YAML type.')}),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(n){return n},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=lm(t.styleAliases||null),sm.indexOf(this.kind)===-1)throw new ze('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}var Pe=am;function Ys(e,t){var n=[];return e[t].forEach(function(i){var r=n.length;n.forEach(function(o,s){o.tag===i.tag&&o.kind===i.kind&&o.multi===i.multi&&(r=s)}),n[r]=i}),n}function cm(){var e={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}},t,n;function i(r){r.multi?(e.multi[r.kind].push(r),e.multi.fallback.push(r)):e[r.kind][r.tag]=e.fallback[r.tag]=r}for(t=0,n=arguments.length;t=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),wm=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function Am(e){return!(e===null||!wm.test(e)||e[e.length-1]==="_")}function Cm(e){var t,n;return t=e.replace(/_/g,"").toLowerCase(),n=t[0]==="-"?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),t===".inf"?n===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:t===".nan"?NaN:n*parseFloat(t,10)}var Sm=/^[-+]?[0-9]+e/;function Em(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(ke.isNegativeZero(e))return"-0.0";return n=e.toString(10),Sm.test(n)?n.replace("e",".e"):n}function Tm(e){return Object.prototype.toString.call(e)==="[object Number]"&&(e%1!==0||ke.isNegativeZero(e))}var sc=new Pe("tag:yaml.org,2002:float",{kind:"scalar",resolve:Am,construct:Cm,predicate:Tm,represent:Em,defaultStyle:"lowercase"}),lc=nc.extend({implicit:[ic,rc,oc,sc]}),ac=lc,cc=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),uc=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function Om(e){return e===null?!1:cc.exec(e)!==null||uc.exec(e)!==null}function Rm(e){var t,n,i,r,o,s,l,a=0,c=null,u,d,g;if(t=cc.exec(e),t===null&&(t=uc.exec(e)),t===null)throw new Error("Date resolve error");if(n=+t[1],i=+t[2]-1,r=+t[3],!t[4])return new Date(Date.UTC(n,i,r));if(o=+t[4],s=+t[5],l=+t[6],t[7]){for(a=t[7].slice(0,3);a.length<3;)a+="0";a=+a}return t[9]&&(u=+t[10],d=+(t[11]||0),c=(u*60+d)*6e4,t[9]==="-"&&(c=-c)),g=new Date(Date.UTC(n,i,r,o,s,l,a)),c&&g.setTime(g.getTime()-c),g}function Fm(e){return e.toISOString()}var fc=new Pe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:Om,construct:Rm,instanceOf:Date,represent:Fm});function km(e){return e==="<<"||e===null}var dc=new Pe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:km}),Io=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= +\r`;function Nm(e){if(e===null)return!1;var t,n,i=0,r=e.length,o=Io;for(n=0;n64)){if(t<0)return!1;i+=6}return i%8===0}function Lm(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=Io,s=0,l=[];for(t=0;t>16&255),l.push(s>>8&255),l.push(s&255)),s=s<<6|o.indexOf(i.charAt(t));return n=r%4*6,n===0?(l.push(s>>16&255),l.push(s>>8&255),l.push(s&255)):n===18?(l.push(s>>10&255),l.push(s>>2&255)):n===12&&l.push(s>>4&255),new Uint8Array(l)}function $m(e){var t="",n=0,i,r,o=e.length,s=Io;for(i=0;i>18&63],t+=s[n>>12&63],t+=s[n>>6&63],t+=s[n&63]),n=(n<<8)+e[i];return r=o%3,r===0?(t+=s[n>>18&63],t+=s[n>>12&63],t+=s[n>>6&63],t+=s[n&63]):r===2?(t+=s[n>>10&63],t+=s[n>>4&63],t+=s[n<<2&63],t+=s[64]):r===1&&(t+=s[n>>2&63],t+=s[n<<4&63],t+=s[64],t+=s[64]),t}function Im(e){return Object.prototype.toString.call(e)==="[object Uint8Array]"}var pc=new Pe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:Nm,construct:Lm,predicate:Im,represent:$m}),Pm=Object.prototype.hasOwnProperty,Dm=Object.prototype.toString;function Um(e){if(e===null)return!0;var t=[],n,i,r,o,s,l=e;for(n=0,i=l.length;n>10)+55296,(e-65536&1023)+56320)}function xc(e,t,n){t==="__proto__"?Object.defineProperty(e,t,{configurable:!0,enumerable:!0,writable:!0,value:n}):e[t]=n}var wc=new Array(256),Ac=new Array(256);for(var vn=0;vn<256;vn++)wc[vn]=Gs(vn)?1:0,Ac[vn]=Gs(vn);function e0(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||Po,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function Cc(e,t){var n={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return n.snippet=rm(n),new ze(t,n)}function q(e,t){throw Cc(e,t)}function zi(e,t){e.onWarning&&e.onWarning.call(null,Cc(e,t))}var Xs={YAML:function(t,n,i){var r,o,s;t.version!==null&&q(t,"duplication of %YAML directive"),i.length!==1&&q(t,"YAML directive accepts exactly one argument"),r=/^([0-9]+)\.([0-9]+)$/.exec(i[0]),r===null&&q(t,"ill-formed argument of the YAML directive"),o=parseInt(r[1],10),s=parseInt(r[2],10),o!==1&&q(t,"unacceptable YAML version of the document"),t.version=i[0],t.checkLineBreaks=s<2,s!==1&&s!==2&&zi(t,"unsupported YAML version of the document")},TAG:function(t,n,i){var r,o;i.length!==2&&q(t,"TAG directive accepts exactly two arguments"),r=i[0],o=i[1],vc.test(r)||q(t,"ill-formed tag handle (first argument) of the TAG directive"),en.call(t.tagMap,r)&&q(t,'there is a previously declared suffix for "'+r+'" tag handle'),_c.test(o)||q(t,"ill-formed tag prefix (second argument) of the TAG directive");try{o=decodeURIComponent(o)}catch{q(t,"tag prefix is malformed: "+o)}t.tagMap[r]=o}};function Zt(e,t,n,i){var r,o,s,l;if(t1&&(e.result+=ke.repeat(` +`,t-1))}function t0(e,t,n){var i,r,o,s,l,a,c,u,d=e.kind,g=e.result,m;if(m=e.input.charCodeAt(e.position),Qe(m)||An(m)||m===35||m===38||m===42||m===33||m===124||m===62||m===39||m===34||m===37||m===64||m===96||(m===63||m===45)&&(r=e.input.charCodeAt(e.position+1),Qe(r)||n&&An(r)))return!1;for(e.kind="scalar",e.result="",o=s=e.position,l=!1;m!==0;){if(m===58){if(r=e.input.charCodeAt(e.position+1),Qe(r)||n&&An(r))break}else if(m===35){if(i=e.input.charCodeAt(e.position-1),Qe(i))break}else{if(e.position===e.lineStart&&mr(e)||n&&An(m))break;if(Rt(m))if(a=e.line,c=e.lineStart,u=e.lineIndent,Oe(e,!1,-1),e.lineIndent>=t){l=!0,m=e.input.charCodeAt(e.position);continue}else{e.position=s,e.line=a,e.lineStart=c,e.lineIndent=u;break}}l&&(Zt(e,o,s,!1),Uo(e,e.line-a),o=s=e.position,l=!1),pn(m)||(s=e.position+1),m=e.input.charCodeAt(++e.position)}return Zt(e,o,s,!1),e.result?!0:(e.kind=d,e.result=g,!1)}function n0(e,t){var n,i,r;if(n=e.input.charCodeAt(e.position),n!==39)return!1;for(e.kind="scalar",e.result="",e.position++,i=r=e.position;(n=e.input.charCodeAt(e.position))!==0;)if(n===39)if(Zt(e,i,e.position,!0),n=e.input.charCodeAt(++e.position),n===39)i=e.position,e.position++,r=e.position;else return!0;else Rt(n)?(Zt(e,i,r,!0),Uo(e,Oe(e,!1,t)),i=r=e.position):e.position===e.lineStart&&mr(e)?q(e,"unexpected end of the document within a single quoted scalar"):(e.position++,r=e.position);q(e,"unexpected end of the stream within a single quoted scalar")}function i0(e,t){var n,i,r,o,s,l;if(l=e.input.charCodeAt(e.position),l!==34)return!1;for(e.kind="scalar",e.result="",e.position++,n=i=e.position;(l=e.input.charCodeAt(e.position))!==0;){if(l===34)return Zt(e,n,e.position,!0),e.position++,!0;if(l===92){if(Zt(e,n,e.position,!0),l=e.input.charCodeAt(++e.position),Rt(l))Oe(e,!1,t);else if(l<256&&wc[l])e.result+=Ac[l],e.position++;else if((s=Xm(l))>0){for(r=s,o=0;r>0;r--)l=e.input.charCodeAt(++e.position),(s=Gm(l))>=0?o=(o<<4)+s:q(e,"expected hexadecimal character");e.result+=Zm(o),e.position++}else q(e,"unknown escape sequence");n=i=e.position}else Rt(l)?(Zt(e,n,i,!0),Uo(e,Oe(e,!1,t)),n=i=e.position):e.position===e.lineStart&&mr(e)?q(e,"unexpected end of the document within a double quoted scalar"):(e.position++,i=e.position)}q(e,"unexpected end of the stream within a double quoted scalar")}function r0(e,t){var n=!0,i,r,o,s=e.tag,l,a=e.anchor,c,u,d,g,m,y=Object.create(null),h,_,C,w;if(w=e.input.charCodeAt(e.position),w===91)u=93,m=!1,l=[];else if(w===123)u=125,m=!0,l={};else return!1;for(e.anchor!==null&&(e.anchorMap[e.anchor]=l),w=e.input.charCodeAt(++e.position);w!==0;){if(Oe(e,!0,t),w=e.input.charCodeAt(e.position),w===u)return e.position++,e.tag=s,e.anchor=a,e.kind=m?"mapping":"sequence",e.result=l,!0;n?w===44&&q(e,"expected the node content, but found ','"):q(e,"missed comma between flow collection entries"),_=h=C=null,d=g=!1,w===63&&(c=e.input.charCodeAt(e.position+1),Qe(c)&&(d=g=!0,e.position++,Oe(e,!0,t))),i=e.line,r=e.lineStart,o=e.position,Pn(e,t,Yi,!1,!0),_=e.tag,h=e.result,Oe(e,!0,t),w=e.input.charCodeAt(e.position),(g||e.line===i)&&w===58&&(d=!0,w=e.input.charCodeAt(++e.position),Oe(e,!0,t),Pn(e,t,Yi,!1,!0),C=e.result),m?Cn(e,l,y,_,h,C,i,r,o):d?l.push(Cn(e,null,y,_,h,C,i,r,o)):l.push(h),Oe(e,!0,t),w=e.input.charCodeAt(e.position),w===44?(n=!0,w=e.input.charCodeAt(++e.position)):n=!1}q(e,"unexpected end of the stream within a flow collection")}function o0(e,t){var n,i,r=Ur,o=!1,s=!1,l=t,a=0,c=!1,u,d;if(d=e.input.charCodeAt(e.position),d===124)i=!1;else if(d===62)i=!0;else return!1;for(e.kind="scalar",e.result="";d!==0;)if(d=e.input.charCodeAt(++e.position),d===43||d===45)Ur===r?r=d===43?Js:Wm:q(e,"repeat of a chomping mode identifier");else if((u=Qm(d))>=0)u===0?q(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):s?q(e,"repeat of an indentation width identifier"):(l=t+u-1,s=!0);else break;if(pn(d)){do d=e.input.charCodeAt(++e.position);while(pn(d));if(d===35)do d=e.input.charCodeAt(++e.position);while(!Rt(d)&&d!==0)}for(;d!==0;){for(Do(e),e.lineIndent=0,d=e.input.charCodeAt(e.position);(!s||e.lineIndentl&&(l=e.lineIndent),Rt(d)){a++;continue}if(e.lineIndentt)&&a!==0)q(e,"bad indentation of a sequence entry");else if(e.lineIndentt)&&(_&&(s=e.line,l=e.lineStart,a=e.position),Pn(e,t,Ji,!0,r)&&(_?y=e.result:h=e.result),_||(Cn(e,d,g,m,y,h,s,l,a),m=y=h=null),Oe(e,!0,-1),w=e.input.charCodeAt(e.position)),(e.line===o||e.lineIndent>t)&&w!==0)q(e,"bad indentation of a mapping entry");else if(e.lineIndentt?a=1:e.lineIndent===t?a=0:e.lineIndentt?a=1:e.lineIndent===t?a=0:e.lineIndent tag; it should be "scalar", not "'+e.kind+'"'),d=0,g=e.implicitTypes.length;d"),e.result!==null&&y.kind!==e.kind&&q(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+y.kind+'", not "'+e.kind+'"'),y.resolve(e.result,e.tag)?(e.result=y.construct(e.result,e.tag),e.anchor!==null&&(e.anchorMap[e.anchor]=e.result)):q(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return e.listener!==null&&e.listener("close",e),e.tag!==null||e.anchor!==null||u}function u0(e){var t=e.position,n,i,r,o=!1,s;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);(s=e.input.charCodeAt(e.position))!==0&&(Oe(e,!0,-1),s=e.input.charCodeAt(e.position),!(e.lineIndent>0||s!==37));){for(o=!0,s=e.input.charCodeAt(++e.position),n=e.position;s!==0&&!Qe(s);)s=e.input.charCodeAt(++e.position);for(i=e.input.slice(n,e.position),r=[],i.length<1&&q(e,"directive name must not be less than one character in length");s!==0;){for(;pn(s);)s=e.input.charCodeAt(++e.position);if(s===35){do s=e.input.charCodeAt(++e.position);while(s!==0&&!Rt(s));break}if(Rt(s))break;for(n=e.position;s!==0&&!Qe(s);)s=e.input.charCodeAt(++e.position);r.push(e.input.slice(n,e.position))}s!==0&&Do(e),en.call(Xs,i)?Xs[i](e,i,r):zi(e,'unknown document directive "'+i+'"')}if(Oe(e,!0,-1),e.lineIndent===0&&e.input.charCodeAt(e.position)===45&&e.input.charCodeAt(e.position+1)===45&&e.input.charCodeAt(e.position+2)===45?(e.position+=3,Oe(e,!0,-1)):o&&q(e,"directives end mark is expected"),Pn(e,e.lineIndent-1,Ji,!1,!0),Oe(e,!0,-1),e.checkLineBreaks&&Jm.test(e.input.slice(t,e.position))&&zi(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&mr(e)){e.input.charCodeAt(e.position)===46&&(e.position+=3,Oe(e,!0,-1));return}if(e.position"u"&&(n=t,t=null);var i=Sc(e,n);if(typeof t!="function")return i;for(var r=0,o=i.length;r=55296&&n<=56319&&t+1=56320&&i<=57343)?(n-55296)*1024+i-56320+65536:n}function $c(e){var t=/^\n* /;return t.test(e)}var Ic=1,co=2,Pc=3,Dc=4,wn=5;function j0(e,t,n,i,r,o,s,l){var a,c=0,u=null,d=!1,g=!1,m=i!==-1,y=-1,h=U0(Xn(e,0))&&M0(Xn(e,e.length-1));if(t||s)for(a=0;a=65536?a+=2:a++){if(c=Xn(e,a),!hi(c))return wn;h=h&&nl(c,u,l),u=c}else{for(a=0;a=65536?a+=2:a++){if(c=Xn(e,a),c===di)d=!0,m&&(g=g||a-y-1>i&&e[y+1]!==" ",y=a);else if(!hi(c))return wn;h=h&&nl(c,u,l),u=c}g=g||m&&a-y-1>i&&e[y+1]!==" "}return!d&&!g?h&&!s&&!r(e)?Ic:o===pi?wn:co:n>9&&$c(e)?wn:s?o===pi?wn:co:g?Dc:Pc}function B0(e,t,n,i,r){e.dump=(function(){if(t.length===0)return e.quotingType===pi?'""':"''";if(!e.noCompatMode&&(k0.indexOf(t)!==-1||N0.test(t)))return e.quotingType===pi?'"'+t+'"':"'"+t+"'";var o=e.indent*Math.max(1,n),s=e.lineWidth===-1?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o),l=i||e.flowLevel>-1&&n>=e.flowLevel;function a(c){return D0(e,c)}switch(j0(t,l,e.indent,s,a,e.quotingType,e.forceQuotes&&!i,r)){case Ic:return t;case co:return"'"+t.replace(/'/g,"''")+"'";case Pc:return"|"+il(t,e.indent)+rl(el(t,o));case Dc:return">"+il(t,e.indent)+rl(el(H0(t,s),o));case wn:return'"'+V0(t)+'"';default:throw new ze("impossible error: invalid scalar style")}})()}function il(e,t){var n=$c(e)?String(t):"",i=e[e.length-1]===` +`,r=i&&(e[e.length-2]===` +`||e===` +`),o=r?"+":i?"":"-";return n+o+` +`}function rl(e){return e[e.length-1]===` +`?e.slice(0,-1):e}function H0(e,t){for(var n=/(\n+)([^\n]*)/g,i=(function(){var c=e.indexOf(` +`);return c=c!==-1?c:e.length,n.lastIndex=c,ol(e.slice(0,c),t)})(),r=e[0]===` +`||e[0]===" ",o,s;s=n.exec(e);){var l=s[1],a=s[2];o=a[0]===" ",i+=l+(!r&&!o&&a!==""?` +`:"")+ol(a,t),r=o}return i}function ol(e,t){if(e===""||e[0]===" ")return e;for(var n=/ [^ ]/g,i,r=0,o,s=0,l=0,a="";i=n.exec(e);)l=i.index,l-r>t&&(o=s>r?s:l,a+=` +`+e.slice(r,o),r=o+1),s=l;return a+=` +`,e.length-r>t&&s>r?a+=e.slice(r,s)+` +`+e.slice(s+1):a+=e.slice(r),a.slice(1)}function V0(e){for(var t="",n=0,i,r=0;r=65536?r+=2:r++)n=Xn(e,r),i=He[n],!i&&hi(n)?(t+=e[r],n>=65536&&(t+=e[r+1])):t+=i||$0(n);return t}function q0(e,t,n){var i="",r=e.tag,o,s,l;for(o=0,s=n.length;o"u"&&Vt(e,t,null,!1,!1))&&(i!==""&&(i+=","+(e.condenseFlow?"":" ")),i+=e.dump);e.tag=r,e.dump="["+i+"]"}function sl(e,t,n,i){var r="",o=e.tag,s,l,a;for(s=0,l=n.length;s"u"&&Vt(e,t+1,null,!0,!0,!1,!0))&&((!i||r!=="")&&(r+=ao(e,t)),e.dump&&di===e.dump.charCodeAt(0)?r+="-":r+="- ",r+=e.dump);e.tag=o,e.dump=r||"[]"}function K0(e,t,n){var i="",r=e.tag,o=Object.keys(n),s,l,a,c,u;for(s=0,l=o.length;s1024&&(u+="? "),u+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Vt(e,t,c,!1,!1)&&(u+=e.dump,i+=u));e.tag=r,e.dump="{"+i+"}"}function W0(e,t,n,i){var r="",o=e.tag,s=Object.keys(n),l,a,c,u,d,g;if(e.sortKeys===!0)s.sort();else if(typeof e.sortKeys=="function")s.sort(e.sortKeys);else if(e.sortKeys)throw new ze("sortKeys must be a boolean or a function");for(l=0,a=s.length;l1024,d&&(e.dump&&di===e.dump.charCodeAt(0)?g+="?":g+="? "),g+=e.dump,d&&(g+=ao(e,t)),Vt(e,t+1,u,!0,d)&&(e.dump&&di===e.dump.charCodeAt(0)?g+=":":g+=": ",g+=e.dump,r+=g));e.tag=o,e.dump=r||"{}"}function ll(e,t,n){var i,r,o,s,l,a;for(r=n?e.explicitTypes:e.implicitTypes,o=0,s=r.length;o tag resolver accepts not "'+a+'" style');e.dump=i}return!0}return!1}function Vt(e,t,n,i,r,o,s){e.tag=null,e.dump=n,ll(e,n,!1)||ll(e,n,!0);var l=Tc.call(e.dump),a=i,c;i&&(i=e.flowLevel<0||e.flowLevel>t);var u=l==="[object Object]"||l==="[object Array]",d,g;if(u&&(d=e.duplicates.indexOf(n),g=d!==-1),(e.tag!==null&&e.tag!=="?"||g||e.indent!==2&&t>0)&&(r=!1),g&&e.usedDuplicates[d])e.dump="*ref_"+d;else{if(u&&g&&!e.usedDuplicates[d]&&(e.usedDuplicates[d]=!0),l==="[object Object]")i&&Object.keys(e.dump).length!==0?(W0(e,t,e.dump,r),g&&(e.dump="&ref_"+d+e.dump)):(K0(e,t,e.dump),g&&(e.dump="&ref_"+d+" "+e.dump));else if(l==="[object Array]")i&&e.dump.length!==0?(e.noArrayIndent&&!s&&t>0?sl(e,t-1,e.dump,r):sl(e,t,e.dump,r),g&&(e.dump="&ref_"+d+e.dump)):(q0(e,t,e.dump),g&&(e.dump="&ref_"+d+" "+e.dump));else if(l==="[object String]")e.tag!=="?"&&B0(e,e.dump,t,o,a);else{if(l==="[object Undefined]")return!1;if(e.skipInvalid)return!1;throw new ze("unacceptable kind of an object to dump "+l)}e.tag!==null&&e.tag!=="?"&&(c=encodeURI(e.tag[0]==="!"?e.tag.slice(1):e.tag).replace(/!/g,"%21"),e.tag[0]==="!"?c="!"+c:c.slice(0,18)==="tag:yaml.org,2002:"?c="!!"+c.slice(18):c="!<"+c+">",e.dump=c+" "+e.dump)}return!0}function Y0(e,t){var n=[],i=[],r,o;for(uo(e,n,i),r=0,o=i.length;r({...Qc,...e}),Qt={template_name:"未知模板",style_checks_warning:{bold:!0,italic:!1,underline:!1,font_size:!0,font_name:!0,font_color:!1,alignment:!0,space_before:!0,space_after:!0,line_spacing:!0,line_spacingrule:!0,left_indent:!0,right_indent:!0,first_line_indent:!0,builtin_style_name:!0},global_format:{...Qc},abstract:{chinese:{chinese_title:Ce({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"四号"}),chinese_content:Ce({alignment:"两端对齐"})},english:{english_title:Ce({alignment:"居中对齐",first_line_indent:"0字符",font_size:"四号",bold:!1}),english_content:Ce({alignment:"两端对齐"})},keywords:{chinese:Ce({alignment:"两端对齐",first_line_indent:"2字符",font_size:"小四",label:Ce({chinese_font_name:"黑体",font_size:"四号",bold:!1}),rules:{keyword_count:{enabled:!0,count_min:3,count_max:5},trailing_punctuation:{enabled:!0,forbidden_chars:";,。、"}}}),english:Ce({alignment:"两端对齐",first_line_indent:"2字符",font_size:"小四",label:Ce({font_size:"四号",bold:!1}),rules:{keyword_count:{enabled:!0,count_min:3,count_max:5}}})}},headings:{level_1:Ce({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"小二",space_before:"0.5行",space_after:"0.5行",builtin_style_name:"Heading 1"}),level_2:Ce({alignment:"左对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"三号",space_before:"0行",space_after:"0行",builtin_style_name:"Heading 2"}),level_3:Ce({alignment:"左对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"小四",space_before:"0行",space_after:"0行",builtin_style_name:"Heading 3"})},body_text:Ce({rules:{punctuation:{enabled:!0}}}),figures:Ce({alignment:"居中对齐",first_line_indent:"0字符",font_size:"五号",builtin_style_name:"题注",caption_prefix:"图",image:Ce({alignment:"居中对齐",first_line_indent:"0字符"}),rules:{caption_numbering:{enabled:!0,separator:".",label_number_space:!1}}}),tables:Ce({alignment:"居中对齐",first_line_indent:"0字符",font_size:"五号",builtin_style_name:"题注",caption_prefix:"表",object:Ce({alignment:"居中对齐",first_line_indent:"0字符"}),content:Ce({chinese_font_name:"宋体",english_font_name:"Times New Roman",font_size:"五号",line_spacingrule:"单倍行距",alignment:"居中对齐",first_line_indent:"0字符",space_before:"0行",space_after:"0行"}),rules:{caption_numbering:{enabled:!0,separator:".",label_number_space:!1}}}),references:{title:Ce({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"三号"}),content:Ce({alignment:"两端对齐",first_line_indent:"-2.2字符",left_indent:"0.26字符",chinese_font_name:"宋体",font_size:"五号"})},acknowledgements:{title:Ce({alignment:"居中对齐",first_line_indent:"0字符",chinese_font_name:"黑体",font_size:"小二"}),content:Ce({alignment:"两端对齐",font_size:"五号"})},numbering:{enabled:!0,level_1:{enabled:!0,template:"%1",suffix:"space"},level_2:{enabled:!0,template:"%1.%2",suffix:"space"},level_3:{enabled:!0,template:"%1.%2.%3",suffix:"space"},references:{enabled:!0,template:"[%1]",suffix:"space"},captions:{enabled:!1,separator:".",label_number_space:!1}}},X0=["左对齐","居中对齐","右对齐","两端对齐","分散对齐"],Q0=["单倍行距","1.5倍行距","2倍行距","最小值","固定值","多倍行距"],Z0=["宋体","黑体","楷体","仿宋","微软雅黑","汉仪小标宋"],eb=["Times New Roman","Arial","Calibri","Courier New","Helvetica"],tb=["一号","小一","二号","小二","三号","小三","四号","小四","五号","小五","六号","七号"],gi=(e,t)=>{const n={...e};for(const i of Object.keys(t))i in n?typeof t[i]=="object"&&t[i]!==null&&!Array.isArray(t[i])&&(n[i]=gi(n[i],t[i])):n[i]=JSON.parse(JSON.stringify(t[i]));return n},nb=e=>{e.abstract.chinese.chinese_title={...e.global_format},e.abstract.chinese.chinese_content={...e.global_format},e.abstract.english.english_title={...e.global_format},e.abstract.english.english_content={...e.global_format},e.abstract.keywords.english={...e.global_format,label:e.abstract.keywords.english.label,count_min:e.abstract.keywords.english.count_min,count_max:e.abstract.keywords.english.count_max,trailing_punct_forbidden:e.abstract.keywords.english.trailing_punct_forbidden},e.abstract.keywords.chinese={...e.global_format,label:e.abstract.keywords.chinese.label,count_min:e.abstract.keywords.chinese.count_min,count_max:e.abstract.keywords.chinese.count_max,trailing_punct_forbidden:e.abstract.keywords.chinese.trailing_punct_forbidden},e.headings.level_1={...e.global_format},e.headings.level_2={...e.global_format},e.headings.level_3={...e.global_format},e.body_text={...e.global_format},e.figures={...e.global_format,caption_prefix:e.figures.caption_prefix},e.tables={...e.global_format,caption_prefix:e.tables.caption_prefix,content:e.tables.content},e.references.title={...e.global_format},e.references.content={...e.global_format},e.acknowledgements.title={...e.global_format},e.acknowledgements.content={...e.global_format}},ib={class:"config-section"},rb={key:0,class:"section-content"},ob={__name:"ConfigSection",props:{title:{type:String,required:!0},initialExpanded:{type:Boolean,default:!0}},setup(e){const n=he(e.initialExpanded),i=()=>{n.value=!n.value};return(r,o)=>(U(),V("div",ib,[f("div",{class:"section-header",onClick:i},[f("h2",null,ee(e.title),1),(U(),V("svg",{class:ye(["toggle-arrow",{expanded:n.value}]),width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[...o[0]||(o[0]=[f("polyline",{points:"6 9 12 15 18 9"},null,-1)])],2))]),n.value?(U(),V("div",rb,[df(r.$slots,"default",{},void 0)])):et("",!0)]))}},ct=Re(ob,[["__scopeId","data-v-88bb2378"]]),sb={class:"warning-fields-config"},lb={class:"select-all-bar"},ab={class:"select-all-label"},cb=["checked"],ub={class:"grid grid-cols-3 gap-2"},fb={class:"form-item"},db={class:"form-item"},pb={class:"form-item"},hb={class:"form-item"},gb={class:"form-item"},mb={class:"form-item"},bb={class:"form-item"},yb={class:"form-item"},vb={class:"form-item"},_b={class:"form-item"},xb={class:"form-item"},wb={class:"form-item"},Ab={class:"form-item"},Cb={class:"form-item"},Sb={class:"form-item"},Eb={__name:"WarningFieldsConfig",props:{config:{type:Object,required:!0}},setup(e){const t=e,n=["bold","italic","underline","font_size","font_name","font_color","alignment","space_before","space_after","line_spacing","line_spacingrule","left_indent","right_indent","first_line_indent","builtin_style_name"],i=Te(()=>n.every(o=>t.config[o]));function r(){const o=!i.value;n.forEach(s=>{t.config[s]=o})}return(o,s)=>(U(),V("div",sb,[f("div",lb,[f("label",ab,[f("input",{type:"checkbox",checked:i.value,onChange:r},null,40,cb),f("span",null,ee(i.value?"取消全选":"全选"),1)])]),f("div",ub,[f("div",fb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[0]||(s[0]=l=>e.config.bold=l)},null,512),[[ue,e.config.bold]]),s[15]||(s[15]=se(" 加粗",-1))])]),f("div",db,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[1]||(s[1]=l=>e.config.italic=l)},null,512),[[ue,e.config.italic]]),s[16]||(s[16]=se(" 斜体",-1))])]),f("div",pb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[2]||(s[2]=l=>e.config.underline=l)},null,512),[[ue,e.config.underline]]),s[17]||(s[17]=se(" 下划线",-1))])]),f("div",hb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[3]||(s[3]=l=>e.config.font_size=l)},null,512),[[ue,e.config.font_size]]),s[18]||(s[18]=se(" 字号",-1))])]),f("div",gb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[4]||(s[4]=l=>e.config.font_name=l)},null,512),[[ue,e.config.font_name]]),s[19]||(s[19]=se(" 字体名称",-1))])]),f("div",mb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[5]||(s[5]=l=>e.config.font_color=l)},null,512),[[ue,e.config.font_color]]),s[20]||(s[20]=se(" 字体颜色",-1))])]),f("div",bb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[6]||(s[6]=l=>e.config.alignment=l)},null,512),[[ue,e.config.alignment]]),s[21]||(s[21]=se(" 对齐方式",-1))])]),f("div",yb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[7]||(s[7]=l=>e.config.space_before=l)},null,512),[[ue,e.config.space_before]]),s[22]||(s[22]=se(" 段前间距",-1))])]),f("div",vb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[8]||(s[8]=l=>e.config.space_after=l)},null,512),[[ue,e.config.space_after]]),s[23]||(s[23]=se(" 段后间距",-1))])]),f("div",_b,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[9]||(s[9]=l=>e.config.line_spacing=l)},null,512),[[ue,e.config.line_spacing]]),s[24]||(s[24]=se(" 行距",-1))])]),f("div",xb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[10]||(s[10]=l=>e.config.line_spacingrule=l)},null,512),[[ue,e.config.line_spacingrule]]),s[25]||(s[25]=se(" 行距类型",-1))])]),f("div",wb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[11]||(s[11]=l=>e.config.left_indent=l)},null,512),[[ue,e.config.left_indent]]),s[26]||(s[26]=se(" 文本之前",-1))])]),f("div",Ab,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[12]||(s[12]=l=>e.config.right_indent=l)},null,512),[[ue,e.config.right_indent]]),s[27]||(s[27]=se(" 文本之后",-1))])]),f("div",Cb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[13]||(s[13]=l=>e.config.first_line_indent=l)},null,512),[[ue,e.config.first_line_indent]]),s[28]||(s[28]=se(" 段落首行缩进",-1))])]),f("div",Sb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":s[14]||(s[14]=l=>e.config.builtin_style_name=l)},null,512),[[ue,e.config.builtin_style_name]]),s[29]||(s[29]=se(" 内置样式名称",-1))])])])]))}},Tb=Re(Eb,[["__scopeId","data-v-315bca75"]]),Ob={class:"format-config"},Rb={class:"grid grid-cols-2 gap-4"},Fb={class:"form-item"},kb=["value"],Nb={class:"form-item"},Lb={class:"form-item"},$b={class:"form-item"},Ib=["value"],Pb={class:"form-item"},Db={class:"form-item"},Ub={class:"form-item"},Mb={class:"form-item"},jb={class:"form-item"},Bb={class:"form-item"},Hb=["value"],Vb={class:"form-item"},qb=["value"],Kb={class:"form-item"},Wb=["value"],Yb={class:"form-item"},Jb={class:"form-item"},zb={class:"form-item"},Gb={class:"form-item"},Xb={__name:"FormatConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",Ob,[f("div",Rb,[f("div",Fb,[n[16]||(n[16]=f("label",null,"对齐方式:",-1)),P(f("select",{"onUpdate:modelValue":n[0]||(n[0]=i=>e.config.alignment=i)},[(U(!0),V(ve,null,Ut(Ye(X0),i=>(U(),V("option",{key:i,value:i},ee(i),9,kb))),128))],512),[[Tt,e.config.alignment]])]),f("div",Nb,[n[17]||(n[17]=f("label",null,"段前间距:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.space_before=i)},null,512),[[xe,e.config.space_before]])]),f("div",Lb,[n[18]||(n[18]=f("label",null,"段后间距:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[2]||(n[2]=i=>e.config.space_after=i)},null,512),[[xe,e.config.space_after]])]),f("div",$b,[n[19]||(n[19]=f("label",null,"行距类型:",-1)),P(f("select",{"onUpdate:modelValue":n[3]||(n[3]=i=>e.config.line_spacingrule=i)},[(U(!0),V(ve,null,Ut(Ye(Q0),i=>(U(),V("option",{key:i,value:i},ee(i),9,Ib))),128))],512),[[Tt,e.config.line_spacingrule]])]),f("div",Pb,[n[20]||(n[20]=f("label",null,"行距参数:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[4]||(n[4]=i=>e.config.line_spacing=i)},null,512),[[xe,e.config.line_spacing]])]),f("div",Db,[n[21]||(n[21]=f("label",null,"文本之前:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[5]||(n[5]=i=>e.config.left_indent=i)},null,512),[[xe,e.config.left_indent]])]),f("div",Ub,[n[22]||(n[22]=f("label",null,"文本之后:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[6]||(n[6]=i=>e.config.right_indent=i)},null,512),[[xe,e.config.right_indent]])]),f("div",Mb,[n[23]||(n[23]=f("label",null,"段落首行缩进:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[7]||(n[7]=i=>e.config.first_line_indent=i)},null,512),[[xe,e.config.first_line_indent]])]),f("div",jb,[n[24]||(n[24]=f("label",null,"内置样式名称:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[8]||(n[8]=i=>e.config.builtin_style_name=i)},null,512),[[xe,e.config.builtin_style_name]])]),f("div",Bb,[n[25]||(n[25]=f("label",null,"中文字体名称:",-1)),P(f("select",{"onUpdate:modelValue":n[9]||(n[9]=i=>e.config.chinese_font_name=i)},[(U(!0),V(ve,null,Ut(Ye(Z0),i=>(U(),V("option",{key:i,value:i},ee(i),9,Hb))),128))],512),[[Tt,e.config.chinese_font_name]])]),f("div",Vb,[n[26]||(n[26]=f("label",null,"英文字体名称:",-1)),P(f("select",{"onUpdate:modelValue":n[10]||(n[10]=i=>e.config.english_font_name=i)},[(U(!0),V(ve,null,Ut(Ye(eb),i=>(U(),V("option",{key:i,value:i},ee(i),9,qb))),128))],512),[[Tt,e.config.english_font_name]])]),f("div",Kb,[n[27]||(n[27]=f("label",null,"字号:",-1)),P(f("select",{"onUpdate:modelValue":n[11]||(n[11]=i=>e.config.font_size=i)},[(U(!0),V(ve,null,Ut(Ye(tb),i=>(U(),V("option",{key:i,value:i},ee(i),9,Wb))),128))],512),[[Tt,e.config.font_size]])]),f("div",Yb,[n[28]||(n[28]=f("label",null,"字体颜色:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[12]||(n[12]=i=>e.config.font_color=i)},null,512),[[xe,e.config.font_color]])]),f("div",Jb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[13]||(n[13]=i=>e.config.bold=i)},null,512),[[ue,e.config.bold]]),n[29]||(n[29]=se(" 加粗",-1))])]),f("div",zb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[14]||(n[14]=i=>e.config.italic=i)},null,512),[[ue,e.config.italic]]),n[30]||(n[30]=se(" 斜体",-1))])]),f("div",Gb,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[15]||(n[15]=i=>e.config.underline=i)},null,512),[[ue,e.config.underline]]),n[31]||(n[31]=se(" 下划线",-1))])])])]))}},Ae=Re(Xb,[["__scopeId","data-v-5177a808"]]),Qb={class:"global-format-config"},Zb={key:0,class:"mt-4"},ey={__name:"GlobalFormatConfig",props:{config:{type:Object,required:!0},showApplyButton:{type:Boolean,default:!1}},emits:["apply-to-all"],setup(e){return(t,n)=>(U(),V("div",Qb,[j(Ae,{config:e.config},null,8,["config"]),e.showApplyButton?(U(),V("div",Zb,[f("button",{onClick:n[0]||(n[0]=i=>t.$emit("apply-to-all")),class:"btn btn-green"},"应用到所有配置")])):et("",!0)]))}},ty=Re(ey,[["__scopeId","data-v-98ee8f2a"]]),ny={class:"abstract-config"},iy={class:"grid grid-cols-2 gap-4 mb-4"},ry={class:"form-item"},oy={class:"form-item"},sy={class:"form-item"},ly={class:"form-item"},ay={class:"grid grid-cols-2 gap-4 mb-4"},cy={class:"form-item"},uy={class:"form-item"},fy={class:"form-item"},dy={__name:"AbstractConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",ny,[n[14]||(n[14]=f("h3",null,"中文摘要",-1)),n[15]||(n[15]=f("h4",null,"中文标题",-1)),n[16]||(n[16]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),j(Ae,{config:e.config.chinese.chinese_title},null,8,["config"]),n[17]||(n[17]=f("h4",{class:"mt-4"},"中文内容",-1)),j(Ae,{config:e.config.chinese.chinese_content},null,8,["config"]),n[18]||(n[18]=f("h3",{class:"mt-4"},"英文摘要",-1)),n[19]||(n[19]=f("h4",null,"英文标题",-1)),n[20]||(n[20]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),j(Ae,{config:e.config.english.english_title},null,8,["config"]),n[21]||(n[21]=f("h4",{class:"mt-4"},"英文内容",-1)),j(Ae,{config:e.config.english.english_content},null,8,["config"]),n[22]||(n[22]=f("h3",{class:"mt-4"},"关键词配置",-1)),n[23]||(n[23]=f("h4",null,"中文关键词",-1)),f("div",iy,[f("div",ry,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.keywords.chinese.rules.keyword_count.enabled=i)},null,512),[[ue,e.config.keywords.chinese.rules.keyword_count.enabled]]),n[7]||(n[7]=se(" 启用数量检查",-1))])]),f("div",oy,[n[8]||(n[8]=f("label",null,"最少数量:",-1)),P(f("input",{type:"number","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.keywords.chinese.rules.keyword_count.count_min=i)},null,512),[[xe,e.config.keywords.chinese.rules.keyword_count.count_min,void 0,{number:!0}]])]),f("div",sy,[n[9]||(n[9]=f("label",null,"最大数量:",-1)),P(f("input",{type:"number","onUpdate:modelValue":n[2]||(n[2]=i=>e.config.keywords.chinese.rules.keyword_count.count_max=i)},null,512),[[xe,e.config.keywords.chinese.rules.keyword_count.count_max,void 0,{number:!0}]])]),f("div",ly,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[3]||(n[3]=i=>e.config.keywords.chinese.rules.trailing_punctuation.enabled=i)},null,512),[[ue,e.config.keywords.chinese.rules.trailing_punctuation.enabled]]),n[10]||(n[10]=se(" 禁止末尾标点",-1))])])]),n[24]||(n[24]=f("h5",{class:"subsection-title"},"中文关键词内容格式",-1)),j(Ae,{config:e.config.keywords.chinese},null,8,["config"]),n[25]||(n[25]=f("h5",{class:"subsection-title mt-3"},'中文关键词标签格式("关键词:")',-1)),j(Ae,{config:e.config.keywords.chinese.label},null,8,["config"]),n[26]||(n[26]=f("h4",{class:"mt-4"},"英文关键词",-1)),f("div",ay,[f("div",cy,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[4]||(n[4]=i=>e.config.keywords.english.rules.keyword_count.enabled=i)},null,512),[[ue,e.config.keywords.english.rules.keyword_count.enabled]]),n[11]||(n[11]=se(" 启用数量检查",-1))])]),f("div",uy,[n[12]||(n[12]=f("label",null,"最少数量:",-1)),P(f("input",{type:"number","onUpdate:modelValue":n[5]||(n[5]=i=>e.config.keywords.english.rules.keyword_count.count_min=i)},null,512),[[xe,e.config.keywords.english.rules.keyword_count.count_min,void 0,{number:!0}]])]),f("div",fy,[n[13]||(n[13]=f("label",null,"最大数量:",-1)),P(f("input",{type:"number","onUpdate:modelValue":n[6]||(n[6]=i=>e.config.keywords.english.rules.keyword_count.count_max=i)},null,512),[[xe,e.config.keywords.english.rules.keyword_count.count_max,void 0,{number:!0}]])])]),n[27]||(n[27]=f("h5",{class:"subsection-title"},"英文关键词内容格式",-1)),j(Ae,{config:e.config.keywords.english},null,8,["config"]),n[28]||(n[28]=f("h5",{class:"subsection-title mt-3"},'英文关键词标签格式("Keywords:")',-1)),j(Ae,{config:e.config.keywords.english.label},null,8,["config"])]))}},py=Re(dy,[["__scopeId","data-v-74d28b59"]]),hy={class:"headings-config"},gy={__name:"HeadingsConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",hy,[n[0]||(n[0]=f("h3",null,"一级标题",-1)),n[1]||(n[1]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),j(Ae,{config:e.config.level_1},null,8,["config"]),n[2]||(n[2]=f("h3",{class:"mt-4"},"二级标题",-1)),n[3]||(n[3]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),j(Ae,{config:e.config.level_2},null,8,["config"]),n[4]||(n[4]=f("h3",{class:"mt-4"},"三级标题",-1)),n[5]||(n[5]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),j(Ae,{config:e.config.level_3},null,8,["config"])]))}},my=Re(gy,[["__scopeId","data-v-82e39cec"]]),by={class:"figures-config"},yy={class:"grid grid-cols-2 gap-4 mb-4"},vy={class:"form-item"},_y={class:"form-item"},xy={__name:"FiguresConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",by,[f("div",yy,[f("div",vy,[n[2]||(n[2]=f("label",null,"图注编号前缀:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.caption_prefix=i)},null,512),[[xe,e.config.caption_prefix]])]),f("div",_y,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.rules.caption_numbering.enabled=i)},null,512),[[ue,e.config.rules.caption_numbering.enabled]]),n[3]||(n[3]=se(" 启用编号检查",-1))])])]),n[4]||(n[4]=f("h5",{class:"subsection-title"},"题注格式",-1)),j(Ae,{config:e.config},null,8,["config"]),n[5]||(n[5]=f("h5",{class:"subsection-title mt-3"},"图片段落格式(包含内联图片的段落)",-1)),j(Ae,{config:e.config.image},null,8,["config"])]))}},wy=Re(xy,[["__scopeId","data-v-adb40b62"]]),Ay={class:"tables-config"},Cy={class:"grid grid-cols-2 gap-4 mb-4"},Sy={class:"form-item"},Ey={class:"form-item"},Ty={__name:"TablesConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",Ay,[f("div",Cy,[f("div",Sy,[n[2]||(n[2]=f("label",null,"表注编号前缀:",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.caption_prefix=i)},null,512),[[xe,e.config.caption_prefix]])]),f("div",Ey,[f("label",null,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.rules.caption_numbering.enabled=i)},null,512),[[ue,e.config.rules.caption_numbering.enabled]]),n[3]||(n[3]=se(" 启用编号检查",-1))])])]),n[4]||(n[4]=f("h5",{class:"subsection-title"},"题注格式",-1)),j(Ae,{config:e.config},null,8,["config"]),n[5]||(n[5]=f("h5",{class:"subsection-title mt-3"},"表格对象格式(表格整体对齐、环绕)",-1)),j(Ae,{config:e.config.object},null,8,["config"]),n[6]||(n[6]=f("h5",{class:"subsection-title mt-3"},"表格内容格式(单元格内文字)",-1)),j(Ae,{config:e.config.content},null,8,["config"])]))}},Oy=Re(Ty,[["__scopeId","data-v-8d8e2f5a"]]),Ry={class:"references-config"},Fy={__name:"ReferencesConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",Ry,[n[0]||(n[0]=f("h3",null,"参考文献标题",-1)),j(Ae,{config:e.config.title},null,8,["config"]),n[1]||(n[1]=f("h3",{class:"mt-4"},"参考文献内容",-1)),j(Ae,{config:e.config.content},null,8,["config"])]))}},ky=Re(Fy,[["__scopeId","data-v-ef2c2d78"]]),Ny={class:"acknowledgements-config"},Ly={__name:"AcknowledgementsConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",Ny,[n[0]||(n[0]=f("h3",null,"致谢标题",-1)),n[1]||(n[1]=f("div",{class:"grid grid-cols-2 gap-4 mb-4"},null,-1)),j(Ae,{config:e.config.title},null,8,["config"]),n[2]||(n[2]=f("h3",{class:"mt-4"},"致谢内容",-1)),j(Ae,{config:e.config.content},null,8,["config"])]))}},$y=Re(Ly,[["__scopeId","data-v-31b00dfd"]]),Iy={class:"numbering-config"},Py={class:"master-switch"},Dy={class:"switch-label"},Uy={key:0,class:"levels-config"},My={class:"level-item"},jy={class:"level-controls"},By={class:"inline-check"},Hy=["disabled"],Vy=["disabled"],qy={class:"level-item"},Ky={class:"level-controls"},Wy={class:"inline-check"},Yy=["disabled"],Jy=["disabled"],zy={class:"level-item"},Gy={class:"level-controls"},Xy={class:"inline-check"},Qy=["disabled"],Zy=["disabled"],e1={class:"level-item"},t1={class:"level-controls"},n1={class:"inline-check"},i1=["disabled"],r1=["disabled"],o1={class:"level-item"},s1={class:"level-controls"},l1={class:"inline-check"},a1=["disabled"],c1=["disabled"],u1={__name:"NumberingConfig",props:{config:{type:Object,required:!0}},setup(e){return(t,n)=>(U(),V("div",Iy,[f("div",Py,[f("label",Dy,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[0]||(n[0]=i=>e.config.enabled=i)},null,512),[[ue,e.config.enabled]]),n[16]||(n[16]=f("span",null,"启用标题自动编号",-1))])]),e.config.enabled?(U(),V("div",Uy,[f("div",My,[n[22]||(n[22]=f("h4",null,"一级标题",-1)),f("div",jy,[f("label",By,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[1]||(n[1]=i=>e.config.level_1.enabled=i)},null,512),[[ue,e.config.level_1.enabled]]),n[17]||(n[17]=f("span",null,"启用",-1))]),f("div",{class:ye(["field",{disabled:!e.config.level_1.enabled}])},[n[18]||(n[18]=f("label",null,"编号模板",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[2]||(n[2]=i=>e.config.level_1.template=i),disabled:!e.config.level_1.enabled},null,8,Hy),[[xe,e.config.level_1.template]]),n[19]||(n[19]=f("span",{class:"hint"},"如 %1",-1))],2),f("div",{class:ye(["field",{disabled:!e.config.level_1.enabled}])},[n[21]||(n[21]=f("label",null,"后缀",-1)),P(f("select",{"onUpdate:modelValue":n[3]||(n[3]=i=>e.config.level_1.suffix=i),disabled:!e.config.level_1.enabled},[...n[20]||(n[20]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,Vy),[[Tt,e.config.level_1.suffix]])],2)])]),f("div",qy,[n[28]||(n[28]=f("h4",null,"二级标题",-1)),f("div",Ky,[f("label",Wy,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[4]||(n[4]=i=>e.config.level_2.enabled=i)},null,512),[[ue,e.config.level_2.enabled]]),n[23]||(n[23]=f("span",null,"启用",-1))]),f("div",{class:ye(["field",{disabled:!e.config.level_2.enabled}])},[n[24]||(n[24]=f("label",null,"编号模板",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[5]||(n[5]=i=>e.config.level_2.template=i),disabled:!e.config.level_2.enabled},null,8,Yy),[[xe,e.config.level_2.template]]),n[25]||(n[25]=f("span",{class:"hint"},"如 %1.%2",-1))],2),f("div",{class:ye(["field",{disabled:!e.config.level_2.enabled}])},[n[27]||(n[27]=f("label",null,"后缀",-1)),P(f("select",{"onUpdate:modelValue":n[6]||(n[6]=i=>e.config.level_2.suffix=i),disabled:!e.config.level_2.enabled},[...n[26]||(n[26]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,Jy),[[Tt,e.config.level_2.suffix]])],2)])]),f("div",zy,[n[34]||(n[34]=f("h4",null,"三级标题",-1)),f("div",Gy,[f("label",Xy,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[7]||(n[7]=i=>e.config.level_3.enabled=i)},null,512),[[ue,e.config.level_3.enabled]]),n[29]||(n[29]=f("span",null,"启用",-1))]),f("div",{class:ye(["field",{disabled:!e.config.level_3.enabled}])},[n[30]||(n[30]=f("label",null,"编号模板",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[8]||(n[8]=i=>e.config.level_3.template=i),disabled:!e.config.level_3.enabled},null,8,Qy),[[xe,e.config.level_3.template]]),n[31]||(n[31]=f("span",{class:"hint"},"如 %1.%2.%3",-1))],2),f("div",{class:ye(["field",{disabled:!e.config.level_3.enabled}])},[n[33]||(n[33]=f("label",null,"后缀",-1)),P(f("select",{"onUpdate:modelValue":n[9]||(n[9]=i=>e.config.level_3.suffix=i),disabled:!e.config.level_3.enabled},[...n[32]||(n[32]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,Zy),[[Tt,e.config.level_3.suffix]])],2)])]),f("div",e1,[n[40]||(n[40]=f("h4",null,"参考文献",-1)),f("div",t1,[f("label",n1,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[10]||(n[10]=i=>e.config.references.enabled=i)},null,512),[[ue,e.config.references.enabled]]),n[35]||(n[35]=f("span",null,"启用",-1))]),f("div",{class:ye(["field",{disabled:!e.config.references.enabled}])},[n[36]||(n[36]=f("label",null,"编号模板",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[11]||(n[11]=i=>e.config.references.template=i),disabled:!e.config.references.enabled},null,8,i1),[[xe,e.config.references.template]]),n[37]||(n[37]=f("span",{class:"hint"},"如 [%1]",-1))],2),f("div",{class:ye(["field",{disabled:!e.config.references.enabled}])},[n[39]||(n[39]=f("label",null,"后缀",-1)),P(f("select",{"onUpdate:modelValue":n[12]||(n[12]=i=>e.config.references.suffix=i),disabled:!e.config.references.enabled},[...n[38]||(n[38]=[f("option",{value:"space"},"空格",-1),f("option",{value:"tab"},"制表符",-1),f("option",{value:"nothing"},"无",-1)])],8,r1),[[Tt,e.config.references.suffix]])],2)])]),f("div",o1,[n[45]||(n[45]=f("h4",null,"题注编号",-1)),f("div",s1,[f("label",l1,[P(f("input",{type:"checkbox","onUpdate:modelValue":n[13]||(n[13]=i=>e.config.captions.enabled=i)},null,512),[[ue,e.config.captions.enabled]]),n[41]||(n[41]=f("span",null,"启用",-1))]),f("div",{class:ye(["field",{disabled:!e.config.captions.enabled}])},[n[42]||(n[42]=f("label",null,"分隔符",-1)),P(f("input",{type:"text","onUpdate:modelValue":n[14]||(n[14]=i=>e.config.captions.separator=i),disabled:!e.config.captions.enabled},null,8,a1),[[xe,e.config.captions.separator]]),n[43]||(n[43]=f("span",{class:"hint"},"章节号与编号间的分隔符,如 . - :",-1))],2),f("label",{class:ye(["inline-check",{disabled:!e.config.captions.enabled}])},[P(f("input",{type:"checkbox","onUpdate:modelValue":n[15]||(n[15]=i=>e.config.captions.label_number_space=i),disabled:!e.config.captions.enabled},null,8,c1),[[ue,e.config.captions.label_number_space]]),n[44]||(n[44]=f("span",null,"标签与编号间加空格",-1))],2)])])])):et("",!0)]))}},f1=Re(u1,[["__scopeId","data-v-21ca7315"]]),d1={class:"yaml-output"},p1={class:"yaml-content"},h1={class:"yaml-actions"},g1={__name:"YamlOutput",props:{yamlContent:{type:String,required:!0}},emits:["reset-to-default","import-yaml"],setup(e,{emit:t}){const n=e,i=t,r=he(null),o=()=>{navigator.clipboard.writeText(n.yamlContent)},s=()=>{r.value.click()},l=a=>{const c=a.target.files[0];if(!c)return;const u=new FileReader;u.onload=d=>{try{i("import-yaml",an.load(d.target.result))}catch(g){alert("导入失败: "+g.message)}},u.onerror=()=>{alert("文件读取失败")},u.readAsText(c,"utf-8"),a.target.value=""};return(a,c)=>(U(),V("div",d1,[c[1]||(c[1]=f("div",{class:"yaml-header"},"生成的 YAML 配置",-1)),f("div",p1,[f("pre",null,ee(e.yamlContent),1)]),f("div",h1,[f("button",{onClick:o,class:"btn btn-green"},"复制"),f("button",{onClick:s,class:"btn btn-ghost"},"导入 YAML"),f("button",{onClick:c[0]||(c[0]=u=>a.$emit("reset-to-default")),class:"btn btn-ghost"},"重置")]),f("input",{type:"file",ref_key:"fileInput",ref:r,style:{display:"none"},accept:".yaml,.yml",onChange:l},null,544)]))}},m1=Re(g1,[["__scopeId","data-v-235091b7"]]),b1={class:"config-generator"},y1={class:"app-content"},v1={class:"config-sections"},_1={class:"form-item",style:{"margin-bottom":"10px"}},x1={class:"yaml-preview"},w1={__name:"ConfigGenerator",emits:["config-updated"],setup(e,{expose:t,emit:n}){const i=he(JSON.parse(JSON.stringify(Qt))),r=Te(()=>an.dump(i.value,{indent:2,skipInvalid:!0})),o=()=>{i.value=JSON.parse(JSON.stringify(Qt))},s=()=>{nb(i.value)},l=d=>{i.value=gi(d,Qt)},a=()=>JSON.parse(JSON.stringify(i.value)),c=d=>{i.value=gi(JSON.parse(JSON.stringify(d)),Qt)},u=n;return fn(i,d=>{u("config-updated",JSON.parse(JSON.stringify(d)))},{deep:!0}),Mn(()=>{u("config-updated",JSON.parse(JSON.stringify(i.value)))}),t({exportConfig:a,importConfig:c,resetToDefault:o,handleApplyGlobalFormat:s}),(d,g)=>(U(),V("div",b1,[f("div",y1,[f("div",v1,[j(ct,{title:"模板信息"},{default:it(()=>[f("div",_1,[g[1]||(g[1]=f("label",null,"模板名称:",-1)),P(f("input",{type:"text","onUpdate:modelValue":g[0]||(g[0]=m=>i.value.template_name=m),style:{width:"300px"}},null,512),[[xe,i.value.template_name]])])]),_:1}),j(ct,{title:"警告字段配置"},{default:it(()=>[j(Tb,{config:i.value.style_checks_warning},null,8,["config"])]),_:1}),j(ct,{title:"全局基础格式配置"},{default:it(()=>[j(ty,{config:i.value.global_format,"show-apply-button":!0,onApplyToAll:s},null,8,["config"])]),_:1}),j(ct,{title:"摘要配置"},{default:it(()=>[j(py,{config:i.value.abstract},null,8,["config"])]),_:1}),j(ct,{title:"标题配置"},{default:it(()=>[j(my,{config:i.value.headings},null,8,["config"])]),_:1}),j(ct,{title:"正文配置"},{default:it(()=>[j(Ae,{config:i.value.body_text},null,8,["config"])]),_:1}),j(ct,{title:"插图配置"},{default:it(()=>[j(wy,{config:i.value.figures},null,8,["config"])]),_:1}),j(ct,{title:"表格配置"},{default:it(()=>[j(Oy,{config:i.value.tables},null,8,["config"])]),_:1}),j(ct,{title:"参考文献配置"},{default:it(()=>[j(ky,{config:i.value.references},null,8,["config"])]),_:1}),j(ct,{title:"致谢配置"},{default:it(()=>[j($y,{config:i.value.acknowledgements},null,8,["config"])]),_:1}),j(ct,{title:"标题自动编号"},{default:it(()=>[j(f1,{config:i.value.numbering},null,8,["config"])]),_:1})]),f("div",x1,[j(m1,{"yaml-content":r.value,onResetToDefault:o,onImportYaml:l},null,8,["yaml-content"])])])]))}},A1=Re(w1,[["__scopeId","data-v-7e8333a6"]]),C1={class:"config-sidebar"},S1={class:"config-list"},E1=["onClick"],T1={class:"config-name"},O1={key:0,class:"loading-text"},R1={key:1,class:"empty-text"},F1={__name:"ConfigSidebar",emits:["config-selected"],setup(e,{emit:t}){const n=t,i=he([]),r=he(!1),o=he(""),s=window.__API_BASE__||"";async function l(){r.value=!0;try{const u=await(await fetch(`${s}/configs`)).json();u.code===200&&(i.value=u.data||[])}catch(c){console.error("获取配置列表失败:",c)}finally{r.value=!1}}async function a(c){try{const d=await(await fetch(`${s}/configs/${encodeURIComponent(c)}`)).json();d.code===200&&(o.value=c,n("config-selected",{filename:c,content:d.data}))}catch(u){console.error("读取配置失败:",u)}}return Mn(l),(c,u)=>(U(),V("div",C1,[f("div",{class:"sidebar-header"},[u[0]||(u[0]=f("h3",null,"配置模板",-1)),f("button",{class:"btn-refresh",onClick:l,title:"刷新列表"},"↻")]),f("div",S1,[(U(!0),V(ve,null,Ut(i.value,d=>(U(),V("div",{key:d,class:ye(["config-item",{active:d===o.value}]),onClick:g=>a(d)},[f("span",T1,ee(d),1)],10,E1))),128)),r.value?(U(),V("div",O1,"加载中...")):et("",!0),!r.value&&i.value.length===0?(U(),V("div",R1,[...u[1]||(u[1]=[se(" 暂无配置文件",-1),f("br",null,null,-1),se("将 YAML 放入 configs/ 目录 ",-1)])])):et("",!0)])]))}},k1=Re(F1,[["__scopeId","data-v-95c48163"]]),N1={class:"settings-page"},L1={class:"settings-card"},$1={key:0,class:"connection-url"},I1={class:"form-group"},P1={class:"form-group"},D1={class:"form-actions"},U1=["disabled"],M1={__name:"SettingsPage",setup(e){const t=he(De.host),n=he(De.port),i=he(!1),r=he(null);Mn(()=>{Ja(),t.value=De.host,n.value=De.port});const o=Te(()=>r.value===null?"bar-untested":r.value?"bar-ok":"bar-fail"),s=Te(()=>r.value===null?"未测试连接":r.value?"连接成功":"连接失败");function l(){De.host=t.value,De.port=n.value,za(),r.value=null}async function a(){i.value=!0,r.value=null;try{const u=await fetch(`${Wi.value}/openapi.json`,{signal:AbortSignal.timeout(5e3)});r.value=u.ok}catch{r.value=!1}finally{i.value=!1}}function c(){kg(),t.value=De.host,n.value=De.port,r.value=null}return(u,d)=>(U(),V("div",N1,[f("div",L1,[d[5]||(d[5]=f("h2",{class:"settings-title"},"后端连接设置",-1)),d[6]||(d[6]=f("p",{class:"settings-desc"},"配置后端 API 服务的地址和端口,修改后自动保存。",-1)),f("div",{class:ye(["connection-bar",o.value])},[d[2]||(d[2]=f("span",{class:"connection-dot"},null,-1)),f("span",null,ee(s.value),1),r.value?(U(),V("span",$1,ee(Ye(Wi)),1)):et("",!0)],2),f("div",I1,[d[3]||(d[3]=f("label",{class:"form-label"},"后端 IP 地址",-1)),P(f("input",{"onUpdate:modelValue":d[0]||(d[0]=g=>t.value=g),class:"form-input",placeholder:"127.0.0.1",onInput:l},null,544),[[xe,t.value]])]),f("div",P1,[d[4]||(d[4]=f("label",{class:"form-label"},"后端端口",-1)),P(f("input",{"onUpdate:modelValue":d[1]||(d[1]=g=>n.value=g),type:"number",class:"form-input",placeholder:"8000",min:"1",max:"65535",onInput:l},null,544),[[xe,n.value,void 0,{number:!0}]])]),f("div",D1,[f("button",{class:"btn btn-green",onClick:a,disabled:i.value},ee(i.value?"测试中...":"测试连接"),9,U1),f("button",{class:"btn btn-ghost",onClick:c},"恢复默认")])])]))}},j1=Re(M1,[["__scopeId","data-v-fc9e8f83"]]),B1={class:"app-container"},H1={class:"nav-bar"},V1={class:"nav-content"},q1={class:"nav-actions"},K1={key:0,class:"config-actions"},W1=["disabled"],Y1=["disabled"],J1={class:"nav-tabs"},z1={class:"main-area"},G1={class:"content-area"},X1={__name:"App",setup(e){const t=he(null),n=he("config"),i=he(JSON.parse(JSON.stringify(Qt))),r=he(null),o=he(null),s=m=>{i.value=m};Mn(()=>{Ja(),i.value=JSON.parse(JSON.stringify(Qt)),t.value&&(window.__toast=t.value.toast)});const l=()=>{var m,y;if(i.value)try{const h=an.dump(i.value,{indent:2,skipInvalid:!0}),_=new Blob([h],{type:"application/x-yaml"}),C=URL.createObjectURL(_),w=document.createElement("a");w.href=C,w.download="wordformat-config.yaml",document.body.appendChild(w),w.click(),URL.revokeObjectURL(C),document.body.removeChild(w),(m=t.value)==null||m.toast.success("配置已下载!")}catch(h){console.error("保存配置失败:",h),(y=t.value)==null||y.toast.error("保存配置失败:"+h.message)}},a=()=>{var m;(m=o.value)==null||m.click()},c=async m=>{var h,_,C;const y=(h=m.target.files)==null?void 0:h[0];if(y)try{const w=await y.text(),$=an.load(w),R=gi($,Qt);i.value=R,r.value&&r.value.importConfig(R),(_=t.value)==null||_.toast.success("配置加载成功!")}catch(w){console.error("加载配置失败:",w),(C=t.value)==null||C.toast.error("加载配置失败:"+w.message)}finally{m.target.value=""}},u=window.__API_BASE__||"",d=async()=>{var m,y,h;if(i.value)try{const _=an.dump(i.value,{indent:2,skipInvalid:!0}),C=prompt("请输入配置文件名(如 my-thesis.yaml):","custom.yaml");if(!C)return;const $=await(await fetch(`${u}/configs/save`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filename:C,content:_})})).json();$.code===200?(m=t.value)==null||m.toast.success($.msg):(y=t.value)==null||y.toast.error($.msg||"保存失败")}catch(_){(h=t.value)==null||h.toast.error("保存配置失败:"+_.message)}},g=({filename:m,content:y})=>{var h,_;try{const C=an.load(y),w=gi(C,Qt);i.value=w,r.value&&r.value.importConfig(w),(h=t.value)==null||h.toast.success(`已加载配置: ${m}`)}catch(C){(_=t.value)==null||_.toast.error("解析配置失败:"+C.message)}};return(m,y)=>(U(),V("div",B1,[j(Dd,{ref_key:"toastRef",ref:t},null,512),f("div",H1,[f("div",V1,[y[3]||(y[3]=f("h1",{class:"app-title"},"WordFormat 工具",-1)),f("div",q1,[n.value==="config"?(U(),V("div",K1,[f("button",{class:"btn secondary-btn",onClick:l,disabled:!i.value}," 保存配置 ",8,W1),f("button",{class:"btn secondary-btn",onClick:a}," 加载配置 "),f("button",{class:"btn secondary-btn",onClick:d,disabled:!i.value}," 保存到服务器 ",8,Y1)])):et("",!0),f("div",J1,[f("button",{class:ye(["nav-tab",{active:n.value==="config"}]),onClick:y[0]||(y[0]=h=>n.value="config")}," 配置生成器 ",2),f("button",{class:ye(["nav-tab",{active:n.value==="checker"}]),onClick:y[1]||(y[1]=h=>n.value="checker")}," 文档标签核对 ",2),f("button",{class:ye(["nav-tab",{active:n.value==="settings"}]),onClick:y[2]||(y[2]=h=>n.value="settings")}," 设置 ",2)])])])]),f("div",z1,[n.value==="config"?(U(),Nn(k1,{key:0,onConfigSelected:g})):et("",!0),f("div",G1,[P(j(A1,{ref_key:"configGeneratorRef",ref:r,onConfigUpdated:s},null,512),[[Tr,n.value==="config"]]),P(j(Kg,{"generated-config":i.value},null,8,["generated-config"]),[[Tr,n.value==="checker"]]),P(j(j1,null,null,512),[[Tr,n.value==="settings"]])])]),f("input",{ref_key:"fileInputRef",ref:o,type:"file",accept:".yaml,.yml",style:{display:"none"},onChange:c},null,544)]))}},Bo=kd(X1),br={info:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.info(e,t)},success:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.success(e,t)},warn:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.warn(e,t)},error:(e,t)=>{var n;return(n=window.__toast)==null?void 0:n.error(e,t)}};Bo.config.globalProperties.$toast=br;Bo.config.errorHandler=(e,t,n)=>{console.error("[Vue Error]",e,n),br.error(`[${n}] ${e.message||e}`)};window.addEventListener("error",e=>{var t;console.error("[Global Error]",e.error),br.error(((t=e.error)==null?void 0:t.message)||e.message)});window.addEventListener("unhandledrejection",e=>{var t;console.error("[Unhandled Rejection]",e.reason),br.error(((t=e.reason)==null?void 0:t.message)||String(e.reason))});Bo.mount("#app"); diff --git a/src/wordformat/api/static/assets/index-D7BJOfFL.css b/src/wordformat/api/static/assets/index-D7BJOfFL.css new file mode 100644 index 0000000..4c3ec32 --- /dev/null +++ b/src/wordformat/api/static/assets/index-D7BJOfFL.css @@ -0,0 +1 @@ +.toast-container{position:fixed;top:16px;right:16px;z-index:99999;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast-item{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:10px;background:#1e293b;box-shadow:0 8px 32px #00000059;min-width:280px;max-width:480px;pointer-events:auto;font-size:14px;border:1px solid #334155}.toast-msg{flex:1;color:#e2e8f0}.toast-close{background:none;border:none;font-size:22px;cursor:pointer;color:#64748b;padding:0 4px;line-height:1}.toast-close:hover{color:#e2e8f0}.toast-info{border-left:4px solid #3b82f6}.toast-success{border-left:4px solid #22c55e}.toast-warn{border-left:4px solid #f59e0b}.toast-error{border-left:4px solid #ef4444}.toast-enter-active{transition:all .3s ease}.toast-leave-active{transition:all .2s ease}.toast-enter-from,.toast-leave-to{opacity:0;transform:translate(40px)}.upload-group[data-v-6d870395]{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.upload-btn[data-v-6d870395]{padding:6px 12px;font-size:12px;font-weight:500;border:1px solid #475569;border-radius:6px;background:#1e293b;color:#cbd5e1;cursor:pointer;transition:all .2s;font-family:inherit}.upload-btn[data-v-6d870395]:hover{background:#334155;border-color:#64748b;color:#e2e8f0}.file-hidden[data-v-6d870395]{display:none}.file-tip[data-v-6d870395]{font-size:11px;color:#64748b;white-space:nowrap}.go-btn[data-v-6d870395]{padding:6px 14px;font-size:12px;font-weight:600;border:none;border-radius:6px;background:#22c55e;color:#052e16;cursor:pointer;transition:all .2s;font-family:inherit}.go-btn[data-v-6d870395]:hover:not(:disabled){background:#16a34a}.go-btn[data-v-6d870395]:disabled{opacity:.4;cursor:not-allowed}.format-btn-group[data-v-99eed13a]{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.btn[data-v-99eed13a]{padding:6px 12px;font-size:12px;font-weight:500;border:none;border-radius:6px;cursor:pointer;transition:all .2s;font-family:inherit}.btn[data-v-99eed13a]:disabled{opacity:.4;cursor:not-allowed}.btn-amber[data-v-99eed13a]{background:#d97706;color:#fef3c7}.btn-amber[data-v-99eed13a]:hover:not(:disabled){background:#b45309}.btn-green[data-v-99eed13a]{background:#22c55e;color:#052e16}.btn-green[data-v-99eed13a]:hover:not(:disabled){background:#16a34a}.node-list-section[data-v-d86ce66e]{width:100%;flex:1}.card[data-v-d86ce66e]{background-color:#1e293b;border:1px solid #334155;border-radius:10px;padding:1rem;display:flex;flex-direction:column;height:100%}.node-list[data-v-d86ce66e]{display:flex;flex-direction:column;gap:.125rem;overflow-y:auto;flex:1;min-height:calc(100vh - 110px)}.node-item[data-v-d86ce66e]{position:relative;margin:2px 0;border-radius:6px;transition:background-color .2s ease;display:flex;align-items:center;min-height:36px;padding:4px 8px;cursor:pointer;gap:.5rem;flex-wrap:wrap}.node-item[data-v-d86ce66e]:hover{background-color:#334155}.node-item.error[data-v-d86ce66e]{background-color:#450a0a;border-left:3px solid #ef4444}.node-item.other[data-v-d86ce66e]{background-color:#1e293b;border-left:3px solid #475569;opacity:.7}.node-item.selected[data-v-d86ce66e]{background-color:#1e3a5f;border-left:3px solid #3b82f6;opacity:1}.level-dot[data-v-d86ce66e]{width:8px;height:8px;border-radius:50%;flex-shrink:0}.node-tag[data-v-d86ce66e]{min-width:140px;font-size:12px;padding:2px 6px;border-radius:3px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:0}.node-score[data-v-d86ce66e]{min-width:60px;font-size:12px;padding:2px 6px;border-radius:3px;background:#064e3b;color:#6ee7b7;text-align:center;flex-shrink:0}.node-content[data-v-d86ce66e]{flex:1;font-size:13px;color:#e2e8f0;word-break:break-all;line-height:1.4}.node-meta[data-v-d86ce66e]{font-size:11px;color:#64748b;display:flex;gap:10px;align-items:center;flex-shrink:0;white-space:nowrap}.node-fingerprint[data-v-d86ce66e]{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace}.init-tip[data-v-d86ce66e],.loading-tip[data-v-d86ce66e],.empty-tip[data-v-d86ce66e]{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;color:#64748b;gap:.75rem;padding:6rem 0}.init-icon[data-v-d86ce66e]{width:48px;height:48px;color:#334155}.init-sub-tip[data-v-d86ce66e]{font-size:12px;color:#475569;margin-top:.25rem;text-align:center;line-height:1.5}.loading-spinner[data-v-d86ce66e]{width:20px;height:20px;border:3px solid #334155;border-radius:50%;border-top-color:#22c55e;animation:spin-d86ce66e 1s ease-in-out infinite}.empty-tip[data-v-d86ce66e]{font-size:13px}@keyframes spin-d86ce66e{to{transform:rotate(360deg)}}.node-tag.other[data-v-d86ce66e]{background:#334155;color:#94a3b8;font-weight:500}.node-tag.abstract_chinese_title[data-v-d86ce66e]{background:#064e3b;color:#6ee7b7}.node-tag.abstract_chinese_title_content[data-v-d86ce66e]{background:#0c4a6e;color:#7dd3fc}.node-tag.abstract_english_title[data-v-d86ce66e]{background:#4c1d95;color:#c4b5fd}.node-tag.abstract_english_title_content[data-v-d86ce66e]{background:#581c87;color:#d8b4fe}.node-tag.keywords_chinese[data-v-d86ce66e]{background:#713f12;color:#fde68a}.node-tag.keywords_english[data-v-d86ce66e]{background:#7f1d1d;color:#fecaca}.node-tag.chinese_title[data-v-d86ce66e]{background:#0c4a6e;color:#7dd3fc}.node-tag.english_title[data-v-d86ce66e]{background:#064e3b;color:#6ee7b7}.node-tag.heading_level_1[data-v-d86ce66e]{background:#312e81;color:#c7d2fe}.node-tag.heading_level_2[data-v-d86ce66e]{background:#4c1d95;color:#d8b4fe}.node-tag.heading_level_3[data-v-d86ce66e]{background:#581c87;color:#e9d5ff}.node-tag.heading_mulu[data-v-d86ce66e]{background:#713f12;color:#fde68a}.node-tag.heading_fulu[data-v-d86ce66e]{background:#1e293b;color:#94a3b8}.node-tag.references_title[data-v-d86ce66e]{background:#164e63;color:#67e8f9}.node-tag.acknowledgements_title[data-v-d86ce66e]{background:#064e3b;color:#6ee7b7}.node-tag.caption_figure[data-v-d86ce66e],.node-tag.caption_table[data-v-d86ce66e]{background:#1e293b;color:#94a3b8}.node-tag.body_text[data-v-d86ce66e]{background:#0f172a;color:#94a3b8}.search-highlight[data-v-d86ce66e]{background-color:#713f12;color:#fde68a;padding:0 2px;border-radius:2px}.replace-badge[data-v-d86ce66e]{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:#22c55e;color:#052e16;font-size:11px;font-weight:700;flex-shrink:0;cursor:default}.node-detail-section[data-v-caa1c263]{margin-left:auto}.detail-card[data-v-caa1c263]{position:sticky;top:84px;max-height:calc(100vh - 120px);min-height:auto;overflow-y:auto;display:flex;flex-direction:column;background-color:#1e293b;border:1px solid #334155;border-radius:10px;padding:1rem}.detail-title[data-v-caa1c263]{font-size:14px;font-weight:600;color:#e2e8f0;padding-bottom:.5rem;border-bottom:1px solid #334155;margin-bottom:1rem}.no-select-tip[data-v-caa1c263]{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;color:#64748b;gap:.75rem;padding:6rem 0}.no-select-icon[data-v-caa1c263]{width:48px;height:48px;color:#334155}.property-card[data-v-caa1c263]{border:1px solid #334155;border-radius:6px;overflow:hidden;margin-bottom:8px}.property-card-header[data-v-caa1c263]{padding:6px 8px;font-size:12px;font-weight:500;background-color:#0f172a;color:#94a3b8;border-bottom:1px solid #334155}.property-card-body[data-v-caa1c263]{padding:8px;display:flex;flex-direction:column;gap:.75rem}.property-item[data-v-caa1c263]{display:flex;flex-direction:column;gap:2px}.property-label[data-v-caa1c263]{font-size:12px;font-weight:500;color:#64748b}.label-tip[data-v-caa1c263]{font-size:11px;font-weight:400;color:#475569}.property-value[data-v-caa1c263]{font-size:13px;color:#e2e8f0;padding:6px 8px;border-radius:6px;border:1px solid #334155;background-color:#0f172a;line-height:1.4;word-break:break-all}.content-value[data-v-caa1c263]{max-height:8rem;overflow-y:auto}.replace-label[data-v-caa1c263]{color:#4ade80;font-weight:600}.replace-value[data-v-caa1c263]{border-color:#166534;background-color:#052e16;color:#6ee7b7}.status-value[data-v-caa1c263]{border:none;padding:6px 8px}.status-normal[data-v-caa1c263]{background-color:#052e16;color:#4ade80}.status-error[data-v-caa1c263]{background-color:#450a0a;color:#fca5a5}.status-other[data-v-caa1c263]{background-color:#1e293b;color:#94a3b8}.category-select[data-v-caa1c263]{width:100%;font-size:13px;padding:6px 8px;border-radius:6px;border:1px solid #475569;background:#0f172a;color:#e2e8f0;cursor:pointer;margin:4px 0;box-sizing:border-box}.category-select[data-v-caa1c263]:focus{outline:1px solid #22c55e;border-color:#22c55e}.category-desc[data-v-caa1c263]{font-size:11px;color:#64748b;line-height:1.4;padding:4px 0 0}.check-result[data-v-caa1c263]{padding:6px 8px;border-radius:6px;font-size:13px;text-align:center;margin-top:8px}.result-normal[data-v-caa1c263]{background-color:#052e16;color:#4ade80}.result-error[data-v-caa1c263]{background-color:#450a0a;color:#fca5a5}.result-other[data-v-caa1c263]{background-color:#1e293b;color:#94a3b8}.flex[data-v-caa1c263]{display:flex}.items-center[data-v-caa1c263]{align-items:center}.mr-2[data-v-caa1c263]{margin-right:.5rem}.mt-4[data-v-caa1c263]{margin-top:1rem}.fingerprint-value[data-v-caa1c263]{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px}.doc-tag-check-container[data-v-e6786e76]{width:100%;min-height:100vh;display:flex;flex-direction:column;background-color:#0f172a}.header-bar[data-v-e6786e76]{background-color:#1e293b;border-bottom:1px solid #334155;padding:.75rem 1.5rem}.header-content[data-v-e6786e76]{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:1rem;max-width:1280px;margin:0 auto;width:100%}.header-left[data-v-e6786e76]{display:flex;flex-direction:column;gap:.25rem}.tool-title[data-v-e6786e76]{font-size:1.15rem;font-weight:600;color:#f1f5f9;margin:0;font-family:"Georgia, Times New Roman",serif}.stats-info[data-v-e6786e76]{font-size:.8125rem;color:#64748b}.stats-info span[data-v-e6786e76]{font-weight:600;color:#22c55e}.header-right[data-v-e6786e76]{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.search-box[data-v-e6786e76]{position:relative;display:flex;align-items:center}.search-input[data-v-e6786e76]{padding:6px 28px 6px 10px;font-size:13px;border:1px solid #475569;border-radius:6px;width:180px;outline:none;background:#0f172a;color:#e2e8f0;font-family:inherit}.search-input[data-v-e6786e76]:focus{border-color:#22c55e;box-shadow:0 0 0 2px #22c55e26}.search-icon[data-v-e6786e76]{position:absolute;right:8px;width:16px;height:16px;color:#64748b;pointer-events:none}.btn[data-v-e6786e76]{padding:6px 12px;font-size:12px;border-radius:6px;border:1px solid transparent;cursor:pointer;transition:all .2s;white-space:nowrap;font-family:inherit}.btn[data-v-e6786e76]:disabled{opacity:.4;cursor:not-allowed}.primary-btn[data-v-e6786e76]{background-color:#22c55e;color:#052e16}.primary-btn[data-v-e6786e76]:hover:not(:disabled){background-color:#16a34a}.secondary-btn[data-v-e6786e76]{background-color:#334155;color:#cbd5e1;border:1px solid #475569}.secondary-btn[data-v-e6786e76]:hover:not(:disabled){background-color:#475569;border-color:#64748b}.main-content[data-v-e6786e76]{flex:1;display:grid;grid-template-columns:1fr 400px;gap:1.5rem;padding:1.5rem;width:100%;max-width:1280px;margin:0 auto}@media(max-width:992px){.main-content[data-v-e6786e76]{grid-template-columns:1fr}}.config-section[data-v-88bb2378]{margin-bottom:18px;border:1px solid #334155;border-radius:10px;overflow:hidden;background-color:#1e293b;transition:border-color .2s}.config-section[data-v-88bb2378]:hover{border-color:#475569}.section-header[data-v-88bb2378]{display:flex;justify-content:space-between;align-items:center;padding:14px 20px;background-color:#0f172a;cursor:pointer;transition:background-color .2s}.section-header[data-v-88bb2378]:hover{background-color:#1e293b}.section-header h2[data-v-88bb2378]{margin:0;font-size:15px;font-weight:600;color:#e2e8f0}.toggle-arrow[data-v-88bb2378]{color:#64748b;transition:transform .2s;flex-shrink:0}.toggle-arrow.expanded[data-v-88bb2378]{transform:rotate(180deg)}.section-content[data-v-88bb2378]{padding:18px 20px;border-top:1px solid #334155}.section-content h3[data-v-88bb2378]{margin-top:0;margin-bottom:14px;font-size:14px;color:#94a3b8}.select-all-bar[data-v-315bca75]{margin-bottom:12px;padding-bottom:10px;border-bottom:1px solid #334155}.select-all-label[data-v-315bca75]{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-weight:600;font-size:13px;color:#22c55e}.select-all-label input[type=checkbox][data-v-315bca75]{width:16px;height:16px;cursor:pointer;accent-color:#22c55e}.form-item[data-v-315bca75]{margin-bottom:8px;display:flex;flex-direction:row;align-items:center;gap:4px}.form-item label[data-v-315bca75]{font-weight:500;color:#94a3b8;font-size:13px;white-space:nowrap;cursor:pointer}.form-item input[type=checkbox][data-v-315bca75]{margin-right:6px;accent-color:#22c55e}.grid[data-v-315bca75]{display:grid}.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(6,1fr)}.gap-2[data-v-315bca75]{gap:6px}@media(min-width:1024px){.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(7,1fr)}}@media(min-width:1200px){.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(8,1fr)}}@media(max-width:768px){.grid-cols-3[data-v-315bca75]{grid-template-columns:repeat(2,1fr)}}.form-item[data-v-5177a808]{margin-bottom:6px;display:flex;align-items:center;gap:8px}.form-item label[data-v-5177a808]{font-weight:500;color:#94a3b8;font-size:13px;white-space:nowrap;min-width:80px}.form-item input[type=text][data-v-5177a808],.form-item input[type=number][data-v-5177a808],.form-item select[data-v-5177a808]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #475569;border-radius:6px;font-size:13px;background:#0f172a;color:#e2e8f0;outline:none;transition:border-color .2s}.form-item input[data-v-5177a808]:focus,.form-item select[data-v-5177a808]:focus{border-color:#22c55e;box-shadow:0 0 0 2px #22c55e26}.form-item input[type=text][data-v-5177a808]:disabled,.form-item select[data-v-5177a808]:disabled{opacity:.4}.form-item[data-v-5177a808]:has(input[type=checkbox]){width:auto}.form-item:has(input[type=checkbox]) label[data-v-5177a808]{min-width:auto}.form-item input[type=checkbox][data-v-5177a808]{margin-right:5px;accent-color:#22c55e}.grid[data-v-5177a808]{display:grid}.grid-cols-2[data-v-5177a808]{grid-template-columns:repeat(4,1fr)}.gap-4[data-v-5177a808]{gap:10px}@media(min-width:1200px){.grid-cols-2[data-v-5177a808]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1600px){.grid-cols-2[data-v-5177a808]{grid-template-columns:repeat(6,1fr)}}@media(max-width:768px){.grid-cols-2[data-v-5177a808]{grid-template-columns:1fr}.form-item[data-v-5177a808]{flex-direction:column;align-items:flex-start}.form-item label[data-v-5177a808]{min-width:auto}.form-item input[type=text][data-v-5177a808],.form-item input[type=number][data-v-5177a808],.form-item select[data-v-5177a808]{width:120px}}.btn-green[data-v-98ee8f2a]{padding:8px 16px;border:none;border-radius:6px;font-size:13px;cursor:pointer;background:#22c55e;color:#052e16;font-family:inherit;transition:background .2s}.btn-green[data-v-98ee8f2a]:hover{background:#16a34a}.mt-4[data-v-98ee8f2a]{margin-top:14px}.form-item[data-v-74d28b59]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-74d28b59]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:120px}.form-item input[type=text][data-v-74d28b59],.form-item input[type=number][data-v-74d28b59],.form-item select[data-v-74d28b59]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-74d28b59]{margin-right:5px}.form-item[data-v-74d28b59]:has(input[type=checkbox]){width:auto}.form-item:has(input[type=checkbox]) label[data-v-74d28b59]{min-width:auto}.grid[data-v-74d28b59]{display:grid}.grid-cols-2[data-v-74d28b59]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-74d28b59]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-74d28b59]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-74d28b59]{gap:10px}.mb-4[data-v-74d28b59]{margin-bottom:12px}.subsection-title[data-v-74d28b59]{font-size:12px;font-weight:600;color:#94a3b8;margin-bottom:4px}.mt-3[data-v-74d28b59]{margin-top:8px}.mt-4[data-v-74d28b59]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-74d28b59]{grid-template-columns:1fr}.form-item[data-v-74d28b59]{flex-direction:column;align-items:flex-start}.form-item label[data-v-74d28b59]{min-width:auto}.form-item input[type=text][data-v-74d28b59],.form-item input[type=number][data-v-74d28b59],.form-item select[data-v-74d28b59]{width:120px}}.form-item[data-v-82e39cec]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-82e39cec]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:80px}.form-item input[type=text][data-v-82e39cec],.form-item input[type=number][data-v-82e39cec],.form-item select[data-v-82e39cec]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-82e39cec]{margin-right:5px}.grid[data-v-82e39cec]{display:grid}.grid-cols-2[data-v-82e39cec]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-82e39cec]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-82e39cec]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-82e39cec]{gap:10px}.mb-4[data-v-82e39cec]{margin-bottom:12px}.mt-4[data-v-82e39cec]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-82e39cec]{grid-template-columns:1fr}.form-item[data-v-82e39cec]{flex-direction:column;align-items:flex-start}.form-item label[data-v-82e39cec]{min-width:auto}.form-item input[type=text][data-v-82e39cec],.form-item input[type=number][data-v-82e39cec],.form-item select[data-v-82e39cec]{width:120px}}.form-item[data-v-adb40b62]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-adb40b62]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:100px}.form-item input[type=text][data-v-adb40b62],.form-item input[type=number][data-v-adb40b62],.form-item select[data-v-adb40b62]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-adb40b62]{margin-right:5px}.grid[data-v-adb40b62]{display:grid}.grid-cols-2[data-v-adb40b62]{grid-template-columns:repeat(4,1fr)}.gap-4[data-v-adb40b62]{gap:10px}.mb-4[data-v-adb40b62]{margin-bottom:12px}.subsection-title[data-v-adb40b62]{font-size:12px;font-weight:600;color:#94a3b8;margin-bottom:4px}.mt-3[data-v-adb40b62]{margin-top:8px}@media(min-width:1024px){.grid-cols-2[data-v-adb40b62]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-adb40b62]{grid-template-columns:repeat(6,1fr)}}@media(max-width:768px){.grid-cols-2[data-v-adb40b62]{grid-template-columns:1fr}.form-item[data-v-adb40b62]{flex-direction:column;align-items:flex-start}.form-item label[data-v-adb40b62]{min-width:auto}.form-item input[type=text][data-v-adb40b62],.form-item input[type=number][data-v-adb40b62],.form-item select[data-v-adb40b62]{width:120px}}.form-item[data-v-8d8e2f5a]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-8d8e2f5a]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:100px}.form-item input[type=text][data-v-8d8e2f5a],.form-item input[type=number][data-v-8d8e2f5a],.form-item select[data-v-8d8e2f5a]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-8d8e2f5a]{margin-right:5px}.grid[data-v-8d8e2f5a]{display:grid}.grid-cols-2[data-v-8d8e2f5a]{grid-template-columns:repeat(4,1fr)}.gap-4[data-v-8d8e2f5a]{gap:10px}.mb-4[data-v-8d8e2f5a]{margin-bottom:12px}.subsection-title[data-v-8d8e2f5a]{font-size:12px;font-weight:600;color:#94a3b8;margin-bottom:4px}.mt-3[data-v-8d8e2f5a]{margin-top:8px}@media(min-width:1024px){.grid-cols-2[data-v-8d8e2f5a]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-8d8e2f5a]{grid-template-columns:repeat(6,1fr)}}@media(max-width:768px){.grid-cols-2[data-v-8d8e2f5a]{grid-template-columns:1fr}.form-item[data-v-8d8e2f5a]{flex-direction:column;align-items:flex-start}.form-item label[data-v-8d8e2f5a]{min-width:auto}.form-item input[type=text][data-v-8d8e2f5a],.form-item input[type=number][data-v-8d8e2f5a],.form-item select[data-v-8d8e2f5a]{width:120px}}.form-item[data-v-ef2c2d78]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-ef2c2d78]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:100px}.form-item input[type=text][data-v-ef2c2d78],.form-item input[type=number][data-v-ef2c2d78],.form-item select[data-v-ef2c2d78]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-ef2c2d78]{margin-right:5px}.form-item[data-v-ef2c2d78]:has(input[type=checkbox]){width:auto}.form-item:has(input[type=checkbox]) label[data-v-ef2c2d78]{min-width:auto}.grid[data-v-ef2c2d78]{display:grid}.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-ef2c2d78]{gap:10px}.mb-4[data-v-ef2c2d78]{margin-bottom:12px}.mt-4[data-v-ef2c2d78]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-ef2c2d78]{grid-template-columns:1fr}.form-item[data-v-ef2c2d78]{flex-direction:column;align-items:flex-start}.form-item label[data-v-ef2c2d78]{min-width:auto}.form-item input[type=text][data-v-ef2c2d78],.form-item input[type=number][data-v-ef2c2d78],.form-item select[data-v-ef2c2d78]{width:120px}}.form-item[data-v-31b00dfd]{margin-bottom:5px;display:flex;align-items:center;gap:8px}.form-item label[data-v-31b00dfd]{font-weight:500;color:#555;font-size:13px;white-space:nowrap;min-width:80px}.form-item input[type=text][data-v-31b00dfd],.form-item input[type=number][data-v-31b00dfd],.form-item select[data-v-31b00dfd]{width:90px;min-width:80px;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:13px}.form-item input[type=checkbox][data-v-31b00dfd]{margin-right:5px}.grid[data-v-31b00dfd]{display:grid}.grid-cols-2[data-v-31b00dfd]{grid-template-columns:repeat(4,1fr)}@media(min-width:1024px){.grid-cols-2[data-v-31b00dfd]{grid-template-columns:repeat(5,1fr)}}@media(min-width:1200px){.grid-cols-2[data-v-31b00dfd]{grid-template-columns:repeat(6,1fr)}}.gap-4[data-v-31b00dfd]{gap:10px}.mb-4[data-v-31b00dfd]{margin-bottom:12px}.mt-4[data-v-31b00dfd]{margin-top:12px}@media(max-width:768px){.grid-cols-2[data-v-31b00dfd]{grid-template-columns:1fr}.form-item[data-v-31b00dfd]{flex-direction:column;align-items:flex-start}.form-item label[data-v-31b00dfd]{min-width:auto}.form-item input[type=text][data-v-31b00dfd],.form-item input[type=number][data-v-31b00dfd],.form-item select[data-v-31b00dfd]{width:120px}}.master-switch[data-v-21ca7315]{margin-bottom:16px}.switch-label[data-v-21ca7315]{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-weight:600;font-size:13px;color:#22c55e}.switch-label input[type=checkbox][data-v-21ca7315]{width:16px;height:16px;cursor:pointer;accent-color:#22c55e}.levels-config[data-v-21ca7315]{display:flex;flex-direction:column;gap:12px}.level-item[data-v-21ca7315]{border:1px solid #334155;border-radius:8px;padding:12px;background:#0f172a}.level-item h4[data-v-21ca7315]{margin:0 0 10px;font-size:13px;font-weight:600;color:#e2e8f0}.level-controls[data-v-21ca7315]{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.inline-check[data-v-21ca7315]{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-size:13px;color:#cbd5e1;white-space:nowrap}.inline-check input[type=checkbox][data-v-21ca7315]{width:14px;height:14px;cursor:pointer;accent-color:#22c55e}.field[data-v-21ca7315]{display:flex;align-items:center;gap:6px}.field.disabled[data-v-21ca7315]{opacity:.4;pointer-events:none}.field label[data-v-21ca7315]{font-size:12px;color:#64748b;white-space:nowrap}.field input[type=text][data-v-21ca7315]{width:80px;padding:4px 8px;border:1px solid #475569;border-radius:5px;font-size:13px;font-family:monospace;background:#1e293b;color:#e2e8f0;outline:none}.field input[type=text][data-v-21ca7315]:focus{border-color:#22c55e;box-shadow:0 0 0 2px #22c55e26}.field select[data-v-21ca7315]{padding:4px 8px;border:1px solid #475569;border-radius:5px;font-size:13px;background:#1e293b;color:#e2e8f0;outline:none}.hint[data-v-21ca7315]{font-size:11px;color:#64748b;white-space:nowrap}.yaml-output[data-v-235091b7]{border:1px solid #334155;border-radius:10px;overflow:hidden}.yaml-header[data-v-235091b7]{padding:12px 18px;background:#0f172a;font-size:14px;font-weight:600;color:#e2e8f0}.yaml-content[data-v-235091b7]{padding:16px 18px;background:#020617;max-height:360px;overflow-y:auto}.yaml-content pre[data-v-235091b7]{margin:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.6;color:#94a3b8;white-space:pre;word-wrap:break-word;-moz-tab-size:2;tab-size:2}.yaml-actions[data-v-235091b7]{padding:10px 18px;background:#0f172a;border-top:1px solid #334155;display:flex;gap:8px}.btn[data-v-235091b7]{padding:6px 14px;border:none;border-radius:6px;font-size:12px;cursor:pointer;font-family:inherit;transition:all .2s}.btn-green[data-v-235091b7]{background:#22c55e;color:#052e16}.btn-green[data-v-235091b7]:hover{background:#16a34a}.btn-ghost[data-v-235091b7]{background:transparent;color:#94a3b8;border:1px solid #475569}.btn-ghost[data-v-235091b7]:hover{background:#1e293b;color:#e2e8f0}.config-generator[data-v-7e8333a6]{width:100%}.app-content[data-v-7e8333a6]{display:flex;gap:20px;width:100%}.config-sections[data-v-7e8333a6]{flex:1;min-width:0}.yaml-preview[data-v-7e8333a6]{width:380px;min-width:280px;position:sticky;top:84px;align-self:flex-start;max-height:calc(100vh - 110px);overflow-y:auto}@media(max-width:1200px){.app-content[data-v-7e8333a6]{flex-direction:column}.yaml-preview[data-v-7e8333a6]{width:100%;position:static;max-height:none}}@media(max-width:768px){.app-content[data-v-7e8333a6]{gap:10px}}.config-sidebar[data-v-95c48163]{width:200px;min-width:180px;background:#1e293b;border-right:1px solid #334155;padding:1rem 0;height:100%;display:flex;flex-direction:column}.sidebar-header[data-v-95c48163]{display:flex;align-items:center;justify-content:space-between;padding:0 1rem .5rem}.sidebar-header h3[data-v-95c48163]{font-size:.85rem;color:#94a3b8;font-weight:600}.btn-refresh[data-v-95c48163]{background:none;border:1px solid #475569;color:#94a3b8;border-radius:4px;cursor:pointer;font-size:1rem;padding:0 6px}.btn-refresh[data-v-95c48163]:hover{color:#e2e8f0;background:#334155}.config-list[data-v-95c48163]{flex:1;overflow-y:auto;padding:0 .5rem}.config-item[data-v-95c48163]{padding:.4rem .75rem;cursor:pointer;border-radius:4px;font-size:.8rem;color:#cbd5e1;margin-bottom:2px;transition:background .15s}.config-item[data-v-95c48163]:hover{background:#334155}.config-item.active[data-v-95c48163]{background:#22c55e;color:#052e16;font-weight:600}.loading-text[data-v-95c48163],.empty-text[data-v-95c48163]{padding:.5rem;font-size:.75rem;color:#64748b;text-align:center}.settings-page[data-v-fc9e8f83]{max-width:520px;margin:0 auto}.settings-card[data-v-fc9e8f83]{background:#1e293b;border:1px solid #334155;border-radius:12px;padding:2rem}.settings-title[data-v-fc9e8f83]{font-size:1.15rem;font-weight:600;color:#f1f5f9;margin-bottom:.35rem;font-family:"Georgia, Times New Roman",serif}.settings-desc[data-v-fc9e8f83]{font-size:.8125rem;color:#64748b;margin-bottom:1.5rem}.connection-bar[data-v-fc9e8f83]{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-radius:8px;font-size:.8125rem;margin-bottom:1.5rem}.connection-dot[data-v-fc9e8f83]{width:8px;height:8px;border-radius:50%;flex-shrink:0}.bar-untested[data-v-fc9e8f83]{background:#0f172a;border:1px solid #334155;color:#64748b}.bar-untested .connection-dot[data-v-fc9e8f83]{background:#64748b}.bar-ok[data-v-fc9e8f83]{background:#052e16;border:1px solid #166534;color:#4ade80}.bar-ok .connection-dot[data-v-fc9e8f83]{background:#22c55e}.bar-fail[data-v-fc9e8f83]{background:#450a0a;border:1px solid #7f1d1d;color:#fca5a5}.bar-fail .connection-dot[data-v-fc9e8f83]{background:#ef4444}.connection-url[data-v-fc9e8f83]{margin-left:auto;font-family:monospace;font-size:.75rem;opacity:.8}.form-group[data-v-fc9e8f83]{margin-bottom:1rem}.form-label[data-v-fc9e8f83]{display:block;font-size:.8125rem;font-weight:500;color:#94a3b8;margin-bottom:.375rem}.form-input[data-v-fc9e8f83]{width:100%;padding:.625rem .75rem;font-size:.875rem;border:1px solid #475569;border-radius:8px;outline:none;background:#0f172a;color:#e2e8f0;transition:border-color .2s;font-family:inherit;box-sizing:border-box}.form-input[data-v-fc9e8f83]:focus{border-color:#22c55e;box-shadow:0 0 0 3px #22c55e26}.form-actions[data-v-fc9e8f83]{display:flex;gap:.75rem;margin-top:1.5rem}.btn[data-v-fc9e8f83]{padding:.5rem 1rem;font-size:.8125rem;font-weight:500;border:none;border-radius:6px;cursor:pointer;transition:all .2s;font-family:inherit}.btn[data-v-fc9e8f83]:disabled{opacity:.4;cursor:not-allowed}.btn-green[data-v-fc9e8f83]{background:#22c55e;color:#052e16}.btn-green[data-v-fc9e8f83]:hover:not(:disabled){background:#16a34a}.btn-ghost[data-v-fc9e8f83]{background:transparent;color:#94a3b8;border:1px solid #475569}.btn-ghost[data-v-fc9e8f83]:hover{background:#1e293b;color:#e2e8f0}*{margin:0;padding:0;box-sizing:border-box}body{background-color:#0f172a;color:#e2e8f0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,PingFang SC,Microsoft YaHei,sans-serif;-webkit-font-smoothing:antialiased}.app-container{width:100%;min-height:100vh;display:flex;flex-direction:column}.nav-bar{background-color:#1e293b;border-bottom:1px solid #334155;padding:0 2rem;position:sticky;top:0;z-index:100;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.nav-content{max-width:1400px;margin:0 auto;width:100%;display:flex;justify-content:space-between;align-items:center;height:64px}.app-title{font-family:Georgia,Times New Roman,serif;font-size:1.4rem;font-weight:600;color:#f1f5f9;margin:0;letter-spacing:-.02em}.nav-actions{display:flex;align-items:center;gap:.75rem}.config-actions{display:flex;gap:.5rem}.nav-tabs{display:flex;gap:.25rem;background:#0f172a;border-radius:8px;padding:3px}.btn{padding:.5rem 1rem;font-size:.8125rem;font-weight:500;border:none;border-radius:6px;cursor:pointer;transition:all .2s ease;font-family:inherit}.btn:disabled{opacity:.4;cursor:not-allowed}.primary-btn{background-color:#22c55e;color:#052e16}.primary-btn:hover:not(:disabled){background-color:#16a34a}.secondary-btn{background-color:#334155;color:#cbd5e1;border:1px solid #475569}.secondary-btn:hover:not(:disabled){background-color:#475569;border-color:#64748b}.nav-tab{padding:.45rem 1.25rem;font-size:.875rem;font-weight:500;border:none;border-radius:6px;background-color:transparent;color:#94a3b8;cursor:pointer;transition:all .2s ease;font-family:inherit}.nav-tab:hover{background-color:#1e293b;color:#e2e8f0}.nav-tab.active{background-color:#22c55e;color:#052e16}.main-area{display:flex;flex:1;overflow:hidden}.content-area{flex:1;padding:1.5rem 2rem;max-width:1400px;margin:0 auto;width:100%}@media(max-width:768px){.nav-content{flex-direction:column;height:auto;padding:1rem 0;gap:.75rem}.nav-tabs{width:100%;justify-content:center}.content-area{padding:1rem}} diff --git a/src/wordformat/api/static/index.html b/src/wordformat/api/static/index.html index 45aeba9..983750c 100644 --- a/src/wordformat/api/static/index.html +++ b/src/wordformat/api/static/index.html @@ -5,12 +5,8 @@ WordFormat - 论文格式自动化处理工具 - - - - - - + + diff --git a/src/wordformat/base.py b/src/wordformat/base.py index 4df0ee6..fab8dba 100644 --- a/src/wordformat/base.py +++ b/src/wordformat/base.py @@ -3,16 +3,26 @@ # @Author : afish # @File : DocxBase.py +import re + from docx import Document from loguru import logger from wordformat.agent.onnx_infer import onnx_batch_infer, onnx_single_infer - -# from wordformat.config.config import get_config, init_config from wordformat.settings import BATCH_SIZE from wordformat.utils import get_paragraph_numbering_text, get_paragraph_xml_fingerprint +def _para_contains_image(para) -> bool: + """检查段落是否包含内联图片(w:drawing)。""" + from docx.oxml.ns import qn + + for r in para._element.findall(qn("w:r")): + if r.find(qn("w:drawing")) is not None: + return True + return False + + class DocxBase: def __init__(self, docx_file, configpath): self.re_dict = {} @@ -31,40 +41,48 @@ def __init__(self, docx_file, configpath): # raise def parse(self) -> list[dict]: - paragraphs = [] - paragraph_objects = [] - result = [] - # 收集所有非空段落及其对象 - for para in self.document.paragraphs: + # 收集所有段落(含空段),空段/图片段直接标记,不走 AI 推理 + all_paras = list(self.document.paragraphs) + text_indices = [] + texts_for_ai = [] + for idx, para in enumerate(all_paras): text = para.text.strip() - if text: - # 拼接自动编号文字(para.text 不包含编号) - numbering_text = get_paragraph_numbering_text(para) - if numbering_text: - full_text = f"{numbering_text} {text}" - else: - full_text = para.text - paragraphs.append(full_text) - paragraph_objects.append(para) - - # 按批次BATCH_SIZE进行批量推理 - for i in range(0, len(paragraphs), BATCH_SIZE): - batch_texts = paragraphs[i : i + BATCH_SIZE] - batch_paras = paragraph_objects[i : i + BATCH_SIZE] + if not text: + continue + numbering_text = get_paragraph_numbering_text(para) + full_text = f"{numbering_text} {text}" if numbering_text else para.text + texts_for_ai.append(full_text) + text_indices.append(idx) + + result = [None] * len(all_paras) + for i, para in enumerate(all_paras): + if i not in text_indices: + has_image = _para_contains_image(para) + result[i] = { + "category": "figure_image" if has_image else "body_text", + "score": 1.0, + "comment": "图片段落" if has_image else "空段落", + "paragraph": "", + "fingerprint": get_paragraph_xml_fingerprint(para), + } + + # 对非空段进行批量 AI 推理 + for i in range(0, len(texts_for_ai), BATCH_SIZE): + batch_texts = texts_for_ai[i : i + BATCH_SIZE] + batch_indices = text_indices[i : i + BATCH_SIZE] try: batch_results = onnx_batch_infer(batch_texts) except Exception as e: logger.error(f"批量推理失败,降级到单条处理: {e}") - batch_results = [onnx_single_infer(text) for text in batch_texts] + batch_results = [onnx_single_infer(t) for t in batch_texts] - # batch 结果,应用后处理逻辑 - for _j, (text, para_obj, pred) in enumerate( - zip(batch_texts, batch_paras, batch_results, strict=False) + for idx, text, pred in zip( + batch_indices, batch_texts, batch_results, strict=False ): tag = pred["label"] score = pred["score"] - + para_obj = all_paras[idx] response = { "category": tag, "score": score, @@ -72,13 +90,49 @@ def parse(self) -> list[dict]: "paragraph": text, "fingerprint": get_paragraph_xml_fingerprint(para_obj), } - - # 置信度过低处理 if score < 0.6: response["category"] = "body_text" response["comment"] = ( f"原预测标签为 '{tag}',置信度 {score:.4f} < 0.6,已强制设为 'body_text'" ) - result.append(response) + result[idx] = response + assert all(r is not None for r in result), "存在未处理的段落" + # 后处理:已知模式的段落强制修正分类 + _fix_known_categories(result) return result + + +def _fix_known_categories(result: list[dict]) -> None: + """用已知文本模式修正常见 AI 分类错误。""" + abstract_patterns = [ + (r"^(摘要)\s*$", "abstract_chinese_title"), + (r"^(Abstract)\s*$", "abstract_english_title"), + (r"^摘要\s*[::]", "abstract_chinese_title_content"), + (r"^Abstract\s*[::]?", "abstract_english_title_content"), + ] + # 找到第一个摘要段落的位置,之前的内容全部标为 other(封面/声明) + abstract_start = None + for i, item in enumerate(result): + text = (item.get("paragraph") or "").strip() + if re.match(r"^(摘要|Abstract)", text): + abstract_start = i + break + if abstract_start is not None: + for i in range(abstract_start): + result[i]["category"] = "other" + result[i]["comment"] = ( + f"摘要前内容,跳过检查(原:{result[i]['category']})" + ) + result[i]["score"] = 1.0 + # 摘要修正 + for item in result: + if item["category"] == "other": + continue + text = (item.get("paragraph") or "").strip() + if item["category"] == "body_text": + for pat, cat in abstract_patterns: + if re.match(pat, text): + item["category"] = cat + item["comment"] = f"模式修正为 {cat}" + break diff --git a/src/wordformat/cli.py b/src/wordformat/cli.py index 201de8e..43fc021 100644 --- a/src/wordformat/cli.py +++ b/src/wordformat/cli.py @@ -36,103 +36,123 @@ def validate_file( def _show_config(): - """输出所有可配置字段及其说明""" - from wordformat.config.datamodel import ( - CaptionNumberingConfig, - GlobalFormatConfig, - KeywordsConfig, - NumberingConfig, - NumberingLevelConfig, - WarningFieldConfig, - ) + """根据 NodeConfigRoot Pydantic 模型自动生成所有可配置字段的参考说明。 - def _fields(cls): - return [(n, i) for n, i in cls.model_fields.items()] + 递归遍历模型结构,无需手动维护字段列表。新增/删除配置字段时自动反映。 + """ + from pydantic import BaseModel - def _desc(info): - return (info.description or "").replace("\n", " ") + from wordformat.config.datamodel import NodeConfigRoot - def _default(info): + def _default_str(info): if info.default is not None: return repr(info.default) if info.default_factory is not None: return "(子配置)" return "—" - def _print_fields(fields, indent=2): - prefix = " " * indent - for name, info in fields: - print(f"{prefix}{name:<28s} {_desc(info):<40s} 默认: {_default(info)}") - - gf = _fields(GlobalFormatConfig) - wf = _fields(WarningFieldConfig) - kw_extra = [ - (n, i) for n, i in _fields(KeywordsConfig) if n not in {f[0] for f in gf} - ] - nc = _fields(NumberingConfig) - ncp = _fields(CaptionNumberingConfig) - nl = _fields(NumberingLevelConfig) - - # 段落节点名列表(从 NodeConfigRoot 直接读) - paragraph_nodes = [ - ("global_format", "全局基础格式"), - ("abstract.chinese.chinese_title", "中文摘要标题"), - ("abstract.chinese.chinese_content", "中文摘要正文"), - ("abstract.english.english_title", "英文摘要标题"), - ("abstract.english.english_content", "英文摘要正文"), - ("abstract.keywords.chinese", "中文关键词"), - ("abstract.keywords.english", "英文关键词"), - ("headings.level_1", "一级标题"), - ("headings.level_2", "二级标题"), - ("headings.level_3", "三级标题"), - ("body_text", "正文"), - ("figures", "图注"), - ("tables", "表注"), - ("references.title", "参考文献标题"), - ("references.content", "参考文献内容"), - ("acknowledgements.title", "致谢标题"), - ("acknowledgements.content", "致谢内容"), - ] - - # 每个节点的额外字段 - extras = { - "figures": [("caption_prefix", "图注编号前缀", "'图'")], - "tables": [ - ("caption_prefix", "表注编号前缀", "'表'"), - ("content", "表格内容格式(子配置,字段同 global_format)", "(子配置)"), - ], - "abstract.keywords.chinese": [(n, _desc(i), _default(i)) for n, i in kw_extra], - "abstract.keywords.english": [(n, _desc(i), _default(i)) for n, i in kw_extra], - } - - print("config.yaml 完整字段参考\n") - - for path, label in paragraph_nodes: - print(f"[{path}] — {label}") - _print_fields(gf) - for name, desc, default in extras.get(path, []): - print(f" {name:<28s} {desc:<40s} 默认: {default}") - print() - - print("[style_checks_warning] — 格式警告开关") - _print_fields(wf) - print() + def _desc(info): + return (info.description or "").replace("\n", " ") - print("[numbering] — 自动编号总开关(仅 wordf af 模式生效)") - for n, i in nc: - if n not in ("level_1", "level_2", "level_3", "references", "captions"): - print(f" {n:<28s} {_desc(i):<40s} 默认: {_default(i)}") - print() + # 已知的基础类型名称,遇到这些就停止递进 + LEAF_TYPES = { + "GlobalFormatConfig", + "BodyTextConfig", + "HeadingLevelConfig", + "AbstractTitleConfig", + "AbstractContentConfig", + "KeywordLabelConfig", + "KeywordsConfig", + "ReferencesTitleConfig", + "ReferencesContentConfig", + "AcknowledgementsTitleConfig", + "AcknowledgementsContentConfig", + "TableContentConfig", + "WarningFieldConfig", + "CaptionNumberingConfig", + "NumberingLevelConfig", + "KeywordCountRule", + "TrailingPunctRule", + "KeywordsRulesConfig", + "CaptionRulesConfig", + } - print("[numbering.captions] — 题注编号") - _print_fields(ncp) + def _resolve_type(annotation): + """解析 typing 注解,返回实际类型。""" + origin = getattr(annotation, "__origin__", None) + if origin is dict: + args = getattr(annotation, "__args__", ()) + if len(args) == 2: + return _resolve_type(args[1]) + return None + args = getattr(annotation, "__args__", None) + if args: + non_none = [a for a in args if a is not type(None)] + if non_none: + return _resolve_type(non_none[0]) + return None + if isinstance(annotation, type): + return annotation + return None + + def _is_basemodel_subclass(t): + return isinstance(t, type) and issubclass(t, BaseModel) + + def _walk(cls, path="", depth=0): + """递归打印模型字段。""" + for name, info in cls.model_fields.items(): + field_path = f"{path}.{name}" if path else name + target = _resolve_type(info.annotation) + desc_text = _desc(info) + + if target is None: + continue + + target_name = getattr(target, "__name__", "") + + if _is_basemodel_subclass(target) and target_name not in LEAF_TYPES: + # 容器模型:打印节标题后递归 + label = desc_text or target_name + print(f"\n{' ' * depth}[{field_path}] — {label}") + _walk(target, field_path, depth + 1) + elif _is_basemodel_subclass(target) and target_name in LEAF_TYPES: + # 叶子配置模型:展开打印字段,不递归 + label = desc_text or target_name + print(f"\n{' ' * depth}[{field_path}] — {label}") + _print_leaf_fields(target, depth + 1) + elif target is str: + print( + f"{' ' * depth} {name:<30s} {desc_text:<50s} 默认: {_default_str(info)}" + ) + elif target is bool: + print( + f"{' ' * depth} {name:<30s} {desc_text:<50s} 默认: {_default_str(info)}" + ) + elif target is int: + print( + f"{' ' * depth} {name:<30s} {desc_text:<50s} 默认: {_default_str(info)}" + ) + elif target is float: + print( + f"{' ' * depth} {name:<30s} {desc_text:<50s} 默认: {_default_str(info)}" + ) + + def _print_leaf_fields(cls, depth): + for name, info in cls.model_fields.items(): + target = _resolve_type(info.annotation) + if _is_basemodel_subclass(target): + # 嵌套的叶子模型(如 label, content) + print(f"{' ' * depth} [{name}] — {_desc(info)}") + _print_leaf_fields(target, depth + 1) + else: + print( + f"{' ' * depth} {name:<28s} {_desc(info):<50s} 默认: {_default_str(info)}" + ) + + print("config.yaml 完整字段参考(自动生成自 NodeConfigRoot 模型)\n") + _walk(NodeConfigRoot) print() - for key in ("level_1", "level_2", "level_3", "references"): - print(f"[numbering.{key}] — 编号配置") - _print_fields(nl) - print() - def main(): from wordformat.log_config import setup_logger diff --git a/src/wordformat/config/datamodel.py b/src/wordformat/config/datamodel.py index c15cb13..551eab8 100644 --- a/src/wordformat/config/datamodel.py +++ b/src/wordformat/config/datamodel.py @@ -47,6 +47,15 @@ class WarningFieldConfig(BaseModel): builtin_style_name: bool = Field(default=True, description="内置样式名称") +# -------------------------- 规则引擎基类 -------------------------- + + +class BaseRuleConfig(BaseModel): + """所有业务规则的基类,enabled 控制规则开关。""" + + enabled: bool = Field(default=True, description="是否启用此规则") + + # -------------------------- 基础配置模型 -------------------------- class GlobalFormatConfig(BaseModel): """全局基础格式配置模型""" @@ -99,26 +108,22 @@ class KeywordLabelConfig(GlobalFormatConfig): """关键词标签格式配置("关键词:"或"Keywords:"部分的字符格式)""" -class KeywordsConfig(GlobalFormatConfig): - """关键词配置模型(继承全局格式,用于关键词内容部分)""" +class KeywordCountRule(BaseRuleConfig): + """关键词数量校验规则""" - label: KeywordLabelConfig = Field( - default_factory=KeywordLabelConfig, description="关键词标签的字符格式" - ) count_min: int = Field(default=4, description="最小关键字数") - count_max: int = Field(default=4, description="最大关键字数") - trailing_punct_forbidden: bool = Field(default=True, description="禁止最后有标点") + count_max: int = Field(default=6, description="最大关键字数") @field_validator("count_min", "count_max") @classmethod - def validate_keyword_count(cls, v, info): + def validate_keyword_count(cls, v): """验证关键词数量为正整数""" if v <= 0: raise ValueError(f"关键词数量 {v} 必须大于0") return v @model_validator(mode="after") - def validate_count_range(self) -> "KeywordsConfig": + def validate_count_range(self) -> "KeywordCountRule": """验证 count_min <= count_max""" if self.count_min > self.count_max: raise ValueError( @@ -127,6 +132,32 @@ def validate_count_range(self) -> "KeywordsConfig": return self +class TrailingPunctRule(BaseRuleConfig): + """关键词末尾标点校验规则""" + + forbidden_chars: str = Field( + default=";,。、", description="禁止出现在关键词末尾的标点" + ) + + +class KeywordsRulesConfig(BaseModel): + """关键词业务规则集合 —— 所有规则均可通过 enabled 开关控制""" + + keyword_count: KeywordCountRule = Field(default_factory=KeywordCountRule) + trailing_punctuation: TrailingPunctRule = Field(default_factory=TrailingPunctRule) + + +class KeywordsConfig(GlobalFormatConfig): + """关键词配置模型(继承全局格式,用于关键词内容部分)""" + + label: KeywordLabelConfig = Field( + default_factory=KeywordLabelConfig, description="关键词标签的字符格式" + ) + rules: KeywordsRulesConfig = Field( + default_factory=KeywordsRulesConfig, description="关键词业务规则配置" + ) + + class AbstractTitleConfig(GlobalFormatConfig): """摘要标题配置(继承全局格式)""" @@ -196,16 +227,68 @@ class HeadingsConfig(BaseModel): ) +# -------------------------- 正文规则 -------------------------- +class PunctuationRule(BaseRuleConfig): + """半角/全角标点符号校验规则""" + + enabled: bool = Field(default=True, description="是否启用标点符号校验") + + +class BodyTextRulesConfig(BaseModel): + """正文业务规则集合""" + + punctuation: PunctuationRule = Field(default_factory=PunctuationRule) + + # -------------------------- 正文配置模型 -------------------------- class BodyTextConfig(GlobalFormatConfig): """正文配置(继承全局格式)""" + rules: BodyTextRulesConfig = Field( + default_factory=BodyTextRulesConfig, description="正文业务规则配置" + ) + + +# -------------------------- 题注编号配置模型 -------------------------- +class CaptionNumberingConfig(BaseRuleConfig): + """题注编号校验/修正配置模型""" + + enabled: bool = Field(default=False, description="是否启用题注编号校验/修正") + separator: str = Field( + default=".", + description="章节号与题注编号间的分隔符,如 . - : — –", + ) + label_number_space: bool = Field( + default=False, + description="标签与编号之间是否加空格(图 1.1 vs 图1.1)", + ) + + +# -------------------------- 题注规则集合 -------------------------- +class CaptionRulesConfig(BaseModel): + """题注业务规则集合""" + + caption_numbering: CaptionNumberingConfig = Field( + default_factory=CaptionNumberingConfig, + description="题注编号校验/修正规则", + ) + # -------------------------- 插图配置模型 -------------------------- +class ImageFormatConfig(GlobalFormatConfig): + """图片段落格式配置(包含内联图片的段落,非题注)""" + + class FiguresConfig(GlobalFormatConfig): - """插图配置""" + """插图配置(题注格式 + 图片段落格式)""" caption_prefix: Optional[str] = Field(default="图", description="图注编号前缀") + image: ImageFormatConfig = Field( + default_factory=ImageFormatConfig, description="图片段落格式" + ) + rules: CaptionRulesConfig = Field( + default_factory=CaptionRulesConfig, description="题注业务规则配置" + ) # -------------------------- 表格配置模型 -------------------------- @@ -213,13 +296,23 @@ class TableContentConfig(GlobalFormatConfig): """表格内容格式配置(表格内单元格文字的字体、字号、行距等)""" +class TableObjectConfig(GlobalFormatConfig): + """表格对象格式配置(表格整体对齐、环绕等)""" + + class TablesConfig(GlobalFormatConfig): - """表格配置(题注格式 + 表格内容格式)""" + """表格配置(题注格式 + 表格对象格式 + 表格内容格式)""" caption_prefix: Optional[str] = Field(default="表", description="表注编号前缀") + object: TableObjectConfig = Field( + default_factory=TableObjectConfig, description="表格对象格式" + ) content: TableContentConfig = Field( default_factory=TableContentConfig, description="表格内容格式" ) + rules: CaptionRulesConfig = Field( + default_factory=CaptionRulesConfig, description="题注业务规则配置" + ) # -------------------------- 参考文献配置模型 -------------------------- @@ -264,21 +357,6 @@ class AcknowledgementsConfig(BaseModel): ) -# -------------------------- 题注编号配置模型 -------------------------- -class CaptionNumberingConfig(BaseModel): - """题注编号校验/修正配置模型""" - - enabled: bool = Field(default=False, description="是否启用题注编号校验/修正") - separator: str = Field( - default=".", - description="章节号与题注编号间的分隔符,如 . - : — –", - ) - label_number_space: bool = Field( - default=False, - description="标签与编号之间是否加空格(图 1.1 vs 图1.1)", - ) - - # -------------------------- 编号配置模型 -------------------------- class NumberingLevelConfig(BaseModel): """单级标题编号配置""" @@ -347,6 +425,9 @@ class NumberingConfig(BaseModel): class NodeConfigRoot(BaseModel): """配置根节点模型""" + template_name: str = Field( + default="未知模板", description="模板名称(用于检测报告中显示)" + ) style_checks_warning: WarningFieldConfig = Field( default_factory=WarningFieldConfig, description="警告字段配置" ) diff --git a/src/wordformat/rules/__init__.py b/src/wordformat/rules/__init__.py index 6ab0b78..902c3d9 100644 --- a/src/wordformat/rules/__init__.py +++ b/src/wordformat/rules/__init__.py @@ -17,6 +17,7 @@ from .heading import HeadingLevel1Node, HeadingLevel2Node, HeadingLevel3Node from .keywords import KeywordsCN, KeywordsEN from .node import FormatNode +from .object import FigureImage, TableObject from .references import ReferenceEntry, References __all__ = [ @@ -33,6 +34,8 @@ "BodyText", "CaptionFigure", "CaptionTable", + "FigureImage", + "TableObject", "HeadingLevel1Node", "HeadingLevel2Node", "HeadingLevel3Node", diff --git a/src/wordformat/rules/abstract.py b/src/wordformat/rules/abstract.py index 5c802a8..7166280 100644 --- a/src/wordformat/rules/abstract.py +++ b/src/wordformat/rules/abstract.py @@ -17,43 +17,16 @@ class AbstractTitleCN(FormatNode[AbstractTitleConfig]): """摘要标题中文节点""" NODE_TYPE = "abstract.chinese.chinese_title" + NODE_LABEL = "中文摘要标题" CONFIG_MODEL = AbstractTitleConfig CONFIG_PATH = "abstract.chinese.chinese_title" - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - ps = ParagraphStyle.from_config(cfg) - if p: - issues = ps.diff_from_paragraph(self.paragraph) - else: - issues = ps.apply_to_paragraph(self.paragraph) - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - self.add_comment( - doc=doc, runs=self.paragraph.runs, text=ParagraphStyle.to_string(issues) - ) - class AbstractTitleContentCN(FormatNode[AbstractChineseConfig]): """摘要标题正文混合中文节点""" NODE_TYPE = "abstract.chinese" + NODE_LABEL = "中文摘要" CONFIG_MODEL = AbstractChineseConfig CONFIG_PATH = "abstract.chinese" @@ -108,10 +81,14 @@ def _base(self, doc, p: bool, r: bool): else: diff_result = C.apply_to_run(run) self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff_result, target=self.NODE_LABEL), ) self.add_comment( - doc=doc, runs=self.paragraph.runs, text=ParagraphStyle.to_string(issues) + doc=doc, + runs=self.paragraph.runs, + text=ParagraphStyle.to_string(issues, target=self.NODE_LABEL), ) @@ -119,6 +96,7 @@ class AbstractContentCN(FormatNode[AbstractChineseConfig]): """摘要内容中文节点""" NODE_TYPE = "abstract.chinese.chinese_content" + NODE_LABEL = "中文摘要正文" CONFIG_MODEL = AbstractChineseConfig CONFIG_PATH = "abstract.chinese" @@ -144,10 +122,14 @@ def _base(self, doc, p: bool, r: bool): else: diff_result = cstyle.apply_to_run(run) self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff_result, target=self.NODE_LABEL), ) self.add_comment( - doc=doc, runs=self.paragraph.runs, text=ParagraphStyle.to_string(issues) + doc=doc, + runs=self.paragraph.runs, + text=ParagraphStyle.to_string(issues, target=self.NODE_LABEL), ) @@ -155,48 +137,16 @@ class AbstractTitleEN(FormatNode[AbstractTitleConfig]): """摘要标题英文节点""" NODE_TYPE = "abstract.english.english_title" + NODE_LABEL = "英文摘要标题" CONFIG_MODEL = AbstractTitleConfig CONFIG_PATH = "abstract.english.english_title" - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - ps = ParagraphStyle.from_config(cfg) - if p: - issues = ps.diff_from_paragraph(self.paragraph) - else: - issues = ps.apply_to_paragraph(self.paragraph) - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - if issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text="".join(str(dr) for dr in issues), - ) - return [] - class AbstractTitleContentEN(FormatNode[AbstractEnglishConfig]): """摘要标题正文混合英文节点""" NODE_TYPE = "abstract.english" + NODE_LABEL = "英文摘要" CONFIG_MODEL = AbstractEnglishConfig CONFIG_PATH = "abstract.english" @@ -278,11 +228,15 @@ def _base(self, doc, p: bool, r: bool): else: diff_result = c.apply_to_run(run) self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff_result, target=self.NODE_LABEL), ) cum += len(text_clean) self.add_comment( - doc=doc, runs=self.paragraph.runs, text=ParagraphStyle.to_string(issues) + doc=doc, + runs=self.paragraph.runs, + text=ParagraphStyle.to_string(issues, target=self.NODE_LABEL), ) @@ -290,6 +244,7 @@ class AbstractContentEN(FormatNode[AbstractEnglishConfig]): """摘要内容英文节点""" NODE_TYPE = "abstract.english.english_content" + NODE_LABEL = "英文摘要正文" CONFIG_MODEL = AbstractEnglishConfig CONFIG_PATH = "abstract.english" @@ -316,7 +271,9 @@ def _base(self, doc, p: bool, r: bool): diff_result = cstyle.apply_to_run(run) if diff_result: # 可选:仅当有差异时才添加批注 self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff_result, target=self.NODE_LABEL), ) if issues: self.add_comment( diff --git a/src/wordformat/rules/acknowledgement.py b/src/wordformat/rules/acknowledgement.py index 132aa88..07c626b 100644 --- a/src/wordformat/rules/acknowledgement.py +++ b/src/wordformat/rules/acknowledgement.py @@ -8,109 +8,21 @@ AcknowledgementsTitleConfig, ) from wordformat.rules.node import FormatNode -from wordformat.style.check_format import CharacterStyle, ParagraphStyle class Acknowledgements(FormatNode[AcknowledgementsTitleConfig]): """致谢节点""" NODE_TYPE = "acknowledgements" + NODE_LABEL = "致谢标题" CONFIG_MODEL = AcknowledgementsTitleConfig CONFIG_PATH = "acknowledgements.title" - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - # 段落样式 - ps = ParagraphStyle.from_config(cfg) - if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) - else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - # 字符样式 - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 检查每个 run 的字符格式 - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: # 仅当有差异时添加批注 - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 检查段落格式差异 - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - - return [] - class AcknowledgementsCN(FormatNode[AcknowledgementsContentConfig]): """致谢内容""" NODE_TYPE = "acknowledgements.content" + NODE_LABEL = "致谢内容" CONFIG_MODEL = AcknowledgementsContentConfig CONFIG_PATH = "acknowledgements.content" - - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - # 段落样式 - ps = ParagraphStyle( - alignment=cfg.alignment, - space_before=cfg.space_before, - space_after=cfg.space_after, - line_spacing=cfg.line_spacing, - line_spacingrule=cfg.line_spacingrule, - first_line_indent=cfg.first_line_indent, - builtin_style_name=cfg.builtin_style_name, - ) - if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) - else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - # 字符样式 - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 检查每个 run 的字符格式 - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: # 仅当有差异时添加批注 - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 检查段落格式差异 - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - return [] diff --git a/src/wordformat/rules/body.py b/src/wordformat/rules/body.py index b2d3467..c3859ce 100644 --- a/src/wordformat/rules/body.py +++ b/src/wordformat/rules/body.py @@ -9,21 +9,122 @@ from docx.oxml import OxmlElement from docx.oxml.ns import qn -from wordformat.config.datamodel import BodyTextConfig +from wordformat.config.datamodel import BodyTextConfig, PunctuationRule from wordformat.rules.node import FormatNode -from wordformat.style.check_format import CharacterStyle, ParagraphStyle # 匹配正文中的参考文献交叉引用标记 # 支持: [1] [1,2] [1-3] [1,2,3-5] [1,2] [1、2] [1, 2] _CITATION_PATTERN = re.compile(r"\[[\d\-,—、,\s]+\]") +# 半角标点 → 对应全角标点 +_HALF_TO_FULL = { + ",": ",", + ".": "。", + ";": ";", + ":": ":", + "(": "(", + ")": ")", + "[": "【", + "]": "】", + '"': "“", + "'": "‘", + "!": "!", + "?": "?", +} +# 匹配中文上下文中的半角标点(段首/中文后 + 标点 + 中文/段尾) +_PUNCT_PATTERN = re.compile(r"(^|[一-鿿])([,.;:()\[\]\"\'\!\?])([一-鿿]|$)") + + +def _split_run_at(paragraph, start: int, end: int): + """拆分段落 run,返回只含 [start, end) 字符的独立 run。""" + from docx.oxml import OxmlElement + + para_elem = paragraph._element + cum = 0 + for r_elem in para_elem.findall(qn("w:r")): + t_elem = r_elem.find(qn("w:t")) + if t_elem is None or t_elem.text is None: + continue + rl = len(t_elem.text) + r_start, r_end = cum, cum + rl + if r_start <= start and end <= r_end: + i0 = start - r_start + i1 = end - r_start + before_text = t_elem.text[:i0] + punct_text = t_elem.text[i0:i1] + after_text = t_elem.text[i1:] + # 修改原 run 为标点前的文本 + t_elem.text = before_text + if before_text and before_text != before_text.strip(): + t_elem.set(qn("xml:space"), "preserve") + # 创建标点 run + rPr = r_elem.find(qn("w:rPr")) + punct_r = OxmlElement("w:r") + if rPr is not None: + punct_r.append(deepcopy(rPr)) + punct_t = OxmlElement("w:t") + punct_t.text = punct_text + punct_t.set(qn("xml:space"), "preserve") + punct_r.append(punct_t) + r_elem.addnext(punct_r) + # 创建标点后的 run + if after_text: + after_r = OxmlElement("w:r") + if rPr is not None: + after_r.append(deepcopy(rPr)) + after_t = OxmlElement("w:t") + after_t.text = after_text + after_t.set(qn("xml:space"), "preserve") + after_r.append(after_t) + punct_r.addnext(after_r) + # 返回新 run 对象 + for r in paragraph.runs: + if r._element is punct_r: + return r + return None + cum += rl + return None + class BodyText(FormatNode[BodyTextConfig]): """正文节点""" NODE_TYPE = "body_text" + NODE_LABEL = "正文段落" CONFIG_MODEL = BodyTextConfig CONFIG_PATH = "body_text" + RULES = {"punctuation": "_check_punctuation"} + + def _check_punctuation(self, doc, rule_cfg: PunctuationRule, p: bool = False): + """检测中文正文中的半角标点,锚在具体字符上(拆分 run)。""" + if self.paragraph is None: + return + # 找出引用标记区间,跳过引用内的标点 + cite_ranges = [ + (m.start(), m.end()) + for m in _CITATION_PATTERN.finditer(self.paragraph.text) + ] + para_text = self.paragraph.text + for m in _PUNCT_PATTERN.finditer(para_text): + p0, p1 = m.start(2), m.end(2) + if any(cs <= p0 < ce for cs, ce in cite_ranges): + continue + half = m.group(2) + full = _HALF_TO_FULL.get(half, half) + # 拆分 run,使标点独占一个 run + target_run = _split_run_at(self.paragraph, p0, p1) + if target_run is None: + target_run = ( + self.paragraph.runs[0] + if self.paragraph.runs + else self.paragraph.runs + ) + msg = ( + f"{self.NODE_LABEL}-提醒-标点符号问题:" + f'使用了半角英文标点符号"{half}(英文)",' + f'规范:应使用全角中文标点符号"{full}(中文)"' + ) + self.add_comment(doc=doc, runs=target_run, text=msg) def apply_replace(self, doc=None) -> bool: """文本替换后清除引用标记格式。 @@ -44,51 +145,17 @@ def apply_replace(self, doc=None) -> bool: return replaced - def _base(self, doc, p: bool, r: bool): - """检查正文段落的字符与段落格式是否符合规范。""" - cfg = self.pydantic_config - ps = ParagraphStyle.from_config(cfg) - if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) - else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - - return [] - def apply_format(self, doc): - """格式化正文段落,之后将引用标记自动设为上标。""" + """格式化正文段落,引用标记上标仅限第一章。""" super().apply_format(doc) - self._apply_citation_superscript() + chapter = ( + self.value.get("chapter_number", 0) if isinstance(self.value, dict) else 0 + ) + if chapter == 1: + self._apply_citation_superscript() # ------------------------------------------------------------------ - # 引用上标 + # 引用上标(仅第一章) # ------------------------------------------------------------------ def _apply_citation_superscript(self): diff --git a/src/wordformat/rules/caption.py b/src/wordformat/rules/caption.py index c7f9294..5461539 100644 --- a/src/wordformat/rules/caption.py +++ b/src/wordformat/rules/caption.py @@ -10,7 +10,6 @@ TablesConfig, ) from wordformat.rules.node import FormatNode -from wordformat.style.check_format import CharacterStyle, ParagraphStyle from wordformat.utils import parse_caption_text @@ -44,30 +43,68 @@ def _check_caption_numbering( return parsed = parse_caption_text(text) + from wordformat.style.comment_format import format_comment + + target = getattr(node, "NODE_LABEL", "题注") + if parsed is None: - node.add_comment(document, paragraph.runs, f"题注格式无法识别:'{text[:50]}'") + node.add_comment( + document, + paragraph.runs, + format_comment( + target, "格式错误", f"无法识别'{text[:50]}'", "正确题注格式" + ), + ) return issues = [] if parsed["label"] != expected_label: - issues.append(f"题注标签应为'{expected_label}',当前为'{parsed['label']}'") + issues.append( + format_comment( + target, + "标签错误", + f"当前为'{parsed['label']}'", + f"应为'{expected_label}'", + ) + ) # 检查标签与编号之间的空格(跳过续前缀再检查) check_text = text[1:].lstrip() if parsed.get("is_continued") else text label_with_space = check_text.startswith(f"{expected_label} ") if label_with_space != numbering_cfg.label_number_space: want = "有空格" if numbering_cfg.label_number_space else "无空格" - issues.append(f"标签与编号间应为{want}") + issues.append(format_comment(target, "间距错误", "当前不符合", f"应为{want}")) ch = parsed.get("chapter_num") if ch is not None and ch != chapter: - issues.append(f"章节号应为{chapter},当前为{ch}") + issues.append( + format_comment( + target, + "章节号错误", + f"当前为{ch}", + f"应为{chapter}", + ) + ) if parsed["separator"] != separator: - issues.append(f"分隔符应为'{separator}',当前为'{parsed['separator']}'") + issues.append( + format_comment( + target, + "分隔符错误", + f"当前为'{parsed['separator']}'", + f"应为'{separator}'", + ) + ) num = parsed.get("number_num") if num is not None and num != seq: - issues.append(f"题注编号应为{seq},当前为{num}") + issues.append( + format_comment( + target, + "编号错误", + f"当前为{num}", + f"应为{seq}", + ) + ) if issues: - node.add_comment(document, paragraph.runs, ";".join(issues)) + node.add_comment(document, paragraph.runs, "\n".join(issues)) def _apply_caption_numbering( @@ -101,111 +138,33 @@ class CaptionFigure(FormatNode[FiguresConfig]): """题注-图片""" NODE_TYPE = "figures" + NODE_LABEL = "图注" CONFIG_MODEL = FiguresConfig CONFIG_PATH = "figures" + RULES = {"caption_numbering": "_handle_caption_numbering"} - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - # 段落样式 - ps = ParagraphStyle.from_config(cfg) + def _handle_caption_numbering(self, doc, rule_cfg: CaptionNumberingConfig, p: bool): + """题注编号校验/修正""" + prefix = self.pydantic_config.caption_prefix or "图" if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) + _check_caption_numbering(self, doc, prefix, rule_cfg) else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - # 字符样式 - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 检查每个 run 的字符格式 - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 检查段落格式差异 - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - - # 题注编号校验/修正(仅当 value 为 dict 且有 _numbering_cfg 时才执行) - if isinstance(self.value, dict): - numbering_cfg = self.value.get("_numbering_cfg") - if numbering_cfg and numbering_cfg.enabled: - prefix = cfg.caption_prefix or "图" - if p: - _check_caption_numbering(self, doc, prefix, numbering_cfg) - else: - _apply_caption_numbering(self, prefix, numbering_cfg) + _apply_caption_numbering(self, prefix, rule_cfg) class CaptionTable(FormatNode[TablesConfig]): """题注-表格""" NODE_TYPE = "tables" + NODE_LABEL = "表注" CONFIG_MODEL = TablesConfig CONFIG_PATH = "tables" + RULES = {"caption_numbering": "_handle_caption_numbering"} - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - # 段落样式 - ps = ParagraphStyle.from_config(cfg) + def _handle_caption_numbering(self, doc, rule_cfg: CaptionNumberingConfig, p: bool): + """题注编号校验/修正""" + prefix = self.pydantic_config.caption_prefix or "表" if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) + _check_caption_numbering(self, doc, prefix, rule_cfg) else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - # 字符样式 - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 检查每个 run 的字符格式 - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 检查段落格式差异 - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - - # 题注编号校验/修正(仅当 value 为 dict 且有 _numbering_cfg 时才执行) - if isinstance(self.value, dict): - numbering_cfg = self.value.get("_numbering_cfg") - if numbering_cfg and numbering_cfg.enabled: - prefix = cfg.caption_prefix or "表" - if p: - _check_caption_numbering(self, doc, prefix, numbering_cfg) - else: - _apply_caption_numbering(self, prefix, numbering_cfg) + _apply_caption_numbering(self, prefix, rule_cfg) diff --git a/src/wordformat/rules/heading.py b/src/wordformat/rules/heading.py index d4274aa..ccee8d2 100644 --- a/src/wordformat/rules/heading.py +++ b/src/wordformat/rules/heading.py @@ -3,12 +3,10 @@ # @Author : afish # @File : heading.py -from docx.document import Document from loguru import logger from wordformat.config.datamodel import HeadingLevelConfig, NodeConfigRoot from wordformat.rules.node import FormatNode -from wordformat.style.check_format import CharacterStyle, ParagraphStyle class BaseHeadingNode(FormatNode[HeadingLevelConfig]): @@ -57,82 +55,6 @@ def load_config(self, root_config: dict | NodeConfigRoot): logger.error(f"{self.LEVEL}级标题配置加载失败:{str(e)}") raise # 抛出异常,避免后续使用错误配置 - def _base(self, doc: Document, p: bool, r: bool): - """通用标题格式检查逻辑""" - # 修复:空值校验(直接检查底层私有属性 _pydantic_config) - if self._pydantic_config is None: - error_msg = f"{self.LEVEL}级标题配置未加载,跳过检查" - self.add_comment(doc=doc, runs=self.paragraph.runs, text=error_msg) - logger.warning(error_msg) - return [ - {"error": error_msg, "level": self.LEVEL, "node_type": self.NODE_TYPE} - ] - - # 类型断言(读取@property的 pydantic_config,本质是 _pydantic_config) - cfg = self.pydantic_config - - # 段落样式:由 ParagraphStyle.apply_to_paragraph 先应用 builtin_style_name, - # 再应用显式段落格式(对齐、缩进、间距等),后者覆盖前者的对应属性。 - ps = ParagraphStyle.from_config(cfg) - if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) - else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - # 字符样式检查(完整使用所有配置字段) - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 逐run检查并添加批注 - run_issues = [] - for idx, run in enumerate(self.paragraph.runs): - if not run.text.strip(): - continue # 跳过空白run,减少无效检查 - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: - run_issue = { - "run_index": idx, - "run_text": run.text, - "diff": diff_result, - } - run_issues.append(run_issue) - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 段落样式批注 - all_issues = [] - if paragraph_issues: - para_issue = { - "type": "paragraph_style", - "diff": paragraph_issues, - "paragraph_text": self.paragraph.text[:50] + "..." - if len(self.paragraph.text) > 50 - else self.paragraph.text, - } - all_issues.append(para_issue) - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - - # 添加字符样式问题 - if run_issues: - all_issues.extend(run_issues) - - return all_issues - # 各层级标题节点(无需重写check_format,直接复用基类逻辑) class HeadingLevel1Node(BaseHeadingNode): @@ -140,6 +62,7 @@ class HeadingLevel1Node(BaseHeadingNode): LEVEL = 1 NODE_TYPE = "headings.level_1" + NODE_LABEL = "一级标题" class HeadingLevel2Node(BaseHeadingNode): @@ -147,6 +70,7 @@ class HeadingLevel2Node(BaseHeadingNode): LEVEL = 2 NODE_TYPE = "headings.level_2" + NODE_LABEL = "二级标题" class HeadingLevel3Node(BaseHeadingNode): @@ -154,3 +78,4 @@ class HeadingLevel3Node(BaseHeadingNode): LEVEL = 3 NODE_TYPE = "headings.level_3" + NODE_LABEL = "三级标题" diff --git a/src/wordformat/rules/keywords.py b/src/wordformat/rules/keywords.py index a86e58f..eb024de 100644 --- a/src/wordformat/rules/keywords.py +++ b/src/wordformat/rules/keywords.py @@ -4,7 +4,12 @@ from docx.oxml.ns import qn -from wordformat.config.datamodel import KeywordsConfig, NodeConfigRoot +from wordformat.config.datamodel import ( + KeywordCountRule, + KeywordsConfig, + NodeConfigRoot, + TrailingPunctRule, +) from wordformat.rules.node import FormatNode from wordformat.style.check_format import CharacterStyle, ParagraphStyle @@ -52,7 +57,7 @@ def _check_paragraph_style(self, cfg: KeywordsConfig, p: bool) -> str: issues = ps.diff_from_paragraph(self.paragraph) else: issues = ps.apply_to_paragraph(self.paragraph) - return ParagraphStyle.to_string(issues) + return ParagraphStyle.to_string(issues, target=self.NODE_LABEL) def _split_mixed_runs(self) -> None: """检测标签和内容混合在同一个 run 中的情况,拆分为两个独立的 run。 @@ -114,47 +119,71 @@ class KeywordsEN(BaseKeywordsNode): LANG = "en" NODE_TYPE = "abstract.keywords.english" + NODE_LABEL = "英文关键词" + RULES = {"keyword_count": "_check_keyword_count"} def _check_keyword_label(self, run) -> bool: - """检查run是否包含英文关键词标签(Keywords/KEY WORDS)""" - pattern = r"Keywords?|KEY\s*WORDS" - return bool(re.search(pattern, run.text, re.IGNORECASE)) + """判断 run 是否属于英文关键词标签部分。""" + if not run.text.strip(): + return False + if self.paragraph is None: + return bool(re.search(r"Keywords?|KEY\s*WORDS", run.text, re.IGNORECASE)) + full = "".join(r.text for r in self.paragraph.runs) + m = re.match(r"Keywords?\s*[::]?\s*|KEY\s*WORDS\s*", full, re.IGNORECASE) + if not m: + return False + label_end = m.end() + # 找出当前 run 在全文中的位置(用 XML 元素 identity 比较) + pos = 0 + for r in self.paragraph.runs: + rl = len(r.text) + if r._element is run._element: + return pos < label_end + pos += rl + return False def _get_label_split_pattern(self) -> re.Pattern | None: """英文标签拆分模式:匹配 'Keywords:' 或 'Keywords ' 及其变体""" return re.compile(r"Keywords?\s*[::]?\s*", re.IGNORECASE) - def _base(self, doc, p: bool, r: bool): # noqa C901 - """ - 校验英文关键词格式: - - 段落整体格式(对齐、行距等) - - "Keywords:" 部分加粗,其余内容不加粗 - """ - cfg = self.pydantic_config - - # 2. 段落样式检查 - paragraph_issues = self._check_paragraph_style(cfg, p) - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=paragraph_issues, + def _check_keyword_count(self, doc, rule_cfg: KeywordCountRule, p: bool = False): + """校验英文关键词数量""" + keyword_text = "".join([run.text for run in self.paragraph.runs]) + keyword_list = re.split( + r"[,;]", re.sub(r"Keywords?:", "", keyword_text, flags=re.IGNORECASE) + ) + keyword_list = [k.strip() for k in keyword_list if k.strip()] + from wordformat.style.comment_format import format_comment + + target = self.NODE_LABEL + if len(keyword_list) < rule_cfg.count_min: + issue = format_comment( + target, + "数量过少", + f"当前{len(keyword_list)}个", + f"{rule_cfg.count_min}-{rule_cfg.count_max}个", ) + self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) + if len(keyword_list) > rule_cfg.count_max: + issue = format_comment( + target, + "数量过多", + f"当前{len(keyword_list)}个", + f"{rule_cfg.count_min}-{rule_cfg.count_max}个", + ) + self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) - # 3. 拆分标签和内容混合的 run(仅在格式化模式下执行) - if not p: - self._split_mixed_runs() - - # 4. 字符样式检查(区分标签/内容) - label_cfg = cfg.label + # 覆盖默认 handler:区分标签与内容的字符样式 + def _handle_character_style(self, doc, rule_cfg, p: bool): + cfg = self.pydantic_config label_style = CharacterStyle( - font_name_cn=label_cfg.chinese_font_name, - font_name_en=label_cfg.english_font_name, - font_size=label_cfg.font_size, - font_color=label_cfg.font_color, - bold=label_cfg.bold, - italic=label_cfg.italic, - underline=label_cfg.underline, + font_name_cn=cfg.label.chinese_font_name, + font_name_en=cfg.label.english_font_name, + font_size=cfg.label.font_size, + font_color=cfg.label.font_color, + bold=cfg.label.bold, + italic=cfg.label.italic, + underline=cfg.label.underline, ) content_style = CharacterStyle( font_name_cn=cfg.chinese_font_name, @@ -165,50 +194,27 @@ def _base(self, doc, p: bool, r: bool): # noqa C901 italic=cfg.italic, underline=cfg.underline, ) - - # 4. 遍历run校验 for run in self.paragraph.runs: if not run.text.strip(): continue - - if self._check_keyword_label(run): - # 检查标签样式 - if r: - diff = label_style.diff_from_run(run) - else: - diff = label_style.apply_to_run(run) - if diff: - self.add_comment( - doc=doc, - runs=run, - text=CharacterStyle.to_string(diff), - ) + is_label = self._check_keyword_label(run) + cstyle = label_style if is_label else content_style + target = f"{self.NODE_LABEL}标签" if is_label else f"{self.NODE_LABEL}内容" + if p: + diff = cstyle.diff_from_run(run) else: - # 检查内容样式 - if r: - diff = content_style.diff_from_run(run) - else: - diff = content_style.apply_to_run(run) - if diff: - self.add_comment( - doc=doc, - runs=run, - text=CharacterStyle.to_string(diff), - ) - - # 5. 校验关键词数量(KeywordsConfig特有配置) - keyword_text = "".join([run.text for run in self.paragraph.runs]) - # 提取英文关键词(按逗号/分号分割) - keyword_list = re.split( - r"[,;]", re.sub(r"Keywords?:", "", keyword_text, flags=re.IGNORECASE) - ) - keyword_list = [k.strip() for k in keyword_list if k.strip()] - if len(keyword_list) < cfg.count_min: - issue = f"英文关键词数量不足(最少{cfg.count_min}个,当前{len(keyword_list)}个)" - self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) - if len(keyword_list) > cfg.count_max: - issue = f"英文关键词数量超限(最多{cfg.count_max}个,当前{len(keyword_list)}个)" - self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) + diff = cstyle.apply_to_run(run) + if diff: + self.add_comment( + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff, target=target), + ) + + def _base(self, doc, p: bool, r: bool): + """拆分标签和内容混合的 run(仅在应用模式下执行)""" + if not p: + self._split_mixed_runs() # 第三步:中文关键词节点(专属逻辑) @@ -217,11 +223,34 @@ class KeywordsCN(BaseKeywordsNode): LANG = "cn" NODE_TYPE = "abstract.keywords.chinese" + NODE_LABEL = "中文关键词" + RULES = { + "keyword_count": "_check_keyword_count", + "trailing_punctuation": "_check_trailing_punctuation", + } def _check_keyword_label(self, run) -> bool: - """检查run是否包含中文关键词标签(关键词)""" - pattern = r"关[^a-zA-Z0-9\u4e00-\u9fff]*键[^a-zA-Z0-9\u4e00-\u9fff]*词" - return bool(re.search(pattern, run.text)) + """判断 run 是否属于中文关键词标签部分(防拆分)。""" + if not run.text.strip(): + return False + if self.paragraph is None: + p = r"关[^a-zA-Z0-9\u4e00-\u9fff]*键[^a-zA-Z0-9\u4e00-\u9fff]*词" + return bool(re.search(p, run.text)) + full = "".join(r.text for r in self.paragraph.runs) + m = re.search( + r"关[^a-zA-Z0-9\u4e00-\u9fff]*键[^a-zA-Z0-9\u4e00-\u9fff]*词\s*[::]?\s*", + full, + ) + if not m: + return False + label_end = m.end() + pos = 0 + for r in self.paragraph.runs: + rl = len(r.text) + if r._element is run._element: + return pos < label_end + pos += rl + return False def _get_label_split_pattern(self) -> re.Pattern | None: """中文标签拆分模式:匹配 '关键词:' 或 '关键词:' 及其变体""" @@ -229,45 +258,65 @@ def _get_label_split_pattern(self) -> re.Pattern | None: r"关[^a-zA-Z0-9\u4e00-\u9fff]*键[^a-zA-Z0-9\u4e00-\u9fff]*词\s*[::]?\s*" ) - def _base(self, doc, p: bool, r: bool): # noqa C901 - """ - 校验中文关键词格式: - - 段落整体格式(对齐、行距等) - - "关键词:"部分加粗,其余内容不加粗 - - 校验关键词数量、末尾标点 - """ - # 1. 空值校验 - if self.pydantic_config is None: - self.add_comment( - doc=doc, runs=self.paragraph.runs, text="中文关键词配置未加载,跳过检查" + def _check_keyword_count(self, doc, rule_cfg: KeywordCountRule, p: bool = False): + """校验中文关键词数量""" + keyword_text = "".join([run.text for run in self.paragraph.runs]) + keyword_list = re.split(r";", re.sub(r"关键词[::]", "", keyword_text)) + keyword_list = [k.strip() for k in keyword_list if k.strip()] + from wordformat.style.comment_format import format_comment + + target = self.NODE_LABEL + if len(keyword_list) < rule_cfg.count_min: + issue = format_comment( + target, + "数量过少", + f"当前{len(keyword_list)}个", + f"{rule_cfg.count_min}-{rule_cfg.count_max}个", + ) + self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) + if len(keyword_list) > rule_cfg.count_max: + issue = format_comment( + target, + "数量过多", + f"当前{len(keyword_list)}个", + f"{rule_cfg.count_min}-{rule_cfg.count_max}个", ) - return [{"error": "配置未加载", "lang": "cn", "node_type": self.NODE_TYPE}] + self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) - cfg = self.pydantic_config + def _check_trailing_punctuation( + self, doc, rule_cfg: TrailingPunctRule, p: bool = False + ): + """校验中文关键词末尾标点""" + from wordformat.style.comment_format import format_comment - # 2. 段落样式检查(复用基类方法) - paragraph_issues = self._check_paragraph_style(cfg, p) - if paragraph_issues: + keyword_text = "".join([run.text for run in self.paragraph.runs]) + if ( + keyword_text.strip() + and keyword_text.strip()[-1] in rule_cfg.forbidden_chars + ): + punct = keyword_text.strip()[-1] self.add_comment( doc=doc, runs=self.paragraph.runs, - text=paragraph_issues, + text=format_comment( + self.NODE_LABEL, + "标点错误", + f"末尾有'{punct}'", + "末尾无标点", + ), ) - # 3. 拆分标签和内容混合的 run(仅在格式化模式下执行) - if not p: - self._split_mixed_runs() - - # 4. 字符样式检查(区分标签/内容) - label_cfg = cfg.label + # 覆盖默认 handler:区分标签与内容的字符样式 + def _handle_character_style(self, doc, rule_cfg, p: bool): + cfg = self.pydantic_config label_style = CharacterStyle( - font_name_cn=label_cfg.chinese_font_name, - font_name_en=label_cfg.english_font_name, - font_size=label_cfg.font_size, - font_color=label_cfg.font_color, - bold=label_cfg.bold, - italic=label_cfg.italic, - underline=label_cfg.underline, + font_name_cn=cfg.label.chinese_font_name, + font_name_en=cfg.label.english_font_name, + font_size=cfg.label.font_size, + font_color=cfg.label.font_color, + bold=cfg.label.bold, + italic=cfg.label.italic, + underline=cfg.label.underline, ) content_style = CharacterStyle( font_name_cn=cfg.chinese_font_name, @@ -278,56 +327,24 @@ def _base(self, doc, p: bool, r: bool): # noqa C901 italic=cfg.italic, underline=cfg.underline, ) - - # 4. 遍历run校验 for run in self.paragraph.runs: if not run.text.strip(): continue - - if self._check_keyword_label(run): - # 检查标签样式 - if r: - diff = label_style.diff_from_run(run) - else: - diff = label_style.apply_to_run(run) - if diff: - self.add_comment( - doc=doc, - runs=run, - text=CharacterStyle.to_string(diff), - ) + is_label = self._check_keyword_label(run) + cstyle = label_style if is_label else content_style + target = f"{self.NODE_LABEL}标签" if is_label else f"{self.NODE_LABEL}内容" + if p: + diff = cstyle.diff_from_run(run) else: - # 检查内容样式 - if r: - diff = content_style.diff_from_run(run) - else: - diff = content_style.apply_to_run(run) - if diff: - self.add_comment( - doc=doc, - runs=run, - text=CharacterStyle.to_string(diff), - ) - - # 5. 专属校验:关键词数量 + 末尾标点(KeywordsConfig特有配置) - keyword_text = "".join([run.text for run in self.paragraph.runs]) - # 提取中文关键词(按分号分割) - keyword_list = re.split(r";", re.sub(r"关键词[::]", "", keyword_text)) - keyword_list = [k.strip() for k in keyword_list if k.strip()] - - # 数量校验 - if len(keyword_list) < cfg.count_min: - issue = f"中文关键词数量不足(最少{cfg.count_min}个,当前{len(keyword_list)}个)" - self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) - if len(keyword_list) > cfg.count_max: - issue = f"中文关键词数量超限(最多{cfg.count_max}个,当前{len(keyword_list)}个)" - self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) - - # 末尾标点校验 - if ( - cfg.trailing_punct_forbidden - and keyword_text.strip() - and keyword_text.strip()[-1] in ";,。、" - ): - issue = "中文关键词末尾禁止出现标点符号" - self.add_comment(doc=doc, runs=self.paragraph.runs, text=issue) + diff = cstyle.apply_to_run(run) + if diff: + self.add_comment( + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff, target=target), + ) + + def _base(self, doc, p: bool, r: bool): + """拆分标签和内容混合的 run(仅在应用模式下执行)""" + if not p: + self._split_mixed_runs() diff --git a/src/wordformat/rules/node.py b/src/wordformat/rules/node.py index db53eda..919d029 100644 --- a/src/wordformat/rules/node.py +++ b/src/wordformat/rules/node.py @@ -92,6 +92,22 @@ class FormatNode(TreeNode, Generic[T]): CONFIG_MODEL: Type[T] + # 全局错误统计(类变量,一次 check 周期内累加) + _error_stats: dict[str, int] = {"total": 0, "严重": 0, "一般": 0, "提醒": 0} + + # 中文标签,用作批注的 [位置] 部分 + NODE_LABEL: str = "" + + # 子类声明:规则名 → handler 方法名,框架自动按 config 启用/禁用调度 + # 只放需要 YAML 配置控制的业务规则。段落/字符格式由 DEFAULT_RULES 自动处理 + RULES: dict[str, str] = {} + + # 框架自动注入的默认规则,不依赖配置,所有节点默认启用 + DEFAULT_RULES: dict[str, str] = { + "paragraph_style": "_handle_paragraph_style", + "character_style": "_handle_character_style", + } + def __init__( self, value, @@ -104,6 +120,9 @@ def __init__( self.paragraph: Paragraph = paragraph self.expected_rule = expected_rule self._pydantic_config: Optional[T] = None # Pydantic配置对象 + self._comment_texts: list[ + tuple + ] = [] # (runs, text) 缓冲,flush 时按 runs 分组合并 @property def pydantic_config(self) -> T: @@ -156,16 +175,196 @@ def update_paragraph(self, paragraph: Paragraph | dict): self.paragraph = paragraph def _base(self, doc, p: bool, r: bool): - raise NotImplementedError("Subclasses should implement this!") + """子类可覆写以添加自定义逻辑(如拆分混合 run)。标准节点无需覆写。""" + + def _run_rules(self, doc: Document, p: bool) -> None: + """自动调度所有规则:DEFAULT_RULES(无需配置)+ RULES(需 YAML 配置)。 + + p=True 表示检查模式,p=False 表示应用模式。handler 签名为 + (doc, rule_cfg, p),p 默认 False 以兼容不需要区分模式的 handler。 + + DEFAULT_RULES 总是执行,RULES 仅当配置 enabled=true 时执行。提供双向验证: + - 配置有规则但无 handler → warning + - RULES 声明了但配置无对应项 → warning + """ + all_rules = {**self.DEFAULT_RULES, **self.RULES} + if not all_rules: + return + + rules_config = getattr(self._pydantic_config, "rules", None) + + # 双向验证(仅检查自定义 RULES) + if self.RULES: + if rules_config is None: + logger.debug(f"[{self.NODE_TYPE}] RULES 已声明但配置无 rules 节点") + else: + declared_rules = set(self.RULES.keys()) + config_rules = set(type(rules_config).model_fields.keys()) + orphan_handlers = declared_rules - config_rules + orphan_configs = config_rules - declared_rules + if orphan_handlers: + logger.debug( + f"[{self.NODE_TYPE}] RULES 声明了 {orphan_handlers} 但配置无对应项" + ) + if orphan_configs: + logger.debug( + f"[{self.NODE_TYPE}] 配置有 {orphan_configs} 但无对应 handler" + ) + + for rule_name, handler_name in all_rules.items(): + # 默认规则无配置,总是执行 + if rule_name in self.DEFAULT_RULES: + handler = getattr(self, handler_name) + handler(doc, None, p) + continue + + # 自定义规则:读配置,检查 enabled + if rules_config is None: + continue + rule_cfg = getattr(rules_config, rule_name, None) + if rule_cfg is None or not rule_cfg.enabled: + continue + handler = getattr(self, handler_name) + handler(doc, rule_cfg, p) + + # ------------------------------------------------------------------ + # 默认规则 handler:段落样式 + 字符样式 + # ------------------------------------------------------------------ + + def _handle_paragraph_style(self, doc, rule_cfg, p: bool): + """默认段落样式检查/应用。配置需继承 GlobalFormatConfig。""" + if self.paragraph is None or not self.paragraph.runs: + return + from wordformat.style.check_format import ParagraphStyle + + cfg = self.pydantic_config + if not hasattr(cfg, "alignment"): + return + ps = ParagraphStyle.from_config(cfg) + if p: + issues = ps.diff_from_paragraph(self.paragraph) + else: + issues = ps.apply_to_paragraph(self.paragraph) + if issues: + self.add_comment( + doc=doc, + runs=self.paragraph.runs, + text=ParagraphStyle.to_string(issues, target=self.NODE_LABEL), + ) + + def _handle_character_style(self, doc, rule_cfg, p: bool): + """默认字符样式检查/应用。配置需继承 GlobalFormatConfig。""" + if not self.paragraph.runs: + return + from wordformat.style.check_format import CharacterStyle + + cfg = self.pydantic_config + if not hasattr(cfg, "chinese_font_name"): + return + cstyle = CharacterStyle( + font_name_cn=cfg.chinese_font_name, + font_name_en=cfg.english_font_name, + font_size=cfg.font_size, + font_color=cfg.font_color, + bold=cfg.bold, + italic=cfg.italic, + underline=cfg.underline, + ) + for run in self.paragraph.runs: + if not run.text.strip(): + continue + if p: + diff = cstyle.diff_from_run(run) + else: + diff = cstyle.apply_to_run(run) + if diff: + self.add_comment( + doc=doc, + runs=run, + text=CharacterStyle.to_string(diff, target=self.NODE_LABEL), + ) + + def _collect_comment(self, runs, text: str) -> None: + """将批注文本加入缓冲区,(runs, text) 成对存储。""" + if text.strip(): + self._comment_texts.append((runs, text.strip())) + + def _flush_comments(self, doc: Document) -> None: + """将缓冲的批注按锚点分组写入。段落级合并为一条,run 级按 run 分开。""" + if not self._comment_texts or not self.paragraph.runs: + self._comment_texts.clear() + return + groups = self._group_comments() + self._write_comment_groups(doc, groups) + self._comment_texts.clear() + + def _group_comments(self) -> dict[tuple, tuple[tuple, list[str]]]: + """按 runs 分组批注文本。段落级用 ('__para__',),run 级用索引 i。""" + para_runs = list(self.paragraph.runs) + groups: dict[tuple, tuple[tuple, list[str]]] = {} + + def _key(runs): + if isinstance(runs, Sequence) and len(runs) == len(para_runs): + return ("__para__",) + r = runs[0] if isinstance(runs, Sequence) else runs + for i, pr in enumerate(para_runs): + if r is pr or r._element is pr._element: + return (i,) + return (id(runs),) + + for runs, text in self._comment_texts: + k = _key(runs) + if k not in groups: + groups[k] = (runs, []) + groups[k][1].append(text) + return groups + + def _write_comment_groups(self, doc, groups) -> None: + """将分组后的批注写入文档并更新统计。""" + from wordformat.style.comment_format import SEVERITY_ORDER, get_severity + + for runs, texts in groups.values(): + merged = "\n".join(texts) + doc.add_comment( + runs=runs, text=merged, author="Wordformat", initials="afish" + ) + # 提醒级批注用蓝色字体 + max_sev = "提醒" + for t in texts: + sev = get_severity(t) + if SEVERITY_ORDER.get(sev, 3) < SEVERITY_ORDER.get(max_sev, 3): + max_sev = sev + if max_sev == "提醒": + _color_last_comment(doc, "0000FF") + FormatNode._error_stats["total"] += 1 + FormatNode._error_stats[max_sev] = ( + FormatNode._error_stats.get(max_sev, 0) + 1 + ) + for t in texts: + sev = get_severity(t) + if SEVERITY_ORDER.get(sev, 3) < SEVERITY_ORDER.get(max_sev, 3): + max_sev = sev + FormatNode._error_stats[max_sev] = ( + FormatNode._error_stats.get(max_sev, 0) + 1 + ) + + @classmethod + def reset_stats(cls) -> None: + """重置全局错误统计。""" + cls._error_stats = {"total": 0, "严重": 0, "一般": 0, "提醒": 0} def check_format(self, doc: Document): - """虚方法:由子类实现具体的格式检查逻辑""" + """格式检查:先执行样式检查,再自动调度业务规则""" self._base(doc, p=True, r=True) + self._run_rules(doc, p=True) + self._flush_comments(doc) def apply_format(self, doc: Document): - """虚方法:由子类实现具体的格式应用逻辑""" + """格式应用:先清理、应用样式,再自动调度业务规则""" self._clean_paragraph_edge_spaces() self._base(doc, p=False, r=False) + self._run_rules(doc, p=False) + self._flush_comments(doc) def apply_replace(self, doc: Document = None) -> bool: """替换段落文本内容(由 JSON 的 replace 字段驱动)。 @@ -238,5 +437,42 @@ def _clean_paragraph_edge_spaces(self) -> None: break def add_comment(self, doc: Document, runs: Run | Sequence[Run], text: str): - if text.strip(): - doc.add_comment(runs=runs, text=text, author="论文解析器", initials="afish") + """追加批注到缓冲区,按锚点 run 分组,flush 时同组合并为一条。""" + self._collect_comment(runs, text) + + +def _color_last_comment(doc, hex_color: str) -> None: + """将文档最后一条批注的文字颜色设为指定色(如 0000FF 蓝色)。""" + try: + comments = doc._part.comments + if comments is None: + return + last = comments[-1] + for p in last._element.findall( + "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}p" + ): + for r in p.findall( + "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r" + ): + rPr = r.find( + "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}rPr" + ) + if rPr is None: + from docx.oxml import OxmlElement + + rPr = OxmlElement("w:rPr") + r.insert(0, rPr) + color = rPr.find( + "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}color" + ) + if color is None: + from docx.oxml import OxmlElement + + color = OxmlElement("w:color") + rPr.append(color) + color.set( + "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val", + hex_color, + ) + except Exception: + pass diff --git a/src/wordformat/rules/object.py b/src/wordformat/rules/object.py new file mode 100644 index 0000000..936db1f --- /dev/null +++ b/src/wordformat/rules/object.py @@ -0,0 +1,62 @@ +"""图片段落和表格对象节点。""" + +from wordformat.config.datamodel import ImageFormatConfig, TableObjectConfig +from wordformat.rules.node import FormatNode +from wordformat.style.comment_format import format_comment + + +class FigureImage(FormatNode[ImageFormatConfig]): + """图片段落节点(包含内联图片的段落,非题注)。 + + 只检查对齐和首行缩进,不检查行距、字体等。 + """ + + NODE_TYPE = "figure_image" + CONFIG_MODEL = ImageFormatConfig + CONFIG_PATH = "figures.image" + NODE_LABEL = "图片段落" + DEFAULT_RULES = {} + + def _base(self, doc, p: bool, r: bool): + """仅检查对齐和首行缩进。""" + from wordformat.style.check_format import _format_para_value + from wordformat.style.style_enum import Alignment, FirstLineIndent + + cfg = self.pydantic_config + expected_align = Alignment(str(cfg.alignment)) + actual_align = expected_align.get_from_paragraph(self.paragraph) + if expected_align != actual_align: + self.add_comment( + doc=doc, + runs=self.paragraph.runs, + text=format_comment( + self.NODE_LABEL, + "对齐错误", + _format_para_value("alignment", actual_align), + _format_para_value("alignment", expected_align), + ), + ) + + expected_indent = FirstLineIndent(str(cfg.first_line_indent)) + actual_indent = expected_indent.get_from_paragraph(self.paragraph) + if expected_indent != actual_indent: + self.add_comment( + doc=doc, + runs=self.paragraph.runs, + text=format_comment( + self.NODE_LABEL, + "首行缩进错误", + _format_para_value("first_line_indent", actual_indent), + _format_para_value("first_line_indent", expected_indent), + ), + ) + + +class TableObject(FormatNode[TableObjectConfig]): + """表格对象节点(表格整体格式,非题注)。""" + + NODE_TYPE = "table_object" + CONFIG_MODEL = TableObjectConfig + CONFIG_PATH = "tables.object" + NODE_LABEL = "表格对象" + DEFAULT_RULES = {} # 表格对象格式由 Word 表格属性控制 diff --git a/src/wordformat/rules/references.py b/src/wordformat/rules/references.py index 4d26288..30dfdf1 100644 --- a/src/wordformat/rules/references.py +++ b/src/wordformat/rules/references.py @@ -5,98 +5,20 @@ from wordformat.config.datamodel import ReferencesContentConfig, ReferencesTitleConfig from wordformat.rules.node import FormatNode -from wordformat.style.check_format import CharacterStyle, ParagraphStyle class References(FormatNode[ReferencesTitleConfig]): """参考文献节点""" NODE_TYPE = "references" + NODE_LABEL = "参考文献标题" CONFIG_MODEL = ReferencesTitleConfig CONFIG_PATH = "references.title" - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - # 段落样式 - ps = ParagraphStyle.from_config(cfg) - if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) - else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - # 字符样式 - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 检查每个 run 的字符格式 - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: # 仅当有差异时添加批注 - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 检查段落格式差异 - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - return [] - class ReferenceEntry(FormatNode[ReferencesContentConfig]): """参考文献条目节点""" + NODE_LABEL = "参考文献条目" CONFIG_MODEL = ReferencesContentConfig CONFIG_PATH = "references.content" - - def _base(self, doc, p: bool, r: bool): - cfg = self.pydantic_config - # 段落样式 - ps = ParagraphStyle.from_config(cfg) - if p: - paragraph_issues = ps.diff_from_paragraph(self.paragraph) - else: - paragraph_issues = ps.apply_to_paragraph(self.paragraph) - - # 字符样式 - cstyle = CharacterStyle( - font_name_cn=cfg.chinese_font_name, - font_name_en=cfg.english_font_name, - font_size=cfg.font_size, - font_color=cfg.font_color, - bold=cfg.bold, - italic=cfg.italic, - underline=cfg.underline, - ) - - # 检查每个 run 的字符格式 - for run in self.paragraph.runs: - if r: - diff_result = cstyle.diff_from_run(run) - else: - diff_result = cstyle.apply_to_run(run) - if diff_result: # 仅当有差异时添加批注 - self.add_comment( - doc=doc, runs=run, text=CharacterStyle.to_string(diff_result) - ) - - # 检查段落格式差异 - if paragraph_issues: - self.add_comment( - doc=doc, - runs=self.paragraph.runs, - text=ParagraphStyle.to_string(paragraph_issues), - ) - return [] diff --git a/src/wordformat/set_style.py b/src/wordformat/set_style.py index 44ea0e7..3fbdaf2 100644 --- a/src/wordformat/set_style.py +++ b/src/wordformat/set_style.py @@ -409,8 +409,10 @@ def traverse(node, parent_category="", current_chapter: int = 0): seq = counter[chapter] node.value["chapter_number"] = chapter node.value["sequence_number"] = seq - if hasattr(config, "numbering"): - node.value["_numbering_cfg"] = config.numbering.captions + + # 给所有节点注入章节号(BodyText 引用上标需要) + if isinstance(node.value, dict): + node.value.setdefault("chapter_number", current_chapter) if node.paragraph: # 先执行内容替换(check/format 两种模式均执行) @@ -423,8 +425,8 @@ def traverse(node, parent_category="", current_chapter: int = 0): logger.warning(f"Node {node} not format, because: {str(e)}") raise e - # 目录和附录的子节点跳过格式化(top 节点本身跳过格式化,但子节点需要遍历) - SKIP_CHILDREN_CATEGORIES = {"heading_mulu", "heading_fulu"} + # 目录、附录、封面/声明的子节点跳过格式化 + SKIP_CHILDREN_CATEGORIES = {"heading_mulu", "heading_fulu", "other"} if category not in SKIP_CHILDREN_CATEGORIES: for child in node.children: traverse( @@ -434,20 +436,34 @@ def traverse(node, parent_category="", current_chapter: int = 0): traverse(root_node) +def _clear_matched_flags(root_node): + """清除树中所有节点的 _matched 标记,每次匹配前调用。""" + from collections import deque + + q = deque([root_node]) + while q: + n = q.popleft() + if hasattr(n, "_matched"): + del n._matched + q.extend(n.children) + + def xg(root_node, paragraph): """ - 根据段落对象查找对应的节点 - :param root_node: 树的根节点 - :param paragraph: docx文档的段落对象 - :return: 找到的节点 + 根据 XML 指纹匹配树节点。已匹配过的节点不再参与后续匹配, + 防止多个相同指纹的段落(如空段)绑到同一个节点。 """ + fp = get_paragraph_xml_fingerprint(paragraph) def condition(node): - if getattr(node, "fingerprint", False): - return node.fingerprint == get_paragraph_xml_fingerprint(paragraph) + if getattr(node, "fingerprint", False) and not getattr(node, "_matched", False): + return node.fingerprint == fp return False - return find_and_modify_first(root=root_node, condition=condition) + node = find_and_modify_first(root=root_node, condition=condition) + if node: + node._matched = True + return node def format_table_content( @@ -492,12 +508,12 @@ def format_table_content( para_issues = ps.diff_from_paragraph(paragraph) else: para_issues = ps.apply_to_paragraph(paragraph) - para_text = ParagraphStyle.to_string(para_issues) + para_text = ParagraphStyle.to_string(para_issues, target="表格内容") if para_text.strip(): document.add_comment( runs=paragraph.runs, text=para_text, - author="论文解析器", + author="Wordformat", initials="afish", ) @@ -509,16 +525,144 @@ def format_table_content( diff = cstyle.diff_from_run(run) else: diff = cstyle.apply_to_run(run) - run_text = CharacterStyle.to_string(diff) + run_text = CharacterStyle.to_string(diff, target="表格内容") if run_text.strip(): document.add_comment( runs=run, text=run_text, - author="论文解析器", + author="Wordformat", initials="afish", ) +def _build_check_summary(root_node, document, config_model) -> str: + """遍历树和错误统计,生成检测报告摘要文本。""" + from wordformat.rules.node import FormatNode + + stats = FormatNode._error_stats + total = stats["total"] + + # 遍历树,收集文档级统计 + import re + + def _collect_section(node, sections): + cls_name = type(node).__name__ + para = node.paragraph + if para and para.text.strip(): + text = para.text.strip() + if cls_name == "AbstractContentCN": + chinese_only = "".join(ch for ch in text if "一" <= ch <= "鿿") + if chinese_only: + sections["abstract_cn_chars"] = sections.get( + "abstract_cn_chars", 0 + ) + len(chinese_only) + elif cls_name == "AbstractContentEN": + sections["abstract_en_words"] = sections.get( + "abstract_en_words", 0 + ) + len(text.split()) + elif cls_name == "KeywordsCN": + kw_text = re.sub(r"关键词[::]?\s*", "", text) + kws = [k.strip() for k in re.split(r"[;;]", kw_text) if k.strip()] + if kws: + sections["keyword_cn_count"] = len(kws) + elif cls_name == "KeywordsEN": + kw_text = re.sub(r"Keywords?:?\s*", "", text, flags=re.IGNORECASE) + kws = [k.strip() for k in re.split(r"[,;]", kw_text) if k.strip()] + if kws: + sections["keyword_en_count"] = len(kws) + elif cls_name == "ReferenceEntry": + has_chinese = any("一" <= ch <= "鿿" for ch in text) + if has_chinese: + sections["ref_cn"] = sections.get("ref_cn", 0) + 1 + else: + sections["ref_en"] = sections.get("ref_en", 0) + 1 + # 处理混合节点:AbstractTitleContentCN/EN 的子 BodyText 是摘要正文 + if cls_name == "AbstractTitleContentCN": + for child in node.children: + cp = child.paragraph + if cp and cp.text.strip(): + cn = "".join(ch for ch in cp.text.strip() if "一" <= ch <= "鿿") + cnt = len(cn) + cur = sections.get("abstract_cn_chars", 0) + sections["abstract_cn_chars"] = cur + cnt + elif cls_name == "AbstractTitleContentEN": + for child in node.children: + cp = child.paragraph + if cp and cp.text.strip(): + cnt = len(cp.text.strip().split()) + sections["abstract_en_words"] = ( + sections.get("abstract_en_words", 0) + cnt + ) + for child in node.children: + _collect_section(child, sections) + + sections: dict = {} + _collect_section(root_node, sections) + + # 计算万字差错率 + total_chars = sum( + len(p.text) for p in document.paragraphs if p.text and p.text.strip() + ) + error_rate = (total / max(total_chars, 1)) * 10000 if total else 0 + + # 模板名(从 config 读取) + template_name = getattr(config_model, "template_name", None) or "未知模板" + + lines = [ + "检测结果:", + f"检测模板:《{template_name}》", + f"检测错误数:{total},万字差错率:{error_rate:.1f}", + f"严重错误:{stats.get('严重', 0)},一般错误:{stats.get('一般', 0)},提醒:{stats.get('提醒', 0)}", + ] + + # 字数问题 + word_issues = [] + if sections.get("abstract_cn_chars"): + word_issues.append( + f"中文摘要:规范:300字左右,原文:{sections['abstract_cn_chars']}字" + ) + if sections.get("abstract_en_words"): + word_issues.append( + f"英文摘要:规范:300字左右,原文:{sections['abstract_en_words']}词" + ) + if sections.get("keyword_cn_count"): + word_issues.append( + f"中文关键词:规范:3-5个,原文:{sections['keyword_cn_count']}个" + ) + if sections.get("keyword_en_count"): + word_issues.append( + f"英文关键词:规范:3-5个,原文:{sections['keyword_en_count']}个" + ) + ref_cn = sections.get("ref_cn", 0) + ref_en = sections.get("ref_en", 0) + if ref_cn or ref_en: + word_issues.append( + f"参考文献:规范:不少于15条,原文:中文{ref_cn}条;外文{ref_en}条" + ) + if word_issues: + lines.append("字数问题:") + lines.extend(word_issues) + + lines.append("说明:") + lines.append( + "1.请确保文档中正确使用换行符,硬回车(Enter):指换行且生成新段落;软回车(Shift+Enter):指换行但不生成新段落。" + ) + lines.append("2.图片请使用“嵌入型”环绕方式,表格为无环绕方式。") + lines.append("3.提醒不计算错误。") + + return "\n".join(lines) + + +def _add_summary_comment(document, summary: str) -> None: + """将检测报告摘要作为批注添加到文档第一段。空段临时塞空 run 做锚点。""" + para = document.paragraphs[0] + if not para.runs: + para.add_run("") + document.add_comment( + runs=para.runs, text=summary, author="Wordformat", initials="afish" + ) + + def auto_format_thesis_document( jsonpath: str | list, docxpath: str, @@ -587,9 +731,8 @@ def auto_format_thesis_document( style_list.append(style.name) logger.info(f"可用的样式有:{style_list}") + _clear_matched_flags(root_node) for paragraph in document.paragraphs: - if not paragraph.text: - continue node = xg(root_node, paragraph) if node: node.paragraph = paragraph @@ -609,10 +752,18 @@ def auto_format_thesis_document( _fix_all_style_definitions(document, config_model) # 执行格式化 + if check: + FormatNode.reset_stats() apply_format_check_to_all_nodes(root_node, document, config_model, check) - # 表格内容格式化 - format_table_content(document, config_model, check) + # 表格内容格式化(已移除:表格内格式由 Word 表格样式控制,不做段落/字符级检查) + # format_table_content(document, config_model, check) + + # 检测报告摘要(仅 check 模式) + if check: + summary = _build_check_summary(root_node, document, config_model) + if summary: + _add_summary_comment(document, summary) # 处理标题自动编号(仅在格式化模式下执行,检查模式不修改编号) if ( diff --git a/src/wordformat/settings.py b/src/wordformat/settings.py index 08a0469..4659718 100644 --- a/src/wordformat/settings.py +++ b/src/wordformat/settings.py @@ -44,4 +44,5 @@ "top", "heading_mulu", "heading_fulu", + "other", # 封面、声明页等无需格式化的内容 ] diff --git a/src/wordformat/style/check_format.py b/src/wordformat/style/check_format.py index 7d80e01..4782eb5 100644 --- a/src/wordformat/style/check_format.py +++ b/src/wordformat/style/check_format.py @@ -35,6 +35,114 @@ style_checks_warning: WarningFieldConfig | None = None +def _char_warning_enabled(diff_type: str) -> bool: + """判断某个字符 diff_type 是否在 WarningFieldConfig 中开启。""" + if style_checks_warning is None: + return True + mapping = { + "bold": style_checks_warning.bold, + "italic": style_checks_warning.italic, + "underline": style_checks_warning.underline, + "font_size": style_checks_warning.font_size, + "font_color": style_checks_warning.font_color, + "font_name_cn": style_checks_warning.font_name, + "font_name_en": style_checks_warning.font_name, + } + return mapping.get(diff_type, True) + + +# 磅值 → 中文字号反向映射 +_FONT_SIZE_PT_LABELS: dict[float, str] = { + 26: "一号", + 24: "小一", + 22: "二号", + 18: "小二", + 16: "三号", + 15: "小三", + 14: "四号", + 12: "小四", + 10.5: "五号", + 9: "小五", + 7.5: "六号", + 5.5: "七号", +} + + +def _pt_to_label(pt: float) -> str: + """磅值 → 中文标签。精确匹配显示字号,否则直接显示 Xpt。""" + return _FONT_SIZE_PT_LABELS.get(pt, f"{pt}pt") + + +def _format_char_value(diff_type: str, value) -> str: + """将字符 diff 的值格式化为可读文本。""" + if diff_type == "bold": + return "加粗" if value else "不加粗" + if diff_type == "italic": + return "斜体" if value else "非斜体" + if diff_type == "underline": + return "有下划线" if value else "无下划线" + if diff_type == "font_size" and isinstance(value, (int, float)): + return _pt_to_label(float(value)) + return str(value) + + +_LINE_SPACING_LABELS = { + 0: "单倍行距", + 1: "1.5倍行距", + 2: "2倍行距", + 3: "最小值", + 4: "固定值", + 5: "多倍行距", +} + +_ALIGNMENT_LABELS = { + 0: "左对齐", + 1: "居中对齐", + 2: "右对齐", + 3: "两端对齐", + 4: "分散对齐", +} + + +def _format_para_value(diff_type: str, value) -> str: + """将段落 diff 的值格式化为可读文本。""" + if value is None: + return "未设置" + if diff_type == "line_spacing_rule": + try: + return _LINE_SPACING_LABELS.get(int(value), str(value)) + except (ValueError, TypeError): + return str(value) + if diff_type == "alignment": + try: + return _ALIGNMENT_LABELS.get(int(value), str(value)) + except (ValueError, TypeError): + return str(value) + if diff_type == "line_spacing": + if isinstance(value, (int, float)): + return f"{value}倍" + return str(value) + return str(value) + + +def _para_warning_enabled(diff_type: str) -> bool: + """判断某个段落 diff_type 是否在 WarningFieldConfig 中开启。""" + if style_checks_warning is None: + return True + mapping = { + "alignment": style_checks_warning.alignment, + "space_before": style_checks_warning.space_before, + "space_after": style_checks_warning.space_after, + "line_spacing": style_checks_warning.line_spacing, + "line_spacing_rule": style_checks_warning.line_spacingrule, + "first_line_indent": style_checks_warning.first_line_indent, + "left_indent": style_checks_warning.left_indent, + "right_indent": style_checks_warning.right_indent, + "builtin_style_name": style_checks_warning.builtin_style_name, + } + return mapping.get(diff_type, True) + + @dataclass class DIFFResult: """ @@ -100,8 +208,8 @@ def diff_from_run(self, run: Run) -> list[DIFFResult]: # noqa c901 diffs = [] - # 1. 加粗 - bold = run.font.bold + # 1. 加粗(None = 继承,视为不加粗) + bold = bool(run.font.bold) if bold != self.bold: diffs.append( DIFFResult( @@ -112,8 +220,8 @@ def diff_from_run(self, run: Run) -> list[DIFFResult]: # noqa c901 1, ) ) - # 2. 斜体 - italic = run.font.italic + # 2. 斜体(None = 继承,视为非斜体) + italic = bool(run.font.italic) if italic != self.italic: diffs.append( DIFFResult( @@ -125,8 +233,8 @@ def diff_from_run(self, run: Run) -> list[DIFFResult]: # noqa c901 ) ) - # 3. 下划线 - underline = run.font.underline + # 3. 下划线(None = 继承,视为无下划线) + underline = bool(run.font.underline) if underline != self.underline: diffs.append( DIFFResult( @@ -168,9 +276,10 @@ def diff_from_run(self, run: Run) -> list[DIFFResult]: # noqa c901 ) ) - # 6. 东亚字体 - font_name = run_get_font_name(run) - if font_name != self.font_name_cn: + # 6. 东亚字体(仅当 run 含中文字符时才检查) + font_name = run_get_font_name(run) or "" + has_cjk = any("一" <= ch <= "鿿" for ch in run.text) + if has_cjk and str(font_name).lower() != str(self.font_name_cn).lower(): diffs.append( DIFFResult( "font_name_cn", @@ -180,9 +289,9 @@ def diff_from_run(self, run: Run) -> list[DIFFResult]: # noqa c901 1, ) ) - # 7. 非东亚字体 - ascii_font = run.font.name # 注意:可能为 None - if ascii_font != self.font_name_en: + # 7. 非东亚字体(None = 继承,视为空) + ascii_font = run.font.name or "" + if str(ascii_font).lower() != str(self.font_name_en).lower(): diffs.append( DIFFResult( "font_name_en", @@ -235,36 +344,20 @@ def apply_to_run(self, run: Run): return result @staticmethod - def to_string(value: list[DIFFResult]) -> str: - """ - 将列表的DIFFResult转换为字符串 - Args: - value: + def to_string(value: list[DIFFResult], target: str = "") -> str: + """将 DIFFResult 列表转为标准格式批注文本。""" + from .comment_format import CHAR_DIFF_LABELS, format_comment - Returns: - - """ - if style_checks_warning is None: - return "\n".join([str(i) for i in value]) t = [] for diff in value: - if style_checks_warning.bold and diff.diff_type == "bold": - t.append(diff) - if style_checks_warning.italic and diff.diff_type == "italic": - t.append(diff) - if style_checks_warning.underline and diff.diff_type == "underline": - t.append(diff) - if style_checks_warning.font_size and diff.diff_type == "font_size": - t.append(diff) - if style_checks_warning.font_color and diff.diff_type == "font_color": - t.append(diff) - if style_checks_warning.font_name and diff.diff_type in ( - "font_name_cn", - "font_name_en", - ): - t.append(diff) - - return "\n".join([str(i) for i in t]) + if style_checks_warning is not None: + if not _char_warning_enabled(diff.diff_type): + continue + prop = CHAR_DIFF_LABELS.get(diff.diff_type, diff.diff_type) + actual = _format_char_value(diff.diff_type, diff.current_value) + standard = _format_char_value(diff.diff_type, diff.expected_value) + t.append(format_comment(target, prop, actual, standard)) + return "\n".join(t) class ParagraphStyle: @@ -451,8 +544,8 @@ def diff_from_paragraph(self, paragraph: Paragraph) -> list[DIFFResult]: # noqa 1, ) ) - # 缩进:文本之前 - left_indent = self.left_indent.get_from_paragraph(paragraph) + # 缩进:文本之前(None = 未设置,视为0) + left_indent = self.left_indent.get_from_paragraph(paragraph) or 0 if self.left_indent != left_indent: diffs.append( DIFFResult( @@ -463,8 +556,8 @@ def diff_from_paragraph(self, paragraph: Paragraph) -> list[DIFFResult]: # noqa 1, ) ) - # 文本之后缩进 - right_indent = self.right_indent.get_from_paragraph(paragraph) + # 文本之后缩进(None = 未设置,视为0) + right_indent = self.right_indent.get_from_paragraph(paragraph) or 0 if self.right_indent != right_indent: diffs.append( DIFFResult( @@ -490,31 +583,20 @@ def diff_from_paragraph(self, paragraph: Paragraph) -> list[DIFFResult]: # noqa return sorted(diffs, key=lambda x: x.level) @staticmethod - def to_string(value: list[DIFFResult]) -> str: - if style_checks_warning is None: - return "\n".join([str(i) for i in value]) - t = [] - attr = [ - "alignment", - "space_before", - "space_after", - "line_spacing", - "line_spacingrule", - "first_line_indent", - "left_indent", - "right_indent", - "builtin_style_name", - ] - warning = {} - for attr_name in attr: - warning[attr_name] = getattr(style_checks_warning, attr_name) + def to_string(value: list[DIFFResult], target: str = "") -> str: + """将 DIFFResult 列表转为标准格式批注文本。""" + from .comment_format import PARA_DIFF_LABELS, format_comment + t = [] for diff in value: - type_name = diff.diff_type - if warning.get(type_name): - t.append(diff) - - return "\n".join([str(i) for i in t]) + if style_checks_warning is not None: + if not _para_warning_enabled(diff.diff_type): + continue + prop = PARA_DIFF_LABELS.get(diff.diff_type, diff.diff_type) + actual = _format_para_value(diff.diff_type, diff.current_value) + standard = _format_para_value(diff.diff_type, diff.expected_value) + t.append(format_comment(target, prop, actual, standard)) + return "\n".join(t) @classmethod def from_config(cls, config: Any) -> "ParagraphStyle": diff --git a/src/wordformat/style/comment_format.py b/src/wordformat/style/comment_format.py new file mode 100644 index 0000000..bccd569 --- /dev/null +++ b/src/wordformat/style/comment_format.py @@ -0,0 +1,77 @@ +"""批注文本格式化工具。 + +所有 add_comment 调用最终由此模块生成符合标准格式的批注文本: + [位置]-[问题类型]:[现状],规范:[标准] +""" + +# diff_type → 中文问题类型 +CHAR_DIFF_LABELS: dict[str, str] = { + "font_size": "字号错误", + "bold": "加粗错误", + "italic": "斜体错误", + "underline": "下划线错误", + "font_color": "字体颜色错误", + "font_name_cn": "中文字体错误", + "font_name_en": "英文字体错误", +} + +PARA_DIFF_LABELS: dict[str, str] = { + "alignment": "对齐错误", + "first_line_indent": "首行缩进错误", + "line_spacing": "行距问题", + "line_spacing_rule": "行距类型问题", + "space_before": "段前间距错误", + "space_after": "段后间距错误", + "left_indent": "左缩进错误", + "right_indent": "右缩进错误", + "builtin_style_name": "内置样式错误", +} + + +# 问题类型 → 严重等级 +SEVERITY_MAP: dict[str, str] = { + "行距问题": "严重", + "对齐错误": "严重", + "首行缩进错误": "一般", + "段前间距错误": "一般", + "段后间距错误": "一般", + "行距类型问题": "一般", + "左缩进错误": "一般", + "右缩进错误": "一般", + "内置样式错误": "一般", + "字号错误": "一般", + "加粗错误": "一般", + "数量过少": "一般", + "数量过多": "一般", + "编号错误": "一般", + "章节号错误": "一般", + "分隔符错误": "提醒", + "标签错误": "提醒", + "间距错误": "提醒", + "格式错误": "提醒", + "斜体错误": "提醒", + "下划线错误": "提醒", + "字体颜色错误": "提醒", + "中文字体错误": "提醒", + "英文字体错误": "提醒", + "标点错误": "提醒", +} + +_DEFAULT_SEVERITY = "一般" + +# 严重等级排序权重(数值越小越严重) +SEVERITY_ORDER: dict[str, int] = {"严重": 0, "一般": 1, "提醒": 2} + + +def get_severity(comment_text: str) -> str: + """从批注文本中提取严重等级。格式:位置-问题类型:...""" + try: + prop = comment_text.split("-", 1)[1].split(":")[0] + except (IndexError, AttributeError): + return _DEFAULT_SEVERITY + return SEVERITY_MAP.get(prop, _DEFAULT_SEVERITY) + + +def format_comment(target: str, property_name: str, actual: str, standard: str) -> str: + """生成标准批注文本:位置-问题类型:现状,规范:标准。""" + return f"{target}-{property_name}:{actual},规范:{standard}" diff --git a/src/wordformat/style/get_some.py b/src/wordformat/style/get_some.py index 71cea62..b9b46ed 100644 --- a/src/wordformat/style/get_some.py +++ b/src/wordformat/style/get_some.py @@ -209,26 +209,13 @@ def paragraph_get_space_after(paragraph) -> float | None: def paragraph_get_line_spacing(paragraph): # noqa c901 - """ - 获取段落的行距(仅当为“倍数”类型时返回 float,否则返回 None)。 - - 支持的倍数类型: - - SINGLE → 1.0 - - ONE_POINT_FIVE → 1.5 - - DOUBLE → 2.0 - - MULTIPLE → 自定义 float(如 2.3) - - 不支持的类型(返回 None): - - AT_LEAST - - EXACTLY - - 其他异常情况 - """ + """Return line spacing as float; fallback to style chain.""" try: - fmt = paragraph.paragraph_format - rule = fmt.line_spacing_rule - spacing = fmt.line_spacing + from wordformat.style.style_enum import _get_with_style_fallback - # 映射预设规则到倍数值 + rule = _get_with_style_fallback(paragraph, "line_spacing_rule", None) + if rule is None: + return None if rule == WD_LINE_SPACING.SINGLE: return 1.0 elif rule == WD_LINE_SPACING.ONE_POINT_FIVE: @@ -236,53 +223,44 @@ def paragraph_get_line_spacing(paragraph): # noqa c901 elif rule == WD_LINE_SPACING.DOUBLE: return 2.0 elif rule == WD_LINE_SPACING.MULTIPLE: - # spacing 应为 float(如 2.3) + spacing = _get_with_style_fallback(paragraph, "line_spacing", None) if isinstance(spacing, (int, float)) and spacing > 0: return float(spacing) - else: - # 异常值兜底 - return None - else: - # AT_LEAST, EXACTLY 等固定值类型,不视为“倍数行距” - return None - + return None except (AttributeError, TypeError): - # 段落格式异常 return None def paragraph_get_first_line_indent(paragraph: Paragraph) -> float | None: # noqa c901 - """ - 精准获取首行缩进,优先解析XML字符单位(firstLineChars),不兼容物理单位 - :param para: 目标段落对象 - :return: 字符数为浮点数 - """ - try: - p = paragraph._element - pPr = p.find(qn("w:pPr")) - if pPr is None: - return None + """获取首行缩进(字符单位)。优先段落自身,无则查样式链。""" - # 获取XML中的ind节点(缩进核心节点) - ind = pPr.find(qn("w:ind")) + def _read(pPr_elem): + ind = pPr_elem.find(qn("w:ind")) if ind is None: return None - - # 步骤1:优先解析字符单位 firstLineChars(核心:值=字符数×100) - first_line_chars = ind.get(qn("w:firstLineChars")) - if first_line_chars and first_line_chars.lstrip("-").isdigit(): - chars_num = int(first_line_chars) / 100 # 200 → 2.0字符 - return chars_num - - # 步骤2:解析悬挂缩进 hangingChars(返回负值表示悬挂缩进) - hanging_chars = ind.get(qn("w:hangingChars")) - if hanging_chars and hanging_chars.isdigit(): - chars_num = -int(hanging_chars) / 100 # 220 → -2.2字符 - return chars_num - - # 无任何缩进设置 + v = ind.get(qn("w:firstLineChars")) + if v and v.lstrip("-").isdigit(): + return int(v) / 100 + v = ind.get(qn("w:hangingChars")) + if v and v.isdigit(): + return -int(v) / 100 return None + try: + pPr = paragraph._element.find(qn("w:pPr")) + if pPr is not None: + val = _read(pPr) + if val is not None: + return val + style = paragraph.style + while style is not None: + sPr = style.element.find(qn("w:pPr")) + if sPr is not None: + val = _read(sPr) + if val is not None: + return val + style = style.base_style + return None except Exception as e: logger.error(f"获取首行缩进失败:{e}") return None diff --git a/src/wordformat/style/style_enum.py b/src/wordformat/style/style_enum.py index 4d6e9bf..58706e9 100644 --- a/src/wordformat/style/style_enum.py +++ b/src/wordformat/style/style_enum.py @@ -72,6 +72,15 @@ class UnitLabelEnum(metaclass=UnitEnumMeta): _LABEL_MAP = {} + @classmethod + def _missing_(cls, value): + """处理非预定义枚举值(如自定义样式名、任意字体名)。""" + member = object.__new__(cls) + member._name_ = str(value) + member._value_ = value + member.__init__(value) + return member + def __init__(self, value): self.value = value # 获取的原始值 self.original_unit = None # 解析的单位 @@ -170,7 +179,9 @@ def __eq__(self, other): if isinstance(other, self.__class__): return self.rel_value == other.rel_value if isinstance(self.rel_value, str): - return self.value.lower() == other + return str(self.rel_value).lower() == str(other).lower() + if other is None: + return self.rel_value == 0 return self.rel_value == other @@ -474,6 +485,23 @@ def get_from_paragraph(self, paragraph: Paragraph) -> float | None: return None +def _get_with_style_fallback(paragraph, attr: str, default): + """从段落或样式链读取属性值。""" + val = getattr(paragraph.paragraph_format, attr, None) + if val is not None: + return val + style = paragraph.style + while style is not None: + try: + val = getattr(style.paragraph_format, attr, None) + if val is not None: + return val + except AttributeError: + pass + style = style.base_style + return default + + class LineSpacingRule(UnitLabelEnum): """ 设置行距选项 @@ -497,9 +525,18 @@ def base_set(self, docx_obj: Paragraph, **kwargs): raise ValueError(f"无效的行距选项: '{self.value}'") def get_from_paragraph(self, paragraph: Paragraph): - # 默认单倍行距 - linespacingrule = paragraph.paragraph_format.line_spacing_rule - return linespacingrule if linespacingrule else WD_LINE_SPACING.MULTIPLE + rule = _get_with_style_fallback( + paragraph, "line_spacing_rule", WD_LINE_SPACING.MULTIPLE + ) + if rule == WD_LINE_SPACING.MULTIPLE: + spacing = _get_with_style_fallback(paragraph, "line_spacing", None) + if spacing == 1.0: + return WD_LINE_SPACING.SINGLE + if spacing == 1.5: + return WD_LINE_SPACING.ONE_POINT_FIVE + if spacing == 2.0: + return WD_LINE_SPACING.DOUBLE + return rule class LineSpacing(UnitLabelEnum): diff --git a/src/wordformat/word_structure/settings.py b/src/wordformat/word_structure/settings.py index 272100a..62c1fd1 100644 --- a/src/wordformat/word_structure/settings.py +++ b/src/wordformat/word_structure/settings.py @@ -13,12 +13,14 @@ BodyText, CaptionFigure, CaptionTable, + FigureImage, HeadingLevel1Node, HeadingLevel2Node, HeadingLevel3Node, KeywordsCN, KeywordsEN, References, + TableObject, ) # 标签节点映射 @@ -38,7 +40,10 @@ "acknowledgements_title": Acknowledgements, "caption_figure": CaptionFigure, "caption_table": CaptionTable, + "figure_image": FigureImage, + "table_object": TableObject, "body_text": BodyText, + "other": BodyText, # 封面/声明等无需格式化的内容 } LEVEL_MAP = { "heading_level_1": 1, diff --git a/tests/conftest.py b/tests/conftest.py index ede3413..7674416 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -150,8 +150,13 @@ def sample_yaml_config(tmp_path): chinese_font_name: '宋体' font_size: '小四' bold: false - count_min: 3 - count_max: 5 + rules: + keyword_count: + enabled: true + count_min: 3 + count_max: 5 + trailing_punctuation: + enabled: true english: label: font_size: '三号' @@ -160,8 +165,11 @@ def sample_yaml_config(tmp_path): first_line_indent: '0字符' font_size: '小四' bold: false - count_min: 3 - count_max: 5 + rules: + keyword_count: + enabled: true + count_min: 3 + count_max: 5 headings: level_1: alignment: '居中对齐' diff --git a/tests/test_caption_numbering.py b/tests/test_caption_numbering.py index 54d17d8..4ca3ac0 100644 --- a/tests/test_caption_numbering.py +++ b/tests/test_caption_numbering.py @@ -280,7 +280,7 @@ def test_wrong_chapter_adds_comment(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "章节号应为1" in mock_comment.call_args[0][2] + assert "章节号错误" in mock_comment.call_args[0][2] def test_wrong_separator_adds_comment(self): from wordformat.rules.caption import _check_caption_numbering @@ -294,7 +294,7 @@ def test_wrong_separator_adds_comment(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "分隔符" in mock_comment.call_args[0][2] + assert "分隔符错误" in mock_comment.call_args[0][2] def test_wrong_label_adds_comment(self): from wordformat.rules.caption import _check_caption_numbering @@ -308,7 +308,7 @@ def test_wrong_label_adds_comment(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "标签" in mock_comment.call_args[0][2] + assert "标签错误" in mock_comment.call_args[0][2] def test_wrong_sequence_adds_comment(self): from wordformat.rules.caption import _check_caption_numbering @@ -322,7 +322,7 @@ def test_wrong_sequence_adds_comment(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "题注编号应为2" in mock_comment.call_args[0][2] + assert "编号错误" in mock_comment.call_args[0][2] def test_unparseable_adds_comment(self): from wordformat.rules.caption import _check_caption_numbering @@ -336,7 +336,7 @@ def test_unparseable_adds_comment(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "无法识别" in mock_comment.call_args[0][2] + assert "格式错误" in mock_comment.call_args[0][2] def test_label_space_enabled_no_space_in_text(self): """label_number_space=true,题注无空格 → 添加批注。""" @@ -351,7 +351,7 @@ def test_label_space_enabled_no_space_in_text(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "标签与编号间应为有空格" in mock_comment.call_args[0][2] + assert "间距错误" in mock_comment.call_args[0][2] def test_label_space_disabled_with_space_in_text(self): """label_number_space=false,题注有空格 → 添加批注。""" @@ -366,7 +366,7 @@ def test_label_space_disabled_with_space_in_text(self): _check_caption_numbering(node, doc, "图", cfg) mock_comment.assert_called_once() - assert "应为无空格" in mock_comment.call_args[0][2] + assert "间距错误" in mock_comment.call_args[0][2] def test_disabled_does_nothing(self): """配置禁用时不检查。此逻辑在 _base() 中判断,这里验证 disabled 的 cfg 不触发。""" @@ -424,7 +424,7 @@ def test_continued_table_label_space_wrong(self): _check_caption_numbering(node, doc, "表", cfg) mock_comment.assert_called_once() - assert "标签与编号间应为有空格" in mock_comment.call_args[0][2] + assert "间距错误" in mock_comment.call_args[0][2] # ======================== _apply_caption_numbering ======================== @@ -546,11 +546,19 @@ def caption_yaml(self, tmp_path): figures: caption_position: 'below' caption_prefix: '图' + rules: + caption_numbering: + enabled: true + separator: '.' tables: caption_position: 'above' caption_prefix: '表' content: font_size: '五号' + rules: + caption_numbering: + enabled: true + separator: '.' numbering: enabled: false captions: @@ -627,10 +635,10 @@ def _suppress_format_comments(self): mock_cs.diff_from_run.return_value = {} mock_cs.apply_to_run.return_value = {} with patch( - "wordformat.rules.caption.ParagraphStyle.from_config", + "wordformat.style.check_format.ParagraphStyle.from_config", return_value=mock_ps, ), patch( - "wordformat.rules.caption.CharacterStyle", + "wordformat.style.check_format.CharacterStyle", return_value=mock_cs, ): yield @@ -666,7 +674,7 @@ def test_check_mode_wrong_chapter_adds_comment(self, caption_yaml): apply_format_check_to_all_nodes(heading, doc, config, check=True) mock_comment.assert_called_once() - assert "章节号应为1" in mock_comment.call_args[0][2] + assert "章节号错误" in mock_comment.call_args[0][2] @pytest.mark.usefixtures("_suppress_format_comments") def test_apply_mode_rewrites_caption(self, caption_yaml): @@ -738,7 +746,7 @@ def test_multi_chapter_counters_reset(self, caption_yaml): @pytest.mark.usefixtures("_suppress_format_comments") def test_disabled_skips_numbering_check(self, caption_yaml): - """captions.enabled=False 时不检查编号(但仍注入 chapter/seq)。""" + """rules.caption_numbering.enabled=False 时不检查编号(但仍注入 chapter/seq)。""" from wordformat.set_style import apply_format_check_to_all_nodes doc = Document() @@ -746,7 +754,7 @@ def test_disabled_skips_numbering_check(self, caption_yaml): fig = self._make_caption_figure(p) heading = self._make_heading_node(children=[fig]) config = self._init_config(caption_yaml) - config.numbering.captions.enabled = False + config.figures.rules.caption_numbering.enabled = False with patch.object(fig, "add_comment") as mock_comment: apply_format_check_to_all_nodes(heading, doc, config, check=True) diff --git a/tests/test_core.py b/tests/test_core.py index df9bb0a..692b084 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -544,30 +544,40 @@ def test_update_paragraph(self, doc): node.update_paragraph(p) assert node.paragraph is p - def test_base_raises_not_implemented(self, doc): + def test_base_is_noop(self, doc): + """_base() 默认为空操作。""" node = FormatNode(value="test", level=1) - with pytest.raises(NotImplementedError, match="Subclasses should implement"): - node._base(doc, p=True, r=True) + node._base(doc, p=True, r=True) + node._base(doc, p=False, r=False) def test_check_format_raises(self, doc): - node = FormatNode(value="test", level=1) - with pytest.raises(NotImplementedError): + """未加载配置时 check_format 通过 handler 触发 ValueError。""" + p = doc.add_paragraph("test") + node = FormatNode(value="test", level=1, paragraph=p) + with pytest.raises(ValueError, match="尚未加载"): node.check_format(doc) def test_apply_format_raises(self, doc): - node = FormatNode(value="test", level=1) - with pytest.raises(NotImplementedError): + """未加载配置时 apply_format 通过 handler 触发 ValueError。""" + p = doc.add_paragraph("test") + node = FormatNode(value="test", level=1, paragraph=p) + with pytest.raises(ValueError, match="尚未加载"): node.apply_format(doc) - def test_add_comment_with_text(self, doc): + def test_add_comment_buffers(self, doc): + """add_comment 缓冲文本,_flush_comments 合并写入。""" node = FormatNode(value="test", level=1) p = doc.add_paragraph("hello") - run = p.runs[0] + node.paragraph = p + node.add_comment(doc, p.runs[0], "格式错误") + node.add_comment(doc, p.runs[0], "字体问题") with patch.object(doc, "add_comment") as mock_add: - node.add_comment(doc, run, "格式错误") - mock_add.assert_called_once_with( - runs=run, text="格式错误", author="论文解析器", initials="afish" - ) + node._flush_comments(doc) + mock_add.assert_called_once() + merged = mock_add.call_args[1]["text"] + assert "格式错误" in merged + assert "字体问题" in merged + assert merged.count("\n") == 1 def test_add_comment_empty_text_skipped(self, doc): node = FormatNode(value="test", level=1) diff --git a/tests/test_coverage_boost.py b/tests/test_coverage_boost.py index 3c30635..230fb6d 100644 --- a/tests/test_coverage_boost.py +++ b/tests/test_coverage_boost.py @@ -73,11 +73,11 @@ def _load_root_config(config_path): @pytest.fixture -def root_config(config_path): - """从 example/undergrad_thesis.yaml 加载真实 NodeConfigRoot。""" +def root_config(sample_yaml_config): + """从 sample_yaml_config 加载 NodeConfigRoot,与示例文件解耦。""" from wordformat.config.config import init_config - init_config(config_path) - return _load_root_config(config_path) + init_config(sample_yaml_config) + return _load_root_config(sample_yaml_config) # =========================================================================== @@ -109,7 +109,7 @@ def test_apply_format_sets_paragraph_style_and_alignment(self, root_config): node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) # builtin_style_name 已设置为 Heading 1(python-docx 存储为 "Heading1") assert p.style.name == "Heading 1" @@ -141,7 +141,7 @@ def test_apply_format_updates_existing_pstyle(self, root_config): node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) # python-docx 通过 paragraph.style = "Heading 2" 更新了样式 assert p.style.name == "Heading 2" @@ -280,7 +280,7 @@ def test_apply_to_paragraph_path_cn(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) def test_apply_to_paragraph_path_en(self, root_config): """覆盖行 56 (EN): apply_to_paragraph 路径(p=False)。 @@ -293,7 +293,7 @@ def test_apply_to_paragraph_path_en(self, root_config): node = KeywordsEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) def test_split_mixed_runs_cn(self, root_config): """覆盖行 69-106: _split_mixed_runs 拆分标签和内容混合的 run。 @@ -306,7 +306,7 @@ def test_split_mixed_runs_cn(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) # 拆分后应有多个 run assert len(p.runs) >= 2 @@ -319,7 +319,7 @@ def test_split_mixed_runs_en(self, root_config): node = KeywordsEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) assert len(p.runs) >= 2 @@ -344,7 +344,7 @@ def test_split_mixed_runs_in_format_mode_cn(self, root_config): node.load_config(root_config) initial_run_count = len(p.runs) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) # 格式化模式下拆分后 run 数量应增加 assert len(p.runs) >= initial_run_count @@ -361,7 +361,7 @@ def test_en_label_apply_to_run(self, root_config): node = KeywordsEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_en_content_apply_to_run(self, root_config): @@ -379,7 +379,7 @@ def test_en_content_apply_to_run(self, root_config): node = KeywordsEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_cn_label_apply_to_run(self, root_config): @@ -393,7 +393,7 @@ def test_cn_label_apply_to_run(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_cn_content_apply_to_run(self, root_config): @@ -408,7 +408,7 @@ def test_cn_content_apply_to_run(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_cn_split_mixed_runs_format_mode(self, root_config): @@ -419,7 +419,7 @@ def test_cn_split_mixed_runs_format_mode(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment"): - node._base(doc, p=False, r=False) + node.apply_format(doc) assert len(p.runs) >= 2 def test_cn_get_label_split_pattern(self, root_config): diff --git a/tests/test_integration.py b/tests/test_integration.py index 4c0ff68..aa86f8f 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -29,6 +29,7 @@ clear_config, ) from wordformat.config.datamodel import ( + KeywordCountRule, KeywordsConfig, GlobalFormatConfig, FontSizeType, @@ -120,14 +121,14 @@ class TestDataModelValidation: def test_keywords_count_positive(self): """count_min/count_max 必须大于 0""" with pytest.raises(ValueError): - KeywordsConfig(count_min=0) + KeywordCountRule(count_min=0) with pytest.raises(ValueError): - KeywordsConfig(count_max=-1) + KeywordCountRule(count_max=-1) def test_keywords_count_min_le_max(self): """count_min 不应大于 count_max""" with pytest.raises(ValidationError): - KeywordsConfig(count_min=10, count_max=3) + KeywordCountRule(count_min=10, count_max=3) def test_font_size_range_validation(self): """字号数值验证:负数应触发 ValidationError""" @@ -399,7 +400,6 @@ def test_set_tag_main_calls_parse(self, mock_docx_cls): {"category": "body_text", "score": 0.9, "paragraph": "test", "fingerprint": "fp1"} ] result = set_tag_main("dummy.docx", "dummy.yaml") - assert isinstance(result, list) assert len(result) == 1 mock_instance.parse.assert_called_once() @@ -996,7 +996,6 @@ def test_single_infer_truncation(self): def test_batch_infer_empty_texts(self): """Empty texts list returns [] (line 156)""" result = onnx_batch_infer([]) - assert result == [] def test_batch_infer_loads_model_when_tokenizer_none(self): """_tokenizer is None triggers _load_model (line 159)""" @@ -1074,7 +1073,6 @@ def test_batch_infer_result_assembly(self): def test_safe_batch_infer_empty_texts(self): """Empty texts returns [] (line 244)""" result = safe_batch_infer([]) - assert result == [] # ==================== (m) keywords.py 覆盖测试 ==================== @@ -1167,7 +1165,7 @@ def test_empty_run_skip(self, sample_yaml_config): empty_run.text = " " node.paragraph = p # Should not crash, empty run is skipped - node._base(doc, p=True, r=True) + node.check_format(doc) def test_label_style_check(self, sample_yaml_config): """Label run style is checked (line 121)""" @@ -1181,7 +1179,7 @@ def test_label_style_check(self, sample_yaml_config): label_run = p.add_run("Keywords: ") label_run.font.bold = False # Wrong - should be bold per config node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) # Should have added a comment about bold mismatch def test_content_style_check(self, sample_yaml_config): @@ -1198,10 +1196,10 @@ def test_content_style_check(self, sample_yaml_config): content_run = p.add_run("AI, ML") content_run.font.bold = True # Wrong - content should not be bold node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) def test_keyword_count_validation_min(self, sample_yaml_config): - """Keyword count < count_min triggers warning (line 152)""" + """Keyword count < count_min triggers warning (via _run_rules)""" from wordformat.config.config import init_config, get_config init_config(sample_yaml_config) config = get_config() @@ -1213,11 +1211,11 @@ def test_keyword_count_validation_min(self, sample_yaml_config): label_run.font.bold = True content_run = p.add_run("AI") node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) # count_min is 3, only 1 keyword -> should trigger count warning def test_keyword_count_validation_max(self, sample_yaml_config): - """Keyword count > count_max triggers warning (line 153)""" + """Keyword count > count_max triggers warning (via _run_rules)""" from wordformat.config.config import init_config, get_config init_config(sample_yaml_config) config = get_config() @@ -1229,7 +1227,7 @@ def test_keyword_count_validation_max(self, sample_yaml_config): label_run.font.bold = True content_run = p.add_run("AI, ML, NLP, CV, DB, SE") node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) # count_max is 5, 6 keywords -> should trigger count warning @@ -1247,8 +1245,8 @@ def _make_cn_node(self, config_dict=None): node.load_config(config_dict) return node - def test_config_none_check(self): - """pydantic_config is None -> returns error (lines 177-180)""" + def test_config_none_raises(self): + """未加载配置时 check_format 抛出 ValueError。""" from wordformat.rules.keywords import KeywordsCN node = KeywordsCN( value={"category": "abstract.keywords.chinese", "fingerprint": "fp"}, @@ -1256,13 +1254,10 @@ def test_config_none_check(self): ) doc = Document() p = doc.add_paragraph() - p.add_run("关键词:测试") # Need at least one run for add_comment + p.add_run("关键词:测试") node.paragraph = p - # Mock pydantic_config property to return None (bypassing the ValueError guard) - with mock.patch.object(type(node), 'pydantic_config', new_callable=mock.PropertyMock, return_value=None): - result = node._base(doc, p=True, r=True) - assert len(result) == 1 - assert result[0]["error"] == "配置未加载" + with pytest.raises(ValueError, match="尚未加载"): + node.check_format(doc) def test_paragraph_style_check(self, sample_yaml_config): """Paragraph style is checked (line 187)""" @@ -1276,7 +1271,7 @@ def test_paragraph_style_check(self, sample_yaml_config): p.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # Wrong - should be left run = p.add_run("关键词:人工智能") node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) def test_label_style_check(self, sample_yaml_config): """Label run style is checked (line 218)""" @@ -1290,7 +1285,7 @@ def test_label_style_check(self, sample_yaml_config): label_run = p.add_run("关键词") label_run.font.bold = False # Wrong - should be bold node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) def test_content_style_check(self, sample_yaml_config): """Content run style is checked (line 225)""" @@ -1306,10 +1301,10 @@ def test_content_style_check(self, sample_yaml_config): content_run = p.add_run("人工智能;机器学习") content_run.font.bold = True # Wrong - content should not be bold node.paragraph = p - node._base(doc, p=True, r=True) + node.check_format(doc) def test_keyword_count_and_trailing_punctuation(self, sample_yaml_config): - """Keyword count validation + trailing punctuation check (lines 234-239)""" + """Keyword count validation + trailing punctuation check (via _run_rules)""" from wordformat.config.config import init_config, get_config init_config(sample_yaml_config) config = get_config() @@ -1319,8 +1314,8 @@ def test_keyword_count_and_trailing_punctuation(self, sample_yaml_config): p = doc.add_paragraph() run = p.add_run("关键词:人工智能;机器学习;") node.paragraph = p - node._base(doc, p=True, r=True) - # trailing_punct_forbidden should be True by default + node.check_format(doc) + # trailing_punctuation.enabled should be True by default # Text ends with ; which should trigger trailing punctuation warning @@ -1411,8 +1406,7 @@ def test_heading_base_with_config(self, sample_yaml_config): p = doc.add_paragraph() run = p.add_run("第一章 绪论") node.paragraph = p - result = node._base(doc, p=True, r=True) - assert isinstance(result, list) + node.check_format(doc) # 通过 RULES handler 执行格式检查 # ==================== (o) set_style.py 额外覆盖测试 ==================== @@ -1529,11 +1523,10 @@ def test_body_text_apply_format(self, sample_yaml_config): run = p.add_run("test content") run.font.size = Pt(14) # Wrong size node.paragraph = p - result = node._base(doc, p=False, r=False) - assert isinstance(result, list) + node.apply_format(doc) def test_body_text_apply_to_run(self, sample_yaml_config): - """BodyText._base with r=False triggers apply_to_run (line 45)""" + """apply_format 通过 handler 修正字符格式。""" from wordformat.config.config import init_config, get_config from wordformat.rules.body import BodyText init_config(sample_yaml_config) @@ -1549,7 +1542,7 @@ def test_body_text_apply_to_run(self, sample_yaml_config): run = p.add_run("test") run.font.bold = True # Wrong - should be False per config node.paragraph = p - node._base(doc, p=True, r=False) + node.apply_format(doc) assert run.font.bold is False # Should have been fixed diff --git a/tests/test_rules.py b/tests/test_rules.py index be2e287..1c72174 100644 --- a/tests/test_rules.py +++ b/tests/test_rules.py @@ -2,7 +2,7 @@ rules 模块测试 —— 聚焦真实行为验证,无填充。 """ import re -from unittest.mock import MagicMock, patch +from unittest.mock import patch import pytest from docx import Document @@ -58,11 +58,11 @@ def _load_yaml(path): @pytest.fixture -def root_config(config_path): - """从 example/undergrad_thesis.yaml 加载真实 NodeConfigRoot。""" +def root_config(sample_yaml_config): + """从 sample_yaml_config 加载 NodeConfigRoot,与示例文件解耦。""" from wordformat.config.config import init_config - init_config(config_path) - return _load_root_config(config_path) + init_config(sample_yaml_config) + return _load_root_config(sample_yaml_config) @pytest.fixture @@ -91,23 +91,25 @@ def run_with_text(para): class TestFormatNodeBase: """FormatNode 基类的核心契约。""" - def test_base_raises_not_implemented(self, doc, para): - """_base 必须抛出 NotImplementedError。""" + def test_base_is_noop(self, doc, para): + """_base() 默认为空操作。""" node = FormatNodeBase(value=para, level=0, paragraph=para) - with pytest.raises(NotImplementedError): - node._base(doc, p=True, r=True) + node._base(doc, p=True, r=True) + node._base(doc, p=False, r=False) def test_check_format_calls_base_with_true(self, doc, para): """check_format 应以 p=True, r=True 调用 _base。""" node = FormatNodeBase(value=para, level=0, paragraph=para) - with patch.object(node, "_base") as mock_base: + with patch.object(node, "_base") as mock_base, \ + patch.object(node, "_run_rules"): node.check_format(doc) mock_base.assert_called_once_with(doc, p=True, r=True) def test_apply_format_calls_base_with_false(self, doc, para): """apply_format 应以 p=False, r=False 调用 _base。""" node = FormatNodeBase(value=para, level=0, paragraph=para) - with patch.object(node, "_base") as mock_base: + with patch.object(node, "_base") as mock_base, \ + patch.object(node, "_run_rules"): node.apply_format(doc) mock_base.assert_called_once_with(doc, p=False, r=False) @@ -177,7 +179,7 @@ def test_abstract_title_cn(self, root_config): node.load_config(root_config) assert node._pydantic_config is not None assert node._pydantic_config.chinese_font_name == "黑体" - assert node._pydantic_config.bold is False + assert node._pydantic_config.bold is True def test_abstract_content_cn(self, root_config): node = _make_node(AbstractContentCN) @@ -234,7 +236,7 @@ def test_references(self, root_config): node = _make_node(References) node.load_config(root_config) assert node._pydantic_config is not None - assert node._pydantic_config.bold is False + assert node._pydantic_config.bold is True def test_reference_entry(self, root_config): node = _make_node(ReferenceEntry) @@ -246,7 +248,7 @@ def test_acknowledgements(self, root_config): node = _make_node(Acknowledgements) node.load_config(root_config) assert node._pydantic_config is not None - assert node._pydantic_config.bold is False + assert node._pydantic_config.bold is True def test_acknowledgements_cn(self, root_config): node = _make_node(AcknowledgementsCN) @@ -261,8 +263,8 @@ def test_keywords_cn_from_dict(self, config_path): node.load_config(raw) assert node._pydantic_config is not None # dict 路径下 LANG='cn' 找不到 YAML 中的 'chinese' 键,使用默认值 - assert node._pydantic_config.count_min == 4 - assert node._pydantic_config.count_max == 4 + assert node._pydantic_config.rules.keyword_count.count_min == 4 + assert node._pydantic_config.rules.keyword_count.count_max == 6 def test_keywords_en_from_dict(self, config_path): """KeywordsEN 支持从 dict 加载配置。""" @@ -332,33 +334,38 @@ class TestKeywordsLogic: """关键词节点的标签识别、数量校验、标点校验。""" def test_cn_label_detection(self): - """中文关键词标签识别。""" - node = _make_node(KeywordsCN) - mock_run = MagicMock() - mock_run.text = "关键词" - assert node._check_keyword_label(mock_run) is True + """中文关键词标签识别(使用真实 paragraph runs)。""" + doc = Document() + p = doc.add_paragraph("关键词") + node = KeywordsCN(value=p, level=0, paragraph=p) + assert node._check_keyword_label(p.runs[0]) is True - mock_run.text = "关 键 词" - assert node._check_keyword_label(mock_run) is True + p2 = doc.add_paragraph("关 键 词") + node.paragraph = p2 + assert node._check_keyword_label(p2.runs[0]) is True - mock_run.text = "机器学习" - assert node._check_keyword_label(mock_run) is False + p3 = doc.add_paragraph("机器学习") + node.paragraph = p3 + assert node._check_keyword_label(p3.runs[0]) is False def test_en_label_detection(self): - """英文关键词标签识别。""" - node = _make_node(KeywordsEN) - mock_run = MagicMock() - mock_run.text = "Keywords" - assert node._check_keyword_label(mock_run) is True + """英文关键词标签识别(使用真实 paragraph runs)。""" + doc = Document() + p = doc.add_paragraph("Keywords") + node = KeywordsEN(value=p, level=0, paragraph=p) + assert node._check_keyword_label(p.runs[0]) is True - mock_run.text = "Keyword" - assert node._check_keyword_label(mock_run) is True + p2 = doc.add_paragraph("Keyword") + node.paragraph = p2 + assert node._check_keyword_label(p2.runs[0]) is True - mock_run.text = "KEY WORDS" - assert node._check_keyword_label(mock_run) is True + p3 = doc.add_paragraph("KEY WORDS") + node.paragraph = p3 + assert node._check_keyword_label(p3.runs[0]) is True - mock_run.text = "machine learning" - assert node._check_keyword_label(mock_run) is False + p4 = doc.add_paragraph("machine learning") + node.paragraph = p4 + assert node._check_keyword_label(p4.runs[0]) is False def test_cn_count_validation_too_few(self, root_config): """中文关键词数量不足时应触发 add_comment。""" @@ -368,10 +375,10 @@ def test_cn_count_validation_too_few(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) # 应至少有一条数量不足的 comment texts = [c.kwargs["text"] for c in mock_comment.call_args_list] - assert any("数量不足" in t for t in texts) + assert any("数量过少" in t for t in texts) def test_cn_count_validation_too_many(self, root_config): """中文关键词数量超限时应触发 add_comment。""" @@ -381,9 +388,9 @@ def test_cn_count_validation_too_many(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) texts = [c.kwargs["text"] for c in mock_comment.call_args_list] - assert any("数量超限" in t for t in texts) + assert any("数量过多" in t for t in texts) def test_cn_trailing_punct_detection(self, root_config): """中文关键词末尾标点校验。""" @@ -393,9 +400,9 @@ def test_cn_trailing_punct_detection(self, root_config): node = KeywordsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) texts = [c.kwargs["text"] for c in mock_comment.call_args_list] - assert any("末尾禁止" in t for t in texts) + assert any("标点错误" in t for t in texts) def test_en_count_validation_too_few(self, root_config): """英文关键词数量不足。""" @@ -405,9 +412,9 @@ def test_en_count_validation_too_few(self, root_config): node = KeywordsEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) texts = [c.kwargs["text"] for c in mock_comment.call_args_list] - assert any("数量不足" in t for t in texts) + assert any("数量过少" in t for t in texts) def test_cn_no_config_raises_value_error(self, doc): """KeywordsCN 在 _pydantic_config 为 None 时访问 pydantic_config 抛出 ValueError。 @@ -417,7 +424,7 @@ def test_cn_no_config_raises_value_error(self, doc): node = KeywordsCN(value=p, level=0, paragraph=p) # 不加载配置 with pytest.raises(ValueError, match="尚未加载"): - node._base(doc, p=True, r=True) + node.check_format(doc) def test_keywords_unsupported_type_raises(self): """KeywordsCN.load_config 传入不支持的类型应抛出 TypeError。""" @@ -464,15 +471,12 @@ def test_abstract_title_cn_check_runs(self, root_config): # 至少对 run 和 paragraph 各调用一次 assert mock_comment.call_count >= 2 - def test_heading_no_config_returns_error(self, doc): - """HeadingLevel1Node 在无配置时应返回错误字典。""" + def test_heading_no_config_raises_value_error(self, doc): + """HeadingLevel1Node 未加载配置时 check_format 抛出 ValueError。""" p = doc.add_paragraph("第一章 绪论") node = HeadingLevel1Node(value=p, level=1, paragraph=p) - # 不加载配置 - with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) - assert isinstance(result, list) - assert any(isinstance(item, dict) and "error" in item for item in result) + with pytest.raises(ValueError, match="尚未加载"): + node.check_format(doc) def test_references_check_runs(self, root_config): """References.check_format 应遍历 run 并调用 add_comment。""" @@ -635,7 +639,7 @@ def test_check_with_wrong_format_triggers_comments(self, root_config): node = AbstractTitleCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 def test_apply_fixes_wrong_format(self, root_config): @@ -648,20 +652,17 @@ def test_apply_fixes_wrong_format(self, root_config): node = AbstractTitleCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) # apply 模式也会调用 add_comment assert mock_comment.call_count >= 2 - def test_check_no_runs_still_calls_paragraph_comment(self, root_config): - """段落无 run 时,仍应调用段落级别的 add_comment。""" + def test_check_no_runs_skips_without_error(self, root_config): + """段落无 run 时(空段),check_format 安全跳过不报错。""" doc = Document() p = doc.add_paragraph() node = AbstractTitleCN(value=p, level=0, paragraph=p) node.load_config(root_config) - with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) - # 至少有段落级别的 comment - assert mock_comment.call_count >= 1 + node.check_format(doc) # 不应抛异常 # --------------------------------------------------------------------------- @@ -681,7 +682,7 @@ def test_check_title_run_uses_title_style(self, root_config): node = AbstractTitleContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 def test_check_content_run_uses_content_style(self, root_config): @@ -693,7 +694,7 @@ def test_check_content_run_uses_content_style(self, root_config): node = AbstractTitleContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 def test_apply_title_and_content_runs(self, root_config): @@ -707,7 +708,7 @@ def test_apply_title_and_content_runs(self, root_config): node = AbstractTitleContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 3 def test_check_mode_does_not_mutate_run_text(self, root_config): @@ -719,7 +720,7 @@ def test_check_mode_does_not_mutate_run_text(self, root_config): r.font.size = Pt(10) node = AbstractTitleContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) - node._base(doc, p=True, r=True) + node.check_format(doc) # 修复后:检查模式不应改变 run.text assert r.text == original_text @@ -741,7 +742,7 @@ def test_check_with_wrong_font_size(self, root_config): node = AbstractContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 def test_apply_fixes_font_size(self, root_config): @@ -753,7 +754,7 @@ def test_apply_fixes_font_size(self, root_config): node = AbstractContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 2 def test_check_multiple_runs(self, root_config): @@ -767,7 +768,7 @@ def test_check_multiple_runs(self, root_config): node = AbstractContentCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) # 2 run comments + 1 paragraph comment assert mock_comment.call_count >= 3 @@ -791,7 +792,7 @@ def test_check_with_wrong_format(self, root_config): node = AbstractTitleEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_check_returns_empty_list(self, root_config): @@ -802,8 +803,7 @@ def test_check_returns_empty_list(self, root_config): r.font.size = Pt(10) node = AbstractTitleEN(value=p, level=0, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert result == [] + node.check_format(doc) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -815,7 +815,7 @@ def test_apply_with_wrong_format(self, root_config): node = AbstractTitleEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 @@ -836,7 +836,7 @@ def test_check_title_run_uses_title_style(self, root_config): node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 def test_check_content_run_uses_content_style(self, root_config): @@ -848,7 +848,7 @@ def test_check_content_run_uses_content_style(self, root_config): node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 def test_apply_mixed_runs(self, root_config): @@ -862,7 +862,7 @@ def test_apply_mixed_runs(self, root_config): node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 3 def test_check_title_normalizes_case_lower(self, root_config): @@ -873,7 +873,7 @@ def test_check_title_normalizes_case_lower(self, root_config): r.font.size = Pt(10) node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) - node._base(doc, p=True, r=True) + node.check_format(doc) assert r.text.startswith("Abstract") def test_check_title_normalizes_case_upper(self, root_config): @@ -884,7 +884,7 @@ def test_check_title_normalizes_case_upper(self, root_config): r.font.size = Pt(10) node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) - node._base(doc, p=True, r=True) + node.check_format(doc) assert r.text.startswith("Abstract") def test_split_abstract_across_runs(self, root_config): @@ -897,7 +897,7 @@ def test_split_abstract_across_runs(self, root_config): r2.font.size = Pt(10) node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) - node._base(doc, p=True, r=True) + node.check_format(doc) # r1 开头被修正为 "Abstract",r2 保持 "body text" 部分 assert r1.text.startswith("Abstract") assert "body text" in r2.text @@ -914,7 +914,7 @@ def test_split_abstract_across_three_runs(self, root_config): r3.font.size = Pt(10) node = AbstractTitleContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) - node._base(doc, p=True, r=True) + node.check_format(doc) # r1 应被修正为 "Abstract" assert r1.text.startswith("Abstract") # r2 和 r3 开头部分属于标题前缀,应被清空 @@ -940,7 +940,7 @@ def test_check_with_wrong_format(self, root_config): node = AbstractContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_apply_with_wrong_format(self, root_config): @@ -954,7 +954,7 @@ def test_apply_with_wrong_format(self, root_config): with patch.object(node, "add_comment") as mock_comment: # 配置中 line_spacing 为 "0倍",现会触发 ValueError,mock 掉该步 with patch("wordformat.style.check_format.LineSpacing.format"): - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_check_multiple_runs(self, root_config): @@ -968,7 +968,7 @@ def test_check_multiple_runs(self, root_config): node = AbstractContentEN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 2 @@ -990,7 +990,7 @@ def test_check_with_wrong_format(self, root_config): node = Acknowledgements(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_check_returns_empty_list(self, root_config): @@ -1001,8 +1001,7 @@ def test_check_returns_empty_list(self, root_config): r.font.size = Pt(10) node = Acknowledgements(value=p, level=0, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert result == [] + node.check_format(doc) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1013,7 +1012,7 @@ def test_apply_with_wrong_format(self, root_config): node = Acknowledgements(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_check_no_diffs_no_comment(self, root_config): @@ -1024,7 +1023,7 @@ def test_check_no_diffs_no_comment(self, root_config): node = Acknowledgements(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) # 即使格式正确,段落级别的 diff 仍可能触发 comment # 但如果没有差异,不应有 comment # 注意:新 Document 的段落默认对齐方式可能与配置不同 @@ -1047,7 +1046,7 @@ def test_check_with_wrong_format(self, root_config): node = AcknowledgementsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_check_returns_empty_list(self, root_config): @@ -1058,8 +1057,7 @@ def test_check_returns_empty_list(self, root_config): r.font.size = Pt(10) node = AcknowledgementsCN(value=p, level=0, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert result == [] + node.check_format(doc) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1070,7 +1068,7 @@ def test_apply_with_wrong_format(self, root_config): node = AcknowledgementsCN(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_check_first_line_indent(self, root_config): @@ -1084,7 +1082,7 @@ def test_check_first_line_indent(self, root_config): # 验证配置中有 first_line_indent 字段 assert hasattr(node._pydantic_config, "first_line_indent") with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 @@ -1105,7 +1103,7 @@ def test_check_with_wrong_format(self, root_config): node = CaptionFigure(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_apply_with_wrong_format(self, root_config): @@ -1117,7 +1115,7 @@ def test_apply_with_wrong_format(self, root_config): node = CaptionFigure(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 @@ -1138,7 +1136,7 @@ def test_check_with_wrong_format(self, root_config): node = CaptionTable(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_apply_with_wrong_format(self, root_config): @@ -1150,7 +1148,7 @@ def test_apply_with_wrong_format(self, root_config): node = CaptionTable(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 @@ -1172,9 +1170,8 @@ def test_check_with_wrong_format(self, root_config): node = HeadingLevel1Node(value=p, level=1, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 - assert isinstance(result, list) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1185,9 +1182,8 @@ def test_apply_with_wrong_format(self, root_config): node = HeadingLevel1Node(value=p, level=1, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 - assert isinstance(result, list) def test_check_returns_issues_list(self, root_config): """返回值应为包含 issue 字典的列表。""" @@ -1197,10 +1193,8 @@ def test_check_returns_issues_list(self, root_config): r.font.size = Pt(10) node = HeadingLevel1Node(value=p, level=1, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert isinstance(result, list) + node.check_format(doc) # 应有 run_issues 或 paragraph_issues - assert len(result) >= 1 def test_check_skips_empty_runs(self, root_config): """空白 run 应被跳过。""" @@ -1212,7 +1206,7 @@ def test_check_skips_empty_runs(self, root_config): node = HeadingLevel1Node(value=p, level=1, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) + node.check_format(doc) # 空白 run 不应触发 comment run_comments = [ c for c in mock_comment.call_args_list @@ -1238,9 +1232,8 @@ def test_check_with_wrong_format(self, root_config): node = HeadingLevel2Node(value=p, level=2, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 - assert isinstance(result, list) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1251,9 +1244,8 @@ def test_apply_with_wrong_format(self, root_config): node = HeadingLevel2Node(value=p, level=2, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 - assert isinstance(result, list) def test_check_returns_issues(self, root_config): """返回值应包含 issue 字典。""" @@ -1263,9 +1255,7 @@ def test_check_returns_issues(self, root_config): r.font.size = Pt(10) node = HeadingLevel2Node(value=p, level=2, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert isinstance(result, list) - assert len(result) >= 1 + node.check_format(doc) # --------------------------------------------------------------------------- @@ -1285,9 +1275,8 @@ def test_check_with_wrong_format(self, root_config): node = HeadingLevel3Node(value=p, level=3, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 - assert isinstance(result, list) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1298,9 +1287,8 @@ def test_apply_with_wrong_format(self, root_config): node = HeadingLevel3Node(value=p, level=3, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 - assert isinstance(result, list) def test_check_returns_issues(self, root_config): """返回值应包含 issue 字典。""" @@ -1310,9 +1298,7 @@ def test_check_returns_issues(self, root_config): r.font.size = Pt(10) node = HeadingLevel3Node(value=p, level=3, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert isinstance(result, list) - assert len(result) >= 1 + node.check_format(doc) # --------------------------------------------------------------------------- @@ -1333,7 +1319,7 @@ def test_check_with_wrong_format(self, root_config): node = References(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_check_returns_empty_list(self, root_config): @@ -1344,8 +1330,7 @@ def test_check_returns_empty_list(self, root_config): r.font.size = Pt(10) node = References(value=p, level=0, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert result == [] + node.check_format(doc) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1356,7 +1341,7 @@ def test_apply_with_wrong_format(self, root_config): node = References(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 @@ -1377,7 +1362,7 @@ def test_check_with_wrong_format(self, root_config): node = ReferenceEntry(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=True, r=True) + node.check_format(doc) assert mock_comment.call_count >= 1 def test_check_returns_empty_list(self, root_config): @@ -1388,8 +1373,7 @@ def test_check_returns_empty_list(self, root_config): r.font.size = Pt(10) node = ReferenceEntry(value=p, level=0, paragraph=p) node.load_config(root_config) - result = node._base(doc, p=True, r=True) - assert result == [] + node.check_format(doc) def test_apply_with_wrong_format(self, root_config): """apply 模式:应修正格式。""" @@ -1400,7 +1384,7 @@ def test_apply_with_wrong_format(self, root_config): node = ReferenceEntry(value=p, level=0, paragraph=p) node.load_config(root_config) with patch.object(node, "add_comment") as mock_comment: - result = node._base(doc, p=False, r=False) + node.apply_format(doc) assert mock_comment.call_count >= 1 def test_check_alignment_and_indent(self, root_config): diff --git a/tests/test_style.py b/tests/test_style.py index bc7a2e4..ad20e06 100644 --- a/tests/test_style.py +++ b/tests/test_style.py @@ -133,7 +133,7 @@ def test_diff_boolean_mismatch(self, doc, mock_warning, prop, expected_val, curr def test_diff_font_size_and_name_cn(self, doc, mock_warning): _set_warning(mock_warning) cs = CharacterStyle(font_size="小四", font_name_cn="宋体") - run = doc.add_paragraph().add_run("t") + run = doc.add_paragraph().add_run("测试") run.font.size = Pt(14) run_set_font_name(run, "黑体") types = [d.diff_type for d in cs.diff_from_run(run)] @@ -151,9 +151,9 @@ def test_apply_to_run_fixes_bold(self, doc, mock_warning): _clear_warning() def test_to_string_filters_by_warning(self, mock_warning, mock_warning_off): - diffs = [DIFFResult(diff_type="bold", comment="b")] + diffs = [DIFFResult(diff_type="bold", current_value=True, expected_value=False)] _set_warning(mock_warning) - assert "b" in CharacterStyle.to_string(diffs) + assert "加粗错误" in CharacterStyle.to_string(diffs) _set_warning(mock_warning_off) assert CharacterStyle.to_string(diffs) == "" _clear_warning() @@ -184,12 +184,12 @@ def test_diff_detects_alignment(self, doc, mock_warning): assert "alignment" in [d.diff_type for d in ParagraphStyle(alignment="左对齐").diff_from_paragraph(p)] _clear_warning() - def test_diff_builtin_style_case_mismatch(self, doc, mock_warning): - """BuiltInStyle('正文').rel_value='Normal' but get_from_paragraph returns 'normal'.""" + def test_diff_builtin_style_name_match(self, doc, mock_warning): + """BuiltInStyle('正文').rel_value='Normal' 与 'normal' 应视为一致。""" _set_warning(mock_warning) p = doc.add_paragraph() types = [d.diff_type for d in ParagraphStyle(builtin_style_name="正文").diff_from_paragraph(p)] - assert "builtin_style_name" in types + assert "builtin_style_name" not in types # 英文"normal" = 中文"正文" _clear_warning() def test_to_string_line_spacing_rule_key_bug(self, doc, mock_warning): @@ -2266,7 +2266,7 @@ def test_apply_to_run_fixes_font_name_cn(self, doc, mock_warning): _set_warning(mock_warning) cs = CharacterStyle(font_name_cn="黑体") p = doc.add_paragraph() - run = p.add_run("test") + run = p.add_run("测试") # Default CN font is 宋体, so 黑体 should trigger a fix run_set_font_name(run, "宋体") result = cs.apply_to_run(run) @@ -2279,27 +2279,28 @@ class TestCharacterStyleToStringNone: """Cover line 244: CharacterStyle.to_string with style_checks_warning is None""" def test_to_string_warning_none(self): - """When style_checks_warning is None, return all diffs joined (line 244)""" + """style_checks_warning=None 时返回所有 diff 的标准格式文本。""" import wordformat.style.check_format as m m.style_checks_warning = None diffs = [ - DIFFResult(diff_type="bold", comment="bold_issue"), - DIFFResult(diff_type="italic", comment="italic_issue"), + DIFFResult(diff_type="bold", current_value=True, expected_value=False), + DIFFResult(diff_type="italic", current_value=True, expected_value=False), ] - result = CharacterStyle.to_string(diffs) - assert "bold_issue" in result - assert "italic_issue" in result + result = CharacterStyle.to_string(diffs, target="测试") + assert "加粗错误" in result + assert "斜体错误" in result + assert "测试" in result class TestCharacterStyleToStringBoldFilter: """Cover line 250: CharacterStyle.to_string with style_checks_warning.bold = True""" def test_to_string_bold_filtered_in(self, mock_warning): - """warning.bold=True includes bold diffs (line 250)""" + """warning.bold=True 时 bold diff 被包含。""" _set_warning(mock_warning) - diffs = [DIFFResult(diff_type="bold", comment="b")] - result = CharacterStyle.to_string(diffs) - assert "b" in result + diffs = [DIFFResult(diff_type="bold", current_value=True, expected_value=False)] + result = CharacterStyle.to_string(diffs, target="测试") + assert "加粗错误" in result _clear_warning() @@ -2307,35 +2308,35 @@ class TestCharacterStyleToStringVariousFilters: """Cover lines 252, 254, 256: CharacterStyle.to_string with italic/underline/font_size/font_color/font_name filters""" def test_to_string_italic_filtered(self, mock_warning): - """warning.italic=True includes italic diffs (line 252)""" + """warning.italic=True 时 italic diff 被包含。""" _set_warning(mock_warning) - diffs = [DIFFResult(diff_type="italic", comment="i")] + diffs = [DIFFResult(diff_type="italic", current_value=True, expected_value=False)] result = CharacterStyle.to_string(diffs) - assert "i" in result + assert "斜体错误" in result _clear_warning() def test_to_string_font_size_filtered(self, mock_warning): - """warning.font_size=True includes font_size diffs (line 254)""" + """warning.font_size=True 时 font_size diff 被包含。""" _set_warning(mock_warning) - diffs = [DIFFResult(diff_type="font_size", comment="fs")] + diffs = [DIFFResult(diff_type="font_size", current_value=10.0, expected_value=12.0)] result = CharacterStyle.to_string(diffs) - assert "fs" in result + assert "字号错误" in result _clear_warning() def test_to_string_font_color_filtered(self, mock_warning): - """warning.font_color=True includes font_color diffs (line 256)""" + """warning.font_color=True 时 font_color diff 被包含。""" _set_warning(mock_warning) - diffs = [DIFFResult(diff_type="font_color", comment="fc")] + diffs = [DIFFResult(diff_type="font_color", current_value="红色", expected_value="黑色")] result = CharacterStyle.to_string(diffs) - assert "fc" in result + assert "字体颜色错误" in result _clear_warning() def test_to_string_font_name_filtered(self, mock_warning): - """warning.font_name=True includes font_name_cn/en diffs (lines 257-261)""" + """warning.font_name=True 时 font_name_cn diff 被包含。""" _set_warning(mock_warning) - diffs = [DIFFResult(diff_type="font_name_cn", comment="fnc")] + diffs = [DIFFResult(diff_type="font_name_cn", current_value="宋体", expected_value="黑体")] result = CharacterStyle.to_string(diffs) - assert "fnc" in result + assert "中文字体错误" in result _clear_warning() @@ -2343,13 +2344,13 @@ class TestParagraphStyleToStringNone: """Cover line 478: ParagraphStyle.to_string with style_checks_warning is None""" def test_to_string_warning_none(self): - """When style_checks_warning is None, return all diffs joined (line 478)""" + """style_checks_warning=None 时返回所有 diff 的标准格式文本。""" import wordformat.style.check_format as m m.style_checks_warning = None diffs = [ - DIFFResult(diff_type="alignment", comment="align_issue"), - DIFFResult(diff_type="space_before", comment="sb_issue"), + DIFFResult(diff_type="alignment", current_value="左对齐", expected_value="居中对齐"), + DIFFResult(diff_type="space_before", current_value="0行", expected_value="0.5行"), ] result = ParagraphStyle.to_string(diffs) - assert "align_issue" in result - assert "sb_issue" in result + assert "对齐错误" in result + assert "段前间距错误" in result diff --git a/wordformat-skill/SKILL.md b/wordformat-skill/SKILL.md index 3d9f7d7..0cd7c50 100644 --- a/wordformat-skill/SKILL.md +++ b/wordformat-skill/SKILL.md @@ -57,11 +57,33 @@ pip install wordformat # 海外 ## 工作流程 -两个独立任务,先任务一再任务二。每个任务完成后**必须将产物复制到用户工作目录**。 +根据用户意图走不同路径: + +- **仅文本替换**:只想修正论文中某些段落的文字内容(如错别字、措辞),不检查格式 → [纯文本替换流程](#纯文本替换流程) +- **格式校验/修正**:检查或修正论文格式 → 下面两个独立任务,先任务一再任务二 + +每个任务完成后**必须将产物复制到用户工作目录**。 + +--- + +## 纯文本替换流程 + +> 用户只想换文字(错别字、措辞修正),不需要格式批注/编号/样式修改。 + +1. 生成 JSON:`wordf gj -d 论文.docx -c config.yaml` +2. 编辑 JSON:在需要替换的段落对象中添加 `"replace": "新的正确文本"` +3. 执行替换:`wordf af -d 论文.docx -c config.yaml -f output/论文_xxx.json` +4. 交付:`cp output/论文--修改版.docx <用户工作目录>/` + +> `wordf af` 执行替换的同时也会应用格式修正。如果 config.yaml 格式规范与论文当前格式一致,则仅文本被替换、格式不变。**用户说"只换文字"时走此流程,不要追加 `cf` 检查或格式批注操作。** + +--- + +## 格式校验/修正流程 --- -## 任务一:准备配置文件 +### 任务一:准备配置文件 > **🚨 用户已提供 .yaml 配置 → 直接跳到步骤 1.2 验证,禁止新建。** > **🚨 用户说"用上次的配置"/"和上次一样" → 复用已有配置,禁止新建。** @@ -126,7 +148,7 @@ cp config.yaml <用户工作目录>/ --- -## 任务二:执行格式化 +### 任务二:执行格式化 > 前提:有 `config.yaml` 和 `.docx` 论文。 diff --git a/wordformat-skill/data/config_spec.md b/wordformat-skill/data/config_spec.md index 7e26786..66471b9 100644 --- a/wordformat-skill/data/config_spec.md +++ b/wordformat-skill/data/config_spec.md @@ -59,14 +59,28 @@ abstract: english: # 同上 ``` -keywords 专用字段: +keywords 除 16 个 GlobalFormat 字段外,附加: + +```yaml +label: # KeywordLabelConfig,关键词标签的字符格式 +rules: + keyword_count: # 关键词数量校验 + enabled: true + count_min: 4 + count_max: 6 + trailing_punctuation: # 末尾标点校验(仅中文) + enabled: true + forbidden_chars: ";,。、" +``` | 字段 | 类型 | 默认值 | |------|------|--------| | `label` | GlobalFormat | 关键词标签("关键词:")的字符格式 | -| `count_min` | int | `4` | -| `count_max` | int | `4` | -| `trailing_punct_forbidden` | bool | `true` | +| `rules.keyword_count.enabled` | bool | `true` | +| `rules.keyword_count.count_min` | int | `4` | +| `rules.keyword_count.count_max` | int | `6` | +| `rules.trailing_punctuation.enabled` | bool | `true` | +| `rules.trailing_punctuation.forbidden_chars` | string | `";,。、"` | ### headings(标题) @@ -83,7 +97,7 @@ headings: ### figures(图注) -继承 15 字段 + `caption_prefix`(默认 `图`)。 +继承 16 字段 + `caption_prefix`(默认 `图`)+ `rules`。 ```yaml figures: @@ -93,11 +107,16 @@ figures: alignment: '居中对齐' first_line_indent: '0字符' builtin_style_name: '题注' + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false ``` ### tables(表注 + 表格内容) -继承 15 字段 + `caption_prefix`(默认 `表`)+ `content` 子配置(继承 15 字段,控制单元格内文字)。 +继承 16 字段 + `caption_prefix`(默认 `表`)+ `content` 子配置 + `rules`。 ```yaml tables: @@ -108,6 +127,11 @@ tables: <<: *global_format font_size: '五号' line_spacingrule: '单倍行距' + rules: + caption_numbering: + enabled: true + separator: '.' + label_number_space: false ``` ### references(参考文献) @@ -170,11 +194,18 @@ numbering: | `style_checks_warning` | bold, italic, underline, font_size, font_name, font_color, alignment, space_before, space_after, line_spacing, line_spacingrule, left_indent, right_indent, first_line_indent, builtin_style_name | | `global_format` | 同上 + chinese_font_name, english_font_name, font_size, font_color, bold, italic, underline | | `abstract.{zh/en}.{title/content}` | 同 global_format | -| `abstract.keywords.{zh/en}` | 同 global_format + label(同 global_format) + count_min, count_max, trailing_punct_forbidden | +| `abstract.keywords.{zh/en}` | 同 global_format + label(同 global_format) + rules | +| `abstract.keywords.{zh/en}.rules` | keyword_count, trailing_punctuation | +| `abstract.keywords.{zh/en}.rules.keyword_count` | enabled, count_min, count_max | +| `abstract.keywords.{zh/en}.rules.trailing_punctuation` | enabled, forbidden_chars | | `headings.level_1/2/3` | 同 global_format | | `body_text` | 同 global_format | -| `figures` | 同 global_format + caption_prefix | -| `tables` | 同 global_format + caption_prefix + content(同 global_format) | +| `figures` | 同 global_format + caption_prefix + rules | +| `figures.rules` | caption_numbering | +| `figures.rules.caption_numbering` | enabled, separator, label_number_space | +| `tables` | 同 global_format + caption_prefix + content(同 global_format) + rules | +| `tables.rules` | caption_numbering | +| `tables.rules.caption_numbering` | enabled, separator, label_number_space | | `references.title` | 同 global_format | | `references.content` | 同 global_format | | `acknowledgements.title/content` | 同 global_format | diff --git a/wordformat-skill/scripts/validate_config.py b/wordformat-skill/scripts/validate_config.py index e8183bf..bcc41e5 100644 --- a/wordformat-skill/scripts/validate_config.py +++ b/wordformat-skill/scripts/validate_config.py @@ -105,10 +105,8 @@ def _get_pip_mirror() -> list[str]: # abstract.keywords.chinese / english 合法字段 KEYWORDS_FIELDS = GLOBAL_FORMAT_FIELDS | { - "keywords_bold", - "count_min", - "count_max", - "trailing_punct_forbidden", + "label", + "rules", } # headings 各级别合法字段 @@ -117,11 +115,14 @@ def _get_pip_mirror() -> list[str]: # figures 合法字段 FIGURES_FIELDS = GLOBAL_FORMAT_FIELDS | { "caption_prefix", + "rules", } # tables 合法字段 TABLES_FIELDS = GLOBAL_FORMAT_FIELDS | { "caption_prefix", + "content", + "rules", } # references.title 合法字段 diff --git a/wordformat-skill/scripts/validate_json.py b/wordformat-skill/scripts/validate_json.py index ec412ff..13e6b55 100644 --- a/wordformat-skill/scripts/validate_json.py +++ b/wordformat-skill/scripts/validate_json.py @@ -39,6 +39,8 @@ "acknowledgements_title", "caption_figure", "caption_table", + "figure_image", + "table_object", "body_text", "other", }