新增余额明细页面,修复页面useId不更新的问题
This commit is contained in:
@@ -22,9 +22,9 @@ import type { User } from "@/models/user"
|
||||
const Schema = z.object({
|
||||
deduction: z
|
||||
.string()
|
||||
.min(1, "请输入余额")
|
||||
.min(1, "请输入扣款金额")
|
||||
.refine(val => !Number.isNaN(Number(val)), "请输入有效的数字")
|
||||
.refine(val => Number(val) >= 0, "余额不能为负数"),
|
||||
.refine(val => Number(val) >= 0, "金额不能为负数"),
|
||||
})
|
||||
|
||||
type FormValues = z.infer<typeof Schema>
|
||||
@@ -95,7 +95,7 @@ export function DeductionDialog({
|
||||
<DialogHeader>
|
||||
<DialogTitle>扣款</DialogTitle>
|
||||
<DialogDescription>
|
||||
用户 {currentUser?.name || currentUser?.username} 的金额
|
||||
扣减用户 {currentUser?.name || currentUser?.username} 的余额
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -104,30 +104,20 @@ export function DeductionDialog({
|
||||
<Field data-invalid={!!errors.deduction}>
|
||||
<FieldLabel>扣款(元)</FieldLabel>
|
||||
<Input
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
type="text"
|
||||
placeholder="请输入扣款金额"
|
||||
{...register("deduction", {
|
||||
setValueAs: value => {
|
||||
if (!value) return ""
|
||||
const num = Number(value)
|
||||
if (Number.isNaN(num)) return value
|
||||
return num.toFixed(2)
|
||||
},
|
||||
})}
|
||||
{...register("deduction")}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let value = e.target.value
|
||||
if (value.startsWith("-")) {
|
||||
value = value.replace("-", "")
|
||||
value = value.replace(/[^\d.]/g, "")
|
||||
const dotCount = (value.match(/\./g) || []).length
|
||||
if (dotCount > 1) {
|
||||
value = value.slice(0, value.lastIndexOf("."))
|
||||
}
|
||||
if (value.includes(".")) {
|
||||
const parts = value.split(".")
|
||||
if (parts[1] && parts[1].length > 2) {
|
||||
value = `${parts[0]}.${parts[1].slice(0, 2)}`
|
||||
}
|
||||
const [int, dec] = value.split(".")
|
||||
value = `${int}.${dec.slice(0, 2)}`
|
||||
}
|
||||
|
||||
setValue("deduction", value)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -104,30 +104,20 @@ export function DepositDialog({
|
||||
<Field data-invalid={!!errors.deposit}>
|
||||
<FieldLabel>充值(元)</FieldLabel>
|
||||
<Input
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
type="text" // 改为 text,避免 number 输入冲突
|
||||
placeholder="请输入充值金额"
|
||||
{...register("deposit", {
|
||||
setValueAs: value => {
|
||||
if (!value) return ""
|
||||
const num = Number(value)
|
||||
if (Number.isNaN(num)) return value
|
||||
return num.toFixed(2)
|
||||
},
|
||||
})}
|
||||
{...register("deposit")}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let value = e.target.value
|
||||
if (value.startsWith("-")) {
|
||||
value = value.replace("-", "")
|
||||
value = value.replace(/[^\d.]/g, "")
|
||||
const dotCount = (value.match(/\./g) || []).length
|
||||
if (dotCount > 1) {
|
||||
value = value.slice(0, value.lastIndexOf("."))
|
||||
}
|
||||
if (value.includes(".")) {
|
||||
const parts = value.split(".")
|
||||
if (parts[1] && parts[1].length > 2) {
|
||||
value = `${parts[0]}.${parts[1].slice(0, 2)}`
|
||||
}
|
||||
const [int, dec] = value.split(".")
|
||||
value = `${int}.${dec.slice(0, 2)}`
|
||||
}
|
||||
|
||||
setValue("deposit", value)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import {
|
||||
ScopeBalanceActivityReadOfUser,
|
||||
ScopeBatchReadOfUser,
|
||||
ScopeBillReadOfUser,
|
||||
ScopeChannelReadOfUser,
|
||||
@@ -77,7 +78,7 @@ const filterSchema = z
|
||||
|
||||
type FormValues = z.infer<typeof filterSchema>
|
||||
|
||||
export default function UserPage() {
|
||||
export default function CustPage() {
|
||||
const [filters, setFilters] = useState<FilterValues>({})
|
||||
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false)
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
|
||||
@@ -229,7 +230,11 @@ export default function UserPage() {
|
||||
</div>
|
||||
|
||||
<FieldGroup className="flex-row justify-start mt-4 gap-2">
|
||||
<Button type="submit">筛选</Button>
|
||||
<Auth scope={ScopeUserWrite}>
|
||||
<Button type="button" onClick={() => setIsAddDialogOpen(true)}>
|
||||
添加用户
|
||||
</Button>
|
||||
</Auth>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
@@ -241,11 +246,7 @@ export default function UserPage() {
|
||||
>
|
||||
重置
|
||||
</Button>
|
||||
<Auth scope={ScopeUserWrite}>
|
||||
<Button type="button" onClick={() => setIsAddDialogOpen(true)}>
|
||||
添加用户
|
||||
</Button>
|
||||
</Auth>
|
||||
<Button type="submit">筛选</Button>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
|
||||
@@ -253,10 +254,14 @@ export default function UserPage() {
|
||||
<DataTable<User>
|
||||
{...table}
|
||||
columns={[
|
||||
{ header: "账号", accessorKey: "username" },
|
||||
{ header: "手机", accessorKey: "phone" },
|
||||
{ header: "邮箱", accessorKey: "email" },
|
||||
{ header: "姓名", accessorKey: "name" },
|
||||
{
|
||||
header: "创建时间",
|
||||
accessorKey: "created_at",
|
||||
cell: ({ row }) =>
|
||||
format(new Date(row.original.created_at), "yyyy-MM-dd HH:mm"),
|
||||
},
|
||||
// { header: "邮箱", accessorKey: "email" },
|
||||
{
|
||||
header: "客户来源",
|
||||
accessorKey: "source",
|
||||
@@ -286,7 +291,22 @@ export default function UserPage() {
|
||||
)
|
||||
},
|
||||
},
|
||||
{ header: "折扣", accessorKey: "discount.name" },
|
||||
{ header: "账号", accessorKey: "username" },
|
||||
{
|
||||
header: "账号状态",
|
||||
accessorKey: "status",
|
||||
cell: ({ row }) => (row.original.status === 1 ? "正常" : "禁用"),
|
||||
},
|
||||
{ header: "客户经理", accessorKey: "admin.name" },
|
||||
{ header: "姓名", accessorKey: "name" },
|
||||
{
|
||||
header: "身份证号",
|
||||
accessorKey: "id_no",
|
||||
cell: ({ row }) => {
|
||||
const idNo = row.original.id_no
|
||||
return idNo ? `${idNo.slice(0, 6)}****${idNo.slice(-4)}` : ""
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "实名状态",
|
||||
accessorKey: "id_type",
|
||||
@@ -303,36 +323,6 @@ export default function UserPage() {
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "身份证号",
|
||||
accessorKey: "id_no",
|
||||
cell: ({ row }) => {
|
||||
const idNo = row.original.id_no
|
||||
return idNo ? `${idNo.slice(0, 6)}****${idNo.slice(-4)}` : ""
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "账号状态",
|
||||
accessorKey: "status",
|
||||
cell: ({ row }) => (row.original.status === 1 ? "正常" : "禁用"),
|
||||
},
|
||||
{
|
||||
header: "联系方式",
|
||||
cell: ({ row }) => {
|
||||
const qq = row.original.contact_qq || ""
|
||||
const wechat = row.original.contact_wechat || ""
|
||||
const hasQQ = qq.trim() !== ""
|
||||
const hasWechat = wechat.trim() !== ""
|
||||
if (!hasQQ && !hasWechat) return null
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
{hasWechat && <div>微信:{wechat}</div>}
|
||||
{hasQQ && <div>QQ:{qq}</div>}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{ header: "客户经理", accessorKey: "admin.name" },
|
||||
{
|
||||
header: "最后登录时间",
|
||||
accessorKey: "last_login",
|
||||
@@ -349,11 +339,22 @@ export default function UserPage() {
|
||||
accessorKey: "last_login_ip",
|
||||
cell: ({ row }) => row.original.last_login_ip || "",
|
||||
},
|
||||
{ header: "折扣", accessorKey: "discount.name" },
|
||||
{
|
||||
header: "创建时间",
|
||||
accessorKey: "created_at",
|
||||
cell: ({ row }) =>
|
||||
format(new Date(row.original.created_at), "yyyy-MM-dd HH:mm"),
|
||||
header: "联系方式",
|
||||
cell: ({ row }) => {
|
||||
const qq = row.original.contact_qq || ""
|
||||
const wechat = row.original.contact_wechat || ""
|
||||
const hasQQ = qq.trim() !== ""
|
||||
const hasWechat = wechat.trim() !== ""
|
||||
if (!hasQQ && !hasWechat) return null
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
{hasWechat && <div>微信:{wechat}</div>}
|
||||
{hasQQ && <div>QQ:{qq}</div>}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "action",
|
||||
@@ -451,6 +452,18 @@ export default function UserPage() {
|
||||
IP管理
|
||||
</Button>
|
||||
</Auth>
|
||||
<Auth scope={ScopeBalanceActivityReadOfUser}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
router.push(
|
||||
`/client/balance?userId=${row.original.id}&phone=${row.original.phone}`,
|
||||
)
|
||||
}}
|
||||
>
|
||||
余额操作
|
||||
</Button>
|
||||
</Auth>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user