布局优化: - 操作栏改为「主操作 + 选项组 + 次要操作」三段式, 勾选项与操作按钮视觉分层,不再混排成一条 - 统计条并入浅色卡片,用 gap 替代多个 flex:1 空白撑开块 - 差异导航加「定位」标签,序号改 tabular-nums 防跳动 - 「重新编辑/导出」并入统计条右侧,释放一行纵向空间 - 表头「行号 行号」改为「原 新」,左右分栏各加竖分隔线 - 输入区行数改为胶囊标签,标题与行数两端对齐 修复: - 删除行红底打错列:原 :first-of-type 因前置 .cell-no 兄弟而选不中, 改为显式 col-left / col-right 类名,新增/删除/修改各自单侧或双侧着色 - 只看差异在无结果时禁用(此前点了无反应),清空时重置该状态 - 导出 HTML 的着色规则与页面保持一致,并支持字符级 <mark> 高亮 交互: - 新增 Ctrl/Cmd+Enter 触发比对、Esc 返回编辑 - 键盘监听仅在 activated 注册,避免 keep-alive 下重复绑定导致按键触发多次
This commit is contained in:
+196
-78
@@ -2,42 +2,68 @@
|
|||||||
<div class="text-diff-page">
|
<div class="text-diff-page">
|
||||||
<!-- 操作栏 start -->
|
<!-- 操作栏 start -->
|
||||||
<div class="diff-toolbar">
|
<div class="diff-toolbar">
|
||||||
<Button type="primary" icon="md-git-compare" :loading="comparing" @click="doCompare()">比对</Button>
|
<!-- 主操作 -->
|
||||||
|
<Tooltip content="开始比对(Ctrl + Enter)" transfer>
|
||||||
|
<Button type="primary" icon="md-git-compare" :loading="comparing" @click="doCompare()">开始比对</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<!-- 视图选项:与操作按钮视觉分层 -->
|
||||||
|
<div class="toolbar-group">
|
||||||
<Checkbox v-model="ignoreWhitespace">忽略空白</Checkbox>
|
<Checkbox v-model="ignoreWhitespace">忽略空白</Checkbox>
|
||||||
<Checkbox v-model="onlyChanges">只看差异</Checkbox>
|
<Checkbox v-model="onlyChanges" :disabled="!hasResult">只看差异</Checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="toolbar-gap"></div>
|
<div class="toolbar-gap"></div>
|
||||||
|
|
||||||
|
<!-- 次要操作 -->
|
||||||
|
<div class="toolbar-group">
|
||||||
|
<Tooltip content="交换左右两侧内容" transfer>
|
||||||
<Button icon="md-swap" :disabled="comparing" @click="swapSides()">交换</Button>
|
<Button icon="md-swap" :disabled="comparing" @click="swapSides()">交换</Button>
|
||||||
<Button icon="md-trash" :disabled="comparing" @click="clearAll()">清空</Button>
|
</Tooltip>
|
||||||
|
<Tooltip content="填充一组示例数据" transfer>
|
||||||
<Button icon="md-flask" :disabled="comparing" @click="fillSample()">示例</Button>
|
<Button icon="md-flask" :disabled="comparing" @click="fillSample()">示例</Button>
|
||||||
<Button icon="md-download" :disabled="!hasResult" @click="exportHtml()">导出</Button>
|
</Tooltip>
|
||||||
|
<Button icon="md-trash" :disabled="comparing" @click="clearAll()">清空</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 操作栏 end -->
|
<!-- 操作栏 end -->
|
||||||
|
|
||||||
<!-- 统计条 start -->
|
<!-- 统计条 start -->
|
||||||
<div class="diff-stats" v-if="hasResult">
|
<div class="diff-stats" v-if="hasResult">
|
||||||
<span class="stat-item">
|
<div class="stat-group">
|
||||||
<span class="stat-dot added-dot"></span>新增 <b class="stat-num added-text">{{ stats.added }}</b> 行
|
<span class="stat-item added-item">
|
||||||
|
<i class="stat-dot"></i>新增<b class="stat-num">{{ stats.added }}</b>
|
||||||
</span>
|
</span>
|
||||||
<span class="stat-item">
|
<span class="stat-item removed-item">
|
||||||
<span class="stat-dot removed-dot"></span>删除 <b class="stat-num removed-text">{{ stats.removed }}</b> 行
|
<i class="stat-dot"></i>删除<b class="stat-num">{{ stats.removed }}</b>
|
||||||
</span>
|
</span>
|
||||||
<span class="stat-item">
|
<span class="stat-item changed-item">
|
||||||
<span class="stat-dot changed-dot"></span>修改 <b class="stat-num changed-text">{{ stats.changed }}</b> 行
|
<i class="stat-dot"></i>修改<b class="stat-num">{{ stats.changed }}</b>
|
||||||
</span>
|
</span>
|
||||||
<span class="stat-item muted">相同 {{ stats.unchanged }} 行</span>
|
<span class="stat-item plain-item">相同<b class="stat-num">{{ stats.unchanged }}</b></span>
|
||||||
<div class="toolbar-gap"></div>
|
</div>
|
||||||
<span class="stat-item muted" v-if="elapsed">耗时 {{ elapsed }} ms</span>
|
|
||||||
<template v-if="changeRows.length > 0">
|
<div class="stat-divider" v-if="changeRows.length > 0"></div>
|
||||||
<div class="toolbar-gap"></div>
|
|
||||||
<span class="stat-item nav-group">
|
<!-- 差异导航 -->
|
||||||
|
<div class="nav-group" v-if="changeRows.length > 0">
|
||||||
|
<span class="nav-label">定位</span>
|
||||||
<Button size="small" icon="md-arrow-up" :disabled="navIndex <= 0" @click="gotoChange(-1)"></Button>
|
<Button size="small" icon="md-arrow-up" :disabled="navIndex <= 0" @click="gotoChange(-1)"></Button>
|
||||||
<span class="nav-text">{{ navIndex + 1 }} / {{ changeRows.length }}</span>
|
<span class="nav-text">{{ navIndex + 1 }}<em>/</em>{{ changeRows.length }}</span>
|
||||||
<Button size="small" icon="md-arrow-down" :disabled="navIndex >= changeRows.length - 1" @click="gotoChange(1)"></Button>
|
<Button size="small" icon="md-arrow-down" :disabled="navIndex >= changeRows.length - 1" @click="gotoChange(1)"></Button>
|
||||||
</span>
|
</div>
|
||||||
</template>
|
|
||||||
<div class="toolbar-gap"></div>
|
<div class="toolbar-gap"></div>
|
||||||
|
|
||||||
|
<div class="stat-group right-group">
|
||||||
|
<span class="stat-item plain-item" v-if="elapsed">耗时{{ elapsed }} ms</span>
|
||||||
<Tag v-if="hasDiff" type="warning">存在差异</Tag>
|
<Tag v-if="hasDiff" type="warning">存在差异</Tag>
|
||||||
<Tag v-else type="success">完全一致</Tag>
|
<Tag v-else type="success">完全一致</Tag>
|
||||||
|
<Button size="small" icon="md-create" @click="backToEdit()">重新编辑</Button>
|
||||||
|
<Tooltip content="导出为带颜色标记的 HTML 文件" transfer>
|
||||||
|
<Button size="small" icon="md-download" :disabled="!hasResult" @click="exportHtml()">导出</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 统计条 end -->
|
<!-- 统计条 end -->
|
||||||
|
|
||||||
@@ -75,18 +101,14 @@
|
|||||||
|
|
||||||
<!-- 结果区 start -->
|
<!-- 结果区 start -->
|
||||||
<div class="diff-result-area" v-if="hasResult">
|
<div class="diff-result-area" v-if="hasResult">
|
||||||
<div class="result-toolbar">
|
|
||||||
<Button size="small" icon="md-create" @click="backToEdit()">重新编辑</Button>
|
|
||||||
<span class="result-hint">左侧为原始内容,右侧为对比内容</span>
|
|
||||||
</div>
|
|
||||||
<div class="diff-table-wrap">
|
<div class="diff-table-wrap">
|
||||||
<div class="diff-table">
|
<div class="diff-table">
|
||||||
<div class="diff-row diff-head-row">
|
<div class="diff-row diff-head-row">
|
||||||
<div class="cell-no">行号</div>
|
<div class="cell-no">原</div>
|
||||||
<div class="cell-no">行号</div>
|
<div class="cell-no col-right">新</div>
|
||||||
<div class="cell-mark"></div>
|
<div class="cell-mark"></div>
|
||||||
<div class="cell-text">原始内容</div>
|
<div class="cell-text col-left">原始内容</div>
|
||||||
<div class="cell-text">对比内容</div>
|
<div class="cell-text col-right">对比内容</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(row, idx) in visibleRows"
|
<div v-for="(row, idx) in visibleRows"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
@@ -94,9 +116,9 @@
|
|||||||
:class="[rowClass(row), { active: activeRowIndex === idx }]"
|
:class="[rowClass(row), { active: activeRowIndex === idx }]"
|
||||||
:ref="'row' + idx">
|
:ref="'row' + idx">
|
||||||
<div class="cell-no">{{ row.leftNo > 0 ? row.leftNo : '' }}</div>
|
<div class="cell-no">{{ row.leftNo > 0 ? row.leftNo : '' }}</div>
|
||||||
<div class="cell-no">{{ row.rightNo > 0 ? row.rightNo : '' }}</div>
|
<div class="cell-no col-right">{{ row.rightNo > 0 ? row.rightNo : '' }}</div>
|
||||||
<div class="cell-mark"></div>
|
<div class="cell-mark"></div>
|
||||||
<div class="cell-text">
|
<div class="cell-text col-left">
|
||||||
<template v-if="row.leftParts">
|
<template v-if="row.leftParts">
|
||||||
<span v-for="(part, k) in row.leftParts"
|
<span v-for="(part, k) in row.leftParts"
|
||||||
:key="'l' + k"
|
:key="'l' + k"
|
||||||
@@ -104,7 +126,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<span v-else class="placeholder-text">—</span>
|
<span v-else class="placeholder-text">—</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-text">
|
<div class="cell-text col-right">
|
||||||
<template v-if="row.rightParts">
|
<template v-if="row.rightParts">
|
||||||
<span v-for="(part, k) in row.rightParts"
|
<span v-for="(part, k) in row.rightParts"
|
||||||
:key="'r' + k"
|
:key="'r' + k"
|
||||||
@@ -216,6 +238,7 @@
|
|||||||
clearAll () {
|
clearAll () {
|
||||||
this.leftText = ''
|
this.leftText = ''
|
||||||
this.rightText = ''
|
this.rightText = ''
|
||||||
|
this.onlyChanges = false
|
||||||
this.backToEdit()
|
this.backToEdit()
|
||||||
},
|
},
|
||||||
swapSides () {
|
swapSides () {
|
||||||
@@ -322,15 +345,27 @@
|
|||||||
exportHtml () {
|
exportHtml () {
|
||||||
const rows = this.rows
|
const rows = this.rows
|
||||||
let body = ''
|
let body = ''
|
||||||
|
// 与页面保持一致:新增只染右栏、删除只染左栏、修改两侧都染
|
||||||
|
const cellClass = row => {
|
||||||
|
if (row.type === 'insert') return 'txt side-right hit'
|
||||||
|
if (row.type === 'delete') return 'txt side-left hit'
|
||||||
|
if (row.type === 'replace') return 'txt hit'
|
||||||
|
return 'txt'
|
||||||
|
}
|
||||||
|
const renderParts = parts => {
|
||||||
|
if (!parts) return '<span class="ph">—</span>'
|
||||||
|
return parts.map(p => {
|
||||||
|
const text = escapeHtml(p.text)
|
||||||
|
return p.changed ? '<mark>' + text + '</mark>' : text
|
||||||
|
}).join('')
|
||||||
|
}
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
const cls = this.rowClass(row)
|
const cls = this.rowClass(row)
|
||||||
const left = row.leftParts ? row.leftParts.map(p => escapeHtml(p.text)).join('') : ''
|
|
||||||
const right = row.rightParts ? row.rightParts.map(p => escapeHtml(p.text)).join('') : ''
|
|
||||||
body += '<tr class="' + cls + '">'
|
body += '<tr class="' + cls + '">'
|
||||||
body += '<td class="no">' + (row.leftNo > 0 ? row.leftNo : '') + '</td>'
|
body += '<td class="no">' + (row.leftNo > 0 ? row.leftNo : '') + '</td>'
|
||||||
body += '<td class="no">' + (row.rightNo > 0 ? row.rightNo : '') + '</td>'
|
body += '<td class="no">' + (row.rightNo > 0 ? row.rightNo : '') + '</td>'
|
||||||
body += '<td class="txt">' + left + '</td>'
|
body += '<td class="' + cellClass(row) + ' side-left">' + renderParts(row.leftParts) + '</td>'
|
||||||
body += '<td class="txt">' + right + '</td>'
|
body += '<td class="' + cellClass(row) + ' side-right">' + renderParts(row.rightParts) + '</td>'
|
||||||
body += '</tr>'
|
body += '</tr>'
|
||||||
})
|
})
|
||||||
const html = '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8">'
|
const html = '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8">'
|
||||||
@@ -339,16 +374,19 @@
|
|||||||
+ '.bar{padding:10px 12px;background:#f0f3fa;border-radius:6px;margin-bottom:12px}'
|
+ '.bar{padding:10px 12px;background:#f0f3fa;border-radius:6px;margin-bottom:12px}'
|
||||||
+ 'table{border-collapse:collapse;width:100%;table-layout:fixed}'
|
+ 'table{border-collapse:collapse;width:100%;table-layout:fixed}'
|
||||||
+ 'td{border:1px solid #e8eaec;padding:2px 6px;vertical-align:top;white-space:pre-wrap;word-break:break-all}'
|
+ 'td{border:1px solid #e8eaec;padding:2px 6px;vertical-align:top;white-space:pre-wrap;word-break:break-all}'
|
||||||
+ 'td.no{width:48px;background:#f8f8f9;color:#808695;text-align:right;user-select:none}'
|
+ 'td.no{width:44px;background:#f8f8f9;color:#808695;text-align:right;user-select:none;font-variant-numeric:tabular-nums}'
|
||||||
+ 'td.txt{width:40%}'
|
+ 'td.txt{width:41%}'
|
||||||
+ 'tr.row-insert td{background:#e8f8ee}'
|
+ 'td.side-left{border-right:1px solid #dcdee2}'
|
||||||
+ 'tr.row-delete td{background:#fdecec}'
|
+ 'tr.row-insert td.side-right{background:#e8f8ee}'
|
||||||
|
+ 'tr.row-delete td.side-left{background:#fdecec}'
|
||||||
+ 'tr.row-replace td{background:#fff8e1}'
|
+ 'tr.row-replace td{background:#fff8e1}'
|
||||||
|
+ 'mark{background:#e6a23c;color:#fff;border-radius:2px;padding:0 1px}'
|
||||||
|
+ 'span.ph{color:#c5c8ce}'
|
||||||
+ '</style></head><body>'
|
+ '</style></head><body>'
|
||||||
+ '<div class="bar">新增 ' + this.stats.added + ' 行 | 删除 ' + this.stats.removed
|
+ '<div class="bar">新增 ' + this.stats.added + ' 行 | 删除 ' + this.stats.removed
|
||||||
+ ' 行 | 修改 ' + this.stats.changed + ' 行 | 相同 ' + this.stats.unchanged + ' 行</div>'
|
+ ' 行 | 修改 ' + this.stats.changed + ' 行 | 相同 ' + this.stats.unchanged + ' 行</div>'
|
||||||
+ '<table><tr><td class="no">行</td><td class="no">行</td><td class="txt">原始内容</td>'
|
+ '<table><tr><td class="no">原</td><td class="no">新</td><td class="txt side-left">原始内容</td>'
|
||||||
+ '<td class="txt">对比内容</td></tr>' + body + '</table></body></html>'
|
+ '<td class="txt side-right">对比内容</td></tr>' + body + '</table></body></html>'
|
||||||
|
|
||||||
this.downloadFile('text-diff-result.html', html, 'text/html')
|
this.downloadFile('text-diff-result.html', html, 'text/html')
|
||||||
},
|
},
|
||||||
@@ -362,7 +400,32 @@
|
|||||||
a.click()
|
a.click()
|
||||||
document.body.removeChild(a)
|
document.body.removeChild(a)
|
||||||
URL.revokeObjectURL(url)
|
URL.revokeObjectURL(url)
|
||||||
|
},
|
||||||
|
// Ctrl/Cmd + Enter 触发比对;输入框内换行不受影响
|
||||||
|
onKeydown (event) {
|
||||||
|
const isCompare = (event.ctrlKey || event.metaKey) && event.key === 'Enter'
|
||||||
|
if (isCompare) {
|
||||||
|
event.preventDefault()
|
||||||
|
if (!this.comparing) this.doCompare()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
// Esc 退出结果视图
|
||||||
|
if (event.key === 'Escape' && this.hasResult) {
|
||||||
|
this.backToEdit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// keep-alive 下 mounted 与 activated 都会触发,同一函数重复 addEventListener
|
||||||
|
// 会导致一次按键触发多次,因此只放在 activated 注册,deactivated 统一解绑
|
||||||
|
activated () {
|
||||||
|
window.removeEventListener('keydown', this.onKeydown)
|
||||||
|
window.addEventListener('keydown', this.onKeydown)
|
||||||
|
},
|
||||||
|
deactivated () {
|
||||||
|
window.removeEventListener('keydown', this.onKeydown)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
window.removeEventListener('keydown', this.onKeydown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,66 +448,115 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #e8eaec;
|
||||||
}
|
}
|
||||||
|
|
||||||
.diff-toolbar .ivu-checkbox-wrapper {
|
// 选项组:浅底 + 圆角,与操作按钮形成视觉分层
|
||||||
margin-right: 16px;
|
.toolbar-group {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-group .ivu-checkbox-wrapper {
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-gap {
|
.toolbar-gap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统计条并入浅色卡片,与内容区形成区块感
|
||||||
.diff-stats {
|
.diff-stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 10px 0;
|
gap: 8px 14px;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
background: #f7f8fa;
|
||||||
|
border: 1px solid #e8eaec;
|
||||||
|
border-radius: 4px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #515a6e;
|
color: #515a6e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-item {
|
.stat-group {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 18px;
|
gap: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-item.muted {
|
.right-group {
|
||||||
color: #808695;
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-dot {
|
.stat-dot {
|
||||||
|
align-self: center;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
margin-right: 6px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.added-dot { background: #19be6b; }
|
.added-item .stat-dot { background: #19be6b; }
|
||||||
.removed-dot { background: #ed4014; }
|
.removed-item .stat-dot { background: #ed4014; }
|
||||||
.changed-dot { background: #ff9900; }
|
.changed-item .stat-dot { background: #ff9900; }
|
||||||
|
|
||||||
.stat-num {
|
.stat-item b {
|
||||||
margin: 0 4px 0 2px;
|
margin-left: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.added-text { color: #19be6b; }
|
.added-item b { color: #19be6b; }
|
||||||
.removed-text { color: #ed4014; }
|
.removed-item b { color: #ed4014; }
|
||||||
.changed-text { color: #ff9900; }
|
.changed-item b { color: #ff9900; }
|
||||||
|
|
||||||
.nav-group .ivu-btn {
|
.plain-item {
|
||||||
margin: 0 4px;
|
color: #808695;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 16px;
|
||||||
|
background: #dcdee2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 差异导航
|
||||||
|
.nav-group {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-label {
|
||||||
|
color: #808695;
|
||||||
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-text {
|
.nav-text {
|
||||||
min-width: 54px;
|
min-width: 48px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-text em {
|
||||||
|
font-style: normal;
|
||||||
|
color: #c5c8ce;
|
||||||
|
margin: 0 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.diff-input-area {
|
.diff-input-area {
|
||||||
@@ -464,7 +576,8 @@
|
|||||||
|
|
||||||
.input-head {
|
.input-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,9 +588,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.input-meta {
|
.input-meta {
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #808695;
|
color: #808695;
|
||||||
|
background: #f7f8fa;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.diff-textarea {
|
.diff-textarea {
|
||||||
@@ -501,18 +616,6 @@
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-hint {
|
|
||||||
margin-left: 12px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #808695;
|
|
||||||
}
|
|
||||||
|
|
||||||
.diff-table-wrap {
|
.diff-table-wrap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -545,7 +648,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cell-no {
|
.cell-no {
|
||||||
flex: 0 0 52px;
|
flex: 0 0 48px;
|
||||||
padding: 3px 8px;
|
padding: 3px 8px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: #808695;
|
color: #808695;
|
||||||
@@ -554,11 +657,19 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后一个行号列与色条之间加一条竖分隔,强化左右分栏
|
||||||
|
.cell-no.col-right {
|
||||||
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-mark {
|
.cell-mark {
|
||||||
flex: 0 0 4px;
|
flex: 0 0 4px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
border-left: 1px solid #dcdee2;
|
||||||
|
border-right: 1px solid #dcdee2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-text {
|
.cell-text {
|
||||||
@@ -570,15 +681,22 @@
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
border-right: 1px solid #f0f2f5;
|
}
|
||||||
|
|
||||||
|
// 左右两栏之间用竖线分隔,长文本下更易对照
|
||||||
|
.cell-text.col-left {
|
||||||
|
border-right: 1px solid #dcdee2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.diff-row.row-insert .cell-mark { background: #19be6b; }
|
.diff-row.row-insert .cell-mark { background: #19be6b; }
|
||||||
.diff-row.row-delete .cell-mark { background: #ed4014; }
|
.diff-row.row-delete .cell-mark { background: #ed4014; }
|
||||||
.diff-row.row-replace .cell-mark { background: #ff9900; }
|
.diff-row.row-replace .cell-mark { background: #ff9900; }
|
||||||
|
|
||||||
.diff-row.row-insert .cell-text:last-child { background: #e8f8ee; }
|
// 新增:仅右侧栏着色
|
||||||
.diff-row.row-delete .cell-text:first-of-type { background: #fdecec; }
|
.diff-row.row-insert .cell-text.col-right { background: #e8f8ee; }
|
||||||
|
// 删除:仅左侧栏着色
|
||||||
|
.diff-row.row-delete .cell-text.col-left { background: #fdecec; }
|
||||||
|
// 修改:两侧都着色
|
||||||
.diff-row.row-replace .cell-text { background: #fff8e1; }
|
.diff-row.row-replace .cell-text { background: #fff8e1; }
|
||||||
|
|
||||||
.diff-row.active .cell-text {
|
.diff-row.active .cell-text {
|
||||||
|
|||||||
Reference in New Issue
Block a user