Skip to content

Commit 7adac5e

Browse files
aixierclaude
andcommitted
feat: 完善智能卡片选择和HTML编辑功能
主要更新: - 实现智能卡片自动检测和选择功能 - 修复卡片点击事件处理,确保事件正确传递 - 优化HTML编辑器的事件监听机制 - 添加直接在卡片元素上的点击监听器 - 改进pointer-events和z-index处理 - 统一卡片选择逻辑到selectCard函数 技术改进: - 使用事件委托处理动态添加的card-detected类 - 在捕获阶段监听事件确保优先处理 - 智能选卡模式下禁用selection overlay避免事件阻挡 - 为检测到的卡片添加适当的CSS属性确保可点击 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 8e5ab62 commit 7adac5e

77 files changed

Lines changed: 11116 additions & 12145 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 373 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,373 @@
1+
# HtmlEditModal 卡片选择工具可行性分析
2+
3+
## 1. 背景与需求
4+
5+
### 1.1 当前状态
6+
- HtmlEditModal 已实现涂抹框选功能,允许用户通过画笔选择页面元素
7+
- 后端 `/api/html/edit` 接口已经支持接收选中的元素并进行AI修改
8+
- 界面布局已经成熟,包含工具栏、内容区、选中元素列表等
9+
10+
### 1.2 新需求
11+
- 在现有工具栏中增加"卡片选择"模式
12+
- 用户点击该模式后,点击任何卡片即可选中整张卡片
13+
- 保持现有界面布局和后端接口不变
14+
- 与现有涂抹选择功能并存,用户可自由切换
15+
16+
## 2. 技术可行性分析
17+
18+
### 2.1 前端实现可行性
19+
20+
#### 2.1.1 工具栏扩展
21+
```javascript
22+
// 现有工具定义
23+
const tools = [
24+
{ mode: 'paint', icon: 'Brush', label: '涂抹选择' },
25+
// 新增卡片选择工具
26+
{ mode: 'card', icon: 'CreditCard', label: '卡片选择' }
27+
]
28+
```
29+
30+
**可行性:高**
31+
- 工具栏已采用动态渲染方式,易于扩展
32+
- 通过 `v-for` 循环渲染工具按钮,添加新工具无需修改模板结构
33+
- 现有的 `toggleTool(mode)` 方法可直接支持新模式
34+
35+
#### 2.1.2 卡片检测与识别
36+
```javascript
37+
// 卡片识别逻辑
38+
function detectCardElement(clickedElement) {
39+
// 向上遍历DOM树,寻找卡片容器
40+
let current = clickedElement
41+
while (current && current !== document.body) {
42+
// 检测常见的卡片类名
43+
if (current.classList.contains('card') ||
44+
current.classList.contains('card-container') ||
45+
current.classList.contains('card-item') ||
46+
current.getAttribute('data-card') !== null) {
47+
return current
48+
}
49+
current = current.parentElement
50+
}
51+
return null
52+
}
53+
```
54+
55+
**可行性:高**
56+
- 根据提取结果,卡片都有明确的 class 标识(如 `card-container`
57+
- 可以通过 DOM 树遍历准确定位卡片边界
58+
- 支持多种卡片识别策略(类名、属性、结构特征)
59+
60+
#### 2.1.3 点击事件处理
61+
```javascript
62+
// 在 SelectionOverlay 组件中添加卡片模式处理
63+
if (this.config.mode === 'card') {
64+
canvas.addEventListener('click', (e) => {
65+
const rect = canvas.getBoundingClientRect()
66+
const x = e.clientX - rect.left
67+
const y = e.clientY - rect.top
68+
69+
// 获取iframe中对应位置的元素
70+
const element = getElementAtPosition(x, y)
71+
72+
// 检测是否为卡片
73+
const card = detectCardElement(element)
74+
if (card) {
75+
// 创建覆盖整个卡片的选区
76+
this.createCardSelection(card)
77+
}
78+
})
79+
}
80+
```
81+
82+
**可行性:高**
83+
- SelectionOverlay 已经支持多种模式(paint、rect)
84+
- 可以复用现有的选区创建和管理机制
85+
- iframe 内容访问机制已经建立
86+
87+
### 2.2 与现有功能的兼容性
88+
89+
#### 2.2.1 选区数据结构兼容
90+
```javascript
91+
// 现有选区结构
92+
{
93+
id: 'selection_xxx',
94+
rect: { x, y, width, height },
95+
elements: [
96+
{
97+
selected_element: '<div class="card">...</div>',
98+
selection_coverage_percentage: 100
99+
}
100+
]
101+
}
102+
```
103+
104+
**兼容性:完全兼容**
105+
- 卡片选择生成的数据结构与涂抹选择完全一致
106+
- 后端接口无需任何修改
107+
- 选中元素列表展示逻辑无需调整
108+
109+
#### 2.2.2 交互模式切换
110+
```javascript
111+
// 模式切换已经实现
112+
toggleTool(mode) {
113+
if (toolActive.value && currentMode.value === mode) {
114+
toolActive.value = false
115+
} else {
116+
currentMode.value = mode
117+
overlayConfig.mode = mode
118+
toolActive.value = true
119+
}
120+
}
121+
```
122+
123+
**兼容性:完全兼容**
124+
- 现有的工具切换机制可直接支持新模式
125+
- 不同模式间的切换逻辑已经完善
126+
- 清除选区、撤销等功能可共享
127+
128+
### 2.3 用户体验优势
129+
130+
#### 2.3.1 操作简化
131+
- **涂抹模式**:需要精确涂抹覆盖想要的内容,可能需要多次操作
132+
- **卡片模式**:一次点击即可选中整张卡片,效率提升显著
133+
134+
#### 2.3.2 精确度提升
135+
- **涂抹模式**:可能选中部分卡片或跨越多个元素
136+
- **卡片模式**:确保选中完整的语义单元(整张卡片)
137+
138+
#### 2.3.3 视觉反馈
139+
```javascript
140+
// 卡片悬停效果
141+
if (mode === 'card') {
142+
// 鼠标悬停时高亮潜在可选卡片
143+
canvas.addEventListener('mousemove', (e) => {
144+
const card = detectCardAtPosition(e.x, e.y)
145+
if (card) {
146+
showCardOutline(card) // 显示卡片轮廓
147+
}
148+
})
149+
}
150+
```
151+
152+
## 3. 实现方案设计
153+
154+
### 3.1 最小化改动方案
155+
156+
#### 3.1.1 文件修改清单
157+
1. `/terminal-ui/src/components/HtmlEditModal/index.vue`
158+
- 添加卡片选择工具到 tools 数组
159+
- 更新提示文本逻辑
160+
161+
2. `/terminal-ui/src/components/SelectionOverlay/index.vue`
162+
- 添加卡片模式的事件处理
163+
- 实现卡片检测算法
164+
- 添加卡片悬停效果
165+
166+
3. `/terminal-ui/src/adapters/HTMLSelectionAdapter.js`(可选)
167+
- 添加卡片识别辅助方法
168+
169+
#### 3.1.2 核心代码改动
170+
```vue
171+
<!-- HtmlEditModal/index.vue -->
172+
<script setup>
173+
// 工具配置 - 添加卡片选择
174+
const tools = ref([
175+
{ mode: 'paint', icon: markRaw(Brush), label: '涂抹选择' },
176+
{ mode: 'card', icon: markRaw(CreditCard), label: '卡片选择' } // 新增
177+
])
178+
179+
// 更新提示文本
180+
const currentTip = computed(() => {
181+
if (!toolActive.value) {
182+
return '当前为浏览模式,点击工具按钮激活选择功能'
183+
}
184+
if (currentMode.value === 'card') {
185+
return '点击任意卡片即可选中整张卡片' // 新增提示
186+
}
187+
if (selectedElements.value.length === 0) {
188+
return '使用涂抹工具选择要编辑的内容'
189+
}
190+
return `已选择 ${selectedElements.value.length} 个元素`
191+
})
192+
</script>
193+
```
194+
195+
### 3.2 SelectionOverlay 组件扩展
196+
197+
```vue
198+
<!-- SelectionOverlay/index.vue -->
199+
<script setup>
200+
// 卡片检测算法
201+
const detectCard = (element) => {
202+
const cardSelectors = [
203+
'.card',
204+
'.card-container',
205+
'.card-item',
206+
'[data-card]',
207+
'.post-card',
208+
'.content-card'
209+
]
210+
211+
// 从点击元素向上查找
212+
let current = element
213+
while (current && current !== document.body) {
214+
for (const selector of cardSelectors) {
215+
if (current.matches && current.matches(selector)) {
216+
return current
217+
}
218+
}
219+
current = current.parentElement
220+
}
221+
return null
222+
}
223+
224+
// 卡片模式处理
225+
const handleCardMode = () => {
226+
if (props.config.mode !== 'card') return
227+
228+
canvas.value.addEventListener('click', handleCardClick)
229+
canvas.value.addEventListener('mousemove', handleCardHover)
230+
}
231+
232+
// 卡片点击处理
233+
const handleCardClick = (e) => {
234+
const element = getElementAtCanvasPosition(e.offsetX, e.offsetY)
235+
const card = detectCard(element)
236+
237+
if (card) {
238+
// 获取卡片边界
239+
const rect = card.getBoundingClientRect()
240+
const containerRect = props.container.getBoundingClientRect()
241+
242+
// 创建选区
243+
const selection = {
244+
id: `card_${Date.now()}`,
245+
rect: {
246+
x: rect.left - containerRect.left,
247+
y: rect.top - containerRect.top,
248+
width: rect.width,
249+
height: rect.height
250+
},
251+
elements: [{
252+
selected_element: card.outerHTML,
253+
selection_coverage_percentage: 100
254+
}]
255+
}
256+
257+
// 添加到选区列表
258+
selections.value.push(selection)
259+
emits('selection-complete', selection)
260+
}
261+
}
262+
263+
// 卡片悬停效果
264+
const handleCardHover = (e) => {
265+
const element = getElementAtCanvasPosition(e.offsetX, e.offsetY)
266+
const card = detectCard(element)
267+
268+
if (card) {
269+
canvas.value.style.cursor = 'pointer'
270+
// 绘制卡片轮廓提示
271+
drawCardOutline(card)
272+
} else {
273+
canvas.value.style.cursor = 'default'
274+
clearCardOutline()
275+
}
276+
}
277+
</script>
278+
```
279+
280+
## 4. 风险评估与应对
281+
282+
### 4.1 技术风险
283+
284+
| 风险项 | 可能性 | 影响 | 应对措施 |
285+
|-------|--------|------|----------|
286+
| 卡片边界识别不准 ||| 提供多种识别策略,支持配置 |
287+
| 嵌套卡片处理 ||| 优先选择最内层卡片,提供切换选项 |
288+
| 动态加载的卡片 ||| 使用 MutationObserver 监听DOM变化 |
289+
| 性能问题 ||| 使用防抖处理鼠标移动事件 |
290+
291+
### 4.2 用户体验风险
292+
293+
| 风险项 | 可能性 | 影响 | 应对措施 |
294+
|-------|--------|------|----------|
295+
| 误选相邻卡片 ||| 提供视觉反馈,悬停时显示将选中的区域 |
296+
| 无法选中部分内容 ||| 保留涂抹模式,用户可切换使用 |
297+
| 卡片定义不明确 ||| 提供卡片识别规则说明 |
298+
299+
## 5. 实施建议
300+
301+
### 5.1 分阶段实施
302+
303+
#### Phase 1: 基础功能(2小时)
304+
- [ ] 添加卡片选择工具到工具栏
305+
- [ ] 实现基础的卡片点击选择
306+
- [ ] 确保与后端接口兼容
307+
308+
#### Phase 2: 体验优化(1小时)
309+
- [ ] 添加卡片悬停提示效果
310+
- [ ] 优化卡片识别算法
311+
- [ ] 添加卡片选择的视觉反馈
312+
313+
#### Phase 3: 高级功能(可选,1小时)
314+
- [ ] 支持批量选择多张卡片(Ctrl+点击)
315+
- [ ] 支持卡片选择的快捷键
316+
- [ ] 添加智能卡片边界检测
317+
318+
### 5.2 测试要点
319+
320+
1. **功能测试**
321+
- 卡片选择的准确性
322+
- 模式切换的流畅性
323+
- 选区数据的正确性
324+
325+
2. **兼容性测试**
326+
- 与涂抹模式的切换
327+
- 与现有编辑功能的配合
328+
- 不同HTML结构的适配
329+
330+
3. **性能测试**
331+
- 大量卡片场景的响应速度
332+
- 内存占用情况
333+
- 渲染性能
334+
335+
## 6. 技术优势总结
336+
337+
### 6.1 实现简单
338+
- 复用现有的 SelectionOverlay 架构
339+
- 无需修改后端接口
340+
- 代码改动量小(预计不超过200行)
341+
342+
### 6.2 用户友好
343+
- 一键选中整张卡片,操作直观
344+
- 保留原有涂抹功能,灵活性高
345+
- 视觉反馈清晰,用户体验好
346+
347+
### 6.3 维护方便
348+
- 代码结构清晰,易于理解
349+
- 与现有功能解耦,便于独立维护
350+
- 可配置性强,易于扩展
351+
352+
## 7. 结论
353+
354+
**可行性评级:⭐⭐⭐⭐⭐(非常可行)**
355+
356+
### 7.1 技术可行性
357+
- 现有架构完全支持该功能扩展
358+
- 无需大规模重构
359+
- 技术风险低,实现路径清晰
360+
361+
### 7.2 业务价值
362+
- 显著提升用户选择卡片的效率
363+
- 降低操作复杂度
364+
- 提高编辑精确度
365+
366+
### 7.3 实施建议
367+
建议立即实施该功能:
368+
1. 技术方案成熟,风险可控
369+
2. 用户体验提升明显
370+
3. 开发成本低,收益高
371+
372+
预计总开发时间:3-4小时
373+
预计测试时间:1-2小时

0 commit comments

Comments
 (0)