feat: simplify KOC resource imports
This commit is contained in:
@@ -2261,9 +2261,9 @@ function ResourcesPage({
|
||||
<button type="button" onClick={closeImport} aria-label="关闭">×</button>
|
||||
</div>
|
||||
<div className="import-guide-strip">
|
||||
<span>1</span><p>填写账号主页与合作来源</p>
|
||||
<span>1</span><p>账号链接必填,其余资料选填</p>
|
||||
<i />
|
||||
<span>2</span><p>系统解析公开账号资料</p>
|
||||
<span>2</span><p>系统只补全空缺的公开资料</p>
|
||||
<i />
|
||||
<span>3</span><p>确认后写入资源库</p>
|
||||
</div>
|
||||
@@ -2282,7 +2282,7 @@ function ResourcesPage({
|
||||
</label>
|
||||
{!importPreview && (
|
||||
<div className="import-template-note">
|
||||
<div><strong>还没有模板?</strong><span>只需填写小红书账号主页;合作来源可选填,账号名称、小红书号、IP属地和粉丝数会自动解析。</span></div>
|
||||
<div><strong>还没有模板?</strong><span>只有账号链接必填;已有昵称、账号ID、IP属地、粉丝数和合作来源可直接填写,系统只补全空缺字段。</span></div>
|
||||
<a className="ghost-button" download href="/KOC资源导入模板.xlsx">下载模板</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
parseResourceImportFile,
|
||||
RESOURCE_IMPORT_MAX_BYTES,
|
||||
resourcePlatformUid,
|
||||
resourceImportMissingFields,
|
||||
type ResourceImportRow,
|
||||
} from "../../../lib/resource-import";
|
||||
|
||||
@@ -86,20 +87,38 @@ async function enrichRows(rows: ResourceImportRow[], accounts: AccountRow[]) {
|
||||
return row;
|
||||
}
|
||||
const existing = existingByProfile.get(identityKey(row.platform, row.profileUrl));
|
||||
if (existing?.nickname && existing.public_account_id) {
|
||||
return {
|
||||
...row,
|
||||
nickname: existing.nickname,
|
||||
publicAccountId: existing.public_account_id,
|
||||
ipLocation: existing.ip_location || "待识别",
|
||||
followers: Number(existing.followers || 0),
|
||||
};
|
||||
const existingIpLocation =
|
||||
existing?.ip_location && existing.ip_location !== "待识别"
|
||||
? existing.ip_location
|
||||
: "";
|
||||
const baseline: ResourceImportRow = {
|
||||
...row,
|
||||
nickname: row.nickname || existing?.nickname || "",
|
||||
publicAccountId: row.publicAccountId || existing?.public_account_id || "",
|
||||
ipLocation: row.ipLocation || existingIpLocation,
|
||||
followers: row.followersResolved
|
||||
? row.followers
|
||||
: Number(existing?.followers || 0),
|
||||
followersResolved:
|
||||
row.followersResolved || Number(existing?.followers || 0) > 0,
|
||||
};
|
||||
if (resourceImportMissingFields(baseline).length === 0) {
|
||||
return baseline;
|
||||
}
|
||||
|
||||
let details = await resolveXhsProfileDetailsFromMcp(row.profileUrl, mcpConfig)
|
||||
.catch(() => resolveXhsPublicAccountDetails(row.profileUrl));
|
||||
if (!details.nickname || !details.redId || details.followers === null) {
|
||||
const publicDetails = await resolveXhsPublicAccountDetails(row.profileUrl);
|
||||
let details = await resolveXhsProfileDetailsFromMcp(row.profileUrl, mcpConfig).catch(
|
||||
() => ({ nickname: null, redId: null, followers: null, ipLocation: null }),
|
||||
);
|
||||
const mcpResult = {
|
||||
nickname: baseline.nickname || details.nickname?.trim() || "",
|
||||
publicAccountId: baseline.publicAccountId || details.redId?.trim() || "",
|
||||
ipLocation: baseline.ipLocation || details.ipLocation?.trim() || "",
|
||||
followersResolved: baseline.followersResolved || details.followers !== null,
|
||||
};
|
||||
if (resourceImportMissingFields(mcpResult).length > 0) {
|
||||
const publicDetails = await resolveXhsPublicAccountDetails(row.profileUrl).catch(
|
||||
() => ({ nickname: null, redId: null, followers: null, ipLocation: null }),
|
||||
);
|
||||
details = {
|
||||
nickname: details.nickname || publicDetails.nickname,
|
||||
redId: details.redId || publicDetails.redId,
|
||||
@@ -107,18 +126,16 @@ async function enrichRows(rows: ResourceImportRow[], accounts: AccountRow[]) {
|
||||
ipLocation: details.ipLocation || publicDetails.ipLocation,
|
||||
};
|
||||
}
|
||||
const errors = [...row.errors];
|
||||
const nickname = details.nickname?.trim() || existing?.nickname || "";
|
||||
const publicAccountId = details.redId?.trim() || existing?.public_account_id || "";
|
||||
if (!nickname) errors.push("无法识别账号名称,请确认主页可公开访问");
|
||||
if (!publicAccountId) errors.push("无法识别小红书号,请确认主页可公开访问");
|
||||
return {
|
||||
...row,
|
||||
nickname,
|
||||
publicAccountId,
|
||||
ipLocation: details.ipLocation?.trim() || existing?.ip_location || "待识别",
|
||||
followers: details.followers ?? Number(existing?.followers || 0),
|
||||
errors,
|
||||
...baseline,
|
||||
nickname: baseline.nickname || details.nickname?.trim() || "待识别账号",
|
||||
publicAccountId: baseline.publicAccountId || details.redId?.trim() || "",
|
||||
ipLocation: baseline.ipLocation || details.ipLocation?.trim() || "待识别",
|
||||
followers: baseline.followersResolved
|
||||
? baseline.followers
|
||||
: (details.followers ?? 0),
|
||||
followersResolved:
|
||||
baseline.followersResolved || details.followers !== null,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -251,7 +268,7 @@ export async function POST(request: Request) {
|
||||
profile_url = CASE WHEN ? != '' THEN ? ELSE profile_url END,
|
||||
ip_location = CASE
|
||||
WHEN ? != '' AND ? != '待识别' THEN ? ELSE ip_location END,
|
||||
followers = CASE WHEN ? > 0 OR followers = 0 THEN ? ELSE followers END,
|
||||
followers = CASE WHEN ? = 1 THEN ? ELSE followers END,
|
||||
cooperation_source = ?,
|
||||
last_seen_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?`,
|
||||
@@ -265,7 +282,7 @@ export async function POST(request: Request) {
|
||||
row.ipLocation,
|
||||
row.ipLocation,
|
||||
row.ipLocation,
|
||||
row.followers,
|
||||
row.followersResolved ? 1 : 0,
|
||||
row.followers,
|
||||
row.cooperationSource,
|
||||
row.accountId,
|
||||
|
||||
Reference in New Issue
Block a user