CI / verify (push) Canceled after 0s
- 配置版本: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 认证,只读/读写两种范围;令牌管理与改密/退出仅限登录会话
70 lines
2.5 KiB
Vue
70 lines
2.5 KiB
Vue
<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>
|