fix: format business ability estimates

This commit is contained in:
admin123 2026-05-18 18:40:34 +08:00
parent 249e6a5971
commit 39c4191a95
3 changed files with 53 additions and 13 deletions

View File

@ -158,19 +158,19 @@ export function mapBusinessAbilityEstimateResponse(
return {
oneToTwenty: {
expectedCpe: formatDecimal(readNumber(data?.cpe_1_20), 1),
expectedCpm: formatDecimal(readNumber(data?.cpm_1_20), 0),
expectedCpm: formatFixedDecimal(readNumber(data?.cpm_1_20), 1),
expectedPlay,
hotRate
},
overSixty: {
expectedCpe: formatDecimal(readNumber(data?.cpe_60), 1),
expectedCpm: formatDecimal(readNumber(data?.cpm_60), 0),
expectedCpm: formatFixedDecimal(readNumber(data?.cpm_60), 1),
expectedPlay,
hotRate
},
twentyToSixty: {
expectedCpe: formatDecimal(readNumber(data?.cpe_20_60), 1),
expectedCpm: formatDecimal(readNumber(data?.cpm_20_60), 0),
expectedCpm: formatFixedDecimal(readNumber(data?.cpm_20_60), 1),
expectedPlay,
hotRate
}
@ -203,7 +203,7 @@ function formatBasisPointRate(value: number | null): string {
function formatDecimalRate(value: number | null): string {
if (value === null) {
return "";
return "缺失";
}
return `${formatDecimal(value * 100, 0)}%`;
@ -230,6 +230,14 @@ function formatDecimal(value: number | null, digits: number): string {
return fixed.replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
}
function formatFixedDecimal(value: number | null, digits: number): string {
if (value === null || !Number.isFinite(value)) {
return "";
}
return value.toFixed(digits);
}
function readNestedNumber(
data: Record<string, unknown> | null,
objectKey: string,

View File

@ -39,15 +39,15 @@ describe("audience-profile-csv", () => {
estimates: {
oneToTwenty: {
expectedCpe: "2.1",
expectedCpm: "120",
expectedCpm: "120.0",
expectedPlay: "250w",
hotRate: "100%"
},
twentyToSixty: {
expectedCpe: "3.7",
expectedCpm: "212",
expectedCpm: "212.0",
expectedPlay: "250w",
hotRate: "100%"
hotRate: "缺失"
}
},
status: "success",
@ -109,8 +109,8 @@ describe("audience-profile-csv", () => {
expect(rowLine).toContain("60%");
expect(readCsvValue(csv, "商业能力-个人视频-播放量中位数")).toBe("3738.4w");
expect(readCsvValue(csv, "商业能力-星图视频-平均转发")).toBe("68.4w");
expect(readCsvValue(csv, "商业能力-1-20s视频-预期CPM")).toBe("120");
expect(readCsvValue(csv, "商业能力-20-60s视频-爆文率")).toBe("100%");
expect(readCsvValue(csv, "商业能力-1-20s视频-预期CPM")).toBe("120.0");
expect(readCsvValue(csv, "商业能力-20-60s视频-爆文率")).toBe("缺失");
});
test("leaves distribution cells empty when profile loading fails", () => {

View File

@ -47,25 +47,57 @@ describe("business-ability-client", () => {
expect(mapBusinessAbilityEstimateResponse(buildEstimatePayload())).toEqual({
oneToTwenty: {
expectedCpe: "2.1",
expectedCpm: "120",
expectedCpm: "120.0",
expectedPlay: "250w",
hotRate: "100%"
},
overSixty: {
expectedCpe: "4.2",
expectedCpm: "240",
expectedCpm: "240.0",
expectedPlay: "250w",
hotRate: "100%"
},
twentyToSixty: {
expectedCpe: "3.7",
expectedCpm: "212",
expectedCpm: "212.0",
expectedPlay: "250w",
hotRate: "100%"
}
});
});
test("keeps decimal CPM values and marks missing hot rate", () => {
expect(mapBusinessAbilityEstimateResponse({
base_resp: { status_code: 0, status_message: "" },
cpe_1_20: "1.6347",
cpe_20_60: "2.002",
cpe_60: "2.104",
cpm_1_20: "21.7955",
cpm_20_60: "27.5628",
cpm_60: "29.877",
vv: "1010234"
})).toEqual({
oneToTwenty: {
expectedCpe: "1.6",
expectedCpm: "21.8",
expectedPlay: "101w",
hotRate: "缺失"
},
overSixty: {
expectedCpe: "2.1",
expectedCpm: "29.9",
expectedPlay: "101w",
hotRate: "缺失"
},
twentyToSixty: {
expectedCpe: "2",
expectedCpm: "27.6",
expectedPlay: "101w",
hotRate: "缺失"
}
});
});
test("loads personal video, Xingtu video, and duration estimate metrics", async () => {
const requestedUrls: string[] = [];
const fetchImpl = vi.fn(async (input: string) => {
@ -92,7 +124,7 @@ describe("business-ability-client", () => {
})
).resolves.toMatchObject({
estimates: expect.objectContaining({
twentyToSixty: expect.objectContaining({ expectedCpm: "212" })
twentyToSixty: expect.objectContaining({ expectedCpm: "212.0" })
}),
status: "success",
videos: {