feat: 完善范式润色功能和相关组件

- 新增范式选择模态框 (ParadigmSelectorModal)
- 新增差异标注面板 (DiffAnnotationPanel)
- 新增精确差异处理工具 (preciseDiff.js)
- 更新各面板组件支持范式润色功能
- 更新范式配置文件 (paradigms.js)
- 更新依赖配置

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2026-01-10 03:02:21 +08:00
parent 56fda55709
commit f9f0785106
14 changed files with 1426 additions and 493 deletions

114
src/utils/preciseDiff.js Normal file
View File

@@ -0,0 +1,114 @@
/**
* 精确文本差异计算工具
* 使用 diff-match-patch 算法实现字符级别的精确对比
*/
import DiffMatchPatch from 'diff-match-patch'
const dmp = new DiffMatchPatch()
/**
* 计算两段文本的精确差异(字符级别)
* @param {string} original - 原文
* @param {string} rewritten - 修改后的文本
* @returns {Array<{type: 'unchanged'|'modified'|'added'|'removed', original: string, rewritten: string}>}
*/
export const computePreciseDiff = (original, rewritten) => {
if (!original && !rewritten) return []
if (!original) {
return [{ type: 'added', original: '', rewritten: rewritten }]
}
if (!rewritten) {
return [{ type: 'removed', original: original, rewritten: '' }]
}
// 使用 diff-match-patch 计算差异
const diffs = dmp.diff_main(original, rewritten)
dmp.diff_cleanupSemantic(diffs) // 语义清理,让差异更可读
const result = []
for (const [op, text] of diffs) {
if (op === 0) {
// 相同部分
result.push({
type: 'unchanged',
original: text,
rewritten: text
})
} else if (op === -1) {
// 删除
result.push({
type: 'removed',
original: text,
rewritten: ''
})
} else if (op === 1) {
// 新增
result.push({
type: 'added',
original: '',
rewritten: text
})
}
}
// 合并相邻的删除和新增为修改
return mergeAdjacentChanges(result)
}
/**
* 合并相邻的删除和新增为修改
* @param {Array} diffs - 差异数组
* @returns {Array} - 合并后的差异数组
*/
const mergeAdjacentChanges = (diffs) => {
const merged = []
let i = 0
while (i < diffs.length) {
const current = diffs[i]
const next = diffs[i + 1]
// 如果当前是删除,下一个是新增,合并为修改
if (current.type === 'removed' && next?.type === 'added') {
merged.push({
type: 'modified',
original: current.original,
rewritten: next.rewritten
})
i += 2
}
// 如果当前是新增,下一个是删除,也合并为修改
else if (current.type === 'added' && next?.type === 'removed') {
merged.push({
type: 'modified',
original: next.original,
rewritten: current.rewritten
})
i += 2
}
else {
merged.push(current)
i++
}
}
return merged
}
/**
* 获取精确差异统计
* @param {Array} diffSegments - 差异片段
* @returns {{total: number, modified: number, added: number, removed: number, unchanged: number}}
*/
export const getPreciseDiffStats = (diffSegments) => {
const nonUnchanged = diffSegments.filter(s => s.type !== 'unchanged')
return {
total: nonUnchanged.length,
modified: diffSegments.filter(s => s.type === 'modified').length,
added: diffSegments.filter(s => s.type === 'added').length,
removed: diffSegments.filter(s => s.type === 'removed').length,
unchanged: diffSegments.filter(s => s.type === 'unchanged').length
}
}