mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 01:36:37 +08:00
prettier
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as React from "react"
|
||||
import {Input} from "@/components/ui/input"
|
||||
import {Switch} from "@/components/ui/switch"
|
||||
import {ManageDetailPanel, ManagePage} from "@/components/common/general/manage-pannel"
|
||||
import {Tabs, TabsList, TabsTrigger} from "@/components/ui/tabs"
|
||||
import {ShieldCheck} from "lucide-react"
|
||||
|
||||
import {formatDateTime} from "@/lib/utils"
|
||||
import type {SystemConfig} from "@/lib/services/admin"
|
||||
import {AdminProvider, useAdmin} from "@/contexts/admin-context"
|
||||
import * as React from 'react';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import {
|
||||
ManageDetailPanel,
|
||||
ManagePage,
|
||||
} from '@/components/common/general/manage-pannel';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { ShieldCheck } from 'lucide-react';
|
||||
|
||||
import { formatDateTime } from '@/lib/utils';
|
||||
import type { SystemConfig } from '@/lib/services/admin';
|
||||
import { AdminProvider, useAdmin } from '@/contexts/admin-context';
|
||||
|
||||
/**
|
||||
* 系统配置
|
||||
@@ -38,43 +40,51 @@ function SystemConfigDetailPanel({
|
||||
editData,
|
||||
onEditDataChange,
|
||||
onSave,
|
||||
saving
|
||||
saving,
|
||||
}: {
|
||||
config: SystemConfig | null
|
||||
editData: Partial<SystemConfig>
|
||||
onEditDataChange: (field: keyof SystemConfig, value: SystemConfig[keyof SystemConfig]) => void
|
||||
onSave: () => void
|
||||
saving: boolean
|
||||
config: SystemConfig | null;
|
||||
editData: Partial<SystemConfig>;
|
||||
onEditDataChange: (
|
||||
field: keyof SystemConfig,
|
||||
value: SystemConfig[keyof SystemConfig],
|
||||
) => void;
|
||||
onSave: () => void;
|
||||
saving: boolean;
|
||||
}) {
|
||||
|
||||
return (
|
||||
<ManageDetailPanel
|
||||
isEmpty={!config}
|
||||
onSave={onSave}
|
||||
saving={saving}
|
||||
>
|
||||
<div className="grid grid-cols-1 gap-0">
|
||||
<div className="border border-dashed rounded-lg">
|
||||
<div className="px-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0">
|
||||
<label className="text-xs font-medium text-muted-foreground">配置键</label>
|
||||
<p className="text-xs text-muted-foreground font-mono">{config?.key}</p>
|
||||
<ManageDetailPanel isEmpty={!config} onSave={onSave} saving={saving}>
|
||||
<div className='grid grid-cols-1 gap-0'>
|
||||
<div className='border border-dashed rounded-lg'>
|
||||
<div className='px-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0'>
|
||||
<label className='text-xs font-medium text-muted-foreground'>
|
||||
配置键
|
||||
</label>
|
||||
<p className='text-xs text-muted-foreground font-mono'>
|
||||
{config?.key}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="pl-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0">
|
||||
<label className="text-xs font-medium text-muted-foreground">配置值</label>
|
||||
<div className="flex gap-1 w-[90%] justify-end items-center pr-3">
|
||||
<div className='pl-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0'>
|
||||
<label className='text-xs font-medium text-muted-foreground'>
|
||||
配置值
|
||||
</label>
|
||||
<div className='flex gap-1 w-[90%] justify-end items-center pr-3'>
|
||||
{config?.key.endsWith('_enabled') ? (
|
||||
<Switch
|
||||
checked={editData.value !== undefined ? editData.value === 'true' : (config?.value === 'true')}
|
||||
checked={
|
||||
editData.value !== undefined
|
||||
? editData.value === 'true'
|
||||
: config?.value === 'true'
|
||||
}
|
||||
onCheckedChange={(checked) => {
|
||||
onEditDataChange('value', checked ? 'true' : 'false')
|
||||
onEditDataChange('value', checked ? 'true' : 'false');
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
type={
|
||||
config?.key && (
|
||||
config.key.endsWith('_limit') ||
|
||||
config?.key &&
|
||||
(config.key.endsWith('_limit') ||
|
||||
config.key.endsWith('_minutes') ||
|
||||
config.key.endsWith('_days') ||
|
||||
config.key.endsWith('_seconds') ||
|
||||
@@ -85,79 +95,100 @@ function SystemConfigDetailPanel({
|
||||
config.key.includes('max_') ||
|
||||
config.key.includes('min_') ||
|
||||
config.key.includes('limit') ||
|
||||
config.key.includes('count')
|
||||
) ? "number" : "text"
|
||||
config.key.includes('count'))
|
||||
? 'number'
|
||||
: 'text'
|
||||
}
|
||||
step='1'
|
||||
min='0'
|
||||
value={
|
||||
editData.value !== undefined
|
||||
? editData.value
|
||||
: config?.value || ''
|
||||
}
|
||||
placeholder={
|
||||
editData.value === undefined && !config?.value ? '必需' : ''
|
||||
}
|
||||
step="1"
|
||||
min="0"
|
||||
value={editData.value !== undefined ? editData.value : (config?.value || '')}
|
||||
placeholder={editData.value === undefined && !config?.value ? '必需' : ''}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
const value = e.target.value;
|
||||
if (value === '') {
|
||||
onEditDataChange('value', '')
|
||||
return
|
||||
onEditDataChange('value', '');
|
||||
return;
|
||||
}
|
||||
onEditDataChange('value', value)
|
||||
onEditDataChange('value', value);
|
||||
}}
|
||||
className="!text-[12px] text-right h-4 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:!text-[12px] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-inner-spin-button]"
|
||||
className='!text-[12px] text-right h-4 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:!text-[12px] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-inner-spin-button]'
|
||||
style={{
|
||||
MozAppearance: 'textfield'
|
||||
MozAppearance: 'textfield',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pl-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0">
|
||||
<label className="text-xs font-medium text-muted-foreground">配置描述</label>
|
||||
<div className="flex gap-1 w-[90%]">
|
||||
<div className='pl-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0'>
|
||||
<label className='text-xs font-medium text-muted-foreground'>
|
||||
配置描述
|
||||
</label>
|
||||
<div className='flex gap-1 w-[90%]'>
|
||||
<Input
|
||||
type="text"
|
||||
value={editData.description !== undefined ? editData.description : (config?.description || '')}
|
||||
placeholder="可选描述"
|
||||
type='text'
|
||||
value={
|
||||
editData.description !== undefined
|
||||
? editData.description
|
||||
: config?.description || ''
|
||||
}
|
||||
placeholder='可选描述'
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
onEditDataChange('description', value)
|
||||
const value = e.target.value;
|
||||
onEditDataChange('description', value);
|
||||
}}
|
||||
className="!text-[12px] text-right h-4 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:!text-[12px]"
|
||||
className='!text-[12px] text-right h-4 rounded-none border-none shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:!text-[12px]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="px-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0">
|
||||
<label className="text-xs font-medium text-muted-foreground">公共可见</label>
|
||||
<div className='px-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0'>
|
||||
<label className='text-xs font-medium text-muted-foreground'>
|
||||
公共可见
|
||||
</label>
|
||||
<Switch
|
||||
checked={(editData.visibility ?? config?.visibility ?? 0) === 1}
|
||||
onCheckedChange={(checked) => {
|
||||
onEditDataChange('visibility', checked ? 1 : 0)
|
||||
onEditDataChange('visibility', checked ? 1 : 0);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="px-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0">
|
||||
<label className="text-xs font-medium text-muted-foreground">配置类型</label>
|
||||
<span className={`text-[11px] px-1.5 py-0.5 rounded font-medium ${
|
||||
config?.type === 'system'
|
||||
? 'bg-blue-500/10 text-blue-600 dark:bg-blue-500/20 dark:text-blue-400'
|
||||
: 'bg-indigo-500/10 text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-400'
|
||||
}`}>
|
||||
<div className='px-3 py-2 flex items-center justify-between border-b border-dashed last:border-b-0'>
|
||||
<label className='text-xs font-medium text-muted-foreground'>
|
||||
配置类型
|
||||
</label>
|
||||
<span
|
||||
className={`text-[11px] px-1.5 py-0.5 rounded font-medium ${
|
||||
config?.type === 'system'
|
||||
? 'bg-blue-500/10 text-blue-600 dark:bg-blue-500/20 dark:text-blue-400'
|
||||
: 'bg-indigo-500/10 text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-400'
|
||||
}`}
|
||||
>
|
||||
{config?.type === 'system' ? '系统配置' : '业务配置'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="px-3 py-2 flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-muted-foreground">创建时间</label>
|
||||
<p className="text-xs text-muted-foreground">{config ? formatDateTime(config.created_at) : ''}</p>
|
||||
<div className='px-3 py-2 flex items-center justify-between'>
|
||||
<label className='text-xs font-medium text-muted-foreground'>
|
||||
创建时间
|
||||
</label>
|
||||
<p className='text-xs text-muted-foreground'>
|
||||
{config ? formatDateTime(config.created_at) : ''}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ManageDetailPanel>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 系统配置管理组件
|
||||
*
|
||||
@@ -173,34 +204,39 @@ export function SystemConfigs() {
|
||||
systemConfigsLoading: loading,
|
||||
systemConfigsError: error,
|
||||
refetchSystemConfigs,
|
||||
updateSystemConfig
|
||||
} = useAdmin()
|
||||
updateSystemConfig,
|
||||
} = useAdmin();
|
||||
|
||||
const [activeTab, setActiveTab] = React.useState<'system' | 'business'>('business')
|
||||
const [activeTab, setActiveTab] = React.useState<'system' | 'business'>(
|
||||
'business',
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
refetchSystemConfigs(activeTab)
|
||||
}, [activeTab, refetchSystemConfigs])
|
||||
refetchSystemConfigs(activeTab);
|
||||
}, [activeTab, refetchSystemConfigs]);
|
||||
|
||||
const getInitialEditData = (config: SystemConfig) => ({
|
||||
value: config.value,
|
||||
visibility: config.visibility,
|
||||
description: config.description
|
||||
})
|
||||
description: config.description,
|
||||
});
|
||||
|
||||
const handleSave = async (config: SystemConfig, editData: Partial<SystemConfig>) => {
|
||||
if (!config) return
|
||||
const handleSave = async (
|
||||
config: SystemConfig,
|
||||
editData: Partial<SystemConfig>,
|
||||
) => {
|
||||
if (!config) return;
|
||||
|
||||
await updateSystemConfig(config.key, {
|
||||
value: editData.value ?? config.value,
|
||||
visibility: editData.visibility ?? config.visibility,
|
||||
description: editData.description ?? config.description
|
||||
})
|
||||
}
|
||||
description: editData.description ?? config.description,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ManagePage<SystemConfig>
|
||||
title="系统配置"
|
||||
title='系统配置'
|
||||
icon={ShieldCheck}
|
||||
data={configs}
|
||||
loading={loading}
|
||||
@@ -209,23 +245,72 @@ export function SystemConfigs() {
|
||||
getInitialEditData={getInitialEditData}
|
||||
onSave={handleSave}
|
||||
getId={(config) => config.key}
|
||||
emptyDescription="未发现系统配置"
|
||||
loadingDescription="配置加载中"
|
||||
emptyDescription='未发现系统配置'
|
||||
loadingDescription='配置加载中'
|
||||
headerExtra={
|
||||
<Tabs value={activeTab} onValueChange={(val) => setActiveTab(val as 'system' | 'business')} className="w-[180px]">
|
||||
<TabsList className="grid w-full grid-cols-2 h-8">
|
||||
<TabsTrigger value="business" className="text-[11px] h-7">业务配置</TabsTrigger>
|
||||
<TabsTrigger value="system" className="text-[11px] h-7">系统配置</TabsTrigger>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onValueChange={(val) => setActiveTab(val as 'system' | 'business')}
|
||||
className='w-[180px]'
|
||||
>
|
||||
<TabsList className='grid w-full grid-cols-2 h-8'>
|
||||
<TabsTrigger value='business' className='text-[11px] h-7'>
|
||||
业务配置
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value='system' className='text-[11px] h-7'>
|
||||
系统配置
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
}
|
||||
columns={[
|
||||
{ header: "配置键", cell: (item) => <span className="font-mono font-medium">{item.key}</span>, width: "200px" },
|
||||
{ header: "配置值", cell: (item) => <span className="truncate max-w-[120px] inline-block" title={item.value}>{item.value}</span>, width: "120px" },
|
||||
{ header: "公共可见", cell: (item) => <span>{item.visibility === 1 ? "可见" : "不可见"}</span>, width: "80px" },
|
||||
{ header: "描述", cell: (item) => <span className="truncate max-w-[200px] inline-block text-muted-foreground" title={item.description}>{item.description}</span>, width: "200px" },
|
||||
{
|
||||
header: '配置键',
|
||||
cell: (item) => (
|
||||
<span className='font-mono font-medium'>{item.key}</span>
|
||||
),
|
||||
width: '200px',
|
||||
},
|
||||
{
|
||||
header: '配置值',
|
||||
cell: (item) => (
|
||||
<span
|
||||
className='truncate max-w-[120px] inline-block'
|
||||
title={item.value}
|
||||
>
|
||||
{item.value}
|
||||
</span>
|
||||
),
|
||||
width: '120px',
|
||||
},
|
||||
{
|
||||
header: '公共可见',
|
||||
cell: (item) => (
|
||||
<span>{item.visibility === 1 ? '可见' : '不可见'}</span>
|
||||
),
|
||||
width: '80px',
|
||||
},
|
||||
{
|
||||
header: '描述',
|
||||
cell: (item) => (
|
||||
<span
|
||||
className='truncate max-w-[200px] inline-block text-muted-foreground'
|
||||
title={item.description}
|
||||
>
|
||||
{item.description}
|
||||
</span>
|
||||
),
|
||||
width: '200px',
|
||||
},
|
||||
]}
|
||||
renderDetail={({ selected, hovered, editData, onEditDataChange, onSave, saving }) => (
|
||||
renderDetail={({
|
||||
selected,
|
||||
hovered,
|
||||
editData,
|
||||
onEditDataChange,
|
||||
onSave,
|
||||
saving,
|
||||
}) => (
|
||||
<SystemConfigDetailPanel
|
||||
config={selected || hovered}
|
||||
editData={editData}
|
||||
@@ -235,7 +320,7 @@ export function SystemConfigs() {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default function SystemConfigPage() {
|
||||
@@ -243,5 +328,5 @@ export default function SystemConfigPage() {
|
||||
<AdminProvider>
|
||||
<SystemConfigs />
|
||||
</AdminProvider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user