完善优惠券发放功能
This commit is contained in:
@@ -56,3 +56,7 @@ export async function getUserCoupon(data: {
|
||||
data,
|
||||
)
|
||||
}
|
||||
|
||||
export async function getCouponList(data: { page: number; size: number }) {
|
||||
return callByUser<PageRecord<Coupon>>("/api/admin/coupon-user/page ", data)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
Shield,
|
||||
ShoppingBag,
|
||||
SquarePercent,
|
||||
TicketCheck,
|
||||
TicketPercent,
|
||||
Users,
|
||||
} from "lucide-react"
|
||||
@@ -228,6 +229,11 @@ const menuSections: { title: string; items: NavItemProps[] }[] = [
|
||||
label: "优惠券",
|
||||
requiredScope: ScopeCouponRead,
|
||||
},
|
||||
{
|
||||
href: "/couponList",
|
||||
icon: TicketCheck,
|
||||
label: "已发放优惠券",
|
||||
},
|
||||
{
|
||||
href: "/resources",
|
||||
icon: Package,
|
||||
|
||||
@@ -81,6 +81,7 @@ export default function Appbar(props: { admin: Admin }) {
|
||||
statistics: "数据统计",
|
||||
balance: "余额明细",
|
||||
gateway: "网关列表",
|
||||
couponList: "已发放优惠券",
|
||||
}
|
||||
|
||||
return labels[path] || path
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
"use client"
|
||||
import { useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { getPagCoupon } from "@/actions/coupon"
|
||||
import { DataTable, useDataTable } from "@/components/data-table"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import type { Coupon } from "@/models/coupon"
|
||||
|
||||
export function IssueCouponForUser(props: {
|
||||
userId: number
|
||||
userPhone: string
|
||||
onSuccess?: () => void
|
||||
}) {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const table = useDataTable<Coupon>((page, size) =>
|
||||
getPagCoupon({ page, size }),
|
||||
)
|
||||
|
||||
const handleIssue = async (coupon: Coupon) => {
|
||||
// try {
|
||||
// const result = await issueCouponToUser({
|
||||
// user_id: props.userId,
|
||||
// coupon_id: coupon.id,
|
||||
// coupon_name: coupon.name,
|
||||
// })
|
||||
// if (result.success) {
|
||||
// toast.success(`成功发放「${coupon.name}」给用户 ${props.userPhone}`)
|
||||
// props.onSuccess?.()
|
||||
// setOpen(false)
|
||||
// } else {
|
||||
// toast.error(result.message || "发放失败")
|
||||
// }
|
||||
// } catch (error) {
|
||||
// const message = error instanceof Error ? error.message : "发放失败"
|
||||
// toast.error(`发放优惠券失败: ${message}`)
|
||||
// }
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={newOpen => {
|
||||
setOpen(newOpen)
|
||||
if (newOpen) {
|
||||
table.refresh()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button>发放优惠券</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent
|
||||
className="max-h-[85vh] overflow-y-auto"
|
||||
style={{ width: "auto", minWidth: "800px", maxWidth: "90vw" }}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle>发放优惠券给 {props.userPhone}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<DataTable<Coupon>
|
||||
{...table}
|
||||
columns={[
|
||||
{ header: "优惠券名称", accessorKey: "name" },
|
||||
{ header: "优惠券金额", accessorKey: "amount" },
|
||||
{ header: "最低消费金额", accessorKey: "min_amount" },
|
||||
{
|
||||
header: "状态",
|
||||
accessorKey: "status",
|
||||
cell: ({ row }) => {
|
||||
const status = row.original.status
|
||||
if (status === 0) {
|
||||
return <span className="text-yellow-600">禁用</span>
|
||||
}
|
||||
if (status === 1) {
|
||||
return <span className="text-green-600">正常</span>
|
||||
}
|
||||
return <span>-</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "action",
|
||||
meta: { pin: "right" },
|
||||
header: "操作",
|
||||
cell: ({ row }) => (
|
||||
<Button size="sm" onClick={() => handleIssue(row.original)}>
|
||||
发放
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="ghost">取消</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
@@ -1,41 +1,12 @@
|
||||
"use client"
|
||||
import { format } from "date-fns"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import { Suspense, useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { Suspense } from "react"
|
||||
import { getUserCoupon } from "@/actions/coupon"
|
||||
import { DataTable, useDataTable } from "@/components/data-table"
|
||||
import { Page } from "@/components/page"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/components/ui/alert-dialog"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import type { Coupon } from "@/models/coupon"
|
||||
import { type Coupon, getStatus } from "@/models/coupon"
|
||||
import { formatDate } from "@/models/formatDate"
|
||||
|
||||
export default function CouponPage() {
|
||||
const router = useRouter()
|
||||
@@ -50,22 +21,6 @@ export default function CouponPage() {
|
||||
size,
|
||||
})
|
||||
})
|
||||
console.log(table, "table")
|
||||
|
||||
const expireLabel = (coupon: Coupon) => {
|
||||
switch (coupon.expire_type) {
|
||||
case 0:
|
||||
return "永久有效"
|
||||
case 1:
|
||||
return coupon.expire_at
|
||||
? format(new Date(coupon.expire_at), "yyyy-MM-dd")
|
||||
: ""
|
||||
case 2:
|
||||
return coupon.expire_in ? `发放后${coupon.expire_in}天` : ""
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Page>
|
||||
@@ -82,194 +37,39 @@ export default function CouponPage() {
|
||||
<DataTable<Coupon>
|
||||
{...table}
|
||||
columns={[
|
||||
{ header: "优惠券名称", accessorKey: "name" },
|
||||
{ header: "券码", accessorKey: "code" },
|
||||
{ header: "金额", accessorKey: "amount" },
|
||||
{ header: "最低消费", accessorKey: "min_amount" },
|
||||
{ header: "优惠券名称", accessorKey: "coupon.name" },
|
||||
{ header: "金额", accessorKey: "coupon.amount" },
|
||||
{ header: "最低消费", accessorKey: "coupon.min_amount" },
|
||||
{
|
||||
header: "状态",
|
||||
accessorKey: "coupon_status",
|
||||
header: "优惠券使用状态",
|
||||
accessorKey: "coupon.status",
|
||||
cell: ({ row }) => {
|
||||
const { text, color } = getStatus(row.original.status, "use")
|
||||
return <span className={color}>{text}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "过期信息",
|
||||
id: "expire",
|
||||
cell: ({ row }) => expireLabel(row.original),
|
||||
accessorKey: "expire_at",
|
||||
cell: ({ row }) => formatDate(row.original.expire_at),
|
||||
},
|
||||
{
|
||||
header: "发放时间",
|
||||
accessorKey: "issued_at",
|
||||
// cell: ({ row }) =>
|
||||
// format(new Date(row.original.issued_at), "yyyy-MM-dd HH:mm:ss"),
|
||||
accessorKey: "coupon.created_at",
|
||||
cell: ({ row }) => formatDate(row.original.coupon.created_at),
|
||||
},
|
||||
{
|
||||
header: "备注",
|
||||
accessorKey: "remark",
|
||||
cell: ({ row }) => (
|
||||
<span className="text-gray-500">
|
||||
{row.original.remark || "-"}
|
||||
{row.original.remark || ""}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "action",
|
||||
meta: { pin: "right" },
|
||||
header: "操作",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex gap-2">
|
||||
<UpdateStatusDialog
|
||||
coupon={row.original}
|
||||
userId={Number(userId)}
|
||||
onSuccess={table.refresh}
|
||||
/>
|
||||
<RevokeDialog
|
||||
coupon={row.original}
|
||||
userId={Number(userId)}
|
||||
onSuccess={table.refresh}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Suspense>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
function UpdateStatusDialog({
|
||||
coupon,
|
||||
userId,
|
||||
onSuccess,
|
||||
}: {
|
||||
coupon: Coupon
|
||||
userId: number
|
||||
onSuccess?: () => void
|
||||
}) {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [selectedStatus, setSelectedStatus] =
|
||||
useState(
|
||||
// String(coupon.coupon_status),
|
||||
)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handleConfirm = async () => {
|
||||
// setLoading(true)
|
||||
// try {
|
||||
// const status = Number(selectedStatus)
|
||||
// const result = await updateUserCouponStatus({
|
||||
// user_id: userId,
|
||||
// coupon_id: coupon.id,
|
||||
// coupon_status: status,
|
||||
// })
|
||||
// if (result.success) {
|
||||
// toast.success("状态更新成功")
|
||||
// onSuccess?.()
|
||||
// setOpen(false)
|
||||
// } else {
|
||||
// toast.error(result.message || "更新失败")
|
||||
// }
|
||||
// } catch (error) {
|
||||
// const message = error instanceof Error ? error.message : "更新失败"
|
||||
// toast.error(`状态更新失败: ${message}`)
|
||||
// } finally {
|
||||
// setLoading(false)
|
||||
// }
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" variant="secondary">
|
||||
修改状态
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-sm">
|
||||
<DialogHeader>
|
||||
<DialogTitle>修改优惠券状态</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="py-4">
|
||||
<p className="text-sm text-gray-600 mb-3">
|
||||
优惠券: {coupon.name} ({coupon.code})
|
||||
</p>
|
||||
<Select value={selectedStatus}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择状态" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">未使用</SelectItem>
|
||||
<SelectItem value="2">已使用</SelectItem>
|
||||
<SelectItem value="3">已过期</SelectItem>
|
||||
<SelectItem value="0">已撤销</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="ghost">取消</Button>
|
||||
</DialogClose>
|
||||
<Button onClick={handleConfirm} disabled={loading}>
|
||||
确认
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
function RevokeDialog({
|
||||
coupon,
|
||||
userId,
|
||||
onSuccess,
|
||||
}: {
|
||||
coupon: Coupon
|
||||
userId: number
|
||||
onSuccess?: () => void
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handleConfirm = async () => {
|
||||
// setLoading(true)
|
||||
// try {
|
||||
// const result = await revokeUserCoupon({
|
||||
// user_id: userId,
|
||||
// coupon_id: coupon.id,
|
||||
// })
|
||||
// if (result.success) {
|
||||
// toast.success("撤销成功")
|
||||
// onSuccess?.()
|
||||
// } else {
|
||||
// toast.error(result.message || "撤销失败")
|
||||
// }
|
||||
// } catch (error) {
|
||||
// const message = error instanceof Error ? error.message : "撤销失败"
|
||||
// toast.error(`撤销失败: ${message}`)
|
||||
// } finally {
|
||||
// setLoading(false)
|
||||
// }
|
||||
}
|
||||
|
||||
return (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button size="sm" variant="destructive" disabled={loading}>
|
||||
撤销
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>确认撤销</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
确定要撤销「{coupon.name}」({coupon.code})
|
||||
吗?此操作将标记优惠券为已撤销状态。
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>取消</AlertDialogCancel>
|
||||
<AlertDialogAction variant="destructive" onClick={handleConfirm}>
|
||||
撤销
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client"
|
||||
import { format } from "date-fns"
|
||||
import { Suspense, useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { deleteCoupon, getPagCoupon } from "@/actions/coupon"
|
||||
@@ -19,7 +18,8 @@ import {
|
||||
} from "@/components/ui/alert-dialog"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { ScopeCouponWriteAssign } from "@/lib/scopes"
|
||||
import type { Coupon } from "@/models/coupon"
|
||||
import { type Coupon, getExpireType, getStatus } from "@/models/coupon"
|
||||
import { formatDate } from "@/models/formatDate"
|
||||
import { CreateDiscount } from "./create"
|
||||
import { ReleaseCoupon } from "./release"
|
||||
import { UpdateCoupon } from "./update"
|
||||
@@ -47,34 +47,13 @@ export default function CouponPage() {
|
||||
header: "优惠券状态",
|
||||
accessorKey: "status",
|
||||
cell: ({ row }) => {
|
||||
const status = row.original.status
|
||||
if (status === 0) {
|
||||
return <span className="text-yellow-600">禁用</span>
|
||||
}
|
||||
if (status === 1) {
|
||||
return <span className="text-green-600">正常</span>
|
||||
}
|
||||
return <span>-</span>
|
||||
const { text, color } = getStatus(row.original.status, "coupon")
|
||||
return <span className={color}>{text}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "过期类型",
|
||||
accessorFn: row => {
|
||||
switch (row.expire_type) {
|
||||
case 0:
|
||||
return "不过期"
|
||||
case 1:
|
||||
return "固定日期"
|
||||
case 2:
|
||||
return "相对日期"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "过期时长(天)",
|
||||
accessorKey: "expire_in",
|
||||
cell: ({ row }) => getExpireType(row.original.expire_type),
|
||||
},
|
||||
{
|
||||
header: "过期时间",
|
||||
@@ -82,16 +61,11 @@ export default function CouponPage() {
|
||||
cell: ({ row }) => {
|
||||
const coupon = row.original
|
||||
if (coupon.expire_type === 2 && coupon.expire_in) {
|
||||
const expireDate = new Date(coupon.created_at)
|
||||
expireDate.setDate(expireDate.getDate() + coupon.expire_in)
|
||||
return format(expireDate, "yyyy-MM-dd HH:mm:ss")
|
||||
return `${coupon.expire_in}天`
|
||||
}
|
||||
|
||||
if (coupon.expire_type === 1 && coupon.expire_at) {
|
||||
return format(
|
||||
new Date(coupon.expire_at),
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
)
|
||||
return formatDate(row.original.expire_at)
|
||||
}
|
||||
return <span>永久有效</span>
|
||||
},
|
||||
@@ -99,11 +73,7 @@ export default function CouponPage() {
|
||||
{
|
||||
header: "创建时间",
|
||||
accessorKey: "created_at",
|
||||
cell: ({ row }) =>
|
||||
format(
|
||||
new Date(row.original.created_at),
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
),
|
||||
cell: ({ row }) => formatDate(row.original.created_at),
|
||||
},
|
||||
{
|
||||
id: "action",
|
||||
@@ -115,16 +85,16 @@ export default function CouponPage() {
|
||||
coupon={row.original}
|
||||
onSuccess={table.refresh}
|
||||
/>
|
||||
<DeleteCoupon
|
||||
coupon={row.original}
|
||||
onSuccess={table.refresh}
|
||||
/>
|
||||
<Auth scope={ScopeCouponWriteAssign}>
|
||||
<ReleaseCoupon
|
||||
coupon={row.original}
|
||||
onSuccess={table.refresh}
|
||||
/>
|
||||
</Auth>
|
||||
<DeleteCoupon
|
||||
coupon={row.original}
|
||||
onSuccess={table.refresh}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
64
src/app/(root)/couponList/page.tsx
Normal file
64
src/app/(root)/couponList/page.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
"use client"
|
||||
import { Suspense } from "react"
|
||||
import { getCouponList } from "@/actions/coupon"
|
||||
import { DataTable, useDataTable } from "@/components/data-table"
|
||||
import { Page } from "@/components/page"
|
||||
import { type Coupon, getExpireTypeText, getStatus } from "@/models/coupon"
|
||||
import { formatDate } from "@/models/formatDate"
|
||||
|
||||
export default function CouponList() {
|
||||
const table = useDataTable((page, size) => getCouponList({ page, size }))
|
||||
console.log(table, "table")
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Suspense>
|
||||
<DataTable<Coupon>
|
||||
{...table}
|
||||
columns={[
|
||||
{ header: "优惠券名称", accessorKey: "coupon.name" },
|
||||
// { header: "优惠券数量", accessorKey: "coupon.count" },
|
||||
{ header: "优惠券金额", accessorKey: "coupon.amount" },
|
||||
{ header: "最低消费金额", accessorKey: "coupon.min_amount" },
|
||||
{ header: "用户", accessorKey: "user.name" },
|
||||
// {
|
||||
// header: "优惠券状态",
|
||||
// cell: ({ row }) => {
|
||||
// const { text, color } = getStatus(
|
||||
// row.original.coupon.status,
|
||||
// "coupon",
|
||||
// )
|
||||
// return <span className={color}>{text}</span>
|
||||
// },
|
||||
// },
|
||||
{
|
||||
header: "使用状态",
|
||||
cell: ({ row }) => {
|
||||
const { text, color } = getStatus(row.original.status, "use")
|
||||
return <span className={color}>{text}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "过期类型",
|
||||
cell: ({ row }) => {
|
||||
const expireType = row.original.coupon.expire_type
|
||||
const expireAt = row.original.expire_at
|
||||
return getExpireTypeText(expireType, expireAt)
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "过期时间",
|
||||
accessorKey: "expire_at",
|
||||
cell: ({ row }) => formatDate(row.original.expire_at),
|
||||
},
|
||||
{
|
||||
header: "创建时间",
|
||||
accessorKey: "created_at",
|
||||
cell: ({ row }) => formatDate(row.original.created_at),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Suspense>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { User } from "./user"
|
||||
|
||||
export type Coupon = {
|
||||
id: number
|
||||
name: string
|
||||
@@ -13,4 +15,97 @@ export type Coupon = {
|
||||
updated_at: Date
|
||||
expire_at: Date
|
||||
expire_in: number
|
||||
coupon: useCoupon
|
||||
user: User
|
||||
}
|
||||
type useCoupon = {
|
||||
id: number
|
||||
name: string
|
||||
expire_type: number
|
||||
status: number
|
||||
created_at: Date
|
||||
}
|
||||
|
||||
// 优惠券使用状态
|
||||
export const couponUseStatusMap = {
|
||||
0: { text: "未使用", color: "text-green-600" },
|
||||
1: { text: "已使用", color: "text-blue-600" },
|
||||
2: { text: "已禁用", color: "text-green-600" },
|
||||
} as const
|
||||
|
||||
// 优惠券状态
|
||||
export const couponStatusMap = {
|
||||
0: { text: "禁用", color: "text-yellow-600" },
|
||||
1: { text: "正常", color: "text-green-600" },
|
||||
} as const
|
||||
|
||||
// 优惠券过期类型
|
||||
export const expireTypeMap = {
|
||||
0: "不过期",
|
||||
1: "固定日期",
|
||||
2: "相对日期",
|
||||
} as const
|
||||
|
||||
// 优惠券状态 & 使用状态
|
||||
export const getStatus = (status: number, type: "coupon" | "use") => {
|
||||
if (type === "coupon") {
|
||||
return (
|
||||
couponStatusMap[status as keyof typeof couponStatusMap] || {
|
||||
text: "",
|
||||
color: "text-gray-400",
|
||||
}
|
||||
)
|
||||
}
|
||||
return (
|
||||
couponUseStatusMap[status as keyof typeof couponUseStatusMap] || {
|
||||
text: "",
|
||||
color: "text-gray-400",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const getDaysToExpire = (expireAt: Date | string): number => {
|
||||
if (!expireAt) return 0
|
||||
|
||||
const targetDate = new Date(expireAt)
|
||||
const now = new Date()
|
||||
|
||||
const targetDay = new Date(
|
||||
targetDate.getFullYear(),
|
||||
targetDate.getMonth(),
|
||||
targetDate.getDate(),
|
||||
)
|
||||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
||||
|
||||
const diffTime = targetDay.getTime() - today.getTime()
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
|
||||
|
||||
return diffDays
|
||||
}
|
||||
|
||||
// 过期类型
|
||||
export const getExpireType = (expireType: number): string => {
|
||||
return expireTypeMap[expireType as keyof typeof expireTypeMap] || ""
|
||||
}
|
||||
|
||||
// 获取过期类型显示(带天数)
|
||||
export const getExpireTypeText = (
|
||||
expireType: number,
|
||||
expireAt: Date,
|
||||
): string => {
|
||||
const typeText = getExpireType(expireType)
|
||||
console.log(typeText, "typeText")
|
||||
|
||||
if (expireType === 0) return typeText
|
||||
|
||||
const days = getDaysToExpire(expireAt)
|
||||
console.log(days, "days")
|
||||
|
||||
if (days === 0) {
|
||||
return `${typeText}`
|
||||
} else if (days > 0) {
|
||||
return `${typeText}(${days}天后)`
|
||||
} else {
|
||||
return `${typeText}(已过期${Math.abs(days)}天)`
|
||||
}
|
||||
}
|
||||
|
||||
11
src/models/formatDate.ts
Normal file
11
src/models/formatDate.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { format } from "date-fns"
|
||||
|
||||
export const formatDate = (
|
||||
date: Date | string | null | undefined,
|
||||
formatStr: string = "yyyy-MM-dd HH:mm:ss",
|
||||
): string => {
|
||||
if (!date) return ""
|
||||
const d = new Date(date)
|
||||
if (!Number.isNaN(d.getTime())) return format(d, formatStr)
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user