Files
-Fonu/web/src/components/ConfigDiffView.vue
T
mrlee 862442e77f
CI / verify (push) Canceled after 0s
feat: 配置版本历史/对比/回滚、国内 IM 通知渠道、阈值告警与 API Token(v1.2.9)
- 配置版本:fsutil 版本化备份(内容相同自动去重),主 nginx.conf 与 VPS vhost 的版本列表/逐行差异/一键回滚,回滚先校验语法与 nginx -t 再写回

- agent 0.12.2:写 vhost 前留版本;nginx -t 校验失败改为恢复上一个可用版本(此前直接删文件),新增域名 vhost 版本端点,双架构二进制已重编

- 通知:补企业微信 / 钉钉 / 飞书机器人,切换预设时服务地址跟随该预设默认值

- 阈值告警:新增 internal/monitor 巡检(CPU/内存/磁盘持续超阈值、隧道连续 N 次未注册),默认关闭,带静默期与恢复通知

- API Token:api_tokens 表 + Authorization Bearer 认证,只读/读写两种范围;令牌管理与改密/退出仅限登录会话
2026-09-24 20:50:17 +08:00

70 lines
2.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="config-diff">
<div class="config-diff__head">
<span class="config-diff__range">{{ fromLabel }} → {{ toLabel }}</span>
<span class="config-diff__stats">
<span class="config-diff__add">+{{ stats.added }}</span>
<span class="config-diff__del">−{{ stats.removed }}</span>
</span>
</div>
<div class="config-diff__body">
<div
v-for="(line, index) in lines"
:key="index"
class="config-diff__row"
:class="`config-diff__row--${line.kind}`"
>
<span class="config-diff__sign">{{ sign(line.kind) }}</span>
<span class="config-diff__text">{{ line.text || ' ' }}</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { diffLines, diffStats, type DiffLine } from '../utils/diff'
const props = withDefaults(
defineProps<{
fromText: string
toText: string
fromLabel?: string
toLabel?: string
}>(),
{ fromLabel: '当前', toLabel: '所选版本' },
)
const lines = computed<DiffLine[]>(() => diffLines(props.fromText, props.toText))
const stats = computed(() => diffStats(lines.value))
function sign(kind: DiffLine['kind']): string {
if (kind === 'add') return '+'
if (kind === 'del') return '−'
return ' '
}
</script>
<style scoped>
.config-diff { border: 1px solid var(--fonu-border); border-radius: var(--fonu-radius-sm); overflow: hidden; }
.config-diff__head {
display: flex; align-items: center; justify-content: space-between; gap: var(--fonu-space-3);
padding: 6px var(--fonu-space-3); border-bottom: 1px solid var(--fonu-border);
background: var(--fonu-bg-muted); font-size: 12px; color: var(--fonu-text-secondary);
}
.config-diff__stats { display: flex; gap: 8px; font-family: var(--fonu-mono); }
.config-diff__add { color: var(--fonu-brand-text); }
.config-diff__del { color: var(--fonu-error); }
.config-diff__body { max-height: 420px; overflow: auto; background: var(--fonu-surface); }
.config-diff__row {
display: flex; gap: 8px; padding: 1px 10px;
font-family: var(--fonu-mono); font-size: 12px; line-height: 1.6;
}
.config-diff__row--add { background: var(--fonu-brand-soft); }
.config-diff__row--del { background: var(--fonu-error-soft); }
.config-diff__sign { flex: none; width: 10px; color: var(--fonu-text-muted); }
.config-diff__row--add .config-diff__sign { color: var(--fonu-brand-text); }
.config-diff__row--del .config-diff__sign { color: var(--fonu-error); }
.config-diff__text { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>