feat: LokiDeploy 初始提交 - 轻量级 K8s Loki 部署平台

Go(Gin) + React(Vite + shadcn/ui + Tailwind) 前后端分离,全中文 UI

- 集群管理:Kubeconfig / Token 双接入,kubectl + helm 部署
- 主机管理:SSH 密钥 / 密码双认证,CPU/内存/磁盘使用率监控,SSH 错误中文友好提示
- 存储配置、部署管理、系统设置
- Docker 镜像内置 kubectl + helm,开箱即用
- run.sh 一键启停(start/stop/restart/status)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Logan.LiandClaude committed 2026-06-29 17:03:57 +08:00
commit 2a93de600d
134 files changed
+19595

No files matched your search

+131
View File
@@ -0,0 +1,131 @@
import { useState } from 'react'
import { KeyRound, Settings as SettingsIcon } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { authApi } from '@/srv/api'
export default function Settings() {
const [oldPassword, setOldPassword] = useState('')
const [newPassword, setNewPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [changing, setChanging] = useState(false)
const handleChangePassword = async (e: React.FormEvent) => {
e.preventDefault()
if (newPassword !== confirmPassword) {
alert('两次输入的密码不一致')
return
}
setChanging(true)
try {
await authApi.changePassword(oldPassword, newPassword)
alert('密码修改成功')
setOldPassword('')
setNewPassword('')
setConfirmPassword('')
} catch (err: unknown) {
const message = err instanceof Error ? err.message : '密码修改失败'
alert(message)
} finally {
setChanging(false)
}
}
return (
<div className="space-y-6">
<div>
<h2 className="text-lg font-semibold text-slate-800 dark:text-white">系统设置</h2>
<p className="text-sm text-slate-500">修改登录密码与查看系统信息</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* 修改密码 */}
<Card className="border-slate-200 dark:border-slate-800">
<CardHeader className="pb-3">
<CardTitle className="text-base flex items-center gap-2">
<KeyRound className="w-4 h-4" />
修改密码
</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleChangePassword} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="old-pwd">当前密码</Label>
<Input
id="old-pwd"
type="password"
value={oldPassword}
onChange={(e) => setOldPassword(e.target.value)}
placeholder="请输入当前密码"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="new-pwd">新密码</Label>
<Input
id="new-pwd"
type="password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
placeholder="请输入新密码(至少 6 位)"
required
minLength={6}
/>
</div>
<div className="space-y-2">
<Label htmlFor="confirm-pwd">确认新密码</Label>
<Input
id="confirm-pwd"
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="请再次输入新密码"
required
/>
</div>
<Button type="submit" className="bg-emerald-600 hover:bg-emerald-700" disabled={changing}>
{changing ? '修改中...' : '修改密码'}
</Button>
</form>
</CardContent>
</Card>
{/* 关于 */}
<Card className="border-slate-200 dark:border-slate-800">
<CardHeader className="pb-3">
<CardTitle className="text-base flex items-center gap-2">
<SettingsIcon className="w-4 h-4" />
关于 LokiDeploy
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
<div className="flex justify-between py-2 border-b border-slate-100 dark:border-slate-800">
<span className="text-sm text-slate-500">版本</span>
<span className="text-sm font-medium">v1.0.0</span>
</div>
<div className="flex justify-between py-2 border-b border-slate-100 dark:border-slate-800">
<span className="text-sm text-slate-500">后端</span>
<span className="text-sm font-medium">Go + Gin + JSON 文件存储</span>
</div>
<div className="flex justify-between py-2 border-b border-slate-100 dark:border-slate-800">
<span className="text-sm text-slate-500">前端</span>
<span className="text-sm font-medium">React + TypeScript + Tailwind CSS</span>
</div>
<div className="flex justify-between py-2 border-b border-slate-100 dark:border-slate-800">
<span className="text-sm text-slate-500">部署工具</span>
<span className="text-sm font-medium">kubectl + helm(镜像内置)</span>
</div>
<div className="flex justify-between py-2">
<span className="text-sm text-slate-500">简介</span>
<span className="text-sm font-medium text-right">轻量级 K8s Loki 部署平台</span>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
)
}