feat: 合同富文本改为表头调列宽、首列调行高,避免拖拽把邻列挤窄。
产品表按像素列宽重排,水印改到页面右下角,打开编辑时不再铺满整表绿线。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
bde19c0644
commit
3aa0f0ff2e
12 files changed
+734
-161
No files matched your search
@@ -0,0 +1,51 @@
|
||||
# 富文本表格边缘拖拽 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在 TinyMCE 里只通过第一行右边界调列宽、第一列下边界调行高,拖宽一列时整张表变宽。
|
||||
|
||||
**Architecture:** 列宽、行高的数值变化放在纯函数里。编辑器里另挂一层短句柄,只在鼠标靠近对应边界时出现;松手才记入撤销。打开编辑器时不改表格 HTML。
|
||||
|
||||
**Tech Stack:** Vue 3、TinyMCE、Node `node:test`。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 列宽与行高纯函数
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/utils/tinymce-table-edge-resize.ts`
|
||||
- Test: `web-admin/src/utils/tinymce-table-edge-resize.test.ts`
|
||||
|
||||
- [x] **Step 1: 写出失败测试**
|
||||
|
||||
`applyColumnWidthDelta([100, 36, 46], 1, 20)` 得到宽度 `[100, 56, 46]`、表宽 `202`。位移 `-100` 时该列停在 `28`。`applyRowHeightDelta(30, -40)` 得到 `20`。
|
||||
|
||||
- [x] **Step 2: 运行测试确认失败**
|
||||
|
||||
Run: `node --experimental-strip-types --test src/utils/tinymce-table-edge-resize.test.ts`
|
||||
Expected: FAIL,模块尚不存在。
|
||||
|
||||
- [x] **Step 3: 实现纯函数并通过测试**
|
||||
|
||||
列宽下限 28,行高下限 20。只改目标列,表宽等于各列之和。
|
||||
|
||||
- [x] **Step 4: 再跑测试**
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
### Task 2: 编辑器短句柄
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/utils/tinymce-table-edge-resize.ts`
|
||||
- Modify: `web-admin/src/components/TinyMceEditor/index.vue`
|
||||
- Modify: 合同弹窗、合同详情、报价弹窗里的编辑提示
|
||||
|
||||
- [x] **Step 1: `setupTableEdgeResize`**
|
||||
|
||||
只读不挂句柄。句柄带 `data-mce-bogus="all"`,保存内容时不带上。第一行且 `colspan === 1` 的格子右边界调列宽;该行从第 1 列起始的格子下边界调行高。拖列时写入 `col`、表头单元格、表宽和同样的 `max-width`。拖行时只写该行高度。
|
||||
|
||||
- [x] **Step 2: 在 `TinyMceEditor` 的 `setup` 中调用**
|
||||
|
||||
原生 `table_resize_bars` 保持 `false`。
|
||||
|
||||
- [x] **Step 3: 提示文案改为「表头右边界调列宽,每行最左格下边界调行高」**
|
||||
@@ -0,0 +1,74 @@
|
||||
# 富文本表格:第一行调列宽、第一列调行高
|
||||
|
||||
日期:2026-10-29
|
||||
范围:`web-admin` 的 `TinyMceEditor`(合同打印弹窗、合同详情、报价打印弹窗共用)
|
||||
状态:已确认
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
合同打印富文本里的产品表需要能手调列宽和行高。上一版在整张表的每条竖线、横线上放绿色拖拽条,悬停就铺满表格,并且拖动时按当时被挤窄的视觉宽度写回像素,规格列会被压成一字一行。
|
||||
|
||||
该整表拖拽已经关闭(`table_resize_bars: false`,不再调用整表 `setupExcelLikeTableResize`)。
|
||||
|
||||
本次只恢复一种更小的拖拽:
|
||||
|
||||
- 第一行:拖表头格子的右边界,调整这一列的宽度
|
||||
- 第一列:拖该行最左边格子的下边界,调整这一行的高度
|
||||
|
||||
打开编辑器时不改已有列宽。只有用户真正拖动,才把新的宽或高写入 HTML。保存仍走现有的「保存模板」。
|
||||
|
||||
## 2. 采用方案
|
||||
|
||||
句柄只画在第一行的右边界、第一列的下边界,是贴着格子边缘的短段,不贯穿整张表。
|
||||
|
||||
拖宽某一列时,整张表变宽,其余列的宽度保持不变。拖高某一行时,只改这一行,列宽不动。
|
||||
|
||||
不采用:
|
||||
|
||||
- 整表每条边线都放拖拽条
|
||||
- 锁死表格总宽、从右边一列借宽度
|
||||
|
||||
## 3. 列宽
|
||||
|
||||
产品表第一行是 12 个独立表头,每个 `colspan` 为 1。拖「规格」表头的右边界,只增加规格列的像素宽度,表宽增加同样的像素,单价及后面的列不变。
|
||||
|
||||
规则:
|
||||
|
||||
- 只给第一行里 `colspan === 1` 的单元格放右边界句柄
|
||||
- 第一行若有合并单元格,该格不放列宽句柄,避免把多列宽度写成一列
|
||||
- 列宽下限 28px
|
||||
- 写入 `table-layout: fixed`、表格 `width`(像素)、对应 `<col>` 与该表头单元格的 `width`(像素)
|
||||
- 不把宽度写到明细行的每个 `td` 上
|
||||
- 拖拽写入的表格 `max-width` 使用本次像素总宽,避免编辑器样式里的 `max-width: 100%` 把刚拖宽的表再压回去
|
||||
- 最后一列同样可以拖,表宽跟着增加
|
||||
|
||||
## 4. 行高
|
||||
|
||||
每一行最左边、从第 1 列开始的那个单元格,在其下边界放句柄。合计行左边常是 `colspan="2"` 的「运费」「不含税金额合计」,拖它的下边界只增加这一行的高度,不改任何列宽。
|
||||
|
||||
规则:
|
||||
|
||||
- 行高下限 20px
|
||||
- 拖行高时不重写列宽
|
||||
- 预览、只读编辑器不显示句柄,也不能拖
|
||||
|
||||
## 5. 交互
|
||||
|
||||
- 鼠标靠近对应边界时才出现短句柄,离开后消失
|
||||
- 句柄用主题绿,便于辨认,但长度只覆盖该格的一条边
|
||||
- 松手后记入 TinyMCE 撤销栈
|
||||
- 原生表格调整条保持关闭,不恢复整表绿线
|
||||
|
||||
## 6. 不在本次范围
|
||||
|
||||
- 打开合同时按内容重算产品表列宽(现有 `normalizeContractProductTableWidths` 保持不动)
|
||||
- 水印位置、合计大写是否换行
|
||||
- 工具栏里的合并、拆分、插删行列
|
||||
|
||||
## 7. 验证
|
||||
|
||||
- 纯函数:给定各列宽度与拖拽位移,结果里只有目标列变化,表宽变化量等于该列变化量,邻列不变;列宽不低于 28px
|
||||
- 打开编辑器后、尚未拖拽时,产品表 `col` 宽度与打开前一致
|
||||
- 拖表头右边界后,仅该列与表宽变化
|
||||
- 拖合计行左侧合并格的下边界后,仅该行变高
|
||||
- 预览模式无句柄
|
||||
Reference in new issue
Block a user