Add Geo suffix and Adpingid column to 投手明细
Package now renders as pkg_GEO, where GEO is the region with the highest total spend for that package. The new Adpingid column shows the top-spending Adping within that region, so label and id stay consistent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+48
-20
@@ -1,8 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# 从 xlsx 重算 data.json。取数规则见 README 注释:
|
# 从 xlsx 重算 data.json。
|
||||||
# 平台消耗统计: B=Date, C=Adpingid, D=包名, I=花费
|
# 平台消耗统计: B=Date, C=Adpingid, D=包名, E=地区, I=花费
|
||||||
# 投手: B=Adpingid, L=Media Buyer投放人
|
# 投手: B=Adpingid, D=pkg, L=Media Buyer投放人
|
||||||
# @某某 == 某某;未填投放人的 Adpingid 丢弃;exclude.json 里的包名永久剔除。
|
# 规则:@某某 == 某某;未填投放人的 Adpingid 丢弃;exclude.json 里的包名永久剔除(精确匹配)。
|
||||||
|
# 每个 package 明细:Geo 后缀 = 该 package 花费最高的地区;Adpingid = 该地区内花费最高的 Adping。
|
||||||
import openpyxl, collections, json, datetime, os, sys
|
import openpyxl, collections, json, datetime, os, sys
|
||||||
|
|
||||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
@@ -18,7 +19,7 @@ def key(v):
|
|||||||
|
|
||||||
wb = openpyxl.load_workbook(SRC, data_only=True)
|
wb = openpyxl.load_workbook(SRC, data_only=True)
|
||||||
|
|
||||||
# --- 投手表:Adpingid -> 投放人;同时收集需按 Adping 剔除的 id ---
|
# --- 投手表:Adpingid -> 投放人 ---
|
||||||
amap, dropped_ids = {}, set()
|
amap, dropped_ids = {}, set()
|
||||||
for r in wb['投手'].iter_rows(min_row=2, values_only=True):
|
for r in wb['投手'].iter_rows(min_row=2, values_only=True):
|
||||||
adp, pkg, buyer, status = r[1], r[3], r[11], r[0]
|
adp, pkg, buyer, status = r[1], r[3], r[11], r[0]
|
||||||
@@ -38,14 +39,15 @@ owned = collections.Counter(amap.values()) # 每位投手名下的 Adpingid
|
|||||||
# --- 平台消耗统计 ---
|
# --- 平台消耗统计 ---
|
||||||
rows = []
|
rows = []
|
||||||
for r in wb['平台消耗统计'].iter_rows(min_row=2, values_only=True):
|
for r in wb['平台消耗统计'].iter_rows(min_row=2, values_only=True):
|
||||||
d, adp, pkg, spend = r[1], r[2], r[3], r[8]
|
d, adp, pkg, geo, spend = r[1], r[2], r[3], r[4], r[8]
|
||||||
if d is None or adp is None or not isinstance(d, datetime.datetime):
|
if d is None or adp is None or not isinstance(d, datetime.datetime):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
s = float(spend) if spend is not None else 0.0
|
s = float(spend) if spend is not None else 0.0
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
s = 0.0
|
s = 0.0
|
||||||
rows.append((d.date(), key(adp), (str(pkg).strip() if pkg else '(未知)'), s))
|
rows.append((d.date(), key(adp), (str(pkg).strip() if pkg else '(未知)'),
|
||||||
|
(str(geo).strip() if geo else ''), s))
|
||||||
|
|
||||||
if not rows:
|
if not rows:
|
||||||
sys.exit('ERROR: 平台消耗统计 无有效数据行')
|
sys.exit('ERROR: 平台消耗统计 无有效数据行')
|
||||||
@@ -53,32 +55,55 @@ if not rows:
|
|||||||
end = max(r[0] for r in rows)
|
end = max(r[0] for r in rows)
|
||||||
start = end - datetime.timedelta(days=WINDOW_DAYS - 1)
|
start = end - datetime.timedelta(days=WINDOW_DAYS - 1)
|
||||||
|
|
||||||
buyers = collections.defaultdict(lambda: collections.defaultdict(float))
|
pkg_spend = collections.defaultdict(float) # (buyer, pkg) -> spend
|
||||||
|
geo_spend = collections.defaultdict(float) # (buyer, pkg, geo) -> spend
|
||||||
|
ga_spend = collections.defaultdict(float) # (buyer, pkg, geo, adping) -> spend
|
||||||
ids = collections.defaultdict(set)
|
ids = collections.defaultdict(set)
|
||||||
unmatched = collections.defaultdict(float)
|
unmatched = collections.defaultdict(float)
|
||||||
excluded_spend, excluded_rows = 0.0, 0
|
excluded_spend, excluded_rows = 0.0, 0
|
||||||
|
|
||||||
for d, adp, pkg, s in rows:
|
for d, adp, pkg, geo, s in rows:
|
||||||
if not (start <= d <= end):
|
if not (start <= d <= end):
|
||||||
continue
|
continue
|
||||||
if pkg in EXCL or adp in dropped_ids:
|
if pkg in EXCL or adp in dropped_ids:
|
||||||
excluded_spend += s; excluded_rows += 1
|
excluded_spend += s; excluded_rows += 1
|
||||||
continue
|
continue
|
||||||
if adp in amap:
|
b = amap.get(adp)
|
||||||
buyers[amap[adp]][pkg] += s
|
if b is None:
|
||||||
ids[amap[adp]].add(adp)
|
|
||||||
else:
|
|
||||||
unmatched[(adp, pkg)] += s
|
unmatched[(adp, pkg)] += s
|
||||||
|
continue
|
||||||
|
pkg_spend[(b, pkg)] += s
|
||||||
|
geo_spend[(b, pkg, geo)] += s
|
||||||
|
ga_spend[(b, pkg, geo, adp)] += s
|
||||||
|
ids[b].add(adp)
|
||||||
|
|
||||||
|
by_buyer = collections.defaultdict(dict)
|
||||||
|
for (b, pkg), v in pkg_spend.items():
|
||||||
|
by_buyer[b][pkg] = v
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
for b, pk in buyers.items():
|
for b, pk in by_buyer.items():
|
||||||
|
pkgs = []
|
||||||
|
for pkg, v in sorted(pk.items(), key=lambda x: -x[1])[:5]:
|
||||||
|
# 花费最高的地区,再取该地区内花费最高的 Adpingid
|
||||||
|
top_geo = max((g for (bb, pp, g) in geo_spend if bb == b and pp == pkg),
|
||||||
|
key=lambda g: geo_spend[(b, pkg, g)])
|
||||||
|
top_adp = max((a for (bb, pp, g, a) in ga_spend
|
||||||
|
if bb == b and pp == pkg and g == top_geo),
|
||||||
|
key=lambda a: ga_spend[(b, pkg, top_geo, a)])
|
||||||
|
pkgs.append({
|
||||||
|
"pkg": pkg,
|
||||||
|
"geo": top_geo,
|
||||||
|
"label": f"{pkg}_{top_geo}" if top_geo else pkg,
|
||||||
|
"adping": top_adp,
|
||||||
|
"spend": round(v, 4),
|
||||||
|
})
|
||||||
out.append({
|
out.append({
|
||||||
"name": b, "@name": b,
|
"name": b, "@name": b,
|
||||||
"total": round(sum(pk.values()), 4),
|
"total": round(sum(pk.values()), 4),
|
||||||
"active_ids": len(ids[b]), # 本周期内有消耗的 Adpingid 数
|
"active_ids": len(ids[b]),
|
||||||
"owned_ids": owned[b], # 名下负责的 Adpingid 总数
|
"owned_ids": owned[b],
|
||||||
"pkgs": [{"pkg": k, "spend": round(v, 4)}
|
"pkgs": pkgs,
|
||||||
for k, v in sorted(pk.items(), key=lambda x: -x[1])[:5]],
|
|
||||||
})
|
})
|
||||||
out.sort(key=lambda x: -x['total'])
|
out.sort(key=lambda x: -x['total'])
|
||||||
|
|
||||||
@@ -90,7 +115,8 @@ data = {
|
|||||||
"generated_at": datetime.date.today().isoformat(),
|
"generated_at": datetime.date.today().isoformat(),
|
||||||
"date_range": f"{start:%Y/%m/%d}-{end:%Y/%m/%d}",
|
"date_range": f"{start:%Y/%m/%d}-{end:%Y/%m/%d}",
|
||||||
"note": "投放人以「投手」表 Media Buyer 列为准,@某某 已与某某合并计算;"
|
"note": "投放人以「投手」表 Media Buyer 列为准,@某某 已与某某合并计算;"
|
||||||
"未填写投放人的 Adpingid 不计入;exclude.json 所列包名已排除。",
|
"未填写投放人的 Adpingid 不计入;exclude.json 所列包名已排除。"
|
||||||
|
"Package 后缀为该 Package 花费最高的投放地区,Adpingid 为该地区内花费最高的 Adping。",
|
||||||
},
|
},
|
||||||
"grand_total": round(sum(b['total'] for b in out), 4),
|
"grand_total": round(sum(b['total'] for b in out), 4),
|
||||||
"week34_id_count": sum(len(v) for v in ids.values()),
|
"week34_id_count": sum(len(v) for v in ids.values()),
|
||||||
@@ -104,4 +130,6 @@ print(f"窗口 {start} -> {end}")
|
|||||||
print(f"排除包名命中 {excluded_rows} 行,剔除花费 {excluded_spend:.2f}")
|
print(f"排除包名命中 {excluded_rows} 行,剔除花费 {excluded_spend:.2f}")
|
||||||
print(f"合计 {data['grand_total']:.2f} / Adpingid {data['week34_id_count']}")
|
print(f"合计 {data['grand_total']:.2f} / Adpingid {data['week34_id_count']}")
|
||||||
for b in out:
|
for b in out:
|
||||||
print(f" {b['name']:6s} {b['total']:10.2f}")
|
print(f" {b['name']:6s} {b['total']:10.2f} 在投{b['active_ids']:3d}/负责{b['owned_ids']:3d}")
|
||||||
|
for p in b['pkgs']:
|
||||||
|
print(f" {p['label']:52s} {p['adping']:>10s} {p['spend']:9.2f}")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"source": "数据已处理(平台消耗统计 × 投手表匹配,已剔除未填写投放人的 Adpingid 及排除包名)",
|
"source": "数据已处理(平台消耗统计 × 投手表匹配,已剔除未填写投放人的 Adpingid 及排除包名)",
|
||||||
"generated_at": "2026-08-27",
|
"generated_at": "2026-08-27",
|
||||||
"date_range": "2026/08/24-2026/08/26",
|
"date_range": "2026/08/24-2026/08/26",
|
||||||
"note": "投放人以「投手」表 Media Buyer 列为准,@某某 已与某某合并计算;未填写投放人的 Adpingid 不计入;exclude.json 所列包名已排除。"
|
"note": "投放人以「投手」表 Media Buyer 列为准,@某某 已与某某合并计算;未填写投放人的 Adpingid 不计入;exclude.json 所列包名已排除。Package 后缀为该 Package 花费最高的投放地区,Adpingid 为该地区内花费最高的 Adping。"
|
||||||
},
|
},
|
||||||
"grand_total": 11377.758,
|
"grand_total": 11377.758,
|
||||||
"week34_id_count": 127,
|
"week34_id_count": 127,
|
||||||
@@ -18,22 +18,37 @@
|
|||||||
"pkgs": [
|
"pkgs": [
|
||||||
{
|
{
|
||||||
"pkg": "com.amazon.mShop.android.shopping",
|
"pkg": "com.amazon.mShop.android.shopping",
|
||||||
|
"geo": "BR",
|
||||||
|
"label": "com.amazon.mShop.android.shopping_BR",
|
||||||
|
"adping": "10912510",
|
||||||
"spend": 1418.4064
|
"spend": 1418.4064
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.king.candycrushsodasaga",
|
"pkg": "com.king.candycrushsodasaga",
|
||||||
|
"geo": "BR",
|
||||||
|
"label": "com.king.candycrushsodasaga_BR",
|
||||||
|
"adping": "8460883",
|
||||||
"spend": 994.619
|
"spend": 994.619
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.yandex.lavka",
|
"pkg": "com.yandex.lavka",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.yandex.lavka_RU",
|
||||||
|
"adping": "8156506",
|
||||||
"spend": 365.8305
|
"spend": 365.8305
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "asrtum.ent.domovyata",
|
"pkg": "asrtum.ent.domovyata",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "asrtum.ent.domovyata_RU",
|
||||||
|
"adping": "7872826",
|
||||||
"spend": 354.475
|
"spend": 354.475
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.fxpro.direct.application",
|
"pkg": "com.fxpro.direct.application",
|
||||||
|
"geo": "PK",
|
||||||
|
"label": "com.fxpro.direct.application_PK",
|
||||||
|
"adping": "7202934",
|
||||||
"spend": 237.2
|
"spend": 237.2
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -47,22 +62,37 @@
|
|||||||
"pkgs": [
|
"pkgs": [
|
||||||
{
|
{
|
||||||
"pkg": "com.kwai.bulldog",
|
"pkg": "com.kwai.bulldog",
|
||||||
|
"geo": "ID",
|
||||||
|
"label": "com.kwai.bulldog_ID",
|
||||||
|
"adping": "7815836",
|
||||||
"spend": 1225.92
|
"spend": 1225.92
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "asrtum.ent.domovyata",
|
"pkg": "asrtum.ent.domovyata",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "asrtum.ent.domovyata_RU",
|
||||||
|
"adping": "8628042",
|
||||||
"spend": 387.38
|
"spend": 387.38
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.vitastudio.mahjong",
|
"pkg": "com.vitastudio.mahjong",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.vitastudio.mahjong_RU",
|
||||||
|
"adping": "91496148",
|
||||||
"spend": 347.66
|
"spend": 347.66
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "astrum.ent.m2alyona",
|
"pkg": "astrum.ent.m2alyona",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "astrum.ent.m2alyona_RU",
|
||||||
|
"adping": "11690182",
|
||||||
"spend": 276.14
|
"spend": 276.14
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "tech.jm",
|
"pkg": "tech.jm",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "tech.jm_RU",
|
||||||
|
"adping": "9297014",
|
||||||
"spend": 86.65
|
"spend": 86.65
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -76,22 +106,37 @@
|
|||||||
"pkgs": [
|
"pkgs": [
|
||||||
{
|
{
|
||||||
"pkg": "ru.aliexpress.buyer",
|
"pkg": "ru.aliexpress.buyer",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "ru.aliexpress.buyer_RU",
|
||||||
|
"adping": "6607117",
|
||||||
"spend": 942.263
|
"spend": 942.263
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.king.candycrushsaga",
|
"pkg": "com.king.candycrushsaga",
|
||||||
|
"geo": "TH",
|
||||||
|
"label": "com.king.candycrushsaga_TH",
|
||||||
|
"adping": "5497580",
|
||||||
"spend": 928.304
|
"spend": 928.304
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "ru.kinopoisk",
|
"pkg": "ru.kinopoisk",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "ru.kinopoisk_RU",
|
||||||
|
"adping": "10599681",
|
||||||
"spend": 91.0
|
"spend": 91.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.edadeal.android",
|
"pkg": "com.edadeal.android",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.edadeal.android_RU",
|
||||||
|
"adping": "10599157",
|
||||||
"spend": 84.5
|
"spend": 84.5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "ru.mobstudio.andgalaxy",
|
"pkg": "ru.mobstudio.andgalaxy",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "ru.mobstudio.andgalaxy_RU",
|
||||||
|
"adping": "7953512",
|
||||||
"spend": 30.62
|
"spend": 30.62
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -105,22 +150,37 @@
|
|||||||
"pkgs": [
|
"pkgs": [
|
||||||
{
|
{
|
||||||
"pkg": "ru.kinopoisk",
|
"pkg": "ru.kinopoisk",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "ru.kinopoisk_RU",
|
||||||
|
"adping": "8291713",
|
||||||
"spend": 609.84
|
"spend": 609.84
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "ru.ozon.app.android",
|
"pkg": "ru.ozon.app.android",
|
||||||
|
"geo": "KZ",
|
||||||
|
"label": "ru.ozon.app.android_KZ",
|
||||||
|
"adping": "5963354",
|
||||||
"spend": 590.7586
|
"spend": 590.7586
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.edadeal.android",
|
"pkg": "com.edadeal.android",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.edadeal.android_RU",
|
||||||
|
"adping": "6395488",
|
||||||
"spend": 180.0
|
"spend": 180.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.yandex.bank",
|
"pkg": "com.yandex.bank",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.yandex.bank_RU",
|
||||||
|
"adping": "2937658",
|
||||||
"spend": 93.281
|
"spend": 93.281
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "ru.yandex.music",
|
"pkg": "ru.yandex.music",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "ru.yandex.music_RU",
|
||||||
|
"adping": "8566541",
|
||||||
"spend": 70.57
|
"spend": 70.57
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -134,22 +194,37 @@
|
|||||||
"pkgs": [
|
"pkgs": [
|
||||||
{
|
{
|
||||||
"pkg": "com.king.candycrushsaga",
|
"pkg": "com.king.candycrushsaga",
|
||||||
|
"geo": "MY",
|
||||||
|
"label": "com.king.candycrushsaga_MY",
|
||||||
|
"adping": "5464039",
|
||||||
"spend": 1000.69
|
"spend": 1000.69
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.esprit.rpg.lttlefirykng",
|
"pkg": "com.esprit.rpg.lttlefirykng",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.esprit.rpg.lttlefirykng_RU",
|
||||||
|
"adping": "10514860",
|
||||||
"spend": 120.8
|
"spend": 120.8
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "ru.kinopoisk",
|
"pkg": "ru.kinopoisk",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "ru.kinopoisk_RU",
|
||||||
|
"adping": "91399821",
|
||||||
"spend": 101.76
|
"spend": 101.76
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.reefgames.fabletown",
|
"pkg": "com.reefgames.fabletown",
|
||||||
|
"geo": "RU",
|
||||||
|
"label": "com.reefgames.fabletown_RU",
|
||||||
|
"adping": "91532857",
|
||||||
"spend": 72.909
|
"spend": 72.909
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pkg": "com.netease.newspike",
|
"pkg": "com.netease.newspike",
|
||||||
|
"geo": "US",
|
||||||
|
"label": "com.netease.newspike_US",
|
||||||
|
"adping": "91544364",
|
||||||
"spend": 37.714
|
"spend": 37.714
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
+2
-2
@@ -73,8 +73,8 @@ function render(d){
|
|||||||
new Chart(document.getElementById('spendChart'),{type:'bar',data:{labels:buyers.map(b=>b.name),datasets:[{label:'投放花费',data:buyers.map(b=>b.total),backgroundColor:buyers.map((b,i)=>palette[i%palette.length])}]},plugins:[barLabels],options:{indexAxis:'y',layout:{padding:{right:76}},plugins:{legend:{display:false},tooltip:{callbacks:{label:(c)=>usd(c.parsed.x)}}},scales:{x:{ticks:{color:'#5b6472',callback:axisUsd},grid:{color:'#d6e2f5'}},y:{ticks:{color:'#111111'},grid:{display:false}}}}});
|
new Chart(document.getElementById('spendChart'),{type:'bar',data:{labels:buyers.map(b=>b.name),datasets:[{label:'投放花费',data:buyers.map(b=>b.total),backgroundColor:buyers.map((b,i)=>palette[i%palette.length])}]},plugins:[barLabels],options:{indexAxis:'y',layout:{padding:{right:76}},plugins:{legend:{display:false},tooltip:{callbacks:{label:(c)=>usd(c.parsed.x)}}},scales:{x:{ticks:{color:'#5b6472',callback:axisUsd},grid:{color:'#d6e2f5'}},y:{ticks:{color:'#111111'},grid:{display:false}}}}});
|
||||||
new Chart(document.getElementById('pkgChart'),{type:'bar',data:{labels:buyers.map(b=>b.name),datasets:[{label:'主要Package花费',data:buyers.map(b=>b.pkgs[0].spend),backgroundColor:'#4dd6a8'}]},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:(c)=>usd(c.parsed.y),afterLabel:(ctx)=>buyers[ctx.dataIndex].pkgs[0].pkg}}},scales:{x:{ticks:{color:'#111111'},grid:{display:false}},y:{ticks:{color:'#5b6472',callback:axisUsd},grid:{color:'#d6e2f5'}}}}});
|
new Chart(document.getElementById('pkgChart'),{type:'bar',data:{labels:buyers.map(b=>b.name),datasets:[{label:'主要Package花费',data:buyers.map(b=>b.pkgs[0].spend),backgroundColor:'#4dd6a8'}]},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:(c)=>usd(c.parsed.y),afterLabel:(ctx)=>buyers[ctx.dataIndex].pkgs[0].pkg}}},scales:{x:{ticks:{color:'#111111'},grid:{display:false}},y:{ticks:{color:'#5b6472',callback:axisUsd},grid:{color:'#d6e2f5'}}}}});
|
||||||
document.getElementById('tables').innerHTML=buyers.map(b=>{
|
document.getElementById('tables').innerHTML=buyers.map(b=>{
|
||||||
const rows=b.pkgs.map(p=>'<tr><td class="pkg">'+p.pkg+'</td><td class="num">'+usd(p.spend)+'</td></tr>').join('');
|
const rows=b.pkgs.map(p=>'<tr><td class="pkg">'+(p.label||p.pkg)+'</td><td class="pkg">'+(p.adping||'-')+'</td><td class="num">'+usd(p.spend)+'</td></tr>').join('');
|
||||||
return '<div style="margin-bottom:18px"><div class="buyer-name">'+b.name+' <span style="color:var(--sub);font-weight:400">合计 '+usd(b.total)+' · 在投 Adping '+(b.active_ids??'-')+' 个(共负责 '+(b.owned_ids??'-')+' 个)'+' · 主要订单 '+b.pkgs[0].pkg+'</span></div><details><summary>展开 '+b.pkgs.length+' 个 Package 明细</summary><table><thead><tr><th>Package</th><th class="num">花费</th></tr></thead><tbody>'+rows+'</tbody></table></details></div>';
|
return '<div style="margin-bottom:18px"><div class="buyer-name">'+b.name+' <span style="color:var(--sub);font-weight:400">合计 '+usd(b.total)+' · 在投 Adping '+(b.active_ids??'-')+' 个(共负责 '+(b.owned_ids??'-')+' 个)'+' · 主要订单 '+(b.pkgs[0].label||b.pkgs[0].pkg)+'</span></div><details><summary>展开 '+b.pkgs.length+' 个 Package 明细</summary><table><thead><tr><th>Package</th><th>Adpingid</th><th class="num">花费</th></tr></thead><tbody>'+rows+'</tbody></table></details></div>';
|
||||||
}).join('');
|
}).join('');
|
||||||
document.getElementById('foot').textContent=d.meta.note;
|
document.getElementById('foot').textContent=d.meta.note;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user