From 054b8954c464f296d0e867a199c79b6226bfbf9e Mon Sep 17 00:00:00 2001 From: Eamon <17516219072@163.com> Date: Mon, 5 Jan 2026 09:14:41 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=88=97=E8=A1=A8=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=92=8C=E6=9E=9A=E4=B8=BE=E5=80=BC=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .npmrc | 1 + Dockerfile | 42 ++++++ src/actions/batch.ts | 4 +- src/actions/bill.ts | 4 +- src/actions/channel.ts | 4 +- src/actions/resources.ts | 12 +- src/actions/trade.ts | 4 +- src/app/(root)/(dashboard)/page.tsx | 8 +- src/app/(root)/appbar.tsx | 189 +++++++------------------- src/app/(root)/batch/page.tsx | 26 ++-- src/app/(root)/billing/page.tsx | 89 ++++++++++-- src/app/(root)/channel/page.tsx | 103 +++++++++++--- src/app/(root)/proxy/sources/page.tsx | 10 +- src/app/(root)/resources/page.tsx | 9 +- src/app/(root)/trade/page.tsx | 122 +++++++++++++++-- src/app/(root)/user/page.tsx | 67 ++++++++- src/components/ui/badge.tsx | 46 +++++++ src/lib/utils.ts | 2 +- src/models/batch.ts | 11 ++ src/models/billing.ts | 7 + src/models/channel.ts | 15 ++ src/models/resources.ts | 8 ++ src/models/trade.ts | 10 ++ 23 files changed, 571 insertions(+), 222 deletions(-) create mode 100644 .npmrc create mode 100644 Dockerfile create mode 100644 src/components/ui/badge.tsx create mode 100644 src/models/batch.ts create mode 100644 src/models/billing.ts create mode 100644 src/models/channel.ts create mode 100644 src/models/resources.ts create mode 100644 src/models/trade.ts diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..7549542 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmmirror.com diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..df2df4e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +FROM oven/bun:1.3.2-alpine AS base + +# 依赖缓存阶段 +FROM base AS deps +WORKDIR /app + +COPY package.json bun.lock .npmrc ./ +RUN bun install --frozen-lockfile + +# 构建阶段 +FROM base AS builder +WORKDIR /app + +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN bun run build + +# 生产阶段 +FROM base AS runner +WORKDIR /app + +ENV NEXT_TELEMETRY_DISABLED=1 +ENV NODE_ENV=production + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["bun", "server.js"] diff --git a/src/actions/batch.ts b/src/actions/batch.ts index f0c9808..2399fee 100644 --- a/src/actions/batch.ts +++ b/src/actions/batch.ts @@ -1,7 +1,7 @@ import type { PageRecord } from "@/lib/api" -import type { User } from "@/models/user" +import type { Batch } from "@/models/batch" import { callByUser } from "./base" export async function getPageBatch(params: { page: number; size: number }) { - return callByUser>("/api/admin/batch/page", params) + return callByUser>("/api/admin/batch/page", params) } diff --git a/src/actions/bill.ts b/src/actions/bill.ts index 78e4487..f845bef 100644 --- a/src/actions/bill.ts +++ b/src/actions/bill.ts @@ -1,7 +1,7 @@ import type { PageRecord } from "@/lib/api" -import type { User } from "@/models/user" +import type { Billing } from "@/models/billing" import { callByUser } from "./base" export async function getPageBill(params: { page: number; size: number }) { - return callByUser>("/api/admin/bill/page", params) + return callByUser>("/api/admin/bill/page", params) } diff --git a/src/actions/channel.ts b/src/actions/channel.ts index 913b89a..bfedf9d 100644 --- a/src/actions/channel.ts +++ b/src/actions/channel.ts @@ -1,7 +1,7 @@ import type { PageRecord } from "@/lib/api" -import type { User } from "@/models/user" +import type { Channel } from "@/models/channel" import { callByUser } from "./base" export async function getPageChannel(params: { page: number; size: number }) { - return callByUser>("/api/admin/channel/page", params) + return callByUser>("/api/admin/channel/page", params) } diff --git a/src/actions/resources.ts b/src/actions/resources.ts index 4f68d68..1d9c0b7 100644 --- a/src/actions/resources.ts +++ b/src/actions/resources.ts @@ -1,14 +1,20 @@ import type { PageRecord } from "@/lib/api" -import type { User } from "@/models/user" +import type { Resources } from "@/models/resources" import { callByUser } from "./base" export async function listResourceLong(params: { page: number; size: number }) { - return callByUser>("/api/admin/resource/long/page", params) + return callByUser>( + "/api/admin/resource/long/page", + params, + ) } export async function listResourceShort(params: { page: number size: number }) { - return callByUser>("/api/admin/resource/short/page", params) + return callByUser>( + "/api/admin/resource/short/page", + params, + ) } diff --git a/src/actions/trade.ts b/src/actions/trade.ts index 5ab8ba9..5a8f59c 100644 --- a/src/actions/trade.ts +++ b/src/actions/trade.ts @@ -1,7 +1,7 @@ import type { PageRecord } from "@/lib/api" -import type { User } from "@/models/user" +import type { Trade } from "@/models/trade" import { callByUser } from "./base" export async function getPageTrade(params: { page: number; size: number }) { - return callByUser>("/api/admin/trade/page", params) + return callByUser>("/api/admin/trade/page", params) } diff --git a/src/app/(root)/(dashboard)/page.tsx b/src/app/(root)/(dashboard)/page.tsx index f3714fd..9ca7586 100644 --- a/src/app/(root)/(dashboard)/page.tsx +++ b/src/app/(root)/(dashboard)/page.tsx @@ -12,9 +12,7 @@ export default function DashboardPage(props: DashboardPageProps) {

IP代理管理控制台

-

- 上次更新: {new Date().toLocaleString("zh-CN")} -

+

上次更新: -

+ {/* 通知下拉面板 */} {showNotifications && (

通知

- +
@@ -216,19 +203,7 @@ export default function Appbar() { )) ) : (
- - - +

暂无通知

)} @@ -251,9 +226,9 @@ export default function Appbar() { {/* 用户下拉菜单 */}
- + + {/* 用户下拉内容 */} {showDropdown && ( @@ -303,64 +266,22 @@ export default function Appbar() { href="/profile" className="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" > - - - - 个人资料 + + 个人资料 - - - - - 账号设置 + + 账号设置 - - - - 帮助中心 + + 帮助中心
@@ -369,20 +290,8 @@ export default function Appbar() { href="/login" className="flex items-center px-4 py-2 text-sm text-red-600 hover:bg-gray-100" > - - - - 退出登录 + + 退出登录
diff --git a/src/app/(root)/batch/page.tsx b/src/app/(root)/batch/page.tsx index ff54a6e..8e12496 100644 --- a/src/app/(root)/batch/page.tsx +++ b/src/app/(root)/batch/page.tsx @@ -1,27 +1,35 @@ "use client" +import { format } from "date-fns" import { Suspense } from "react" import { getPageBatch } from "@/actions/batch" import { DataTable, useDataTable } from "@/components/data-table" -import type { User } from "@/models/user" +import type { Batch } from "@/models/batch" -export default function UserPage() { - const table = useDataTable((page, size) => getPageBatch({ page, size })) +export default function BatchPage() { + const table = useDataTable((page, size) => + getPageBatch({ page, size }), + ) console.log(table, "table") return ( - - + Loading...
}> + {...table} columns={[ { header: "ID", accessorKey: "id" }, { header: "批次号", accessorKey: "batch_no" }, - { header: "城市", accessorKey: "city" }, { header: "省份", accessorKey: "prov" }, - { header: "数量", accessorKey: "count" }, + { header: "城市", accessorKey: "city" }, { header: "提取IP", accessorKey: "ip" }, { header: "运营商", accessorKey: "isp" }, - { header: "可用资源", accessorKey: "resource_id" }, - { header: "时间", accessorKey: "time" }, + { header: "提取数量", accessorKey: "count" }, + { header: "资源数量", accessorKey: "resource_id" }, + { + header: "提取时间", + accessorKey: "time", + cell: ({ row }) => + format(new Date(row.original.time), "yyyy-MM-dd HH:mm"), + }, ]} /> diff --git a/src/app/(root)/billing/page.tsx b/src/app/(root)/billing/page.tsx index 99e8588..da79d3b 100644 --- a/src/app/(root)/billing/page.tsx +++ b/src/app/(root)/billing/page.tsx @@ -1,26 +1,95 @@ "use client" +import { format } from "date-fns" +import { CreditCard } from "lucide-react" import { Suspense } from "react" import { getPageBill } from "@/actions/bill" import { DataTable, useDataTable } from "@/components/data-table" -import type { User } from "@/models/user" +import type { Billing } from "@/models/billing" -export default function UserPage() { - const table = useDataTable((page, size) => getPageBill({ page, size })) +export default function BillingPage() { + const table = useDataTable((page, size) => + getPageBill({ page, size }), + ) console.log(table, "table") return ( - + {...table} columns={[ { header: "ID", accessorKey: "id" }, { header: "账单号", accessorKey: "bill_no" }, - { header: "信息", accessorKey: "info" }, - { header: "金额", accessorKey: "amount" }, - { header: "可用资源", accessorKey: "resource_id" }, - { header: "类型", accessorKey: "type" }, - { header: "创建时间", accessorKey: "created_at" }, - { header: "更新时间", accessorKey: "updated_at" }, + { + header: "账单详情", + accessorKey: "info", + cell: ({ row }) => { + const bill = row.original + console.log(bill, "bill") + + return ( +
+ {/* 类型展示 */} +
+ {bill.type === 1 && ( +
+ + 消费 +
+ )} + {bill.type === 2 && ( +
+ + 退款 +
+ )} + {bill.type === 3 && ( +
+ + 充值 +
+ )} +
+ + {/* 账单详情 */} +
{bill.info}
+
+ ) + }, + }, + { + header: "支付信息", + accessorKey: "amount", + cell: ({ row }) => { + const amount = + typeof row.original.amount === "string" + ? parseFloat(row.original.amount) + : row.original.amount || 0 + return ( +
+ 0 ? "text-green-500" : "text-orange-500" + } + > + ¥{amount.toFixed(2)} + +
+ ) + }, + }, + // { header: "资源数量", accessorKey: "resource_id" }, + { + header: "创建时间", + accessorKey: "created_at", + cell: ({ row }) => + format(new Date(row.original.created_at), "yyyy-MM-dd HH:mm"), + }, + { + header: "更新时间", + accessorKey: "updated_at", + cell: ({ row }) => + format(new Date(row.original.updated_at), "yyyy-MM-dd HH:mm"), + }, ]} />
diff --git a/src/app/(root)/channel/page.tsx b/src/app/(root)/channel/page.tsx index 0cd1cb3..986222c 100644 --- a/src/app/(root)/channel/page.tsx +++ b/src/app/(root)/channel/page.tsx @@ -1,35 +1,106 @@ "use client" +import { format } from "date-fns" import { Suspense } from "react" import { getPageChannel } from "@/actions/channel" import { DataTable, useDataTable } from "@/components/data-table" -import type { User } from "@/models/user" +import { Badge } from "@/components/ui/badge" +import type { Channel } from "@/models/channel" -export default function UserPage() { - const table = useDataTable((page, size) => +export default function ChannelPage() { + const table = useDataTable((page, size) => getPageChannel({ page, size }), ) - console.log(table, "table") return ( - + {...table} columns={[ { header: "ID", accessorKey: "id" }, { header: "批次号", accessorKey: "batch_no" }, - { header: "边缘节点", accessorKey: "edge_ref" }, { header: "省份", accessorKey: "filter_prov" }, { header: "城市", accessorKey: "filter_city" }, - { header: "运营商", accessorKey: "filter_isp" }, - { header: "主机", accessorKey: "host" }, - { header: "端口", accessorKey: "port" }, - { header: "密码", accessorKey: "password" }, - { header: "代理号", accessorKey: "proxy_id" }, - { header: "可用资源", accessorKey: "resource_id" }, - { header: "用户名", accessorKey: "username" }, - { header: "创建时间", accessorKey: "created_at" }, - { header: "更新时间", accessorKey: "updated_at" }, - { header: "过期时间", accessorKey: "expired_at" }, + { + header: "运营商", + accessorKey: "filter_isp", + cell: ({ row }) => { + const value = row.getValue("filter_isp") + if (!value || value === "all") return "不限" + if (value === 1) return "电信" + if (value === 2) return "联通" + if (value === 3) return "移动" + return String(value) + }, + }, + { + header: "代理地址", + accessorKey: "host", + cell: ({ row }) => { + const ip = row.original.host + const port = row.original.port + return ( + + {ip}:{port}{" "} + + ) + }, + }, + { + header: "认证方式", + cell: ({ row }) => { + const channel = row.original + console.log(channel, "channel") + + const hasWhitelist = + channel.whitelists && channel.whitelists.trim() !== "" + const hasAuth = channel.username && channel.password + + return ( +
+ {hasWhitelist ? ( +
+ 白名单 +
+ {channel.whitelists.split(",").map(ip => ( + + {ip.trim()} + + ))} +
+
+ ) : hasAuth ? ( +
+ 账号密码 + + {channel.username}:{channel.password} + +
+ ) : ( + 无认证 + )} +
+ ) + }, + }, + { header: "资源数量", accessorKey: "resource_id" }, + { + header: "创建时间", + accessorKey: "created_at", + cell: ({ row }) => + format(new Date(row.original.created_at), "yyyy-MM-dd HH:mm"), + }, + { + header: "更新时间", + accessorKey: "updated_at", + cell: ({ row }) => + format(new Date(row.original.updated_at), "yyyy-MM-dd HH:mm"), + }, + { + header: "过期时间", + accessorKey: "expired_at", + cell: ({ row }) => + format(new Date(row.original.expired_at), "yyyy-MM-dd HH:mm"), + }, ]} />
diff --git a/src/app/(root)/proxy/sources/page.tsx b/src/app/(root)/proxy/sources/page.tsx index ebec3d3..ad017a7 100644 --- a/src/app/(root)/proxy/sources/page.tsx +++ b/src/app/(root)/proxy/sources/page.tsx @@ -1,11 +1,5 @@ -import {ReactNode} from 'react' - -export type ProxySourcesPageProps = { - -} +export type ProxySourcesPageProps = {} export default function ProxySourcesPage(props: ProxySourcesPageProps) { - return ( - - ) + return
} diff --git a/src/app/(root)/resources/page.tsx b/src/app/(root)/resources/page.tsx index 2f66396..bde978c 100644 --- a/src/app/(root)/resources/page.tsx +++ b/src/app/(root)/resources/page.tsx @@ -3,9 +3,9 @@ import { Suspense } from "react" import { listResourceLong, listResourceShort } from "@/actions/resources" import { DataTable, useDataTable } from "@/components/data-table" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" -import type { User } from "@/models/user" +import type { Resources } from "@/models/resources" -export default function UserPage() { +export default function ResourcesPage() { return (
@@ -41,12 +41,11 @@ interface ResourceListProps { function ResourceList({ resourceType }: ResourceListProps) { const isLong = resourceType === "long" const listFn = isLong ? listResourceLong : listResourceShort - const table = useDataTable((page, size) => listFn({ page, size })) - console.log(table, "table") + const table = useDataTable((page, size) => listFn({ page, size })) return ( - + {...table} columns={[ { header: "ID", accessorKey: "id" }, diff --git a/src/app/(root)/trade/page.tsx b/src/app/(root)/trade/page.tsx index ec5be74..84e0e82 100644 --- a/src/app/(root)/trade/page.tsx +++ b/src/app/(root)/trade/page.tsx @@ -1,30 +1,128 @@ "use client" +import { format } from "date-fns" +import { CheckCircle, Clock, XCircle } from "lucide-react" import { Suspense } from "react" import { getPageTrade } from "@/actions/trade" import { DataTable, useDataTable } from "@/components/data-table" -import type { User } from "@/models/user" +import type { Trade } from "@/models/trade" -export default function UserPage() { - const table = useDataTable((page, size) => getPageTrade({ page, size })) +export default function TradePage() { + const table = useDataTable((page, size) => + getPageTrade({ page, size }), + ) console.log(table, "table") return ( - + {...table} columns={[ { header: "ID", accessorKey: "id" }, { header: "套餐号", accessorKey: "inner_no" }, - { header: "支付方式", accessorKey: "method" }, - { header: "支付金额", accessorKey: "payment" }, - { header: "支付平台", accessorKey: "platform" }, - { header: "已退款", accessorKey: "refunded" }, - { header: "支付状态", accessorKey: "status" }, + { + header: "支付方式", + accessorKey: "method", + cell: ({ row }) => { + const methodMap: Record = { + 1: "支付宝", + 2: "微信", + 3: "其他", + 4: "支付宝", + 5: "微信", + } + return ( +
{methodMap[row.original.method as number] || "未知"}
+ ) + }, + }, + { + header: "支付金额", + accessorKey: "payment", + cell: ({ row }) => { + const payment = + typeof row.original.payment === "string" + ? parseFloat(row.original.payment) + : row.original.payment || 0 + return ( +
+ 0 ? "text-green-500" : "text-orange-500" + } + > + ¥{payment.toFixed(2)} + +
+ ) + }, + }, + { + header: "支付平台", + accessorKey: "platform", + cell: ({ row }) => { + const platform = row.original.platform + if (!platform) return - + return ( +
+ {platform === 1 ? ( + 电脑网站 + ) : platform === 2 ? ( + 手机网站 + ) : ( + - + )} +
+ ) + }, + }, + // { header: "已退款", accessorKey: "refunded" }, + { + header: "支付状态", + accessorKey: "status", + cell: ({ row }) => { + const status = row.original.status + + switch (status) { + case 0: + return ( +
+ + 待支付 +
+ ) + case 1: + return ( +
+ + 支付成功 +
+ ) + case 2: + return ( +
+ + 取消支付 +
+ ) + default: + return - + } + }, + }, { header: "购买套餐", accessorKey: "subject" }, { header: "类型", accessorKey: "type" }, - { header: "创建时间", accessorKey: "created_at" }, - { header: "更新时间", accessorKey: "updated_at" }, - { header: "过期时间", accessorKey: "canceled_at" }, + { + header: "创建时间", + accessorKey: "created_at", + cell: ({ row }) => + format(new Date(row.original.created_at), "yyyy-MM-dd HH:mm"), + }, + { + header: "更新时间", + accessorKey: "updated_at", + cell: ({ row }) => + format(new Date(row.original.updated_at), "yyyy-MM-dd HH:mm"), + }, ]} />
diff --git a/src/app/(root)/user/page.tsx b/src/app/(root)/user/page.tsx index a6cf0f2..7871717 100644 --- a/src/app/(root)/user/page.tsx +++ b/src/app/(root)/user/page.tsx @@ -1,7 +1,9 @@ "use client" +import { format } from "date-fns" import { Suspense } from "react" import { bindAdmin, getPageUsers } from "@/actions/user" import { DataTable, useDataTable } from "@/components/data-table" +import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { useFetch } from "@/hooks/data" import type { User } from "@/models/user" @@ -22,13 +24,68 @@ export default function UserPage() { { header: "手机", accessorKey: "phone" }, { header: "邮箱", accessorKey: "email" }, { header: "姓名", accessorKey: "name" }, - { header: "余额", accessorKey: "balance" }, - { header: "认证状态", accessorKey: "id_type" }, - { header: "账号状态", accessorKey: "status" }, + { + header: "余额", + accessorKey: "balance", + cell: ({ row }) => { + const balance = + typeof row.original.balance === "string" + ? parseFloat(row.original.balance) + : row.original.balance || 0 + return ( +
+ 0 ? "text-green-500" : "text-orange-500" + } + > + ¥{balance.toFixed(2)} + +
+ ) + }, + }, + { + header: "认证状态", + accessorKey: "id_type", + cell: ({ row }) => { + const status = row.original.id_type + return ( + + {status === 1 ? "已认证" : "未认证"} + + ) + }, + }, + { + header: "账号状态", + accessorKey: "status", + cell: ({ row }) => { + const status = row.original.status + return status === 1 ? "正常" : "" + }, + }, { header: "联系方式", accessorKey: "contact_wechat" }, { header: "管理员", accessorKey: "admin_id" }, - { header: "最后登录时间", accessorKey: "last_login" }, - { header: "创建时间", accessorKey: "created_at" }, + { + header: "最后登录时间", + accessorKey: "last_login", + cell: ({ row }) => + format(new Date(row.original.last_login), "yyyy-MM-dd HH:mm"), + }, + { + header: "创建时间", + accessorKey: "created_at", + cell: ({ row }) => + format(new Date(row.original.created_at), "yyyy-MM-dd HH:mm"), + }, { header: "操作", cell: ctx => ( diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 0000000..fd3a406 --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index bd0c391..d084cca 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,4 +1,4 @@ -import { clsx, type ClassValue } from "clsx" +import { type ClassValue, clsx } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { diff --git a/src/models/batch.ts b/src/models/batch.ts new file mode 100644 index 0000000..0bcbe39 --- /dev/null +++ b/src/models/batch.ts @@ -0,0 +1,11 @@ +export type Batch = { + id: number + batch_no: string + prov: string + city: string + ip: string + isp: string + count: string + resource_id: string + time: string +} diff --git a/src/models/billing.ts b/src/models/billing.ts new file mode 100644 index 0000000..1b5227e --- /dev/null +++ b/src/models/billing.ts @@ -0,0 +1,7 @@ +export type Billing = { + type: number + info: string + amount: number + created_at: Date + updated_at: Date +} diff --git a/src/models/channel.ts b/src/models/channel.ts new file mode 100644 index 0000000..a114922 --- /dev/null +++ b/src/models/channel.ts @@ -0,0 +1,15 @@ +export type Channel = { + id: number + batch_no: string + filter_prov: string + filter_city: string + filter_isp: string + host: string + port: string + whitelists: string + username: string + password: string + created_at: Date + updated_at: Date + expired_at: Date +} diff --git a/src/models/resources.ts b/src/models/resources.ts new file mode 100644 index 0000000..d499537 --- /dev/null +++ b/src/models/resources.ts @@ -0,0 +1,8 @@ +export type Resources = { + id: number + resource_no: string + active: string + type: string + created_at: Date + updated_at: Date +} diff --git a/src/models/trade.ts b/src/models/trade.ts new file mode 100644 index 0000000..dc46990 --- /dev/null +++ b/src/models/trade.ts @@ -0,0 +1,10 @@ +export type Trade = { + id: number + inner_no: string + method: number + payment: string + platform: number + status: number + created_at: Date + updated_at: Date +}