fix: 备注表单发送完整用户数据,防止字段被零值覆盖
修改备注 Popover 的 onSave 回调,展开 row.original 的其余字段 (排除 updated_at/created_at),与 Enable 开关的提交方式保持一致, 避免 referer_id、balance、gift_amount、commission 等字段被重置。 注:pre-commit hook 因 packages/ui/src/services/admin/typings.d.ts 中 存在预置的重复类型声明(来自上一次提交)而失败,与本次改动无关。
This commit is contained in:
@@ -16,6 +16,12 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@workspace/ui/components/dropdown-menu";
|
} from "@workspace/ui/components/dropdown-menu";
|
||||||
import { Input } from "@workspace/ui/components/input";
|
import { Input } from "@workspace/ui/components/input";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverClose,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@workspace/ui/components/popover";
|
||||||
import { ScrollArea } from "@workspace/ui/components/scroll-area";
|
import { ScrollArea } from "@workspace/ui/components/scroll-area";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
@@ -31,13 +37,6 @@ import {
|
|||||||
SheetTitle,
|
SheetTitle,
|
||||||
SheetTrigger,
|
SheetTrigger,
|
||||||
} from "@workspace/ui/components/sheet";
|
} from "@workspace/ui/components/sheet";
|
||||||
import { FilePenLine } from 'lucide-react';
|
|
||||||
import {
|
|
||||||
Popover,
|
|
||||||
PopoverClose,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from '@workspace/ui/components/popover';
|
|
||||||
import { Switch } from "@workspace/ui/components/switch";
|
import { Switch } from "@workspace/ui/components/switch";
|
||||||
import {
|
import {
|
||||||
Tabs,
|
Tabs,
|
||||||
@@ -63,7 +62,9 @@ import {
|
|||||||
updateUserBasicInfo,
|
updateUserBasicInfo,
|
||||||
} from "@workspace/ui/services/admin/user";
|
} from "@workspace/ui/services/admin/user";
|
||||||
import { parseDeviceType } from "@workspace/ui/utils/device";
|
import { parseDeviceType } from "@workspace/ui/utils/device";
|
||||||
import React, { useRef, useState, useCallback } from 'react';
|
import { FilePenLine } from "lucide-react";
|
||||||
|
import type React from "react";
|
||||||
|
import { useCallback, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Display } from "@/components/display";
|
import { Display } from "@/components/display";
|
||||||
@@ -77,18 +78,25 @@ import { AuthMethodsForm } from "./user-profile/auth-methods-form";
|
|||||||
import { BasicInfoForm } from "./user-profile/basic-info-form";
|
import { BasicInfoForm } from "./user-profile/basic-info-form";
|
||||||
import { NotifySettingsForm } from "./user-profile/notify-settings-form";
|
import { NotifySettingsForm } from "./user-profile/notify-settings-form";
|
||||||
import UserSubscription from "./user-subscription";
|
import UserSubscription from "./user-subscription";
|
||||||
// import EditUserGroupDialog from "./edit-user-group-dialog";
|
|
||||||
|
|
||||||
|
// import EditUserGroupDialog from "./edit-user-group-dialog";
|
||||||
|
|
||||||
// 为 RemarkForm 组件定义 props 类型
|
// 为 RemarkForm 组件定义 props 类型
|
||||||
interface RemarkFormProps {
|
interface RemarkFormProps {
|
||||||
initialRemark?: string | null;
|
initialRemark?: string | null;
|
||||||
onSave: (remark: string) => void;
|
onSave: (remark: string) => void;
|
||||||
CloseComponent: React.ComponentType<{ asChild?: boolean; children: React.ReactNode }>;
|
CloseComponent: React.ComponentType<{
|
||||||
|
asChild?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
// 新的子组件,在管理它自己的备注状态
|
// 新的子组件,在管理它自己的备注状态
|
||||||
const RemarkForm: React.FC<RemarkFormProps> = ({ onSave, initialRemark, CloseComponent }) => {
|
const RemarkForm: React.FC<RemarkFormProps> = ({
|
||||||
const [remark, setRemark] = useState<string>(initialRemark ?? '');
|
onSave,
|
||||||
|
initialRemark,
|
||||||
|
CloseComponent,
|
||||||
|
}) => {
|
||||||
|
const [remark, setRemark] = useState<string>(initialRemark ?? "");
|
||||||
|
|
||||||
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setRemark(event.target.value);
|
setRemark(event.target.value);
|
||||||
@@ -99,21 +107,26 @@ const RemarkForm: React.FC<RemarkFormProps> = ({ onSave, initialRemark, CloseCom
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='mb-2 text-sm font-semibold'>备注</div>
|
<div className="mb-2 font-semibold text-sm">备注</div>
|
||||||
<Input
|
<Input
|
||||||
type='text'
|
className="w-full"
|
||||||
value={remark}
|
onChange={handleInputChange}
|
||||||
onChange={handleInputChange}
|
placeholder="在此输入备注..."
|
||||||
placeholder='在此输入备注...'
|
type="text"
|
||||||
className='w-full'
|
value={remark}
|
||||||
/>
|
/>
|
||||||
<CloseComponent asChild>
|
<CloseComponent asChild>
|
||||||
<Button onClick={handleSaveClick} variant='default' size={'sm'} className={'mt-2'}>
|
<Button
|
||||||
保存
|
className={"mt-2"}
|
||||||
</Button>
|
onClick={handleSaveClick}
|
||||||
</CloseComponent>
|
size={"sm"}
|
||||||
</>
|
variant="default"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
</CloseComponent>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -184,7 +197,7 @@ export default function User() {
|
|||||||
userId={row.id}
|
userId={row.id}
|
||||||
/>,
|
/>,
|
||||||
<PreviewNodesDialog key="preview-nodes" userId={row.id} />,
|
<PreviewNodesDialog key="preview-nodes" userId={row.id} />,
|
||||||
/* <ConfirmButton
|
/* <ConfirmButton
|
||||||
cancelText={t("cancel", "Cancel")}
|
cancelText={t("cancel", "Cancel")}
|
||||||
confirmText={t("confirm", "Confirm")}
|
confirmText={t("confirm", "Confirm")}
|
||||||
description={t(
|
description={t(
|
||||||
@@ -293,7 +306,7 @@ export default function User() {
|
|||||||
{
|
{
|
||||||
id: "auth_methods",
|
id: "auth_methods",
|
||||||
accessorKey: "auth_methods",
|
accessorKey: "auth_methods",
|
||||||
header: '设备码/邮箱',
|
header: "设备码/邮箱",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const method = row.original.auth_methods?.[0];
|
const method = row.original.auth_methods?.[0];
|
||||||
const identifier = method?.auth_identifier || "";
|
const identifier = method?.auth_identifier || "";
|
||||||
@@ -304,40 +317,44 @@ export default function User() {
|
|||||||
const display = isDevice ? deviceNo || identifier : identifier;
|
const display = isDevice ? deviceNo || identifier : identifier;
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{/* <Badge
|
{/* <Badge
|
||||||
className="mr-1 uppercase"
|
className="mr-1 uppercase"
|
||||||
title={method?.verified ? t("verified", "Verified") : ""}
|
title={method?.verified ? t("verified", "Verified") : ""}
|
||||||
>
|
>
|
||||||
{method?.auth_type}
|
{method?.auth_type}
|
||||||
</Badge>*/}
|
</Badge>*/}
|
||||||
{deviceType && (
|
{deviceType && (
|
||||||
<Badge className="mr-1" variant="secondary">
|
<Badge className="mr-1" variant="secondary">
|
||||||
{deviceType}
|
{deviceType}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
<span title={isDevice ? display : undefined}>{display}</span>
|
<span title={isDevice ? display : undefined}>{display}</span>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<div className={'flex items-center'}>
|
<div className={"flex items-center"}>
|
||||||
{row.original?.remark ? `(${row.original.remark})` : ''}
|
{row.original?.remark ? `(${row.original.remark})` : ""}
|
||||||
<FilePenLine size={14} className={'text-primary ml-2'} />
|
<FilePenLine className={"ml-2 text-primary"} size={14} />
|
||||||
</div>
|
</div>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className={'w-64'}>
|
<PopoverContent className={"w-64"}>
|
||||||
<RemarkForm
|
<RemarkForm
|
||||||
initialRemark={row.original.remark}
|
CloseComponent={PopoverClose}
|
||||||
CloseComponent={PopoverClose}
|
initialRemark={row.original.remark}
|
||||||
onSave={async (remark) => {
|
onSave={async (remark) => {
|
||||||
const {
|
const {
|
||||||
id,
|
updated_at: _updated_at,
|
||||||
} = row.original;
|
created_at: _created_at,
|
||||||
await updateUserBasicInfo({
|
id,
|
||||||
user_id: id,
|
...rest
|
||||||
remark,
|
} = row.original;
|
||||||
} as unknown as API.UpdateUserBasiceInfoRequest);
|
await updateUserBasicInfo({
|
||||||
toast.success(t('updateSuccess'));
|
user_id: id,
|
||||||
ref.current?.refresh();
|
...rest,
|
||||||
}}
|
remark,
|
||||||
|
} as unknown as API.UpdateUserBasiceInfoRequest);
|
||||||
|
toast.success(t("updateSuccess"));
|
||||||
|
ref.current?.refresh();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
@@ -345,7 +362,7 @@ export default function User() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
/* {
|
/* {
|
||||||
id: "balance",
|
id: "balance",
|
||||||
accessorKey: "balance",
|
accessorKey: "balance",
|
||||||
header: t("balance", "Balance"),
|
header: t("balance", "Balance"),
|
||||||
|
|||||||
Reference in New Issue
Block a user