feat: 全站 PageShell 设计系统与专业 UI 统一

- 新增 PageShell/PageTabs/ContentPanel/PageLoading/PageEmpty 页面骨架
- index.css 设计令牌文档化,布局令牌与纯色主按钮(去除渐变粉彩)
- 全站路由页接入 PageShell,云账单三 Tab 为标杆
- 主题体系:跟随系统 + 主流/开发者分组,新增 Dracula/Tokyo Night,One Dark 暖灰差异化
- 登录页/侧栏/顶栏去渐变光球,企业克制风
- 修复 AIAlertAnalyzer JSX 与构建依赖导入问题
This commit is contained in:
Logan committed 2026-07-01 12:45:38 +08:00
1 parent 1acb0c49af
commit e363ded445
213 files changed
+7148 -6818

No files matched your search

@@ -124,41 +124,41 @@ export function AlertRuleDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="bg-slate-900 border-slate-700 text-slate-100 max-w-lg">
<DialogContent className="dg-input max-w-lg">
<DialogHeader>
<DialogTitle className="text-slate-100">
<DialogTitle className="text-[var(--dg-text-primary)]">
{editingRule ? '编辑告警规则' : '新建告警规则'}
</DialogTitle>
<DialogDescription className="text-slate-500">
<DialogDescription className="dg-text-muted">
{editingRule ? '修改告警规则的触发条件和通知方式' : '配置监控指标的告警触发条件'}
</DialogDescription>
</DialogHeader>
<div className="space-y-4 max-h-[60vh] overflow-y-auto pr-1">
<div className="space-y-1.5">
<Label className="text-slate-300">规则名称 <span className="text-red-400">*</span></Label>
<Label className="text-[var(--dg-text-secondary)]">规则名称 <span className="dg-text-red">*</span></Label>
<Input
value={ruleForm.name}
onChange={(e) => setRuleForm({ ...ruleForm, name: e.target.value })}
placeholder="如:CPU 使用率告警"
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600"
className="dg-input"
/>
</div>
<div className="space-y-1.5">
<Label className="text-slate-300">描述</Label>
<Label className="text-[var(--dg-text-secondary)]">描述</Label>
<Textarea
value={ruleForm.description}
onChange={(e) => setRuleForm({ ...ruleForm, description: e.target.value })}
placeholder="规则说明"
rows={2}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600 resize-none"
className="dg-input resize-none"
/>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5">
<Label className="text-slate-300">规则类型</Label>
<Label className="text-[var(--dg-text-secondary)]">规则类型</Label>
<select
value={ruleForm.type}
onChange={(e) => {
@@ -166,7 +166,7 @@ export function AlertRuleDialog({
const source = type === 'log' ? 'loki' : 'prometheus';
setRuleForm({ ...ruleForm, type, source });
}}
className="w-full h-9 px-3 rounded-md bg-slate-800/50 border border-slate-700 text-slate-200 text-sm"
className="w-full h-9 px-3 rounded-md bg-[var(--dg-bg-tertiary)]/50 border border-[var(--dg-border)] text-[var(--dg-text-primary)] text-sm"
>
<option value="metric">指标监控</option>
<option value="log">日志告警</option>
@@ -174,11 +174,11 @@ export function AlertRuleDialog({
</select>
</div>
<div className="space-y-1.5">
<Label className="text-slate-300">数据源</Label>
<Label className="text-[var(--dg-text-secondary)]">数据源</Label>
<select
value={ruleForm.source}
onChange={(e) => setRuleForm({ ...ruleForm, source: e.target.value, datasource_id: undefined })}
className="w-full h-9 px-3 rounded-md bg-slate-800/50 border border-slate-700 text-slate-200 text-sm"
className="w-full h-9 px-3 rounded-md bg-[var(--dg-bg-tertiary)]/50 border border-[var(--dg-border)] text-[var(--dg-text-primary)] text-sm"
>
{ruleForm.type === 'log' ? (
<>
@@ -198,11 +198,11 @@ export function AlertRuleDialog({
{ruleForm.type === 'log' && (
<div className="space-y-1.5">
<Label className="text-slate-300">日志数据源 <span className="text-red-400">*</span></Label>
<Label className="text-[var(--dg-text-secondary)]">日志数据源 <span className="dg-text-red">*</span></Label>
<select
value={ruleForm.datasource_id || ''}
onChange={(e) => setRuleForm({ ...ruleForm, datasource_id: Number(e.target.value) || undefined })}
className="w-full h-9 px-3 rounded-md bg-slate-800/50 border border-slate-700 text-slate-200 text-sm"
className="w-full h-9 px-3 rounded-md bg-[var(--dg-bg-tertiary)]/50 border border-[var(--dg-border)] text-[var(--dg-text-primary)] text-sm"
>
<option value="">请选择数据源</option>
{logSources.map((s) => (
@@ -210,20 +210,20 @@ export function AlertRuleDialog({
))}
</select>
{logSources.length === 0 && (
<p className="text-xs text-amber-400/80">请先前往「日志库」添加 {ruleForm.source === 'loki' ? 'Loki' : 'Elasticsearch'} 数据源</p>
<p className="text-xs dg-text-yellow/80">请先前往「日志库」添加 {ruleForm.source === 'loki' ? 'Loki' : 'Elasticsearch'} 数据源</p>
)}
</div>
)}
<div className="space-y-1.5">
<Label className="text-slate-300">触发表达式 <span className="text-red-400">*</span></Label>
<Label className="text-[var(--dg-text-secondary)]">触发表达式 <span className="dg-text-red">*</span></Label>
<Input
value={ruleForm.expression}
onChange={(e) => setRuleForm({ ...ruleForm, expression: e.target.value })}
placeholder={ruleForm.type === 'log' ? '{app="api"} |= "error"' : 'cpu_usage > 80'}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600 font-mono text-sm"
className="dg-input font-mono text-sm"
/>
<p className="text-xs text-slate-600">
<p className="text-xs dg-text-muted">
{ruleForm.type === 'log'
? (ruleForm.source === 'loki' ? 'LogQL 查询或 count_over_time 表达式' : 'Elasticsearch Lucene 查询')
: 'PromQL 或指标表达式,例如 cpu_usage > 80'}
@@ -232,11 +232,11 @@ export function AlertRuleDialog({
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5">
<Label className="text-slate-300">告警级别</Label>
<Label className="text-[var(--dg-text-secondary)]">告警级别</Label>
<select
value={ruleForm.severity}
onChange={(e) => setRuleForm({ ...ruleForm, severity: e.target.value })}
className="w-full h-9 px-3 rounded-md bg-slate-800/50 border border-slate-700 text-slate-200 text-sm"
className="w-full h-9 px-3 rounded-md bg-[var(--dg-bg-tertiary)]/50 border border-[var(--dg-border)] text-[var(--dg-text-primary)] text-sm"
>
<option value="info">提示</option>
<option value="warning">警告</option>
@@ -244,20 +244,20 @@ export function AlertRuleDialog({
</select>
</div>
<div className="space-y-1.5">
<Label className="text-slate-300">持续时间(秒)</Label>
<Label className="text-[var(--dg-text-secondary)]">持续时间(秒)</Label>
<Input
type="number"
value={ruleForm.duration}
onChange={(e) => setRuleForm({ ...ruleForm, duration: Number(e.target.value) })}
className="bg-slate-800/50 border-slate-700 text-slate-200"
className="dg-input"
/>
</div>
</div>
<div className="space-y-1.5">
<Label className="text-slate-300">通知渠道</Label>
<Label className="text-[var(--dg-text-secondary)]">通知渠道</Label>
{notifyChannels.length === 0 ? (
<div className="text-xs text-amber-400/80 bg-amber-500/5 border border-amber-500/20 rounded-md px-3 py-2">
<div className="text-xs dg-text-yellow/80 bg-amber-500/5 border border-amber-500/20 rounded-md px-3 py-2">
暂无已配置的通知渠道,请先在「通知渠道配置」中添加
</div>
) : (
@@ -268,17 +268,17 @@ export function AlertRuleDialog({
return (
<label
key={ch.id}
className="flex items-center gap-2 cursor-pointer select-none text-sm text-slate-300"
className="flex items-center gap-2 cursor-pointer select-none text-sm text-[var(--dg-text-secondary)]"
>
<Switch
checked={checked}
onCheckedChange={() => toggleNotifyChannel(String(ch.id))}
className="data-[state=checked]:bg-blue-600"
/>
<Icon className="h-4 w-4 text-slate-400" />
<Icon className="h-4 w-4 dg-text-secondary" />
<span>
{ch.name}
<span className="text-xs text-slate-500 ml-1">({getChannelTypeLabel(ch.type)})</span>
<span className="text-xs dg-text-muted ml-1">({getChannelTypeLabel(ch.type)})</span>
</span>
</label>
);
@@ -291,7 +291,7 @@ export function AlertRuleDialog({
<DialogFooter>
<Button
variant="outline"
className="border-slate-700 text-slate-300 hover:bg-slate-800"
className="border-[var(--dg-border)] text-[var(--dg-text-secondary)] hover:bg-[var(--dg-bg-hover)]"
onClick={() => onOpenChange(false)}
>
取消