更新用户总览图表,删除多余的console.log
This commit is contained in:
@@ -5,9 +5,8 @@ import {callByUser} from './base'
|
||||
import {listAnnouncements} from './announcement'
|
||||
|
||||
type statisticsResourceUsageReq = {
|
||||
resource_no?: string
|
||||
create_after?: Date
|
||||
create_before?: Date
|
||||
time_start?: Date
|
||||
time_end?: Date
|
||||
}
|
||||
|
||||
type statisticsResourceUsageResp = {
|
||||
@@ -59,10 +58,7 @@ export async function listInitialization(): Promise<ApiResponse<listInitializati
|
||||
message: '公告数据获取失败',
|
||||
}
|
||||
}
|
||||
const usage = await statisticsResourceUsage({
|
||||
create_after: new Date(),
|
||||
create_before: new Date(),
|
||||
})
|
||||
const usage = await statisticsResourceUsage({})
|
||||
if (!usage.success) {
|
||||
return {
|
||||
success: false,
|
||||
|
||||
@@ -21,7 +21,6 @@ async function createWhitelist(props: {
|
||||
host: string
|
||||
remark?: string
|
||||
}) {
|
||||
console.log(props)
|
||||
return await callByUser('/api/whitelist/create', props)
|
||||
}
|
||||
|
||||
@@ -30,7 +29,6 @@ async function updateWhitelist(props: {
|
||||
host?: string
|
||||
remark?: string
|
||||
}) {
|
||||
console.log(props)
|
||||
return await callByUser('/api/whitelist/update', props)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
'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 {Card, CardContent} from '@/components/ui/card'
|
||||
import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card'
|
||||
import {Form, FormField} from '@/components/ui/form'
|
||||
import {Input} from '@/components/ui/input'
|
||||
import {zodResolver} from '@hookform/resolvers/zod'
|
||||
import {useForm} from 'react-hook-form'
|
||||
import zod from 'zod'
|
||||
import {merge} from '@/lib/utils'
|
||||
import {compareAsc, format, addDays} from 'date-fns'
|
||||
import {Button} from '@/components/ui/button'
|
||||
import {useState} from 'react'
|
||||
import {statisticsResourceUsage} from '@/actions/dashboard'
|
||||
import {ExtraResp} from '@/lib/api'
|
||||
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 {CartesianGrid, XAxis, YAxis, Tooltip, Area, AreaChart, Legend} from 'recharts'
|
||||
import mask from '../_assets/Mask group.webp'
|
||||
import Image from 'next/image'
|
||||
|
||||
type ChartsProps = {
|
||||
initialData?: ExtraResp<typeof statisticsResourceUsage>
|
||||
@@ -27,38 +23,38 @@ type ChartsProps = {
|
||||
export default function Charts({initialData}: ChartsProps) {
|
||||
// const [submittedData, setSubmittedData] = useState<ExtraReq<typeof listAccount>>()
|
||||
const [submittedData, setSubmittedData] = useState<ExtraResp<typeof statisticsResourceUsage>>(initialData || [])
|
||||
const formSchema = zod.object({
|
||||
resource_no: zod.string().optional(),
|
||||
create_after: zod.date().optional(),
|
||||
create_before: zod.date().optional(),
|
||||
const filterSchema = zod.object({
|
||||
time_start: zod.date().optional(),
|
||||
time_end: zod.date().optional(),
|
||||
})
|
||||
type FormValues = zod.infer<typeof formSchema>
|
||||
type FilterSchema = zod.infer<typeof filterSchema>
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
const filterForm = useForm<FilterSchema>({
|
||||
resolver: zodResolver(filterSchema),
|
||||
defaultValues: {
|
||||
time_start: undefined,
|
||||
time_end: undefined,
|
||||
},
|
||||
})
|
||||
const handler = form.handleSubmit(
|
||||
async (value) => {
|
||||
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 handler = filterForm.handleSubmit(async () => {
|
||||
const {time_start, time_end} = filterForm.getValues()
|
||||
|
||||
const resp = await statisticsResourceUsage(res)
|
||||
if (!resp.success) {
|
||||
toast.error('接口请求失败:' + resp.message)
|
||||
return
|
||||
}
|
||||
if (!resp.data || resp.data.length === 0) {
|
||||
toast.info('没有查询到相关数据')
|
||||
setSubmittedData([])
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
time_start: time_start,
|
||||
time_end: time_end ? addDays(time_end, 1) : undefined,
|
||||
}
|
||||
const resp = await statisticsResourceUsage(params)
|
||||
if (!resp.success) {
|
||||
toast.error('接口请求失败:' + resp.message)
|
||||
return
|
||||
}
|
||||
|
||||
if (!resp.data || resp.data.length === 0) {
|
||||
toast.info('没有查询到相关数据')
|
||||
setSubmittedData([])
|
||||
return
|
||||
}
|
||||
if (resp.success && resp.data) {
|
||||
const formattedData = resp.data.map(item => ({
|
||||
...item,
|
||||
date: item.date,
|
||||
@@ -66,61 +62,60 @@ export default function Charts({initialData}: ChartsProps) {
|
||||
}))
|
||||
formattedData.sort((a, b) => compareAsc(a.date, b.date))
|
||||
setSubmittedData(formattedData)
|
||||
},
|
||||
)
|
||||
}
|
||||
else {
|
||||
throw new Error('获取数据失败')
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Card className="h-full">
|
||||
<CardContent className="overflow-hidden">
|
||||
<Tabs defaultValue="dynamic" className="h-full gap-4">
|
||||
<TabsList className="h-9">
|
||||
<TabsTrigger value="dynamic" className="data-[state=active]:text-primary">
|
||||
短效动态
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="static" className="data-[state=active]:text-primary">
|
||||
长效动态
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<Form<FormValues> className={merge(`flex items-end gap-4 flex-wrap`)} handler={handler} form={form} >
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-sm">时间范围筛选</Label>
|
||||
<div className="flex items-center">
|
||||
<FormField name="create_after">
|
||||
{({field}) => (
|
||||
<DatePicker
|
||||
{...field}
|
||||
className="w-36"
|
||||
placeholder="开始时间"
|
||||
format="yyyy-MM-dd"
|
||||
/>
|
||||
)}
|
||||
</FormField>
|
||||
<span className="px-1">-</span>
|
||||
<FormField name="create_before">
|
||||
{({field}) => (
|
||||
<DatePicker
|
||||
{...field}
|
||||
className="w-36"
|
||||
placeholder="结束时间"
|
||||
format="yyyy-MM-dd"
|
||||
/>
|
||||
)}
|
||||
</FormField>
|
||||
</div>
|
||||
<CardContent className="overflow-hidden flex flex-col">
|
||||
<CardHeader className="flex-none">
|
||||
<CardTitle>
|
||||
<Image src={mask} alt="Mask group" priority/>
|
||||
每日动态套餐
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<Form form={filterForm} handler={handler} className="flex-none flex flex-wrap justify-end mb-4 gap-4">
|
||||
<fieldset className="flex flex-col gap-2 items-start">
|
||||
<div className="flex gap-1 items-center">
|
||||
<FormField<FilterSchema, 'time_start'> name="time_start">
|
||||
{({field}) => (
|
||||
<DatePicker
|
||||
placeholder="选择开始时间"
|
||||
{...field}
|
||||
format="yyyy-MM-dd"
|
||||
/>
|
||||
)}
|
||||
</FormField>
|
||||
<span>-</span>
|
||||
<FormField<FilterSchema, 'time_end'> name="time_end">
|
||||
{({field}) => (
|
||||
<DatePicker
|
||||
placeholder="选择结束时间"
|
||||
{...field}
|
||||
format="yyyy-MM-dd"
|
||||
/>
|
||||
)}
|
||||
</FormField>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Button className="h-9" type="submit">
|
||||
<span>查询</span>
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
<TabsContent value="dynamic" className="overflow-hidden">
|
||||
{submittedData && <DashboardChart data={submittedData}/>}
|
||||
</TabsContent>
|
||||
<TabsContent value="static" className="flex flex-col items-center justify-center gap-2">
|
||||
<LongChart/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</fieldset>
|
||||
<Button className="h-9" type="submit">查询</Button>
|
||||
<Button
|
||||
theme="outline"
|
||||
className="h-9"
|
||||
onClick={() => {
|
||||
filterForm.reset({
|
||||
time_start: undefined,
|
||||
time_end: undefined,
|
||||
})
|
||||
handler()
|
||||
}}>
|
||||
重置
|
||||
</Button>
|
||||
</Form>
|
||||
{submittedData && <DashboardChart data={submittedData}/>}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
@@ -151,7 +146,7 @@ function DashboardChart(props: DashboardChartProps) {
|
||||
}
|
||||
})
|
||||
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}}>
|
||||
<CartesianGrid vertical={false}/>
|
||||
<XAxis
|
||||
@@ -178,33 +173,3 @@ function DashboardChart(props: DashboardChartProps) {
|
||||
</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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ export default function BillsPage(props: BillsPageProps) {
|
||||
})
|
||||
|
||||
const onSubmit = async (value: FilterSchema) => {
|
||||
console.log(value)
|
||||
await refresh(1, data.size)
|
||||
}
|
||||
|
||||
@@ -65,7 +64,6 @@ export default function BillsPage(props: BillsPageProps) {
|
||||
const res = await listBills({
|
||||
page, size, type, create_after, create_before, trade_id,
|
||||
})
|
||||
console.log(res, 'res')
|
||||
|
||||
if (res.success) {
|
||||
setData(res.data)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {useCallback, useEffect, useState} from 'react'
|
||||
import {useStatus} from '@/lib/states'
|
||||
import {PageRecord} from '@/lib/api'
|
||||
import {Channel} from '@/lib/models'
|
||||
@@ -31,14 +31,32 @@ export default function ChannelsPage(props: ChannelsPageProps) {
|
||||
total: 0,
|
||||
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 date = typeof expiredAt === 'string' ? new Date(expiredAt) : expiredAt
|
||||
return isBefore(date, new Date())
|
||||
}
|
||||
|
||||
const refresh = async (page: number, size: number) => {
|
||||
const refresh = useCallback(async (page: number, size: number) => {
|
||||
try {
|
||||
setStatus('load')
|
||||
|
||||
@@ -54,7 +72,6 @@ export default function ChannelsPage(props: ChannelsPageProps) {
|
||||
const resp = await listChannels({
|
||||
page, size, ...filter, auth_type,
|
||||
})
|
||||
console.log(resp, 'ip管理的respresprespresp')
|
||||
|
||||
if (!resp.success) {
|
||||
throw new Error(resp.message)
|
||||
@@ -83,33 +100,12 @@ export default function ChannelsPage(props: ChannelsPageProps) {
|
||||
description: (e as Error).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [setStatus, filterForm])
|
||||
|
||||
useEffect(() => {
|
||||
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) => {
|
||||
await refresh(1, data.size)
|
||||
})
|
||||
|
||||
@@ -50,6 +50,8 @@ export default function RecordPage(props: RecordPageProps) {
|
||||
setStatus('load')
|
||||
// 获取筛选条件
|
||||
const filter = filterForm.getValues()
|
||||
console.log(filter, 'filter')
|
||||
|
||||
const result = await extractRecord({
|
||||
page,
|
||||
size,
|
||||
|
||||
@@ -55,7 +55,6 @@ export default function WhitelistPage(props: WhitelistPageProps) {
|
||||
setWait(true)
|
||||
try {
|
||||
const resp = await listWhitelist({page, size})
|
||||
console.log(resp, '白名单resp')
|
||||
|
||||
if (!resp.success) {
|
||||
throw new Error(resp.message)
|
||||
|
||||
@@ -337,10 +337,8 @@ function SelectResource() {
|
||||
setStatus('load')
|
||||
try {
|
||||
const resp = await allResource()
|
||||
console.log(resp, '套餐管理resprespresp')
|
||||
|
||||
if (!resp.success) {
|
||||
console.log(11111)
|
||||
throw new Error('获取套餐失败,请稍后再试')
|
||||
}
|
||||
setResources(resp.data ?? [])
|
||||
@@ -543,16 +541,12 @@ function ApplyLink() {
|
||||
const handler = form.handleSubmit(
|
||||
// eslint-disable-next-line react-hooks/refs
|
||||
async (values: z.infer<typeof schema>) => {
|
||||
console.log(values, 'values')
|
||||
|
||||
const params = link(values)
|
||||
console.log(params, 'paramsparams')
|
||||
|
||||
switch (type.current) {
|
||||
case 'copy':
|
||||
const url = new URL(window.location.href).origin
|
||||
const text = `${url}${params}`
|
||||
console.log(text, 'text')
|
||||
|
||||
// 使用 clipboard API 复制链接
|
||||
let copied = false
|
||||
|
||||
@@ -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}`,
|
||||
)
|
||||
eventSource.onmessage = async (event) => {
|
||||
console.log(event, 'eventeventevent')
|
||||
switch (event.data) {
|
||||
case '1':
|
||||
props.onConfirm?.(true)
|
||||
|
||||
@@ -52,7 +52,6 @@ export default function Right() {
|
||||
}
|
||||
try {
|
||||
const priceValue = await getPrice(params)
|
||||
console.log(priceValue, 'priceValue')
|
||||
|
||||
if (priceValue.success && priceValue.data?.price) {
|
||||
const data: PriceData = priceValue.data
|
||||
|
||||
@@ -51,7 +51,6 @@ export default function Right() {
|
||||
}
|
||||
try {
|
||||
const priceResponse = await getPrice(params)
|
||||
console.log(priceResponse, 'priceResponse')
|
||||
|
||||
if (priceResponse.success && priceResponse.data) {
|
||||
const data: PriceData = priceResponse.data
|
||||
|
||||
@@ -6,6 +6,7 @@ import {DayPicker} from 'react-day-picker'
|
||||
|
||||
import {merge} from '@/lib/utils'
|
||||
import {buttonVariants} from '@/components/ui/button'
|
||||
import {zhCN} from 'date-fns/locale'
|
||||
|
||||
function Calendar({
|
||||
className,
|
||||
@@ -15,6 +16,7 @@ function Calendar({
|
||||
}: React.ComponentProps<typeof DayPicker>) {
|
||||
return (
|
||||
<DayPicker
|
||||
locale={zhCN}
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={merge('p-3', className)}
|
||||
classNames={{
|
||||
|
||||
Reference in New Issue
Block a user