网关取消删除添加启用和停用功能 & 产品页套餐添加sort 排序和 count_min 最低购买数量字段
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lanhu-admin",
|
"name": "lanhu-admin",
|
||||||
"version": "1.4.0",
|
"version": "1.5.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -H 0.0.0.0 -p 3001 --turbopack",
|
"dev": "next dev -H 0.0.0.0 -p 3001 --turbopack",
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export async function updateProductSku(data: {
|
|||||||
price?: string
|
price?: string
|
||||||
discount_id?: number | null
|
discount_id?: number | null
|
||||||
price_min?: string
|
price_min?: string
|
||||||
|
count_min?: number | null
|
||||||
}) {
|
}) {
|
||||||
return callByUser<ProductSku>("/api/admin/product/sku/update", {
|
return callByUser<ProductSku>("/api/admin/product/sku/update", {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
@@ -53,6 +54,7 @@ export async function updateProductSku(data: {
|
|||||||
price: data.price,
|
price: data.price,
|
||||||
discount_id: data.discount_id,
|
discount_id: data.discount_id,
|
||||||
price_min: data.price_min,
|
price_min: data.price_min,
|
||||||
|
count_min: data.count_min,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { format } from "date-fns"
|
||||||
import { Suspense, useState } from "react"
|
import { Suspense, useState } from "react"
|
||||||
import { toast } from "sonner"
|
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 { DataTable, useDataTable } from "@/components/data-table"
|
||||||
import { Page } from "@/components/page"
|
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 { Button } from "@/components/ui/button"
|
||||||
|
import { ScopeProxyWrite } from "@/lib/scopes"
|
||||||
import type { Gateway } from "@/models/gateway"
|
import type { Gateway } from "@/models/gateway"
|
||||||
import CreatePage from "./create"
|
import CreatePage from "./create"
|
||||||
import { format } from "date-fns"
|
|
||||||
import { ScopeProxyWrite } from "@/lib/scopes"
|
|
||||||
import { Auth } from "@/components/auth"
|
|
||||||
|
|
||||||
export default function GatewayPage() {
|
export default function GatewayPage() {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
@@ -42,12 +31,11 @@ export default function GatewayPage() {
|
|||||||
{...table}
|
{...table}
|
||||||
status={loading ? "load" : "done"}
|
status={loading ? "load" : "done"}
|
||||||
columns={[
|
columns={[
|
||||||
// { header: "id", accessorKey: "id" },
|
|
||||||
{
|
{
|
||||||
header: "域名",
|
header: "域名",
|
||||||
accessorKey: "host",
|
accessorKey: "host",
|
||||||
},
|
},
|
||||||
{ header: "IP地址", accessorKey: "ip" },
|
{ header: "IP地址", accessorKey: "ip" },
|
||||||
{
|
{
|
||||||
header: "MAC地址",
|
header: "MAC地址",
|
||||||
accessorKey: "mac",
|
accessorKey: "mac",
|
||||||
@@ -74,7 +62,10 @@ export default function GatewayPage() {
|
|||||||
header: "操作",
|
header: "操作",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div className="flex gap-2">
|
<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>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -84,53 +75,3 @@ export default function GatewayPage() {
|
|||||||
</Page>
|
</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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ const schema = z
|
|||||||
"请输入有效的正数单价",
|
"请输入有效的正数单价",
|
||||||
),
|
),
|
||||||
discount_id: z.string().optional(),
|
discount_id: z.string().optional(),
|
||||||
|
count_min: z.string().min(1, "请输入最低购买数量"),
|
||||||
price_min: z
|
price_min: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, "请输入最低价格")
|
.min(1, "请输入最低价格")
|
||||||
@@ -177,19 +178,6 @@ export function CreateProductSku(props: {
|
|||||||
placeholder="请输入单价"
|
placeholder="请输入单价"
|
||||||
{...field}
|
{...field}
|
||||||
aria-invalid={fieldState.invalid}
|
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 && (
|
{fieldState.invalid && (
|
||||||
<FieldError errors={[fieldState.error]} />
|
<FieldError errors={[fieldState.error]} />
|
||||||
@@ -208,19 +196,6 @@ export function CreateProductSku(props: {
|
|||||||
placeholder="请输入最低价格"
|
placeholder="请输入最低价格"
|
||||||
{...field}
|
{...field}
|
||||||
aria-invalid={fieldState.invalid}
|
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 && (
|
{fieldState.invalid && (
|
||||||
<FieldError errors={[fieldState.error]} />
|
<FieldError errors={[fieldState.error]} />
|
||||||
@@ -228,7 +203,26 @@ export function CreateProductSku(props: {
|
|||||||
</Field>
|
</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
|
<Controller
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="discount_id"
|
name="discount_id"
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ function ProductSkus(props: {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ header: "最低价格", accessorKey: "price_min" },
|
{ header: "最低价格", accessorKey: "price_min" },
|
||||||
|
{ header: "最低购买数量", accessorKey: "count_min" },
|
||||||
{
|
{
|
||||||
header: "创建时间",
|
header: "创建时间",
|
||||||
accessorFn: row => format(row.created_at, "yyyy-MM-dd HH:mm"),
|
accessorFn: row => format(row.created_at, "yyyy-MM-dd HH:mm"),
|
||||||
|
|||||||
@@ -46,6 +46,16 @@ const schema = z
|
|||||||
"请输入有效的正数单价",
|
"请输入有效的正数单价",
|
||||||
),
|
),
|
||||||
discount_id: z.string().optional(),
|
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
|
price_min: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, "请输入最低价格")
|
.min(1, "请输入最低价格")
|
||||||
@@ -82,6 +92,7 @@ export function UpdateProductSku(props: {
|
|||||||
price: props.sku.price,
|
price: props.sku.price,
|
||||||
discount_id: props.sku.discount ? String(props.sku.discount.id) : "",
|
discount_id: props.sku.discount ? String(props.sku.discount.id) : "",
|
||||||
price_min: props.sku.price_min ?? "",
|
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)
|
? Number(data.discount_id)
|
||||||
: null,
|
: null,
|
||||||
price_min: data.price_min,
|
price_min: data.price_min,
|
||||||
|
count_min: Number(data.count_min),
|
||||||
})
|
})
|
||||||
|
console.log(resp, "resp")
|
||||||
|
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
toast.success("套餐修改成功")
|
toast.success("套餐修改成功")
|
||||||
@@ -130,6 +143,7 @@ export function UpdateProductSku(props: {
|
|||||||
price: props.sku.price,
|
price: props.sku.price,
|
||||||
discount_id: props.sku.discount ? String(props.sku.discount.id) : "",
|
discount_id: props.sku.discount ? String(props.sku.discount.id) : "",
|
||||||
price_min: props.sku.price_min ?? "",
|
price_min: props.sku.price_min ?? "",
|
||||||
|
count_min: props.sku.count_min ? String(props.sku.count_min) : "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setOpen(value)
|
setOpen(value)
|
||||||
@@ -180,19 +194,6 @@ export function UpdateProductSku(props: {
|
|||||||
placeholder="请输入单价"
|
placeholder="请输入单价"
|
||||||
{...field}
|
{...field}
|
||||||
aria-invalid={fieldState.invalid}
|
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 && (
|
{fieldState.invalid && (
|
||||||
<FieldError errors={[fieldState.error]} />
|
<FieldError errors={[fieldState.error]} />
|
||||||
@@ -205,25 +206,34 @@ export function UpdateProductSku(props: {
|
|||||||
name="price_min"
|
name="price_min"
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel htmlFor="sku-create-price">最低价格</FieldLabel>
|
<FieldLabel htmlFor="sku-update-price-min">
|
||||||
|
最低价格
|
||||||
|
</FieldLabel>
|
||||||
<Input
|
<Input
|
||||||
id="sku-create-price"
|
id="sku-update-price-min"
|
||||||
placeholder="请输入最低价格"
|
placeholder="请输入最低价格"
|
||||||
{...field}
|
{...field}
|
||||||
aria-invalid={fieldState.invalid}
|
aria-invalid={fieldState.invalid}
|
||||||
// onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
/>
|
||||||
// let value = e.target.value
|
{fieldState.invalid && (
|
||||||
// value = value.replace(/[^\d.]/g, "")
|
<FieldError errors={[fieldState.error]} />
|
||||||
// const dotCount = (value.match(/\./g) || []).length
|
)}
|
||||||
// if (dotCount > 1) {
|
</Field>
|
||||||
// value = value.slice(0, value.lastIndexOf("."))
|
)}
|
||||||
// }
|
/>
|
||||||
// if (value.includes(".")) {
|
<Controller
|
||||||
// const [int, dec] = value.split(".")
|
control={form.control}
|
||||||
// value = `${int}.${dec.slice(0, 2)}`
|
name="count_min"
|
||||||
// }
|
render={({ field, fieldState }) => (
|
||||||
// field.onChange(value)
|
<Field>
|
||||||
// }}
|
<FieldLabel htmlFor="sku-update-count-min">
|
||||||
|
最低购买数量
|
||||||
|
</FieldLabel>
|
||||||
|
<Input
|
||||||
|
id="sku-update-count-min"
|
||||||
|
placeholder="请输入最低购买数量"
|
||||||
|
{...field}
|
||||||
|
aria-invalid={fieldState.invalid}
|
||||||
/>
|
/>
|
||||||
{fieldState.invalid && (
|
{fieldState.invalid && (
|
||||||
<FieldError errors={[fieldState.error]} />
|
<FieldError errors={[fieldState.error]} />
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ export type ProductSku = Model & {
|
|||||||
product?: Product
|
product?: Product
|
||||||
price_min?: string
|
price_min?: string
|
||||||
discount?: ProductDiscount
|
discount?: ProductDiscount
|
||||||
|
sort: number
|
||||||
|
count_min: number
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user