feat: 服务表单默认检查 + 至少保留一条 + CHANGELOG 更新

This commit is contained in:
aiyimickey 2026-07-02 10:09:19 +08:00
parent ba7f181501
commit b5b59f1c3b
2 changed files with 23 additions and 2 deletions

View File

@ -1,5 +1,23 @@
# Changelog
## v2026.07.02
### 新增
- **用户管理页面**用户列表、角色编辑admin/editor/viewerAPI 权限守卫
- **角色权限管理页面**11 个权限的开关式管理admin/editor/viewer 三角色独立配置
- **审计日志页面**:分页、筛选(操作类型/对象类型)、真实数据展示
- **容器操作管理**:服务管理页面增加重启/停止/查看日志功能,通过 SSH 执行 Docker 命令,安全边界(不挂载 rw docker.sock所有操作记录审计日志
- **服务 CRUD 表单**:完整的添加/编辑/删除服务对话框,支持 HTTP/Docker 多维度检查配置
- **仪表盘路由**`/` 重定向到 `/dashboard`
### 优化
- **设计规范更新**`tlyq-design-system.md` 新增「光标系统」章节,所有可交互非按钮/链接元素添加 `cursor-pointer`
- **服务表单改进**:新增服务默认包含一条检查方式,至少保留一条检查不允许删除
- **用户管理**:表格显示用户名/显示名/邮箱/角色/状态,支持内联编辑角色
- **审计日志**:支持按操作类型筛选(登录/创建/更新/删除等),按对象类型筛选(认证/服务/告警渠道/用户/角色)
## v2026.07.01
### 新增

View File

@ -6,7 +6,7 @@ import { Plus, RotateCw, Square, ScrollText, X, Save, Trash2, Edit3 } from 'luci
interface Check { type: string; containerName?: string; url?: string }
interface Service { id: number; name: string; category: string; alert_level: string; checks: Check[]; check_interval: number; enabled: number; current_status: string }
const emptyService = { name: '', category: 'endpoint', alert_level: 'warning', checks: [] as Check[], check_interval: 30, check_timeout: 10, enabled: 1 }
const emptyService = { name: '', category: 'endpoint', alert_level: 'warning', checks: [{ type: 'http', url: '' }] as Check[], check_interval: 30, check_timeout: 10, enabled: 1 }
export default function ServicesPage() {
const [services, setServices] = useState<Service[]>([])
@ -63,6 +63,7 @@ export default function ServicesPage() {
}
const removeCheck = (i: number) => {
const checks = [...((editing?.checks as Check[]) || [])]
if (checks.length <= 1) return // 至少保留一条检查方式
checks.splice(i, 1)
update('checks', checks)
}
@ -247,7 +248,9 @@ export default function ServicesPage() {
<input value={c.containerName || ''} onChange={e => updateCheck(i, 'containerName', e.target.value)} placeholder="容器名,如 authelia"
className="flex-1 px-2 py-1.5 rounded border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-xs" />
)}
{((editing.checks as Check[]) || []).length > 1 && (
<button onClick={() => removeCheck(i)} className="text-red-400 hover:text-red-600 p-1"><X size={14} /></button>
)}
</div>
))}
</div>