网关取消删除添加启用和停用功能 & 产品页套餐添加sort 排序和 count_min 最低购买数量字段

This commit is contained in:
Eamon
2026-04-20 16:32:21 +08:00
parent 2377616a07
commit 69c8029b8b
7 changed files with 75 additions and 125 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "lanhu-admin",
"version": "1.4.0",
"version": "1.5.0",
"private": true,
"scripts": {
"dev": "next dev -H 0.0.0.0 -p 3001 --turbopack",

View File

@@ -45,6 +45,7 @@ export async function updateProductSku(data: {
price?: string
discount_id?: number | null
price_min?: string
count_min?: number | null
}) {
return callByUser<ProductSku>("/api/admin/product/sku/update", {
id: data.id,
@@ -53,6 +54,7 @@ export async function updateProductSku(data: {
price: data.price,
discount_id: data.discount_id,
price_min: data.price_min,
count_min: data.count_min,
})
}

View File

@@ -1,33 +1,22 @@
"use client"
import { format } from "date-fns"
import { Suspense, useState } from "react"
import { toast } from "sonner"
import { deletegateway, getGatewayPage } from "@/actions/gateway"
import { getGatewayPage } from "@/actions/gateway"
import { Auth } from "@/components/auth"
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 { Button } from "@/components/ui/button"
import { ScopeProxyWrite } from "@/lib/scopes"
import type { Gateway } from "@/models/gateway"
import CreatePage from "./create"
import { format } from "date-fns"
import { ScopeProxyWrite } from "@/lib/scopes"
import { Auth } from "@/components/auth"
export default function GatewayPage() {
const [loading, setLoading] = useState(false)
const table = useDataTable((page, size) => getGatewayPage({ page, size }))
return (
<Page>
<Auth scope={ScopeProxyWrite}>
@@ -42,12 +31,11 @@ export default function GatewayPage() {
{...table}
status={loading ? "load" : "done"}
columns={[
// { header: "id", accessorKey: "id" },
{
header: "域名",
accessorKey: "host",
},
{ header: "IP地址", accessorKey: "ip" },
{ header: "IP地址", accessorKey: "ip" },
{
header: "MAC地址",
accessorKey: "mac",
@@ -74,7 +62,10 @@ export default function GatewayPage() {
header: "操作",
cell: ({ row }) => (
<div className="flex gap-2">
<Auth scope={ScopeProxyWrite}><Delete gateway={row.original} onSuccess={table.refresh} /></Auth>
<Button className="bg-green-600/60 hover:bg-green-600/60 active:bg-green-600/60">
</Button>
<Button></Button>
</div>
),
},
@@ -84,53 +75,3 @@ export default function GatewayPage() {
</Page>
)
}
function Delete({
gateway,
onSuccess,
}: {
gateway: Gateway
onSuccess?: () => void
}) {
const [loading, setLoading] = useState(false)
const handleConfirm = async () => {
setLoading(true)
try {
const resp = await deletegateway(gateway.id)
if (resp.success) {
toast.success("删除成功")
onSuccess?.()
} else {
toast.error(resp.message ?? "删除失败")
}
} catch (error) {
const message = error instanceof Error ? error.message : error
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>
{gateway.host || gateway.ip}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction variant="destructive" onClick={handleConfirm}>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}

View File

@@ -46,6 +46,7 @@ const schema = z
"请输入有效的正数单价",
),
discount_id: z.string().optional(),
count_min: z.string().min(1, "请输入最低购买数量"),
price_min: z
.string()
.min(1, "请输入最低价格")
@@ -177,19 +178,6 @@ export function CreateProductSku(props: {
placeholder="请输入单价"
{...field}
aria-invalid={fieldState.invalid}
// onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
// let value = e.target.value
// value = value.replace(/[^\d.]/g, "")
// const dotCount = (value.match(/\./g) || []).length
// if (dotCount > 1) {
// value = value.slice(0, value.lastIndexOf("."))
// }
// if (value.includes(".")) {
// const [int, dec] = value.split(".")
// value = `${int}.${dec.slice(0, 2)}`
// }
// field.onChange(value)
// }}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
@@ -208,19 +196,6 @@ export function CreateProductSku(props: {
placeholder="请输入最低价格"
{...field}
aria-invalid={fieldState.invalid}
// onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
// let value = e.target.value
// value = value.replace(/[^\d.]/g, "")
// const dotCount = (value.match(/\./g) || []).length
// if (dotCount > 1) {
// value = value.slice(0, value.lastIndexOf("."))
// }
// if (value.includes(".")) {
// const [int, dec] = value.split(".")
// value = `${int}.${dec.slice(0, 2)}`
// }
// field.onChange(value)
// }}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
@@ -228,7 +203,26 @@ export function CreateProductSku(props: {
</Field>
)}
/>
<Controller
control={form.control}
name="count_min"
render={({ field, fieldState }) => (
<Field>
<FieldLabel htmlFor="sku-create-price">
</FieldLabel>
<Input
id="sku-create-price"
placeholder="请输入最低购买数量"
{...field}
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
control={form.control}
name="discount_id"

View File

@@ -141,6 +141,7 @@ function ProductSkus(props: {
},
},
{ header: "最低价格", accessorKey: "price_min" },
{ header: "最低购买数量", accessorKey: "count_min" },
{
header: "创建时间",
accessorFn: row => format(row.created_at, "yyyy-MM-dd HH:mm"),

View File

@@ -46,6 +46,16 @@ const schema = z
"请输入有效的正数单价",
),
discount_id: z.string().optional(),
count_min: z
.string()
.min(1, "请输入最低购买数量")
.refine(
v =>
!Number.isNaN(Number(v)) &&
Number.isInteger(Number(v)) &&
Number(v) > 0,
"请输入有效的正整数",
),
price_min: z
.string()
.min(1, "请输入最低价格")
@@ -82,6 +92,7 @@ export function UpdateProductSku(props: {
price: props.sku.price,
discount_id: props.sku.discount ? String(props.sku.discount.id) : "",
price_min: props.sku.price_min ?? "",
count_min: String(props.sku.count_min),
},
})
@@ -107,7 +118,9 @@ export function UpdateProductSku(props: {
? Number(data.discount_id)
: null,
price_min: data.price_min,
count_min: Number(data.count_min),
})
console.log(resp, "resp")
if (resp.success) {
toast.success("套餐修改成功")
@@ -130,6 +143,7 @@ export function UpdateProductSku(props: {
price: props.sku.price,
discount_id: props.sku.discount ? String(props.sku.discount.id) : "",
price_min: props.sku.price_min ?? "",
count_min: props.sku.count_min ? String(props.sku.count_min) : "",
})
}
setOpen(value)
@@ -180,19 +194,6 @@ export function UpdateProductSku(props: {
placeholder="请输入单价"
{...field}
aria-invalid={fieldState.invalid}
// onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
// let value = e.target.value
// value = value.replace(/[^\d.]/g, "")
// const dotCount = (value.match(/\./g) || []).length
// if (dotCount > 1) {
// value = value.slice(0, value.lastIndexOf("."))
// }
// if (value.includes(".")) {
// const [int, dec] = value.split(".")
// value = `${int}.${dec.slice(0, 2)}`
// }
// field.onChange(value)
// }}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
@@ -205,25 +206,34 @@ export function UpdateProductSku(props: {
name="price_min"
render={({ field, fieldState }) => (
<Field>
<FieldLabel htmlFor="sku-create-price"></FieldLabel>
<FieldLabel htmlFor="sku-update-price-min">
</FieldLabel>
<Input
id="sku-create-price"
id="sku-update-price-min"
placeholder="请输入最低价格"
{...field}
aria-invalid={fieldState.invalid}
// onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
// let value = e.target.value
// value = value.replace(/[^\d.]/g, "")
// const dotCount = (value.match(/\./g) || []).length
// if (dotCount > 1) {
// value = value.slice(0, value.lastIndexOf("."))
// }
// if (value.includes(".")) {
// const [int, dec] = value.split(".")
// value = `${int}.${dec.slice(0, 2)}`
// }
// field.onChange(value)
// }}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
control={form.control}
name="count_min"
render={({ field, fieldState }) => (
<Field>
<FieldLabel htmlFor="sku-update-count-min">
</FieldLabel>
<Input
id="sku-update-count-min"
placeholder="请输入最低购买数量"
{...field}
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />

View File

@@ -11,4 +11,6 @@ export type ProductSku = Model & {
product?: Product
price_min?: string
discount?: ProductDiscount
sort: number
count_min: number
}