- 列表全选复选框从工具栏移到表格表头,事件委托处理动态元素 - 重复ASIN Tab 标题加总数(XX 为重复 ASIN 数量) - 重复ASIN 筛选独立:ASIN/店铺/国家/上架时间(开始+结束),与原店铺数据筛选互不影响 - 后端支持 asin/shop_name/country/date_from/date_to 参数: 行级筛选命中 ASIN 后展示完整记录(含其他店铺,跨店语义更直观) - 日期文本归一化(支持 2026年8月19日 上午4:34 中文格式) - 按 ASIN 分组表格展示:ASIN/店铺数/记录条数/品牌/对应店铺/国家/上架时间/操作, 详情展开显示每条记录的店铺/分组/国家/日期/价格/品牌 - 修复 _shop_data_crawl_fetch_result_bytes 兼容 result_id 列别名(生产首个真实调用报 KeyError) - 新增单测:筛选语义、日期归一化、record_count
This commit is contained in:
@@ -36,6 +36,12 @@ class ShopDataDuplicateAsinTest(unittest.TestCase):
|
||||
{'shop_name': 'Shop C', 'latest_created_at': datetime(2026, 8, 31, 1, 15, 3)},
|
||||
]
|
||||
# 每家店一个结果文件:Shop A 与 Shop B 共享 ASIN1;Shop C 单独 ASIN3
|
||||
# 国家码按店铺实际 sheet:A=UK+DE、B=仅UK、C=FR
|
||||
self.shop_country = {
|
||||
'Shop A': '["UK","DE"]',
|
||||
'Shop B': '["UK"]',
|
||||
'Shop C': '["FR"]',
|
||||
}
|
||||
self.shop_files = {
|
||||
'Shop A': _make_workbook({
|
||||
'英国': [('2026-08-30', 'B0ABC111', 'GBP 9.99', 'BrandA'),
|
||||
@@ -130,7 +136,8 @@ class ShopDataDuplicateAsinTest(unittest.TestCase):
|
||||
def _run_request(self, query=''):
|
||||
cursor = self._FakeCursor(
|
||||
self.group_rows,
|
||||
[self._result_row(i + 1, row['shop_name'], '["UK","DE"]') for i, row in enumerate(self.group_rows)],
|
||||
[self._result_row(i + 1, row['shop_name'], self.shop_country[row['shop_name']])
|
||||
for i, row in enumerate(self.group_rows)],
|
||||
)
|
||||
connection = self._FakeConnection(cursor)
|
||||
with self.app.test_request_context('/api/admin/shop-data-crawl/duplicate-asins?' + query):
|
||||
@@ -151,6 +158,7 @@ class ShopDataDuplicateAsinTest(unittest.TestCase):
|
||||
item = body['items'][0]
|
||||
self.assertEqual(item['asin'], 'B0ABC111')
|
||||
self.assertEqual(item['shop_count'], 2)
|
||||
self.assertEqual(item['record_count'], 3) # ShopA 英国/德国 + ShopB 英国 共 3 条
|
||||
shops = {occ['shop_name'] for occ in item['occurrences']}
|
||||
self.assertEqual(shops, {'Shop A', 'Shop B'})
|
||||
# 国家与日期从行/表头正确映射
|
||||
@@ -158,6 +166,38 @@ class ShopDataDuplicateAsinTest(unittest.TestCase):
|
||||
self.assertIn('UK', shop_a['country_codes'])
|
||||
self.assertEqual(shop_a['date'], '2026-08-30')
|
||||
|
||||
def test_filters_asin_and_date_range(self):
|
||||
# asin 模糊:匹配 B0ABC222 的只有 Shop B 一家,不构成跨店重复 → total 0
|
||||
response = self._run_request('page=1&page_size=10&asin=B0ABC222')
|
||||
body = response.get_json()
|
||||
self.assertEqual(body['total'], 0)
|
||||
# 日期范围 08-31:B0ABC111 在 Shop B 有该日记录 → 命中,展示完整记录(跨店仍 2 家)
|
||||
response = self._run_request('page=1&page_size=10&date_from=2026-08-31&date_to=2026-08-31')
|
||||
body = response.get_json()
|
||||
self.assertEqual(body['total'], 1)
|
||||
self.assertEqual(body['items'][0]['asin'], 'B0ABC111')
|
||||
self.assertEqual(body['items'][0]['shop_count'], 2) # 完整记录仍跨店
|
||||
# 日期范围 08-30:Shop A 两条命中,同样返回完整记录
|
||||
response = self._run_request('page=1&page_size=10&date_from=2026-08-30T00:00&date_to=2026-08-30T23:59')
|
||||
body = response.get_json()
|
||||
self.assertEqual(body['total'], 1)
|
||||
|
||||
def test_filters_shop_and_country(self):
|
||||
# 店铺过滤 Shop B:命中含 Shop B 记录的 ASIN → B0ABC111,展示完整记录跨店
|
||||
response = self._run_request('page=1&page_size=10&shop_name=Shop+B')
|
||||
body = response.get_json()
|
||||
self.assertEqual(body['total'], 1)
|
||||
self.assertEqual(body['items'][0]['asin'], 'B0ABC111')
|
||||
# 国家过滤 FR:只有 Shop C 有 FR,其 ASIN 仅单店 → 不构成重复 → total 0
|
||||
response = self._run_request('page=1&page_size=10&country=FR')
|
||||
body = response.get_json()
|
||||
self.assertEqual(body['total'], 0)
|
||||
# 国家过滤 DE:Shop A 命中 → B0ABC111 完整记录 → total 1
|
||||
response = self._run_request('page=1&page_size=10&country=DE')
|
||||
body = response.get_json()
|
||||
self.assertEqual(body['total'], 1)
|
||||
self.assertEqual(body['items'][0]['asin'], 'B0ABC111')
|
||||
|
||||
def test_pagination_when_page_out_of_range(self):
|
||||
response = self._run_request('page=2&page_size=10')
|
||||
body = response.get_json()
|
||||
@@ -173,6 +213,20 @@ class ShopDataDuplicateAsinTest(unittest.TestCase):
|
||||
rows = admin_api._shop_data_crawl_parse_workbook(wb)
|
||||
self.assertEqual([row['asin'] for row in rows], ['B0TEST01'])
|
||||
|
||||
def test_date_key_normalizes_chinese_datetime(self):
|
||||
# 中文日期归一化为 ISO 供范围比较
|
||||
cases = {
|
||||
'2026年8月18日 上午4:34': '2026-08-18',
|
||||
'2026年8月19日 05:48': '2026-08-19',
|
||||
'2026-08-19': '2026-08-19',
|
||||
'2026.8.19': '2026-08-19',
|
||||
'2026/8/19': '2026-08-19',
|
||||
'': '',
|
||||
'abc': 'abc', # 无法识别时原样返回,范围比较自然失败
|
||||
}
|
||||
for raw, expected in cases.items():
|
||||
self.assertEqual(admin_api._shop_data_date_key(raw), expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user