refactor: migrate key forms to shadcn field
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import * as React from 'react'
|
||||
import { AlertCircle, LockKeyhole, UserRound } from 'lucide-react'
|
||||
|
||||
import { AppField } from '@/components/app/AppField'
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
|
||||
import { useAuth } from './AuthProvider'
|
||||
|
||||
@@ -70,33 +70,33 @@ export function LoginPage() {
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="username">账号</Label>
|
||||
<AppField label="账号" htmlFor="username" invalid={Boolean(error)} required>
|
||||
<div className="relative">
|
||||
<UserRound className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input
|
||||
id="username"
|
||||
autoComplete="username"
|
||||
aria-invalid={Boolean(error)}
|
||||
className="pl-9"
|
||||
value={username}
|
||||
onChange={(event) => setUsername(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">密码</Label>
|
||||
</AppField>
|
||||
<AppField label="密码" htmlFor="password" invalid={Boolean(error)} required>
|
||||
<div className="relative">
|
||||
<LockKeyhole className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
aria-invalid={Boolean(error)}
|
||||
className="pl-9"
|
||||
value={password}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AppField>
|
||||
<Button type="submit" className="mt-1 w-full" disabled={submitting}>
|
||||
{submitting ? '登录中...' : '登录'}
|
||||
</Button>
|
||||
|
||||
@@ -100,15 +100,16 @@ export function SolutionCreatePage() {
|
||||
<div className="grid gap-4">
|
||||
<AppSection title="基础信息">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<AppField label="方案标题">
|
||||
<AppField label="方案标题" htmlFor="solution-title" required>
|
||||
<Input
|
||||
id="solution-title"
|
||||
required
|
||||
placeholder="例如:认证回调阻塞处理方案"
|
||||
value={form.title}
|
||||
onChange={(event) => updateField('title', event.target.value)}
|
||||
/>
|
||||
</AppField>
|
||||
<AppField label="状态">
|
||||
<AppField label="状态" required>
|
||||
<Select value={form.status} onValueChange={(value) => updateField('status', value)}>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="选择状态" />
|
||||
@@ -121,15 +122,17 @@ export function SolutionCreatePage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</AppField>
|
||||
<AppField label="关联系统">
|
||||
<AppField label="关联系统" htmlFor="solution-related-system">
|
||||
<Input
|
||||
id="solution-related-system"
|
||||
placeholder="例如:CRM、认证中心、支付系统"
|
||||
value={form.related_system}
|
||||
onChange={(event) => updateField('related_system', event.target.value)}
|
||||
/>
|
||||
</AppField>
|
||||
<AppField label="环境范围">
|
||||
<AppField label="环境范围" htmlFor="solution-environment-scope">
|
||||
<Input
|
||||
id="solution-environment-scope"
|
||||
placeholder="例如:生产环境 / Chrome"
|
||||
value={form.environment_scope}
|
||||
onChange={(event) => updateField('environment_scope', event.target.value)}
|
||||
@@ -139,8 +142,9 @@ export function SolutionCreatePage() {
|
||||
</AppSection>
|
||||
|
||||
<AppSection title="问题特征">
|
||||
<AppField label="问题特征">
|
||||
<AppField label="问题特征" htmlFor="solution-problem-signature" required>
|
||||
<Textarea
|
||||
id="solution-problem-signature"
|
||||
required
|
||||
placeholder="描述可复用的问题表现、报错特征、触发条件。"
|
||||
value={form.problem_signature}
|
||||
@@ -151,16 +155,18 @@ export function SolutionCreatePage() {
|
||||
|
||||
<AppSection title="根因与方案">
|
||||
<div className="grid gap-4">
|
||||
<AppField label="根因分析">
|
||||
<AppField label="根因分析" htmlFor="solution-root-cause" required>
|
||||
<Textarea
|
||||
id="solution-root-cause"
|
||||
required
|
||||
placeholder="说明问题的根因或判断依据。"
|
||||
value={form.root_cause}
|
||||
onChange={(event) => updateField('root_cause', event.target.value)}
|
||||
/>
|
||||
</AppField>
|
||||
<AppField label="处理方案">
|
||||
<AppField label="处理方案" htmlFor="solution-content" required>
|
||||
<Textarea
|
||||
id="solution-content"
|
||||
required
|
||||
placeholder="写清楚处理步骤、验证方式和回滚注意事项。"
|
||||
value={form.solution}
|
||||
@@ -171,8 +177,9 @@ export function SolutionCreatePage() {
|
||||
</AppSection>
|
||||
|
||||
<AppSection title="风险提示">
|
||||
<AppField label="风险提示">
|
||||
<AppField label="风险提示" htmlFor="solution-risk-note">
|
||||
<Textarea
|
||||
id="solution-risk-note"
|
||||
placeholder="可选:说明操作风险、影响范围或上线前确认事项。"
|
||||
value={form.risk_note}
|
||||
onChange={(event) => updateField('risk_note', event.target.value)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { AppField } from '@/components/app/AppField'
|
||||
import { AppDataTable, type AppDataTableColumn } from '@/components/app/AppDataTable'
|
||||
import { AppEmptyState } from '@/components/app/AppEmptyState'
|
||||
import { AppPageHeader } from '@/components/app/AppPageHeader'
|
||||
@@ -74,9 +75,11 @@ export function SystemRolesPage() {
|
||||
<div className="mx-auto flex max-w-7xl flex-col gap-4">
|
||||
<AppPageHeader title="角色权限" />
|
||||
|
||||
<form className="grid gap-3 rounded-lg border border-border bg-surface p-3 md:grid-cols-[minmax(0,360px)_auto]" onSubmit={handleCreate}>
|
||||
<Input placeholder="角色名称" value={roleName} onChange={(event) => setRoleName(event.target.value)} required />
|
||||
<Button type="submit">创建角色</Button>
|
||||
<form className="grid gap-3 rounded-lg border border-border bg-surface p-3 md:grid-cols-[minmax(0,360px)_auto] md:items-end" onSubmit={handleCreate}>
|
||||
<AppField label="角色名称" htmlFor="system-role-name" required>
|
||||
<Input id="system-role-name" value={roleName} onChange={(event) => setRoleName(event.target.value)} required />
|
||||
</AppField>
|
||||
<Button type="submit" className="w-full md:w-auto">创建角色</Button>
|
||||
</form>
|
||||
|
||||
{error ? <AppEmptyState title="无法加载角色" description={error} /> : null}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { AppField } from '@/components/app/AppField'
|
||||
import { AppDataTable, type AppDataTableColumn } from '@/components/app/AppDataTable'
|
||||
import { AppEmptyState } from '@/components/app/AppEmptyState'
|
||||
import { AppPageHeader } from '@/components/app/AppPageHeader'
|
||||
@@ -82,11 +83,17 @@ export function SystemUserGroupsPage() {
|
||||
<div className="mx-auto flex max-w-7xl flex-col gap-4">
|
||||
<AppPageHeader title="用户组管理" />
|
||||
|
||||
<form className="grid gap-3 rounded-lg border border-border bg-surface p-3 md:grid-cols-[1fr_1fr_2fr_auto]" onSubmit={handleCreate}>
|
||||
<Input placeholder="用户组名称" value={form.name} onChange={(event) => setForm({ ...form, name: event.target.value })} required />
|
||||
<Input placeholder="编码" value={form.code} onChange={(event) => setForm({ ...form, code: event.target.value })} required />
|
||||
<Input placeholder="说明" value={form.description} onChange={(event) => setForm({ ...form, description: event.target.value })} />
|
||||
<Button type="submit">创建用户组</Button>
|
||||
<form className="grid gap-3 rounded-lg border border-border bg-surface p-3 md:grid-cols-[1fr_1fr_2fr_auto] md:items-end" onSubmit={handleCreate}>
|
||||
<AppField label="用户组名称" htmlFor="system-group-name" required>
|
||||
<Input id="system-group-name" value={form.name} onChange={(event) => setForm({ ...form, name: event.target.value })} required />
|
||||
</AppField>
|
||||
<AppField label="编码" htmlFor="system-group-code" required>
|
||||
<Input id="system-group-code" value={form.code} onChange={(event) => setForm({ ...form, code: event.target.value })} required />
|
||||
</AppField>
|
||||
<AppField label="说明" htmlFor="system-group-description">
|
||||
<Input id="system-group-description" value={form.description} onChange={(event) => setForm({ ...form, description: event.target.value })} />
|
||||
</AppField>
|
||||
<Button type="submit" className="w-full md:w-auto">创建用户组</Button>
|
||||
</form>
|
||||
|
||||
{error ? <AppEmptyState title="无法加载用户组" description={error} /> : null}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { AppField } from '@/components/app/AppField'
|
||||
import { AppDataTable, type AppDataTableColumn } from '@/components/app/AppDataTable'
|
||||
import { AppEmptyState } from '@/components/app/AppEmptyState'
|
||||
import { AppFilterBar } from '@/components/app/AppFilterBar'
|
||||
@@ -141,12 +142,20 @@ export function SystemUsersPage() {
|
||||
<div className="mx-auto flex max-w-7xl flex-col gap-4">
|
||||
<AppPageHeader title="用户管理" />
|
||||
|
||||
<form className="grid gap-3 rounded-lg border border-border bg-surface p-3 md:grid-cols-[1fr_1fr_1fr_1fr_auto]" onSubmit={handleCreateUser}>
|
||||
<Input placeholder="账号" value={form.username} onChange={(event) => setForm({ ...form, username: event.target.value })} required />
|
||||
<Input placeholder="显示名称" value={form.display_name} onChange={(event) => setForm({ ...form, display_name: event.target.value })} />
|
||||
<Input placeholder="邮箱" value={form.email} onChange={(event) => setForm({ ...form, email: event.target.value })} />
|
||||
<Input placeholder="初始密码" type="password" value={form.password} onChange={(event) => setForm({ ...form, password: event.target.value })} required />
|
||||
<Button type="submit">创建用户</Button>
|
||||
<form className="grid gap-3 rounded-lg border border-border bg-surface p-3 md:grid-cols-[1fr_1fr_1fr_1fr_auto] md:items-end" onSubmit={handleCreateUser}>
|
||||
<AppField label="账号" htmlFor="system-user-username" required>
|
||||
<Input id="system-user-username" value={form.username} onChange={(event) => setForm({ ...form, username: event.target.value })} required />
|
||||
</AppField>
|
||||
<AppField label="显示名称" htmlFor="system-user-display-name">
|
||||
<Input id="system-user-display-name" value={form.display_name} onChange={(event) => setForm({ ...form, display_name: event.target.value })} />
|
||||
</AppField>
|
||||
<AppField label="邮箱" htmlFor="system-user-email">
|
||||
<Input id="system-user-email" value={form.email} onChange={(event) => setForm({ ...form, email: event.target.value })} />
|
||||
</AppField>
|
||||
<AppField label="初始密码" htmlFor="system-user-password" required>
|
||||
<Input id="system-user-password" type="password" value={form.password} onChange={(event) => setForm({ ...form, password: event.target.value })} required />
|
||||
</AppField>
|
||||
<Button type="submit" className="w-full md:w-auto">创建用户</Button>
|
||||
</form>
|
||||
|
||||
<AppFilterBar>
|
||||
|
||||
@@ -61,8 +61,9 @@ export function TicketCreatePage() {
|
||||
) : null}
|
||||
|
||||
<AppSection title="基础信息">
|
||||
<AppField label="工单标题">
|
||||
<AppField label="工单标题" htmlFor="ticket-title" required>
|
||||
<Input
|
||||
id="ticket-title"
|
||||
required
|
||||
placeholder="例如:生产环境登录后跳转失败"
|
||||
value={form.title}
|
||||
@@ -73,7 +74,7 @@ export function TicketCreatePage() {
|
||||
|
||||
<AppSection title="影响与优先级">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<AppField label="优先级">
|
||||
<AppField label="优先级" required>
|
||||
<Select value={form.priority} onValueChange={(value) => updateField('priority', value as TicketInput['priority'])}>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="请选择优先级" />
|
||||
@@ -88,8 +89,9 @@ export function TicketCreatePage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</AppField>
|
||||
<AppField label="影响范围">
|
||||
<AppField label="影响范围" htmlFor="ticket-impact-scope">
|
||||
<Input
|
||||
id="ticket-impact-scope"
|
||||
placeholder="例如:单个用户、某部门、全部用户"
|
||||
value={form.impact_scope}
|
||||
onChange={(event) => updateField('impact_scope', event.target.value)}
|
||||
@@ -100,15 +102,17 @@ export function TicketCreatePage() {
|
||||
|
||||
<AppSection title="环境与系统">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<AppField label="关联系统">
|
||||
<AppField label="关联系统" htmlFor="ticket-related-system">
|
||||
<Input
|
||||
id="ticket-related-system"
|
||||
placeholder="例如:CRM、财务系统、数据中台"
|
||||
value={form.related_system}
|
||||
onChange={(event) => updateField('related_system', event.target.value)}
|
||||
/>
|
||||
</AppField>
|
||||
<AppField label="运行环境">
|
||||
<AppField label="运行环境" htmlFor="ticket-environment">
|
||||
<Input
|
||||
id="ticket-environment"
|
||||
placeholder="例如:生产环境、测试环境、Windows 终端"
|
||||
value={form.environment}
|
||||
onChange={(event) => updateField('environment', event.target.value)}
|
||||
@@ -118,8 +122,9 @@ export function TicketCreatePage() {
|
||||
</AppSection>
|
||||
|
||||
<AppSection title="问题描述">
|
||||
<AppField label="详细描述">
|
||||
<AppField label="详细描述" htmlFor="ticket-description" required>
|
||||
<Textarea
|
||||
id="ticket-description"
|
||||
required
|
||||
placeholder="请描述影响范围、报错信息、操作步骤和已尝试的处理方式。"
|
||||
value={form.description}
|
||||
|
||||
Reference in New Issue
Block a user