refactor(api):重构API服务接口与实现
- 移除多余的接口定义文件,简化依赖关系- 更新控制器和服务实现类的注入方式-优化请求参数处理逻辑 - 统一响应数据结构格式- 调整方法签名以提高一致性 - 删除冗余注释和无用代码- 修改系统API调用路径引用位置 - 简化认证服务实现并移除不必要的抽象层 - 优化Excel文件解析相关功能 - 清理无用的工具类和配置项 - 调整错误上报机制的依赖注入方式 - 更新跟卖精灵服务的实现细节- 优化HTTP请求工具函数结构 - 移除废弃的缓存管理服务接口定义 - 调整设备配额检查逻辑复用性 - 优化订单服务的数据返回格式 - 更新产品服务中的数据处理方式 - 重构客户端账户控制器中的设备限制检查逻辑
This commit is contained in:
@@ -1,35 +1,17 @@
|
||||
import { http } from './http';
|
||||
|
||||
export const amazonApi = {
|
||||
// 上传Excel文件解析ASIN列表
|
||||
importAsinFromExcel(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return http.upload<{ code: number, data: { asinList: string[], total: number }, msg: string | null }>('/api/amazon/import/asin', formData);
|
||||
},
|
||||
|
||||
getProductsBatch(asinList: string[], batchId: string, region: string) {
|
||||
return http.post<{ code: number, data: { products: any[] }, msg: string | null }>('/api/amazon/products/batch', { asinList, batchId, region });
|
||||
getProductsBatch(asinList: string[], batchId: string, region: string, signal?: AbortSignal) {
|
||||
return http.post<{ code: number, data: { products: any[] }, msg: string | null }>('/api/amazon/products/batch', { asinList, batchId, region }, signal);
|
||||
},
|
||||
|
||||
getLatestProducts() {
|
||||
return http.get<{ code: number, data: { products: any[] }, msg: string | null }>('/api/amazon/products/latest');
|
||||
},
|
||||
getProductsByBatch(batchId: string) {
|
||||
return http.get<{ products: any[] }>(`/api/amazon/products/batch/${batchId}`);
|
||||
},
|
||||
updateProduct(productData: unknown) {
|
||||
return http.post('/api/amazon/products/update', productData);
|
||||
},
|
||||
deleteProduct(productId: string) {
|
||||
return http.post('/api/amazon/products/delete', { id: productId });
|
||||
},
|
||||
getProductStats() {
|
||||
return http.get('/api/amazon/stats');
|
||||
},
|
||||
searchProducts(searchParams: Record<string, unknown>) {
|
||||
return http.get('/api/amazon/products/search', searchParams);
|
||||
},
|
||||
openGenmaiSpirit() {
|
||||
return http.post('/api/system/genmai/open');
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// HTTP 工具:统一管理后端服务配置和请求
|
||||
export type HttpMethod = 'GET' | 'POST' | 'DELETE';
|
||||
|
||||
// 集中管理所有后端服务配置
|
||||
export const CONFIG = {
|
||||
CLIENT_BASE: 'http://localhost:8081',
|
||||
// RUOYI_BASE: 'http://192.168.1.89:8085',
|
||||
RUOYI_BASE: 'http://8.138.23.49:8085',
|
||||
SSE_URL: 'http://8.138.23.49:8085/monitor/account/events'
|
||||
//RUOYI_BASE: 'http://8.138.23.49:8085',
|
||||
RUOYI_BASE: 'http://192.168.1.89:8085',
|
||||
SSE_URL: 'http://192.168.1.89:8085/monitor/account/events'
|
||||
} as const;
|
||||
|
||||
function resolveBase(path: string): string {
|
||||
// RuoYi 后端路径:鉴权、设备、反馈、版本、工具
|
||||
if (path.startsWith('/monitor/') || path.startsWith('/system/') || path.startsWith('/tool/banma')) {
|
||||
return CONFIG.RUOYI_BASE;
|
||||
}
|
||||
@@ -26,16 +23,17 @@ function buildQuery(params?: Record<string, unknown>): string {
|
||||
return query.toString() ? `?${query}` : '';
|
||||
}
|
||||
|
||||
async function request<T>(path: string, options: RequestInit): Promise<T> {
|
||||
// 获取token
|
||||
let token = '';
|
||||
async function getToken(): Promise<string> {
|
||||
try {
|
||||
const tokenModule = await import('../utils/token');
|
||||
token = tokenModule.getToken() || '';
|
||||
} catch (e) {
|
||||
console.warn('获取token失败:', e);
|
||||
return tokenModule.getToken() || '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
async function request<T>(path: string, options: RequestInit & { signal?: AbortSignal }): Promise<T> {
|
||||
const token = await getToken();
|
||||
const res = await fetch(`${resolveBase(path)}${path}`, {
|
||||
credentials: 'omit',
|
||||
cache: 'no-store',
|
||||
@@ -55,9 +53,6 @@ async function request<T>(path: string, options: RequestInit): Promise<T> {
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
if (contentType.includes('application/json')) {
|
||||
const json: any = await res.json();
|
||||
// 业务状态码判断:支持两种格式
|
||||
// - erp_client_sb (本地服务): code=0 表示成功
|
||||
// - RuoYi 后端: code=200 表示成功
|
||||
if (json.code !== undefined && json.code !== 0 && json.code !== 200) {
|
||||
throw new Error(json.msg || '请求失败');
|
||||
}
|
||||
@@ -68,13 +63,14 @@ async function request<T>(path: string, options: RequestInit): Promise<T> {
|
||||
}
|
||||
|
||||
export const http = {
|
||||
get<T>(path: string, params?: Record<string, unknown>) {
|
||||
return request<T>(`${path}${buildQuery(params)}`, { method: 'GET' });
|
||||
get<T>(path: string, params?: Record<string, unknown>, signal?: AbortSignal) {
|
||||
return request<T>(`${path}${buildQuery(params)}`, { method: 'GET', signal });
|
||||
},
|
||||
post<T>(path: string, body?: unknown) {
|
||||
post<T>(path: string, body?: unknown, signal?: AbortSignal) {
|
||||
return request<T>(path, {
|
||||
method: 'POST',
|
||||
body: body ? JSON.stringify(body) : undefined
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
signal
|
||||
});
|
||||
},
|
||||
|
||||
@@ -82,42 +78,31 @@ export const http = {
|
||||
return request<T>(path, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
async upload<T>(path: string, form: FormData) {
|
||||
// 获取token
|
||||
let token = '';
|
||||
try {
|
||||
const tokenModule = await import('../utils/token');
|
||||
token = tokenModule.getToken() || '';
|
||||
} catch (e) {
|
||||
console.warn('获取token失败:', e);
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
return fetch(`${resolveBase(path)}${path}`, {
|
||||
async upload<T>(path: string, form: FormData, signal?: AbortSignal) {
|
||||
const token = await getToken();
|
||||
const res = await fetch(`${resolveBase(path)}${path}`, {
|
||||
method: 'POST',
|
||||
body: form,
|
||||
credentials: 'omit',
|
||||
cache: 'no-store',
|
||||
headers
|
||||
}).then(async res => {
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '');
|
||||
throw new Error(text || `HTTP ${res.status}`);
|
||||
}
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
if (contentType.includes('application/json')) {
|
||||
const json: any = await res.json();
|
||||
if (json.code !== undefined && json.code !== 0 && json.code !== 200) {
|
||||
throw new Error(json.msg || '请求失败');
|
||||
}
|
||||
return json as T;
|
||||
}
|
||||
return (await res.text()) as unknown as T;
|
||||
headers: token ? { 'Authorization': `Bearer ${token}` } : {},
|
||||
signal
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '');
|
||||
throw new Error(text || `HTTP ${res.status}`);
|
||||
}
|
||||
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
if (contentType.includes('application/json')) {
|
||||
const json: any = await res.json();
|
||||
if (json.code !== undefined && json.code !== 0 && json.code !== 200) {
|
||||
throw new Error(json.msg || '请求失败');
|
||||
}
|
||||
return json as T;
|
||||
}
|
||||
return (await res.text()) as unknown as T;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
12
electron-vue-template/src/renderer/api/system.ts
Normal file
12
electron-vue-template/src/renderer/api/system.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { http } from './http';
|
||||
|
||||
export const systemApi = {
|
||||
openGenmaiSpirit() {
|
||||
return http.post('/api/system/genmai/open');
|
||||
},
|
||||
|
||||
clearCache() {
|
||||
return http.post('/api/system/cache/clear');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,23 +18,11 @@ export const zebraApi = {
|
||||
return http.get('/api/banma/shops', params as Record<string, unknown>)
|
||||
},
|
||||
|
||||
getOrders(params: any) {
|
||||
return http.get('/api/banma/orders', params as Record<string, unknown>)
|
||||
},
|
||||
|
||||
getOrdersByBatch(batchId: string) {
|
||||
return http.get(`/api/banma/orders/batch/${batchId}`)
|
||||
getOrders(params: any, signal?: AbortSignal) {
|
||||
return http.get('/api/banma/orders', params as Record<string, unknown>, signal)
|
||||
},
|
||||
|
||||
getLatestOrders() {
|
||||
return http.get('/api/banma/orders/latest')
|
||||
},
|
||||
|
||||
getOrderStats() {
|
||||
return http.get('/api/banma/orders/stats')
|
||||
},
|
||||
|
||||
searchOrders(searchParams: Record<string, unknown>) {
|
||||
return http.get('/api/banma/orders/search', searchParams)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
import { ref, computed, onMounted, defineAsyncComponent, inject } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { amazonApi } from '../../api/amazon'
|
||||
import { systemApi } from '../../api/system'
|
||||
import { handlePlatformFileExport } from '../../utils/settings'
|
||||
|
||||
const TrialExpiredDialog = defineAsyncComponent(() => import('../common/TrialExpiredDialog.vue'))
|
||||
@@ -21,6 +22,7 @@ const progressVisible = ref(false) // 进度条是否显示(完成后仍保留
|
||||
const localProductData = ref<any[]>([]) // 本地产品数据
|
||||
const currentAsin = ref('') // 当前处理的ASIN
|
||||
const genmaiLoading = ref(false) // Genmai Spirit加载状态
|
||||
let abortController: AbortController | null = null // 请求取消控制器
|
||||
|
||||
// 分页配置
|
||||
const currentPage = ref(1)
|
||||
@@ -130,7 +132,7 @@ async function batchGetProductInfo(asinList: string[]) {
|
||||
currentAsin.value = `正在处理第${i + 1}/${totalBatches}批 (${batchAsins.join(', ')})`
|
||||
|
||||
try {
|
||||
const result = await amazonApi.getProductsBatch(batchAsins, batchId, region.value)
|
||||
const result = await amazonApi.getProductsBatch(batchAsins, batchId, region.value, abortController?.signal)
|
||||
|
||||
if (result?.data?.products?.length > 0) {
|
||||
localProductData.value.push(...result.data.products)
|
||||
@@ -142,7 +144,8 @@ async function batchGetProductInfo(asinList: string[]) {
|
||||
const actualCount = result?.data?.products?.length || 0
|
||||
failedCount += Math.max(0, expectedCount - actualCount)
|
||||
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
if (error.name === 'AbortError') break
|
||||
failedCount += batchAsins.length
|
||||
console.error(`批次${i + 1}失败:`, error)
|
||||
}
|
||||
@@ -164,8 +167,10 @@ async function batchGetProductInfo(asinList: string[]) {
|
||||
|
||||
|
||||
} catch (error: any) {
|
||||
showMessage(error.message || '批量获取产品信息失败', 'error')
|
||||
currentAsin.value = '处理失败'
|
||||
if (error.name !== 'AbortError') {
|
||||
showMessage(error.message || '批量获取产品信息失败', 'error')
|
||||
currentAsin.value = '处理失败'
|
||||
}
|
||||
} finally {
|
||||
tableLoading.value = false
|
||||
}
|
||||
@@ -177,6 +182,7 @@ async function startQueuedFetch() {
|
||||
showMessage('请先导入ASIN列表', 'warning')
|
||||
return
|
||||
}
|
||||
abortController = new AbortController()
|
||||
loading.value = true
|
||||
progressVisible.value = true
|
||||
tableLoading.value = true
|
||||
@@ -185,6 +191,7 @@ async function startQueuedFetch() {
|
||||
} finally {
|
||||
tableLoading.value = false
|
||||
loading.value = false
|
||||
abortController = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,12 +247,13 @@ function isOutOfStock(product: any) {
|
||||
|
||||
// 停止获取操作
|
||||
function stopFetch() {
|
||||
abortController?.abort()
|
||||
abortController = null
|
||||
loading.value = false
|
||||
currentAsin.value = '已停止'
|
||||
showMessage('已停止获取产品数据', 'info')
|
||||
}
|
||||
|
||||
// 打开Genmai Spirit工具
|
||||
async function openGenmaiSpirit() {
|
||||
try {
|
||||
await ElMessageBox.confirm('打开跟卖精灵会关闭所有谷歌浏览器进程,是否继续?', '提示', {
|
||||
@@ -255,7 +263,7 @@ async function openGenmaiSpirit() {
|
||||
})
|
||||
genmaiLoading.value = true
|
||||
try {
|
||||
await amazonApi.openGenmaiSpirit()
|
||||
await systemApi.openGenmaiSpirit()
|
||||
} catch (error: any) {
|
||||
showMessage(error.message || '打开跟卖精灵失败', 'error')
|
||||
} finally {
|
||||
|
||||
@@ -40,6 +40,7 @@ const fetchCurrentPage = ref(1)
|
||||
const fetchTotalPages = ref(0)
|
||||
const fetchTotalItems = ref(0)
|
||||
const isFetching = ref(false)
|
||||
let abortController: AbortController | null = null
|
||||
|
||||
// 试用期过期弹框
|
||||
const showTrialExpiredDialog = ref(false)
|
||||
@@ -113,6 +114,7 @@ async function fetchData() {
|
||||
return
|
||||
}
|
||||
|
||||
abortController = new AbortController()
|
||||
loading.value = true
|
||||
isFetching.value = true
|
||||
showProgress.value = true
|
||||
@@ -130,7 +132,7 @@ async function fetchPageData(startDate: string, endDate: string) {
|
||||
if (!isFetching.value) return
|
||||
|
||||
try {
|
||||
const data = await zebraApi.getOrders({
|
||||
const response = await zebraApi.getOrders({
|
||||
accountId: Number(accountId.value) || undefined,
|
||||
startDate,
|
||||
endDate,
|
||||
@@ -138,8 +140,9 @@ async function fetchPageData(startDate: string, endDate: string) {
|
||||
pageSize: 50,
|
||||
shopIds: selectedShops.value.join(','),
|
||||
batchId: currentBatchId.value
|
||||
})
|
||||
}, abortController?.signal)
|
||||
|
||||
const data = (response as any)?.data || response
|
||||
const orders = data.orders || []
|
||||
allOrderData.value = [...allOrderData.value, ...orders]
|
||||
|
||||
@@ -154,8 +157,10 @@ async function fetchPageData(startDate: string, endDate: string) {
|
||||
progressPercentage.value = 100
|
||||
finishFetching()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取订单数据失败:', e)
|
||||
} catch (e: any) {
|
||||
if (e.name !== 'AbortError') {
|
||||
console.error('获取订单数据失败:', e)
|
||||
}
|
||||
finishFetching()
|
||||
}
|
||||
}
|
||||
@@ -163,6 +168,7 @@ async function fetchPageData(startDate: string, endDate: string) {
|
||||
function finishFetching() {
|
||||
isFetching.value = false
|
||||
loading.value = false
|
||||
abortController = null
|
||||
// 确保进度条完全填满
|
||||
progressPercentage.value = 100
|
||||
currentPage.value = 1
|
||||
@@ -170,6 +176,8 @@ function finishFetching() {
|
||||
}
|
||||
|
||||
function stopFetch() {
|
||||
abortController?.abort()
|
||||
abortController = null
|
||||
isFetching.value = false
|
||||
loading.value = false
|
||||
// 进度条保留显示,不自动隐藏
|
||||
|
||||
Reference in New Issue
Block a user