fix(admin-vue 查询ASIN): 列表筛选/分页参数对齐后端 snake_case,导出 XLSX 带上当前筛选
- query-asin-filter: toQueryAsinQuery 输出 page_size/group_id/shop_name(35bed42b 后端已改显式 snake, camel 参数被静默忽略导致分组/店铺名筛选无作用、pageSize 固定回落 15) - 新增 query-asin-export: 按当前筛选构建导出 URL,页面「导出 XLSX」不再恒为全量 - query-asin-import-api: 导入兜底分组 groupId→group_id(后端 importExcel 已改名,此前同样被丢弃) - query-asin-delete-import-api: 保持 groupId 并加注释(后端仍隐式 camel,统一需两端同步部署) - task-71 测试断言更新为 snake 契约(含 camel 不下发反断言)+ 新增导出 URL 用例 已上线 admin-vue-20260910-145200,线上 chunk 验证含 snake 参数;task-71 10/10 通过,vue-tsc 通过
This commit is contained in:
@@ -8,6 +8,7 @@ import { createQueryAsin, fetchQueryAsinList, fetchShopNamesByGroup } from './qu
|
||||
import { QUERY_ASIN_COUNTRIES, queryAsinDisplayRows, type QueryAsinItem } from './query-asin-model.ts'
|
||||
import { asinCountryLabel } from './asin-country.ts'
|
||||
import { createQueryAsinFilterState, type QueryAsinFilterState } from './query-asin-filter.ts'
|
||||
import { toQueryAsinExportUrl } from './query-asin-export.ts'
|
||||
import { deleteQueryAsinCountryAsin, updateQueryAsinCountryAsin } from './query-asin-detail-api.ts'
|
||||
import { fetchQueryAsinImportProgress, startQueryAsinImport } from './query-asin-import-api.ts'
|
||||
import { fetchQueryAsinDeleteImportProgress, startQueryAsinDeleteImport } from './query-asin-delete-import-api.ts'
|
||||
@@ -263,8 +264,9 @@ async function submitImport(): Promise<void> {
|
||||
|
||||
// ---- 导出 ----
|
||||
function doExport(): void {
|
||||
// 带当前筛选(分组/店铺名/ASIN/国家)导出,范围与列表筛选一致(此前不带参数导致导出恒为全量)。
|
||||
const anchor = document.createElement('a')
|
||||
anchor.href = '/api/admin/query-asins/export'
|
||||
anchor.href = toQueryAsinExportUrl(filter)
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
anchor.remove()
|
||||
|
||||
@@ -8,7 +8,9 @@ import {
|
||||
|
||||
export const QUERY_ASIN_DELETE_IMPORT_ENDPOINT = '/api/admin/query-asins/delete-import'
|
||||
|
||||
/** 启动导入删除;groupId 为 Excel 未提供分组时的兜底,可选(>=1 才下发)。 */
|
||||
/** 启动导入删除;groupId 为 Excel 未提供分组时的兜底,可选(>=1 才下发)。
|
||||
* 注意:后端 deleteImportExcel 仍是隐式 camel 参数名(groupId),此处必须发 groupId;
|
||||
* 与 import 的 group_id 不同源,后端统一为 snake 时需两端同步改。 */
|
||||
export async function startQueryAsinDeleteImport(file: File, groupId?: number): Promise<string> {
|
||||
const form = new FormData()
|
||||
form.append('file', file, file.name)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/** 查询 ASIN 导出 URL 构建:按当前筛选下发 group_id/shop_name/asin/country(对齐 Java export @RequestParam snake_case)。 */
|
||||
import { normalizeQueryAsinCountry, type QueryAsinFilterState } from './query-asin-filter.ts'
|
||||
|
||||
export const QUERY_ASIN_EXPORT_ENDPOINT = '/api/admin/query-asins/export'
|
||||
|
||||
/** 按导出可用筛选(分组/店铺名/ASIN/国家)构建查询串;空白/非法条件不下发,避免导出范围被误解。 */
|
||||
export function buildQueryAsinExportQuery(state: QueryAsinFilterState): string {
|
||||
const params = new URLSearchParams()
|
||||
const groupId = state.groupId
|
||||
if (typeof groupId === 'number' && groupId >= 1) params.set('group_id', String(Math.floor(groupId)))
|
||||
const shopName = (state.shopName || '').trim()
|
||||
if (shopName) params.set('shop_name', shopName)
|
||||
const asin = (state.asin || '').trim()
|
||||
if (asin) params.set('asin', asin)
|
||||
const country = normalizeQueryAsinCountry(state.country)
|
||||
if (country) params.set('country', country)
|
||||
return params.toString()
|
||||
}
|
||||
|
||||
/** 导出下载地址:浏览器直接访问该 URL 触发流式下载;无筛选时为全量导出。 */
|
||||
export function toQueryAsinExportUrl(state: QueryAsinFilterState): string {
|
||||
const query = buildQueryAsinExportQuery(state)
|
||||
return query ? `${QUERY_ASIN_EXPORT_ENDPOINT}?${query}` : QUERY_ASIN_EXPORT_ENDPOINT
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
/** 查询 ASIN 页面筛选/分页状态(任务 71):分组/店铺名/ASIN/国家,仅下发非空且受支持的条件;Java 参数名 camelCase。 */
|
||||
/** 查询 ASIN 页面筛选/分页状态(任务 71):分组/店铺名/ASIN/国家,仅下发非空且受支持的条件;
|
||||
* Java 参数名 snake_case(与 asin-filter 共享契约一致):page_size/group_id/shop_name,裸 camel 后端收不到会导致筛选失效。 */
|
||||
import { ASIN_PAGE_DEFAULT_SIZE } from './asin-filter.ts'
|
||||
import { QUERY_ASIN_COUNTRIES } from './query-asin-model.ts'
|
||||
|
||||
@@ -24,9 +25,9 @@ export interface QueryAsinListParams {
|
||||
|
||||
export interface QueryAsinQuery {
|
||||
page: number
|
||||
pageSize: number
|
||||
groupId?: number
|
||||
shopName?: string
|
||||
page_size: number
|
||||
group_id?: number
|
||||
shop_name?: string
|
||||
asin?: string
|
||||
country?: string
|
||||
}
|
||||
@@ -92,11 +93,11 @@ export function toQueryAsinParams(
|
||||
})
|
||||
}
|
||||
|
||||
/** 前端查询参数 → Java 查询参数;与 QueryAsinController @RequestParam(camel) 对齐,仅下发非空字段。 */
|
||||
/** 前端查询参数 → Java 查询参数;与 QueryAsinController @RequestParam(snake_case: page_size/group_id/shop_name/asin/country) 对齐,仅下发非空字段。 */
|
||||
export function toQueryAsinQuery(params: QueryAsinListParams): QueryAsinQuery {
|
||||
const query: QueryAsinQuery = { page: params.page, pageSize: params.pageSize }
|
||||
if (typeof params.groupId === 'number' && params.groupId >= 1) query.groupId = params.groupId
|
||||
if (params.shopName) query.shopName = params.shopName
|
||||
const query: QueryAsinQuery = { page: params.page, page_size: params.pageSize }
|
||||
if (typeof params.groupId === 'number' && params.groupId >= 1) query.group_id = params.groupId
|
||||
if (params.shopName) query.shop_name = params.shopName
|
||||
if (params.asin) query.asin = params.asin
|
||||
if (params.country) query.country = params.country
|
||||
return query
|
||||
|
||||
@@ -8,12 +8,13 @@ import {
|
||||
|
||||
export const QUERY_ASIN_IMPORT_ENDPOINT = '/api/admin/query-asins/import'
|
||||
|
||||
/** 启动导入添加;groupId 为 Excel 未提供分组时的兜底,可选(>=1 才下发)。 */
|
||||
/** 启动导入添加;groupId 为 Excel 未提供分组时的兜底,可选(>=1 才下发)。
|
||||
* 参数名必须用 group_id:Java importExcel @RequestParam(name="group_id"),发 groupId 会被丢弃致兜底分组失效。 */
|
||||
export async function startQueryAsinImport(file: File, groupId?: number): Promise<string> {
|
||||
const form = new FormData()
|
||||
form.append('file', file, file.name)
|
||||
if (typeof groupId === 'number' && Number.isFinite(groupId) && groupId >= 1) {
|
||||
form.append('groupId', String(Math.floor(groupId)))
|
||||
form.append('group_id', String(Math.floor(groupId)))
|
||||
}
|
||||
const { data } = await http.post<unknown>(QUERY_ASIN_IMPORT_ENDPOINT, form)
|
||||
return parseQueryAsinImportStart(data)
|
||||
|
||||
Reference in New Issue
Block a user