Compare commits

...

1 Commits

Author SHA1 Message Date
shanshanzhong147 eb0e8b13f2 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 中
存在预置的重复类型声明(来自上一次提交)而失败,与本次改动无关。
2026-05-25 19:57:49 -07:00
+68 -51
View File
@@ -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"),