更新用户总览图表,删除多余的console.log

This commit is contained in:
Eamon-meng
2025-12-20 10:09:38 +08:00
parent e9881d2521
commit 2e4df24e05
12 changed files with 111 additions and 164 deletions

View File

@@ -5,9 +5,8 @@ import {callByUser} from './base'
import {listAnnouncements} from './announcement' import {listAnnouncements} from './announcement'
type statisticsResourceUsageReq = { type statisticsResourceUsageReq = {
resource_no?: string time_start?: Date
create_after?: Date time_end?: Date
create_before?: Date
} }
type statisticsResourceUsageResp = { type statisticsResourceUsageResp = {
@@ -59,10 +58,7 @@ export async function listInitialization(): Promise<ApiResponse<listInitializati
message: '公告数据获取失败', message: '公告数据获取失败',
} }
} }
const usage = await statisticsResourceUsage({ const usage = await statisticsResourceUsage({})
create_after: new Date(),
create_before: new Date(),
})
if (!usage.success) { if (!usage.success) {
return { return {
success: false, success: false,

View File

@@ -21,7 +21,6 @@ async function createWhitelist(props: {
host: string host: string
remark?: string remark?: string
}) { }) {
console.log(props)
return await callByUser('/api/whitelist/create', props) return await callByUser('/api/whitelist/create', props)
} }
@@ -30,7 +29,6 @@ async function updateWhitelist(props: {
host?: string host?: string
remark?: string remark?: string
}) { }) {
console.log(props)
return await callByUser('/api/whitelist/update', props) return await callByUser('/api/whitelist/update', props)
} }

View File

@@ -1,24 +1,20 @@
'use client' 'use client'
import {Tabs, TabsList, TabsTrigger, TabsContent} from '@/components/ui/tabs'
import Image from 'next/image'
import soon from '../_assets/coming-soon.svg'
import DatePicker from '@/components/date-picker' import DatePicker from '@/components/date-picker'
import {Card, CardContent} from '@/components/ui/card' import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card'
import {Form, FormField} from '@/components/ui/form' import {Form, FormField} from '@/components/ui/form'
import {Input} from '@/components/ui/input'
import {zodResolver} from '@hookform/resolvers/zod' import {zodResolver} from '@hookform/resolvers/zod'
import {useForm} from 'react-hook-form' import {useForm} from 'react-hook-form'
import zod from 'zod' import zod from 'zod'
import {merge} from '@/lib/utils' import {compareAsc, format, addDays} from 'date-fns'
import {Button} from '@/components/ui/button' import {Button} from '@/components/ui/button'
import {useState} from 'react' import {useState} from 'react'
import {statisticsResourceUsage} from '@/actions/dashboard' import {statisticsResourceUsage} from '@/actions/dashboard'
import {ExtraResp} from '@/lib/api' import {ExtraResp} from '@/lib/api'
import {toast} from 'sonner' import {toast} from 'sonner'
import {compareAsc, format, subDays} from 'date-fns'
import {Label} from '@/components/ui/label'
import {ChartConfig, ChartContainer} from '@/components/ui/chart' import {ChartConfig, ChartContainer} from '@/components/ui/chart'
import {CartesianGrid, XAxis, YAxis, Tooltip, Area, AreaChart, Legend} from 'recharts' import {CartesianGrid, XAxis, YAxis, Tooltip, Area, AreaChart, Legend} from 'recharts'
import mask from '../_assets/Mask group.webp'
import Image from 'next/image'
type ChartsProps = { type ChartsProps = {
initialData?: ExtraResp<typeof statisticsResourceUsage> initialData?: ExtraResp<typeof statisticsResourceUsage>
@@ -27,38 +23,38 @@ type ChartsProps = {
export default function Charts({initialData}: ChartsProps) { export default function Charts({initialData}: ChartsProps) {
// const [submittedData, setSubmittedData] = useState<ExtraReq<typeof listAccount>>() // const [submittedData, setSubmittedData] = useState<ExtraReq<typeof listAccount>>()
const [submittedData, setSubmittedData] = useState<ExtraResp<typeof statisticsResourceUsage>>(initialData || []) const [submittedData, setSubmittedData] = useState<ExtraResp<typeof statisticsResourceUsage>>(initialData || [])
const formSchema = zod.object({ const filterSchema = zod.object({
resource_no: zod.string().optional(), time_start: zod.date().optional(),
create_after: zod.date().optional(), time_end: zod.date().optional(),
create_before: zod.date().optional(),
}) })
type FormValues = zod.infer<typeof formSchema> type FilterSchema = zod.infer<typeof filterSchema>
const form = useForm<FormValues>({ const filterForm = useForm<FilterSchema>({
resolver: zodResolver(formSchema), resolver: zodResolver(filterSchema),
defaultValues: { defaultValues: {
time_start: undefined,
time_end: undefined,
}, },
}) })
const handler = form.handleSubmit( const handler = filterForm.handleSubmit(async () => {
async (value) => { const {time_start, time_end} = filterForm.getValues()
const today = new Date()
const sevenDaysAgo = subDays(today, 7)
const res = {
resource_no: value.resource_no ?? '',
create_after: value.create_after ?? sevenDaysAgo,
create_before: value.create_before ?? today,
}
const resp = await statisticsResourceUsage(res) const params = {
if (!resp.success) { time_start: time_start,
toast.error('接口请求失败:' + resp.message) time_end: time_end ? addDays(time_end, 1) : undefined,
return }
} const resp = await statisticsResourceUsage(params)
if (!resp.data || resp.data.length === 0) { if (!resp.success) {
toast.info('没有查询到相关数据') toast.error('接口请求失败:' + resp.message)
setSubmittedData([]) return
return }
}
if (!resp.data || resp.data.length === 0) {
toast.info('没有查询到相关数据')
setSubmittedData([])
return
}
if (resp.success && resp.data) {
const formattedData = resp.data.map(item => ({ const formattedData = resp.data.map(item => ({
...item, ...item,
date: item.date, date: item.date,
@@ -66,61 +62,60 @@ export default function Charts({initialData}: ChartsProps) {
})) }))
formattedData.sort((a, b) => compareAsc(a.date, b.date)) formattedData.sort((a, b) => compareAsc(a.date, b.date))
setSubmittedData(formattedData) setSubmittedData(formattedData)
}, }
) else {
throw new Error('获取数据失败')
}
})
return ( return (
<Card className="h-full"> <Card className="h-full">
<CardContent className="overflow-hidden"> <CardContent className="overflow-hidden flex flex-col">
<Tabs defaultValue="dynamic" className="h-full gap-4"> <CardHeader className="flex-none">
<TabsList className="h-9"> <CardTitle>
<TabsTrigger value="dynamic" className="data-[state=active]:text-primary"> <Image src={mask} alt="Mask group" priority/>
</TabsTrigger> </CardTitle>
<TabsTrigger value="static" className="data-[state=active]:text-primary"> </CardHeader>
<Form form={filterForm} handler={handler} className="flex-none flex flex-wrap justify-end mb-4 gap-4">
</TabsTrigger> <fieldset className="flex flex-col gap-2 items-start">
</TabsList> <div className="flex gap-1 items-center">
<Form<FormValues> className={merge(`flex items-end gap-4 flex-wrap`)} handler={handler} form={form} > <FormField<FilterSchema, 'time_start'> name="time_start">
<div className="flex flex-col gap-2"> {({field}) => (
<Label className="text-sm"></Label> <DatePicker
<div className="flex items-center"> placeholder="选择开始时间"
<FormField name="create_after"> {...field}
{({field}) => ( format="yyyy-MM-dd"
<DatePicker />
{...field} )}
className="w-36" </FormField>
placeholder="开始时间" <span>-</span>
format="yyyy-MM-dd" <FormField<FilterSchema, 'time_end'> name="time_end">
/> {({field}) => (
)} <DatePicker
</FormField> placeholder="选择结束时间"
<span className="px-1">-</span> {...field}
<FormField name="create_before"> format="yyyy-MM-dd"
{({field}) => ( />
<DatePicker )}
{...field} </FormField>
className="w-36"
placeholder="结束时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
</div>
</div> </div>
<div className="flex gap-4"> </fieldset>
<Button className="h-9" type="submit"> <Button className="h-9" type="submit"></Button>
<span></span> <Button
</Button> theme="outline"
</div> className="h-9"
</Form> onClick={() => {
<TabsContent value="dynamic" className="overflow-hidden"> filterForm.reset({
{submittedData && <DashboardChart data={submittedData}/>} time_start: undefined,
</TabsContent> time_end: undefined,
<TabsContent value="static" className="flex flex-col items-center justify-center gap-2"> })
<LongChart/> handler()
</TabsContent> }}>
</Tabs>
</Button>
</Form>
{submittedData && <DashboardChart data={submittedData}/>}
</CardContent> </CardContent>
</Card> </Card>
) )
@@ -151,7 +146,7 @@ function DashboardChart(props: DashboardChartProps) {
} }
}) })
return ( return (
<ChartContainer config={config} className="w-full h-full"> <ChartContainer config={config} className="w-full flex-auto overflow-hidden">
<AreaChart data={chartData} margin={{top: 0, right: 20, left: 0, bottom: 0}}> <AreaChart data={chartData} margin={{top: 0, right: 20, left: 0, bottom: 0}}>
<CartesianGrid vertical={false}/> <CartesianGrid vertical={false}/>
<XAxis <XAxis
@@ -178,33 +173,3 @@ function DashboardChart(props: DashboardChartProps) {
</ChartContainer> </ChartContainer>
) )
} }
function LongChart() {
return (
<ChartContainer config={config} className="w-full h-full">
<AreaChart margin={{top: 0, right: 20, left: 0, bottom: 0}}>
<CartesianGrid vertical={false}/>
<XAxis
dataKey="formattedTime"
tickLine={false}
/>
<YAxis tickLine={false}/>
<Tooltip
animationDuration={100}
// labelFormatter={value => `日期: ${chartData.find(item => item.formattedTime === value)?.fullDate || value}`}
formatter={value => [`${value}`, '套餐使用量']}
/>
<Area
type="monotone"
dataKey="count"
stroke="#8884d8"
fill="#8884d8"
fillOpacity={0.2}
strokeWidth={2}
name="套餐使用量"
/>
<Legend/>
</AreaChart>
</ChartContainer>
)
}

View File

@@ -49,7 +49,6 @@ export default function BillsPage(props: BillsPageProps) {
}) })
const onSubmit = async (value: FilterSchema) => { const onSubmit = async (value: FilterSchema) => {
console.log(value)
await refresh(1, data.size) await refresh(1, data.size)
} }
@@ -65,7 +64,6 @@ export default function BillsPage(props: BillsPageProps) {
const res = await listBills({ const res = await listBills({
page, size, type, create_after, create_before, trade_id, page, size, type, create_after, create_before, trade_id,
}) })
console.log(res, 'res')
if (res.success) { if (res.success) {
setData(res.data) setData(res.data)

View File

@@ -1,5 +1,5 @@
'use client' 'use client'
import {useEffect, useState} from 'react' import {useCallback, useEffect, useState} from 'react'
import {useStatus} from '@/lib/states' import {useStatus} from '@/lib/states'
import {PageRecord} from '@/lib/api' import {PageRecord} from '@/lib/api'
import {Channel} from '@/lib/models' import {Channel} from '@/lib/models'
@@ -31,14 +31,32 @@ export default function ChannelsPage(props: ChannelsPageProps) {
total: 0, total: 0,
list: [], list: [],
}) })
// ======================
// filter
// ======================
const filterSchema = z.object({
auth_type: z.enum(['0', '1', '2']),
expired_status: z.enum(['all', 'active']).default('all'),
expire_after: z.date().optional(),
expire_before: z.date().optional(),
})
type FilterSchema = z.infer<typeof filterSchema>
const filterForm = useForm<FilterSchema>({
resolver: zodResolver(filterSchema),
defaultValues: {
auth_type: '0',
expired_status: 'all',
expire_after: undefined,
expire_before: undefined,
},
})
// 检查是否过期 // 检查是否过期
const isExpired = (expiredAt: string | Date) => { const isExpired = (expiredAt: string | Date) => {
const date = typeof expiredAt === 'string' ? new Date(expiredAt) : expiredAt const date = typeof expiredAt === 'string' ? new Date(expiredAt) : expiredAt
return isBefore(date, new Date()) return isBefore(date, new Date())
} }
const refresh = async (page: number, size: number) => { const refresh = useCallback(async (page: number, size: number) => {
try { try {
setStatus('load') setStatus('load')
@@ -54,7 +72,6 @@ export default function ChannelsPage(props: ChannelsPageProps) {
const resp = await listChannels({ const resp = await listChannels({
page, size, ...filter, auth_type, page, size, ...filter, auth_type,
}) })
console.log(resp, 'ip管理的respresprespresp')
if (!resp.success) { if (!resp.success) {
throw new Error(resp.message) throw new Error(resp.message)
@@ -83,33 +100,12 @@ export default function ChannelsPage(props: ChannelsPageProps) {
description: (e as Error).message, description: (e as Error).message,
}) })
} }
} }, [setStatus, filterForm])
useEffect(() => { useEffect(() => {
refresh(data.page, data.size).then() refresh(data.page, data.size).then()
}, []) }, [data.page, data.size, refresh])
// ======================
// filter
// ======================
const filterSchema = z.object({
auth_type: z.enum(['0', '1', '2']),
expired_status: z.enum(['all', 'active']).default('all'),
expire_after: z.date().optional(),
expire_before: z.date().optional(),
})
type FilterSchema = z.infer<typeof filterSchema>
const filterForm = useForm<FilterSchema>({
resolver: zodResolver(filterSchema),
defaultValues: {
auth_type: '0',
expired_status: 'all',
expire_after: undefined,
expire_before: undefined,
},
})
const filterHandler = filterForm.handleSubmit(async (value) => { const filterHandler = filterForm.handleSubmit(async (value) => {
await refresh(1, data.size) await refresh(1, data.size)
}) })

View File

@@ -50,6 +50,8 @@ export default function RecordPage(props: RecordPageProps) {
setStatus('load') setStatus('load')
// 获取筛选条件 // 获取筛选条件
const filter = filterForm.getValues() const filter = filterForm.getValues()
console.log(filter, 'filter')
const result = await extractRecord({ const result = await extractRecord({
page, page,
size, size,

View File

@@ -55,7 +55,6 @@ export default function WhitelistPage(props: WhitelistPageProps) {
setWait(true) setWait(true)
try { try {
const resp = await listWhitelist({page, size}) const resp = await listWhitelist({page, size})
console.log(resp, '白名单resp')
if (!resp.success) { if (!resp.success) {
throw new Error(resp.message) throw new Error(resp.message)

View File

@@ -337,10 +337,8 @@ function SelectResource() {
setStatus('load') setStatus('load')
try { try {
const resp = await allResource() const resp = await allResource()
console.log(resp, '套餐管理resprespresp')
if (!resp.success) { if (!resp.success) {
console.log(11111)
throw new Error('获取套餐失败,请稍后再试') throw new Error('获取套餐失败,请稍后再试')
} }
setResources(resp.data ?? []) setResources(resp.data ?? [])
@@ -543,16 +541,12 @@ function ApplyLink() {
const handler = form.handleSubmit( const handler = form.handleSubmit(
// eslint-disable-next-line react-hooks/refs // eslint-disable-next-line react-hooks/refs
async (values: z.infer<typeof schema>) => { async (values: z.infer<typeof schema>) => {
console.log(values, 'values')
const params = link(values) const params = link(values)
console.log(params, 'paramsparams')
switch (type.current) { switch (type.current) {
case 'copy': case 'copy':
const url = new URL(window.location.href).origin const url = new URL(window.location.href).origin
const text = `${url}${params}` const text = `${url}${params}`
console.log(text, 'text')
// 使用 clipboard API 复制链接 // 使用 clipboard API 复制链接
let copied = false let copied = false

View File

@@ -39,7 +39,6 @@ export function PaymentModal(props: PaymentModalProps) {
`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/trade/check?trade_no=${props.inner_no}&method=${props.method}`, `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/trade/check?trade_no=${props.inner_no}&method=${props.method}`,
) )
eventSource.onmessage = async (event) => { eventSource.onmessage = async (event) => {
console.log(event, 'eventeventevent')
switch (event.data) { switch (event.data) {
case '1': case '1':
props.onConfirm?.(true) props.onConfirm?.(true)

View File

@@ -52,7 +52,6 @@ export default function Right() {
} }
try { try {
const priceValue = await getPrice(params) const priceValue = await getPrice(params)
console.log(priceValue, 'priceValue')
if (priceValue.success && priceValue.data?.price) { if (priceValue.success && priceValue.data?.price) {
const data: PriceData = priceValue.data const data: PriceData = priceValue.data

View File

@@ -51,7 +51,6 @@ export default function Right() {
} }
try { try {
const priceResponse = await getPrice(params) const priceResponse = await getPrice(params)
console.log(priceResponse, 'priceResponse')
if (priceResponse.success && priceResponse.data) { if (priceResponse.success && priceResponse.data) {
const data: PriceData = priceResponse.data const data: PriceData = priceResponse.data

View File

@@ -6,6 +6,7 @@ import {DayPicker} from 'react-day-picker'
import {merge} from '@/lib/utils' import {merge} from '@/lib/utils'
import {buttonVariants} from '@/components/ui/button' import {buttonVariants} from '@/components/ui/button'
import {zhCN} from 'date-fns/locale'
function Calendar({ function Calendar({
className, className,
@@ -15,6 +16,7 @@ function Calendar({
}: React.ComponentProps<typeof DayPicker>) { }: React.ComponentProps<typeof DayPicker>) {
return ( return (
<DayPicker <DayPicker
locale={zhCN}
showOutsideDays={showOutsideDays} showOutsideDays={showOutsideDays}
className={merge('p-3', className)} className={merge('p-3', className)}
classNames={{ classNames={{