mirror of
https://gitee.com/wanwujie/sub2api-mobile
synced 2026-04-25 01:04:46 +08:00
feat: add dedicated create-user and create-account admin flows
This commit is contained in:
@@ -198,7 +198,17 @@ export default function AccountsScreen() {
|
||||
<ScreenShell
|
||||
title="账号管理"
|
||||
subtitle="看单账号状态、并发、最近使用和异常信息。"
|
||||
titleAside={<Text className="text-[11px] text-[#a2988a]">更接近网页后台的账号视图。</Text>}
|
||||
titleAside={(
|
||||
<View className="flex-row items-center gap-2">
|
||||
<Text className="text-[11px] text-[#a2988a]">更接近网页后台的账号视图。</Text>
|
||||
<Pressable
|
||||
onPress={() => router.push('/accounts/create')}
|
||||
className="h-8 w-8 items-center justify-center rounded-[10px] bg-[#1d5f55]"
|
||||
>
|
||||
<Text className="text-xl leading-5 text-white">+</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
)}
|
||||
variant="minimal"
|
||||
scroll={false}
|
||||
>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BarChartCard } from '@/src/components/bar-chart-card';
|
||||
import { formatTokenValue } from '@/src/lib/formatters';
|
||||
import { DonutChartCard } from '@/src/components/donut-chart-card';
|
||||
import { LineTrendChart } from '@/src/components/line-trend-chart';
|
||||
import { getAdminSettings, getDashboardModels, getDashboardStats, getDashboardTrend, listAllAccounts } from '@/src/services/admin';
|
||||
import { getAdminSettings, getDashboardModels, getDashboardStats, getDashboardTrend, listAccounts } from '@/src/services/admin';
|
||||
import { adminConfigState, hasAuthenticatedAdminSession } from '@/src/store/admin-config';
|
||||
|
||||
const { useSnapshot } = require('valtio/react');
|
||||
@@ -172,23 +172,37 @@ export default function MonitorScreen() {
|
||||
const [rangeKey, setRangeKey] = useState<RangeKey>('7d');
|
||||
const range = useMemo(() => getDateRange(rangeKey), [rangeKey]);
|
||||
|
||||
const statsQuery = useQuery({ queryKey: ['monitor-stats'], queryFn: getDashboardStats, enabled: hasAccount });
|
||||
const settingsQuery = useQuery({ queryKey: ['admin-settings'], queryFn: getAdminSettings, enabled: hasAccount });
|
||||
const accountPageSize = Math.max(statsQuery.data?.total_accounts ?? 20, 20);
|
||||
const accountsQuery = useQuery({
|
||||
queryKey: ['monitor-accounts', accountPageSize],
|
||||
queryFn: () => listAllAccounts(''),
|
||||
const statsQuery = useQuery({
|
||||
queryKey: ['monitor-stats'],
|
||||
queryFn: getDashboardStats,
|
||||
enabled: hasAccount,
|
||||
staleTime: 60_000,
|
||||
});
|
||||
const settingsQuery = useQuery({
|
||||
queryKey: ['admin-settings'],
|
||||
queryFn: getAdminSettings,
|
||||
enabled: hasAccount,
|
||||
staleTime: 120_000,
|
||||
});
|
||||
const accountsQuery = useQuery({
|
||||
queryKey: ['monitor-accounts'],
|
||||
queryFn: () => listAccounts(''),
|
||||
enabled: hasAccount,
|
||||
staleTime: 60_000,
|
||||
});
|
||||
const trendQuery = useQuery({
|
||||
queryKey: ['monitor-trend', rangeKey, range.start_date, range.end_date, range.granularity],
|
||||
queryFn: () => getDashboardTrend(range),
|
||||
enabled: hasAccount,
|
||||
staleTime: 60_000,
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
const modelsQuery = useQuery({
|
||||
queryKey: ['monitor-models', rangeKey, range.start_date, range.end_date],
|
||||
queryFn: () => getDashboardModels(range),
|
||||
enabled: hasAccount,
|
||||
staleTime: 60_000,
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
|
||||
function refetchAll() {
|
||||
@@ -381,22 +395,11 @@ export default function MonitorScreen() {
|
||||
formatValue={formatCompactNumber}
|
||||
/>
|
||||
|
||||
<Section title="趋势摘要" subtitle="图表 + 最近几个统计点的请求、Token 和成本变化">
|
||||
<Section title="趋势摘要" subtitle="最近几个统计点的请求、Token 和成本变化">
|
||||
{latestTrendPoints.length === 0 ? (
|
||||
<Text style={{ fontSize: 14, color: colors.subtext }}>当前时间范围没有趋势数据。</Text>
|
||||
) : (
|
||||
<View style={{ gap: 12 }}>
|
||||
{throughputPoints.length > 1 ? (
|
||||
<LineTrendChart
|
||||
title="摘要 Token 趋势"
|
||||
subtitle="最近统计点的 Token 变化"
|
||||
points={throughputPoints.slice(-6)}
|
||||
color="#a34d2d"
|
||||
formatValue={formatTokenDisplay}
|
||||
compact
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<View style={{ gap: 10 }}>
|
||||
{latestTrendPoints.map((point) => (
|
||||
<View key={point.date} style={{ backgroundColor: colors.mutedCard, borderRadius: 14, padding: 12 }}>
|
||||
|
||||
@@ -109,6 +109,7 @@ export default function SettingsScreen() {
|
||||
const [connectionState, setConnectionState] = useState<ConnectionState>('idle');
|
||||
const [connectionMessage, setConnectionMessage] = useState('');
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
const [showAdminKey, setShowAdminKey] = useState(false);
|
||||
const { control, handleSubmit, formState, reset } = useForm<FormValues>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: {
|
||||
@@ -227,15 +228,32 @@ export default function SettingsScreen() {
|
||||
control={control}
|
||||
name="adminApiKey"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextInput
|
||||
value={value}
|
||||
onChangeText={onChange}
|
||||
placeholder="admin-xxxxxxxx"
|
||||
placeholderTextColor="#9b9081"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
style={{ backgroundColor: colors.mutedCard, borderRadius: 16, paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, color: colors.text }}
|
||||
/>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
||||
<TextInput
|
||||
value={value}
|
||||
onChangeText={onChange}
|
||||
placeholder="admin-xxxxxxxx"
|
||||
placeholderTextColor="#9b9081"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
secureTextEntry={!showAdminKey}
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: colors.mutedCard,
|
||||
borderRadius: 16,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 14,
|
||||
fontSize: 16,
|
||||
color: colors.text,
|
||||
}}
|
||||
/>
|
||||
<Pressable
|
||||
onPress={() => setShowAdminKey((value) => !value)}
|
||||
style={{ backgroundColor: colors.border, borderRadius: 12, paddingHorizontal: 12, paddingVertical: 10 }}
|
||||
>
|
||||
<Text style={{ fontSize: 12, fontWeight: '700', color: '#4e463e' }}>{showAdminKey ? '隐藏' : '显示'}</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -130,7 +130,7 @@ function UserCard({ user, usage }: { user: AdminUser; usage?: UsageStats }) {
|
||||
<Text numberOfLines={1} style={{ fontSize: 16, fontWeight: '800', color: colors.text }}>{user.email}</Text>
|
||||
<Text style={{ marginTop: 4, fontSize: 12, color: colors.subtext }}>最近使用 {formatActivityTime(user.last_used_at || user.updated_at || user.created_at)}</Text>
|
||||
</View>
|
||||
<View style={{ alignSelf: 'flex-start', backgroundColor: user.status === 'inactive' ? '#cfc5b7' : colors.primary, borderRadius: 999, paddingHorizontal: 10, paddingVertical: 6 }}>
|
||||
<View style={{ alignSelf: 'flex-start', backgroundColor: user.status === 'inactive' || user.status === 'disabled' ? '#cfc5b7' : colors.primary, borderRadius: 999, paddingHorizontal: 10, paddingVertical: 6 }}>
|
||||
<Text style={{ fontSize: 10, fontWeight: '700', color: '#fff' }}>{statusLabel}</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -187,9 +187,24 @@ export default function UsersScreen() {
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1, backgroundColor: colors.page }}>
|
||||
<View style={{ flex: 1, paddingHorizontal: 16, paddingTop: 14 }}>
|
||||
<View style={{ marginBottom: 10 }}>
|
||||
<Text style={{ fontSize: 28, fontWeight: '700', color: colors.text }}>用户</Text>
|
||||
<Text style={{ marginTop: 4, fontSize: 12, color: '#8a8072' }}>查看用户列表并进入详情页管理账号。</Text>
|
||||
<View style={{ marginBottom: 10, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={{ fontSize: 28, fontWeight: '700', color: colors.text }}>用户</Text>
|
||||
<Text style={{ marginTop: 4, fontSize: 12, color: '#8a8072' }}>查看用户列表并进入详情页管理账号。</Text>
|
||||
</View>
|
||||
<Pressable
|
||||
onPress={() => router.push('/users/create-user')}
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 12,
|
||||
backgroundColor: colors.primary,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: '#fff', fontSize: 24, lineHeight: 24, fontWeight: '500' }}>+</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={{ flexDirection: 'row', gap: 10, alignItems: 'center' }}>
|
||||
|
||||
Reference in New Issue
Block a user