xiaodao-spreader 0.1.37 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.ZH.md +121 -48
  2. package/README.md +126 -54
  3. package/dist/style.css +1 -1
  4. package/dist/types/components/spreader/components/dropdown.vue.d.ts +3 -1
  5. package/dist/types/components/spreader/components/note-overlay.vue.d.ts +47 -0
  6. package/dist/types/components/spreader/components/pickers/border-picker.vue.d.ts +16 -2
  7. package/dist/types/components/spreader/components/pickers/calc-picker.vue.d.ts +1 -1
  8. package/dist/types/components/spreader/components/pickers/color-palette.vue.d.ts +17 -0
  9. package/dist/types/components/spreader/components/pickers/color-picker.vue.d.ts +1 -1
  10. package/dist/types/components/spreader/components/pickers/data-validation-dropdown.vue.d.ts +1 -1
  11. package/dist/types/components/spreader/components/pickers/insert-function-dialog.vue.d.ts +1 -1
  12. package/dist/types/components/spreader/components/pickers/merge-picker.vue.d.ts +1 -1
  13. package/dist/types/components/spreader/components/pickers/number-format-dialog.vue.d.ts +1 -1
  14. package/dist/types/components/spreader/components/pickers/outline-picker.vue.d.ts +1 -1
  15. package/dist/types/components/spreader/components/pickers/sort-confirm-dialog.vue.d.ts +1 -1
  16. package/dist/types/components/spreader/components/pickers/sort-picker.vue.d.ts +1 -1
  17. package/dist/types/components/spreader/components/spreader.vue.d.ts +17 -5
  18. package/dist/types/components/spreader/components/toolbar.vue.d.ts +10 -2
  19. package/dist/types/components/spreader/composables/borders-merge.d.ts +19 -3
  20. package/dist/types/components/spreader/composables/core-state.d.ts +28 -2
  21. package/dist/types/components/spreader/composables/find-replace.d.ts +5 -0
  22. package/dist/types/components/spreader/composables/interactions.d.ts +26 -0
  23. package/dist/types/components/spreader/composables/sheets-ops.d.ts +5 -0
  24. package/dist/types/components/spreader/composables/undo-styles.d.ts +5 -0
  25. package/dist/types/components/spreader/core/border-color.d.ts +138 -0
  26. package/dist/types/components/spreader/core/border-icon.d.ts +43 -0
  27. package/dist/types/components/spreader/core/border-pool.d.ts +1 -1
  28. package/dist/types/components/spreader/core/border-resolve.d.ts +12 -3
  29. package/dist/types/components/spreader/core/border-style.d.ts +24 -0
  30. package/dist/types/components/spreader/core/constants.d.ts +3 -2
  31. package/dist/types/components/spreader/core/model-dims.d.ts +19 -0
  32. package/dist/types/components/spreader/core/notes.d.ts +51 -0
  33. package/dist/types/components/spreader/core/sort-icon.d.ts +25 -0
  34. package/dist/types/components/spreader/core/style-pool.d.ts +1 -1
  35. package/dist/types/components/spreader/core/theme.d.ts +5 -0
  36. package/dist/types/components/spreader/core/types.d.ts +38 -4
  37. package/dist/xiaodao-spreader.es.js +8665 -7712
  38. package/dist/xiaodao-spreader.umd.js +9 -9
  39. package/package.json +1 -1
  40. /package/dist/types/components/spreader/components/{data-validation-input-message.vue.d.ts → pickers/data-validation-input-message.vue.d.ts} +0 -0
  41. /package/dist/types/components/spreader/composables/{useFloatMenuPosition.d.ts → float-menu-position.d.ts} +0 -0
package/README.ZH.md CHANGED
@@ -25,7 +25,7 @@
25
25
  - **合并单元格**: 合并居中、跨列合并、取消合并;合并区域边框按锚点存储、公共边渲染时统一解析
26
26
  - **冻结窗格**: 固定顶部行/左侧列,使其在主体滚动时保持可见。工具栏「冻结窗格」下拉提供「冻结窗格」(以当前选区/活动单元格左上角为冻结点,等同 Excel 的 Freeze Panes)、「冻结首行」、「冻结首列」以及「取消冻结」(仅在已冻结时显示,替换「冻结窗格」项)。冻结状态为按工作表的视图状态(`freeze: { rows, cols }`),通过 v-model 持久化;跨冻结线的合并单元格也能正确处理,仅冻结部分固定,非冻结部分随滚动移出
27
27
  - **丰富单元格格式**: 字体、字号(5–72)、加粗、斜体、下划线、删除线、文字颜色、填充颜色、水平/垂直对齐、自动换行
28
- - **边框**: 上/下/左/右/外边框/全部/无,5 种预设样式及自定义颜色;独立边框池存储、公共边渲染时统一解析
28
+ - **边框**: 上/下/左/右/外边框/全部/无,5 种预设样式、自定义颜色及按边线型(实线 / 虚线 / 点线);独立边框池存储、公共边渲染时统一解析
29
29
  - **撤销 / 重做**: 单元格、列宽、行高的完整状态快照(50 步)
30
30
  - **格式刷**: 复制并应用单元格格式到任意区域
31
31
  - **数字格式**: Excel 风格数字格式(常规 / 文本 / 数值 / 货币 / 会计 / 百分比 / 科学计数 / 日期 / 时间 / 日期时间 / 持续时间),提供自定义格式对话框;仅影响显示,绝不修改底层单元格值
@@ -34,8 +34,9 @@
34
34
  - **自动筛选(AutoFilter)**: 类 Excel 的普通区域自动筛选。工具栏「数据 → 筛选」或 `Ctrl+Shift+L` 启用;选择一个数据单元格(或单行多列选区)后启用,即从该表头行向下智能探测连续数据区;各列表头显示筛选下箭头,点击箭头打开筛选面板(值 / 文本 / 数值 / 日期 / 搜索 / 空值 / 多列 AND)。清除某列条件只清该列、移除 AutoFilter 清全部;仅在 Filter Range 内的列拥有箭头;单选已合并单元格且无筛选态时禁用筛选按钮,*见 [自动筛选(AutoFilter)](#自动筛选autofilter)*
35
35
  - **查找与替换**: 工具栏查找按钮或 `Ctrl/Cmd+F`(含 `Ctrl/Cmd+H`)打开;支持「当前工作表 / 整个工作簿 / 当前选区」三种范围,区分大小写、匹配整个单元格;高亮全部匹配并定位当前项、循环查找;单次与全部替换均接入撤销/重做,仅修改单元格原始 `value`(始终保持字符串),不改动格式 / 边框 / 合并
36
36
  - **条件格式**: 按工作表存储条件格式规则(`SheetState.conditionalFormats`)。工具栏「条件格式」下拉提供高亮单元格预设(大于 / 小于 / 介于 / 文本包含 / 重复 / 唯一 / 空白 / 非空白)以及「新建规则」对话框(支持单元格值条件和自定义公式条件)。规则渲染为基础单元格样式之上的临时覆盖层,绝不写回底层 `value` 或 `styleId`。规则优先级(数值越小优先级越高)、`stopIfTrue` 语义、单元格值变化时自动失效缓存。插入/删除行列时通过与自动填充相同的 `shiftFormulaRefs` 引擎自动调整规则范围与公式引用(`$B$2` 绝对引用保持固定)。内置「管理规则」对话框可编辑、排序、删除规则;「清除规则」子菜单支持清除全部或按选区清除。渲染时与基础样式正确合成背景色、文字颜色、粗体、斜体、下划线、删除线。*见 [条件格式](#条件格式)*
37
- - **数据验证**: 按工作表存储类 Excel 数据验证规则。工具栏「数据验证」按钮打开对话框,设置允许类型(任何值 / 列表 / 整数 / 小数 / 日期 / 时间 / 文本长度 / 自定义公式)、运算符(介于 / 不介于 / 等于 / 大于 ……)与条件值。列表验证在单元格内显示下拉,支持搜索与完整键盘操作(↑ ↓ / Home / End / PageUp / PageDown / Enter / Esc)。支持逐条输入信息提示与出错警告(停止 / 警告 / 信息):验证发生在值写入之前,停止级违规直接拒绝录入,警告/信息级由用户确认后继续。同一范围的多条规则必须全部通过。规则随 v-model 持久化、接入撤销/重做,并在行列增删时自动调整范围。复制/粘贴与自动填充走原子校验——出现停止级违规则整次取消。*见 [数据验证](#数据验证)*
37
+ - **数据验证**: 按工作表存储类 Excel 数据验证规则。工具栏「数据验证」按钮打开对话框,设置允许类型(任何值 / 列表 / 整数 / 小数 / 日期 / 时间 / 文本长度 / 自定义公式)、运算符(介于 / 不介于 / 等于 / 大于 ……)与条件值。列表验证在单元格内显示下拉,支持搜索与完整键盘操作(↑ ↓ / Home / End / PageUp / PageDown / Enter / Esc)。支持逐条输入信息提示与出错警告(停止 / 警告 / 信息):验证发生在值写入之前,停止级违规直接拒绝录入,警告/信息级由用户确认后继续。同一范围的多条规则必须全部通过。规则随 v-model 持久化、接入撤销/重做,并在行列增删时自动调整范围。复制/粘贴与自动填充走原子校验-出现停止级违规则整次取消。*见 [数据验证](#数据验证)*
38
38
  - **行列分组与折叠**: 类 Excel 的行/列分组(Outline)。选中整行或整列后,工具栏「分组」下拉(位于排序与筛选之间)提供添加分组 / 取消分组 / 清除分组 / 全部展开 / 全部折叠,直接作用于选中轴;行/列右键菜单提供同构的「分组」子菜单。仅支持一层、互不相交的分组,嵌套或部分重叠会被校验拒绝并提示。分组区间在行号/列号带用交替背景色区分,± 折叠按钮浮动于表头带内,不占用独立 gutter。折叠的行/列不参与内容绘制;插入/删除行列时分组范围自动平移、被清空的分组自动删除。分组状态按工作表持久化(`rowOutlines` / `columnOutlines`),增删与折叠均接入撤销/重做。*见 [行列分组与折叠](#行列分组与折叠)*
39
+ - **单元格批注**: 类 Excel 的单元格批注(Note/Comment)。右键菜单新建 / 编辑 / 删除;单元格右上角红色三角指示器标识含批注;hover 悬停查看、点按编辑;批注独立于单元格值与样式,采用 Note Pool 存储(Sheet 级 notes 池 + cell.noteId 引用),便于排序 / 插入删除时随 cell 一起移动。批注支持多行文本、可选作者、创建 / 修改时间。可通过 `noteAuthor` prop 设置当前作者名。*见 [单元格批注](#单元格批注)*
39
40
  - **自动填充(填充柄)**: 类 Excel 的活动选区右下角填充柄,按住向上/下/左/右拖拽即可填充单元格:单值复制、数字/日期/文本数字自动续序列(如 `1,2 → 3,4,5`)、公式引用按相对/绝对/混合规则平移(如 `=A1*2 → =A2*2`)、源 `styleId` 经样式池复用。拖拽期间实时预览、边缘自动滚动、动态扩展工作表、冻结窗格兼容、单次拖拽仅产生一个撤销步骤,*见 [自动填充](#自动填充)*
40
41
 
41
42
  ### 交互体验
@@ -143,6 +144,7 @@ const myData = ref<SheetModelData[]>([
143
144
  | `height` | `number \| string` | - | 组件高度(像素;传 `string` 或省略则自适应) |
144
145
  | `theme` | `'light' \| 'dark'` | `'light'` | 主题模式 |
145
146
  | `locale` | `string` | `'zh-CN'` | 语言: `'zh-CN'` \| `'en-US'` |
147
+ | `noteAuthor` | `string` | `''`(空串,显示时回退为 i18n 占位符「未命名」) | 当前批注作者名;为空时存入批注的 author 字段为空字符串,显示时回退为 i18n 占位符 |
146
148
 
147
149
  ---
148
150
 
@@ -160,15 +162,17 @@ interface SheetModelData {
160
162
  cells: Record<string, {
161
163
  value: string;
162
164
  styleId?: number;
165
+ /** 批注引用:指向 Sheet 级 notes 池中的 CellNote */
166
+ noteId?: string;
163
167
  }>;
164
168
  merges?: Record<string, SelectionRange>;
165
169
  freeze?: { rows: number; cols: number };
166
170
  colWidths?: Record<number, number>;
167
171
  rowHeights?: Record<number, number>;
168
- /** 逻辑列数(0 基,不含)。省略时默认为 26。 */
169
- colCount?: number;
170
- /** 逻辑行数(0 基,不含)。省略时默认为 200。 */
171
- rowCount?: number;
172
+ // 网格尺寸(colCount/rowCount)不持久化:加载时按内容推导(deriveModelDims),
173
+ // 至少 props 默认 26×200,并按数据 / 自定义行列尺寸 / 各类规则范围扩展
174
+ /** 单元格批注池:按 noteId 存放 CellNote,cell.noteId 引用之;与 cell value/style 完全独立 */
175
+ notes?: Record<string, CellNote>;
172
176
  }
173
177
  ```
174
178
 
@@ -188,7 +192,7 @@ import type {
188
192
  CellData, // { value: string; styleId?: number }
189
193
  CellStyle, // 类型化样式接口(字体、颜色、边框、对齐等)
190
194
  BorderStyle, // 四边边框组合 { top; right; bottom; left }
191
- BorderSide, // 单边边框 { width; color; style }
195
+ BorderSide, // 单边边框 { width; color; style; owner? }
192
196
  BorderSource, // 边框来源 'cell' | 'merge'
193
197
  Range, // { start: number; end: number }
194
198
  SpreadsheetOptions,
@@ -217,41 +221,62 @@ src/
217
221
  └── spreader/
218
222
  ├── index.ts # 统一导出口: 组件 + 类型(barrel)
219
223
  ├── components/
220
- │ ├── spreader.vue # 入口组件: 模板 + 样式 + 组合
221
- │ ├── toolbar.vue # 工具栏(含溢出下拉)
222
- │ ├── tabbar.vue # Sheet 标签栏
223
- │ ├── dropdown.vue # 通用下拉组件
224
- │ ├── find-replace-bar.vue # 查找替换栏 UI
224
+ │ ├── spreader.vue # 入口组件:模板 + 样式 + 组合
225
+ │ ├── toolbar.vue # 工具栏(带溢出下拉)
226
+ │ ├── tabbar.vue # Sheet 标签栏
227
+ │ ├── dropdown.vue # 通用下拉组件
228
+ │ ├── find-replace-bar.vue # 查找/替换栏 UI
229
+ │ ├── note-overlay.vue # 批注查看/编辑浮层(view + edit 双模)
225
230
  │ └── pickers/
226
- │ ├── colorPicker.vue # 文字 / 填充颜色选择器
227
- │ ├── borderPicker.vue # 边框选择器
228
- │ ├── mergePicker.vue # 合并单元格选择器
229
- │ ├── numberFormatDialog.vue # 数字格式自定义对话框
230
- │ ├── sortPicker.vue # 排序下拉
231
- │ ├── sortConfirmDialog.vue # Excel 风格排序提醒对话框
232
- │ ├── calcPicker.vue # 求和 / 平均值 / 计数选择器
233
- │ └── insertFunctionDialog.vue # 插入函数对话框
231
+ │ ├── border-picker.vue # 边框选择器(按边类型 / 颜色 / 线型 + 子菜单)
232
+ │ ├── calc-picker.vue # 求和 / 平均值 / 计数选择器
233
+ │ ├── color-palette.vue # 文字 / 填充 / 边框共用的色板(单一数据源)
234
+ │ ├── color-picker.vue # 文字 / 填充颜色选择器
235
+ │ ├── conditional-format-manager.vue # 条件格式「管理规则」对话框
236
+ │ ├── conditional-format-menu.vue # 条件格式工具栏下拉(预设 + 新建 / 管理 / 清除规则)
237
+ │ ├── conditional-format-rule-editor.vue # 条件格式「新建 / 编辑规则」对话框
238
+ │ ├── data-validation-alert.vue # 数据验证出错警告(Stop / Warning / Information)
239
+ │ ├── data-validation-dialog.vue # 数据验证设置对话框
240
+ │ ├── data-validation-dropdown.vue # 数据验证列表下拉(搜索 + 虚拟列表 + 键盘)
241
+ │ ├── data-validation-input-message.vue # 数据验证输入信息提示气泡(选中单元格时显示)
242
+ │ ├── filter-popup.vue # 自动筛选面板(值 / 文本 / 数值 / 日期 + 搜索 + 空值 + 多列 AND)
243
+ │ ├── insert-function-dialog.vue # 插入函数对话框
244
+ │ ├── merge-picker.vue # 合并单元格选择器
245
+ │ ├── number-format-dialog.vue # 数字格式对话框
246
+ │ ├── outline-picker.vue # 工具栏「分组」下拉(添加 / 取消 / 清除分组,展开 / 折叠)
247
+ │ ├── sort-confirm-dialog.vue # Excel 风格排序提醒对话框
248
+ │ └── sort-picker.vue # 排序下拉
234
249
  ├── composables/
235
- │ ├── core-state.ts # Props、cells/merges/selection、字体度量、导航
236
- │ ├── undo-styles.ts # 撤销重做、格式刷、字体/对齐/颜色
237
- │ ├── borders-merge.ts # 边框操作、合并操作、剪贴板、求和
238
- │ ├── sheets-ops.ts # 行列增删、多 Sheet、v-model 发射、主题、refs
239
- │ ├── find-replace.ts # 查找替换状态与交互(依赖 Vue)
240
- │ └── interactions.ts # 渲染器、编辑栏、标签栏、右键菜单、滚动条、事件
250
+ │ ├── borders-merge.ts # 边框操作、合并操作、剪贴板、求和/平均/计数
251
+ │ ├── core-state.ts # Props、cells/merges/selection、字体度量、导航、行列分组状态
252
+ │ ├── find-replace.ts # 查找/替换状态与交互(依赖 Vue)
253
+ │ ├── interactions.ts # 渲染器、公式栏、标签栏、右键菜单、滚动条、事件
254
+ │ ├── sheets-ops.ts # 行列操作、多 Sheet、v-model emit、主题、refs
255
+ │ ├── undo-styles.ts # 撤销/重做、格式刷、字体/对齐/颜色
256
+ │ └── float-menu-position.ts # 工具栏下拉菜单共享定位(右锚 + 上下翻向夹紧)
241
257
  └── core/
242
- ├── constants.ts # 布局常量、国际化、主题调色板
243
- ├── types.ts # 全部类型定义
244
- ├── style-pool.ts # 样式池:去重、注册、解析、迁移、GC
245
- ├── border-pool.ts # 边框池:去重、注册、解析、迁移、GC
246
- ├── border-resolve.ts # 公共边冲突解析(resolveSharedBorder)
247
- ├── formula.ts # 公式引擎(解析、计算、依赖、缓存)
248
- ├── find-replace-core.ts # 查找替换纯算法(零 Vue 依赖,可单测)
249
- ├── sort-core.ts # 排序纯算法(零 Vue 依赖,可单测)
250
- ├── autofill.ts # 自动填充纯引擎(模式推断、填充柄逻辑,零 Vue 依赖)
251
- ├── number-format.ts # 数字格式引擎(Excel 风格显示格式化)
252
- ├── conditional-formatting.ts # 条件格式引擎(条件求值、规则缓存、公式引用平移)
253
- ├── theme.ts # 主题 CSS 变量构建
254
- └── utils.ts # 纯工具函数(列标签、命中测试、尺寸解析)
258
+ ├── autofill.ts # 自动填充纯引擎(模式推断、填充柄逻辑,零 Vue 依赖)
259
+ ├── border-color.ts # 按边边框颜色:颜色与线型解耦、改色计划
260
+ ├── border-icon.ts # 边框图标单一数据源(toolbar + picker)
261
+ ├── border-pool.ts # 边框池:去重、注册、解析、迁移、GC
262
+ ├── border-resolve.ts # 公共边冲突解析(resolveSharedBorder)
263
+ ├── border-style.ts # 边框线型(实线/虚线/点线):归一化与 dash 图案
264
+ ├── conditional-formatting.ts # 条件格式引擎(条件求值 + 规则缓存,纯逻辑)
265
+ ├── constants.ts # 布局常量、i18n 文案、主题配色
266
+ ├── data-validation.ts # 数据验证引擎(纯逻辑)
267
+ ├── filter-core.ts # 自动筛选引擎(级联候选值,纯逻辑)
268
+ ├── find-replace-core.ts # 查找/替换纯算法(零 Vue 依赖,可单测)
269
+ ├── formula.ts # 公式引擎(解析、求值、依赖追踪)
270
+ ├── model-dims.ts # 模型尺寸由内容推导(纯逻辑)
271
+ ├── notes.ts # 批注池管理:CRUD、持久化、Undo 集成
272
+ ├── number-format.ts # 数字格式引擎(Excel 风格显示格式化)
273
+ ├── outline-core.ts # 行列分组纯引擎(校验 / 平移 / 折叠,零 Vue 依赖)
274
+ ├── sort-core.ts # 排序纯算法(零 Vue 依赖,可单测)
275
+ ├── sort-icon.ts # 排序图标单一数据源(toolbar + picker)
276
+ ├── style-pool.ts # 样式池:去重、注册、解析、迁移、GC
277
+ ├── theme.ts # 主题 CSS 变量构建
278
+ ├── types.ts # 全部类型定义
279
+ └── utils.ts # 纯工具函数(列标转换、命中测试等)
255
280
  ```
256
281
 
257
282
  ### 设计原则
@@ -408,18 +433,18 @@ src/
408
433
 
409
434
  ### 插入 / 删除传播
410
435
 
411
- CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函数——因此 `$B$2`(绝对引用)固定不动,`A1`(相对引用)正确平移。规则范围随之扩展/收缩;完全被移除的规则自动删除。
436
+ CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函数:因此 `$B$2`(绝对引用)固定不动,`A1`(相对引用)正确平移。规则范围随之扩展/收缩;完全被移除的规则自动删除。
412
437
 
413
438
  ### 渲染时样式合成
414
439
 
415
- `resolveConditionalFormatting` 在 `drawCells` 内按视口单元格逐个调用,遍历所有范围包含该单元格的启用规则,按优先级合并后生成临时 `cfStyle`。`applyCfFormat` 将其合成到基础解析样式上,正确处理背景色、文字颜色、粗体、斜体、下划线、删除线——含合并单元格(CF 对锚点求值后传播到整个合并区域)。
440
+ `resolveConditionalFormatting` 在 `drawCells` 内按视口单元格逐个调用,遍历所有范围包含该单元格的启用规则,按优先级合并后生成临时 `cfStyle`。`applyCfFormat` 将其合成到基础解析样式上,正确处理背景色、文字颜色、粗体、斜体、下划线、删除线,含合并单元格(CF 对锚点求值后传播到整个合并区域)。
416
441
 
417
442
  ### UI 组件
418
443
 
419
444
  | 文件 | 职责 |
420
445
  |------|------|
421
446
  | `conditional-format-menu.vue` | 工具栏下拉:高亮单元格预设、空白、重复、唯一、新建规则、管理规则、清除规则子菜单。子菜单采用 Teleport + hover-intent(150ms 延迟)实现跨间隙悬停不丢失 |
422
- | `conditional-format-rule-editor.vue` | 「新建规则」对话框:条件类型下拉(复用 `SpDropdown`)、阈值输入、格式面板(背景色选择器、文字颜色选择器、粗体/斜体/下划线/删除线——全部复用工具栏控件样式),应用范围自动填入当前选区 |
447
+ | `conditional-format-rule-editor.vue` | 「新建规则」对话框:条件类型下拉(复用 `SpDropdown`)、阈值输入、格式面板(背景色选择器、文字颜色选择器、粗体/斜体/下划线/删除线,全部复用工具栏控件样式),应用范围自动填入当前选区 |
423
448
  | `conditional-format-manager.vue` | 「管理规则」对话框:列出当前工作表全部规则,支持拖拽排序(修改 priority)、编辑单条规则、删除单条规则、一键清除全部或清除选区规则 |
424
449
 
425
450
  ---
@@ -436,7 +461,7 @@ CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函
436
461
 
437
462
  | 类型 | 说明 |
438
463
  |------|------|
439
- | `any` | 无约束——在对话框选中「任何值」并确定即清除该范围验证 |
464
+ | `any` | 无约束:在对话框选中「任何值」并确定即清除该范围验证 |
440
465
  | `list` | 单元格内下拉,来源于固定值或单元格范围 |
441
466
  | `wholeNumber` / `decimal` | 数值约束 |
442
467
  | `date` / `time` | 日期 / 时间约束(ISO、`YYYY年M月D日`、美式 `m/d/yyyy` 或 Excel 序列号) |
@@ -451,7 +476,7 @@ CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函
451
476
 
452
477
  ### 验证流程
453
478
 
454
- 验证发生在值写入**之前**。`commitEdit` 返回 `Promise<boolean>`——`false` 表示停止级违规拒绝了录入、编辑器状态保留。警告/信息级会调用 `showValidationAlert` 并等待用户确认后再继续。同一范围有多条规则时**必须全部通过**(`rules.every()`)。
479
+ 验证发生在值写入**之前**。`commitEdit` 返回 `Promise<boolean>`-`false` 表示停止级违规拒绝了录入、编辑器状态保留。警告/信息级会调用 `showValidationAlert` 并等待用户确认后再继续。同一范围有多条规则时**必须全部通过**(`rules.every()`)。
455
480
 
456
481
  ### 范围索引
457
482
 
@@ -459,7 +484,7 @@ CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函
459
484
 
460
485
  ### 原子粘贴 / 自动填充
461
486
 
462
- 复制/粘贴与自动填充先算出全部候选值、跑 `validateCells`,只要出现一条停止级违规就整次取消——不会出现部分提交。
487
+ 复制/粘贴与自动填充先算出全部候选值、跑 `validateCells`,只要出现一条停止级违规就整次取消,不会出现部分提交。
463
488
 
464
489
  ### 插入 / 删除传播
465
490
 
@@ -472,7 +497,7 @@ CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函
472
497
  | `data-validation-dialog.vue` | 工具栏「数据验证」对话框:类型/运算符/值、列表来源、输入信息、出错警告、应用范围;保存时校验最小值/最大值字面量 |
473
498
  | `data-validation-dropdown.vue` | 单元格内列表下拉:虚拟列表、搜索框、完整键盘操作(↑ ↓ / Home / End / PageUp / PageDown / Enter / Esc) |
474
499
  | `data-validation-alert.vue` | 停止 / 警告 / 信息 警告框 |
475
- | `data-validation-input-message.vue` | 悬停提示气泡,显示规则的输入信息(位于 `components/`,不在 `pickers/`) |
500
+ | `data-validation-input-message.vue` | 悬停提示气泡,显示规则的输入信息 |
476
501
 
477
502
  ### 持久化与撤销
478
503
 
@@ -507,6 +532,53 @@ CF 引擎的 `shiftFormulaRefsSafe` 复用公式引擎的 `shiftFormulaRefs` 函
507
532
 
508
533
  ---
509
534
 
535
+
536
+ ## 单元格批注
537
+
538
+ 类 Excel 的单元格批注(Note / Comment)功能,独立于单元格值与样式。核心引擎位于 `spreader/core/notes.ts`,纯逻辑实现;UI 浮层为 `components/note-overlay.vue`。
539
+
540
+ ### 数据模型
541
+
542
+ 批注采用 **Note Pool** 存储:Sheet 级 `notes` 池按 `id` 存放完整 `CellNote` 对象,单元格仅保存 `noteId` 引用。
543
+
544
+ ````typescript
545
+ interface CellNote {
546
+ id: string; // 稳定唯一 ID
547
+ text: string; // 批注正文(多行文本)
548
+ author?: string; // 作者(可选)
549
+ createdAt: number; // 创建时间(epoch ms)
550
+ updatedAt: number; // 最近修改时间(epoch ms)
551
+ }
552
+ ````
553
+
554
+ - **`CellData.noteId`**: 单元格上的批注引用,指向 `SheetState.notes` 池
555
+ - **`SheetModelData.notes`**: v-model 序列化时的批注池,键为 noteId
556
+
557
+ Note Pool 设计使得排序、插入 / 删除行列等操作移动单元格时,`noteId` 随 cell 数据一起搬运,批注不会丢失。
558
+
559
+ ### 交互入口
560
+
561
+ - **右键菜单**: 单元格右键菜单提供「新建批注 / 编辑批注 / 删除批注」三项;无批注时隐藏编辑 / 删除,有批注时隐藏新建
562
+ - **Shift+F2**: 在含批注的单元格上切换编辑浮层
563
+ - **hover 查看**: 鼠标悬停含批注的单元格时弹出只读查看浮层
564
+
565
+ ### 渲染
566
+
567
+ - 含批注的单元格右上角绘制 6px 红色三角指示器(Canvas 绘制,无 DOM 开销)
568
+ - 批注浮层 `note-overlay.vue` 为 Vue DOM 组件,`position: absolute` 驻留于 `.spreadsheet-wrapper` 内,被 `overflow: hidden` 裁剪到表格区域,不溢出覆盖 toolbar / 行列头 / 冻结区域 / 滚动条
569
+ - z-index 分层:非冻结区浮层在 freeze canvas(z-index: 1)之下(z-index: 0),冻结区浮层在 freeze canvas 之上(z-index: 2),滚动条 z-index: 3 永远在最上层
570
+
571
+ ### 作者名
572
+
573
+ 通过 `noteAuthor` prop 设置当前作者名。空串时存入批注的 `author` 字段为空字符串,显示时回退为 i18n 占位符(中文「未命名」/ 英文 Unnamed)。
574
+
575
+ ### 持久化与撤销
576
+
577
+ - 批注随 Sheet v-model(`notes` 字段)持久化,保存 / 加载 / 复制工作表均正确往返
578
+ - 新建 / 修改 / 删除批注各产生一个撤销步骤,与单元格值、样式、边框等操作共享同一撤销栈
579
+
580
+ ---
581
+
510
582
  ## 自动填充
511
583
 
512
584
  一套类 Excel 的填充柄机制(`spreader/core/autofill.ts` 纯引擎 + `composables/interactions.ts` 画布/交互层)。拖动活动选区右下角的小方块即可填充单元格,无 DOM 句柄,全部在 Canvas 上绘制。
@@ -611,9 +683,10 @@ scheduleRender()
611
683
  一套独立的边框存储与渲染机制(`spreader/core/border-pool.ts` + `border-resolve.ts`)。
612
684
 
613
685
  - **独立边框池**:每个 Sheet 维护 `borders: BorderStyle[]` 池(`borders[0]` 恒为空边框 `{}`),样式通过 `borderId`(数组下标)引用边框,相同边框自动去重。
614
- - **公共边统一解析**:相邻单元格的公共边在渲染时经 `resolveSharedBorder()` 解析,宽者优先、同宽取先侧;设置边框**不再**同步修改相邻单元格。
686
+ - **公共边统一解析**:相邻单元格的公共边在渲染时经 `resolveSharedBorder()` 解析,宽者优先、同宽取先侧;若仅一侧带 `owner` 标记(由边框或选区操作显式写入),则该侧在公共边解析中优先、不受宽度影响,使新设置的选区边界边优先于相邻的旧边。设置边框**不再**同步修改相邻单元格。
615
687
  - **合并单元格**:合并区域边框统一存储在锚点(左上角),内部边屏蔽,外边界按行/列分段与相邻区域解析,四角补齐角方块。
616
688
  - **旧数据兼容**:旧版内联边框属性(`borderTopWidth` 等,已废弃)在加载时经 `migrateBordersInStyles()` 自动迁移。
689
+ - **按边颜色与线型(解耦)**:二者均挂在每条独立边 `BorderSide`(`{ width; color; style }`)上。颜色为标准 HEX 字符串;`''` 或省略表示「自动」,渲染回退默认色 `#444`。线型 `style` 取 `solid` / `dashed` / `dotted`;旧数据缺 `style` 一律按 `solid` 处理,且 `solid` 不写 `style` 键,使其去重键与历史空边框数据一致。改颜色只动 `color`、保留 `width`/`style`;改线型只动 `style`、保留 `width`/`color`。边框下拉框提供两个子菜单:颜色选择器(复用文字色板并含「自动」项,只给已存在的边上色)与**线型选择器**(实线 / 虚线 / 点线预览,设置当前画笔线型,随后作用于后续边框操作及选区已存在的边,绝不凭空创建边框)。纯逻辑集中在 `core/border-color.ts`(`withBorderColor` / `withBorderWidth` / `planBorderColorChanges` / `resolveSelectionBorderColor`)与 `core/border-style.ts`(`normalizeBorderLineStyle` / `borderLineDash`),与 Vue/Canvas 完全解耦并具备单元测试。渲染器经 `paintBorderEdge` 绘制虚线/点线(实线保留原 `fillRect` 路径,网格线与选区框不受影响)。
617
690
 
618
691
  ---
619
692
 
@@ -735,7 +808,7 @@ x-spreader 以触屏为第一交互:每个鼠标操作都有对称的触屏路
735
808
  - [x] 排序与筛选:按展示内容排序,含类 Excel「排序提醒」对话框(扩展选定区域 / 仅对选定区域排序);见 [排序与排序提醒](#功能特性)
736
809
  - [x] 自动筛选(AutoFilter):工具栏「筛选」/`Ctrl+Shift+L` 启用,表头下箭头、智能向下探测数据区、值/文本/数值/日期多类型筛选、清除单列与整体移除分离;见 [自动筛选(AutoFilter)](#自动筛选autofilter)
737
810
  - [x] 触屏与移动端交互:选择 / 右键菜单 / 筛选 / 列宽行高 / 框选 / 格式刷 / tab 菜单均补齐对称触屏路径,浮层支持点外部关闭;见 [触屏与移动端交互](#触屏与移动端交互)
738
- - [ ] 单元格批注
811
+ - [x] 单元格批注:Note Pool 存储、右键菜单 CRUD、hover 查看、编辑浮层、持久化与撤销;见 [单元格批注](#单元格批注)
739
812
  - [ ] 打印布局
740
813
 
741
814
  ### 远期