feat: KOC资源卡片支持手动修改账号ID
This commit is contained in:
@@ -3196,6 +3196,10 @@ function ResourcesPage({
|
||||
});
|
||||
const [singleWorking, setSingleWorking] = useState(false);
|
||||
const [singleError, setSingleError] = useState("");
|
||||
const [editAccount, setEditAccount] = useState<Account | null>(null);
|
||||
const [editAccountId, setEditAccountId] = useState("");
|
||||
const [editWorking, setEditWorking] = useState(false);
|
||||
const [editError, setEditError] = useState("");
|
||||
const resourceAccounts = useMemo(() => {
|
||||
const deliveriesByAccount = new Map<string, Distribution[]>();
|
||||
distributions.forEach((distribution) => {
|
||||
@@ -3403,6 +3407,46 @@ function ResourcesPage({
|
||||
setImportWorking(false);
|
||||
}
|
||||
};
|
||||
const closeAccountEdit = () => {
|
||||
if (editWorking) return;
|
||||
setEditAccount(null);
|
||||
setEditAccountId("");
|
||||
setEditError("");
|
||||
};
|
||||
const submitAccountEdit = async () => {
|
||||
if (!editAccount) return;
|
||||
const value = editAccountId.trim();
|
||||
if (!value) {
|
||||
setEditError("请填写新的账号ID");
|
||||
return;
|
||||
}
|
||||
if (!/^[\p{L}\p{N}._-]{2,80}$/u.test(value)) {
|
||||
setEditError("账号ID需为 2-80 位字母、数字或 . _ - 组合");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setEditWorking(true);
|
||||
setEditError("");
|
||||
const response = await fetch("/api/action", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "set_public_account_ids",
|
||||
items: [{ accountId: editAccount.id, publicAccountId: value }],
|
||||
}),
|
||||
});
|
||||
const result = await readApiResponse<{ error?: string }>(response, "保存失败");
|
||||
if (!response.ok) throw new Error(result.error || "保存失败");
|
||||
const label = editAccount.nickname || editAccount.public_account_id || "该账号";
|
||||
setEditAccount(null);
|
||||
setEditAccountId("");
|
||||
await onImported(`已更新 ${label} 的账号ID`);
|
||||
} catch (reason) {
|
||||
setEditError(reason instanceof Error ? reason.message : "保存失败");
|
||||
} finally {
|
||||
setEditWorking(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="stack">
|
||||
<section className="resource-intro">
|
||||
@@ -3548,6 +3592,18 @@ function ResourcesPage({
|
||||
<div className="resource-account-number">
|
||||
<span>{accountIdLabel}</span>
|
||||
<strong>{account.public_account_id || "待识别"}</strong>
|
||||
<button
|
||||
type="button"
|
||||
className="account-id-edit-button"
|
||||
title="手动修改账号ID"
|
||||
onClick={() => {
|
||||
setEditAccount(account);
|
||||
setEditAccountId(account.public_account_id || "");
|
||||
setEditError("");
|
||||
}}
|
||||
>
|
||||
修改
|
||||
</button>
|
||||
</div>
|
||||
<div className="resource-platform-line">
|
||||
<PlatformBadge platform={account.platform} compact />
|
||||
@@ -3601,6 +3657,59 @@ function ResourcesPage({
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
{editAccount && (
|
||||
<div className="modal-backdrop" role="presentation" onMouseDown={closeAccountEdit}>
|
||||
<div
|
||||
className="modal-card compact"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="account-id-edit-title"
|
||||
onMouseDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<div className="modal-heading">
|
||||
<div>
|
||||
<p className="eyebrow">{editAccount.nickname || "账号"}</p>
|
||||
<h2 id="account-id-edit-title">修改账号ID</h2>
|
||||
</div>
|
||||
<button type="button" onClick={closeAccountEdit} aria-label="关闭">×</button>
|
||||
</div>
|
||||
<div className="account-id-edit-form">
|
||||
<label>
|
||||
<span>
|
||||
{editAccount.platform === "小红书"
|
||||
? "小红书号"
|
||||
: editAccount.platform === "抖音"
|
||||
? "抖音号"
|
||||
: "账号ID"}
|
||||
</span>
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
value={editAccountId}
|
||||
placeholder="2-80 位字母、数字或 . _ -"
|
||||
onChange={(event) => setEditAccountId(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") void submitAccountEdit();
|
||||
}}
|
||||
/>
|
||||
<small>只更新账号ID,昵称、粉丝数等其他资料保持不变</small>
|
||||
</label>
|
||||
{editError && <div className="form-error">{editError}</div>}
|
||||
</div>
|
||||
<div className="modal-actions">
|
||||
<button type="button" className="ghost-button" onClick={closeAccountEdit}>取消</button>
|
||||
<button
|
||||
type="button"
|
||||
className="primary-button"
|
||||
disabled={editWorking || !editAccountId.trim()}
|
||||
onClick={() => void submitAccountEdit()}
|
||||
>
|
||||
{editWorking ? "保存中…" : "保存"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{importOpen && (
|
||||
<div className="modal-backdrop" role="presentation" onMouseDown={closeImport}>
|
||||
<div
|
||||
|
||||
@@ -2972,6 +2972,34 @@ a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.account-id-edit-button {
|
||||
flex: 0 0 auto;
|
||||
padding: 1px 6px;
|
||||
border: 1px solid #dce2de;
|
||||
border-radius: 999px;
|
||||
color: #8a978f;
|
||||
background: transparent;
|
||||
font-size: 9px;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.account-id-edit-button:hover {
|
||||
border-color: #70ad95;
|
||||
color: #40806a;
|
||||
}
|
||||
|
||||
.account-id-edit-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.account-id-edit-form small {
|
||||
color: #9aa4a0;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.resource-platform-line {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
|
||||
Reference in New Issue
Block a user