merge: 合入 test(KOC资源卡片手动修改账号ID)
This commit is contained in:
@@ -3196,6 +3196,10 @@ function ResourcesPage({
|
|||||||
});
|
});
|
||||||
const [singleWorking, setSingleWorking] = useState(false);
|
const [singleWorking, setSingleWorking] = useState(false);
|
||||||
const [singleError, setSingleError] = useState("");
|
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 resourceAccounts = useMemo(() => {
|
||||||
const deliveriesByAccount = new Map<string, Distribution[]>();
|
const deliveriesByAccount = new Map<string, Distribution[]>();
|
||||||
distributions.forEach((distribution) => {
|
distributions.forEach((distribution) => {
|
||||||
@@ -3403,6 +3407,46 @@ function ResourcesPage({
|
|||||||
setImportWorking(false);
|
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 (
|
return (
|
||||||
<div className="stack">
|
<div className="stack">
|
||||||
<section className="resource-intro">
|
<section className="resource-intro">
|
||||||
@@ -3548,6 +3592,18 @@ function ResourcesPage({
|
|||||||
<div className="resource-account-number">
|
<div className="resource-account-number">
|
||||||
<span>{accountIdLabel}</span>
|
<span>{accountIdLabel}</span>
|
||||||
<strong>{account.public_account_id || "待识别"}</strong>
|
<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>
|
||||||
<div className="resource-platform-line">
|
<div className="resource-platform-line">
|
||||||
<PlatformBadge platform={account.platform} compact />
|
<PlatformBadge platform={account.platform} compact />
|
||||||
@@ -3601,6 +3657,59 @@ function ResourcesPage({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</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 && (
|
{importOpen && (
|
||||||
<div className="modal-backdrop" role="presentation" onMouseDown={closeImport}>
|
<div className="modal-backdrop" role="presentation" onMouseDown={closeImport}>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -2972,6 +2972,34 @@ a {
|
|||||||
white-space: nowrap;
|
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 {
|
.resource-platform-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user