feat: 修复 H5 底部导航覆盖 + 更新项目进度文档

## H5 底部导航修复 (Bug #10)
- 精简 App.vue,移除重复 tabbar,仅保留全局样式
- uni-page 设置 height: calc(100% - 50px) + overflow-y: auto
- 内容区域精确停在底部导航上方,独立滚动不再叠加
- 恢复 custom-tab-bar 组件

## 项目进度文档
- PROGRESS.md 更新至 10 个 Bug 修复
- 新增 H5 底部导航修复记录
- 新增历史变更条目
This commit is contained in:
TradeMate Dev
2026-05-12 20:24:42 +08:00
parent 69e164dcae
commit 7b62c2f8b4
125 changed files with 19725 additions and 728 deletions
+197 -27
View File
@@ -1,4 +1,4 @@
const BASE_URL = 'http://localhost:8000/api/v1'
export const BASE_URL = 'http://localhost:8000/api/v1'
const getAuthHeader = () => {
const token = uni.getStorageSync('token')
@@ -33,10 +33,104 @@ const request = (url, method = 'GET', data = {}) => {
})
}
const requestWithoutAuth = (url, method = 'GET', data = {}) => {
return new Promise((resolve, reject) => {
uni.request({
url: `${BASE_URL}${url}`,
method,
data,
header: {
'Content-Type': 'application/json',
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data)
} else {
reject(new Error(res.data?.detail || 'Request failed'))
}
},
fail: (err) => {
reject(err)
},
})
})
}
export const authApi = {
login: (phone, password) => request('/auth/login', 'POST', { username: phone, password }),
register: (phone, password, username) => request('/auth/register', 'POST', { phone, password, username }),
getUserInfo: () => request('/auth/me'),
wechatLogin: (code) => request('/auth/wechat-login', 'POST', { code }),
guestLogin: () => requestWithoutAuth('/auth/login/guest', 'POST'),
}
export const marketingApi = {
generate: (productName, description, category, target = 'US importers', style = 'professional') =>
request('/marketing/generate', 'POST', {
product_name: productName,
description,
category,
target,
style,
}),
getKeywords: (productName, description, category = '', language = 'en', count = 10) =>
request('/marketing/keywords', 'POST', {
product_name: productName,
description,
category,
language,
count,
}),
competitorAnalysis: (productName, description, category = '', market = 'US') =>
request('/marketing/competitor-analysis', 'POST', {
product_name: productName,
description,
category,
market,
}),
}
export const quotationApi = {
list: (page = 1, size = 20) => request(`/quotations?page=${page}&size=${size}`),
get: (id) => request(`/quotations/${id}`),
create: (data) => request('/quotations', 'POST', data),
updateStatus: (id, status) => request(`/quotations/${id}/status`, 'PATCH', { status }),
exportPdf: (id) => `${BASE_URL}/quotations/${id}/pdf`,
exportCsv: () => `${BASE_URL}/quotations/export/csv`,
generateFromInquiry: (inquiryText, customerId = null) =>
request('/quotations/generate-from-inquiry', 'POST', { inquiry_text: inquiryText, customer_id: customerId }),
}
export const productApi = {
list: (page = 1, size = 20) => request(`/products?page=${page}&size=${size}`),
get: (id) => request(`/products/${id}`),
create: (data) => request('/products', 'POST', data),
update: (id, data) => request(`/products/${id}`, 'PATCH', data),
delete: (id) => request(`/products/${id}`, 'DELETE'),
}
export const adminApi = {
getDashboard: () => request('/admin/dashboard'),
listUsers: (page = 1, size = 20) => request(`/admin/users?page=${page}&size=${size}`),
updateUserTier: (userId, tier) => request(`/admin/users/${userId}/tier`, 'PATCH', { tier }),
}
export const analyticsApi = {
getOverview: () => request('/analytics/overview'),
getCustomers: () => request('/analytics/customers'),
getTranslations: () => request('/analytics/translations'),
getQuotations: () => request('/analytics/quotations'),
getMessages: () => request('/analytics/messages'),
}
export const teamApi = {
list: () => request('/teams'),
get: (id) => request(`/teams/${id}`),
create: (name, description) => request('/teams', 'POST', { name, description }),
invite: (teamId, userId) => request(`/teams/${teamId}/invite`, 'POST', { user_id: userId }),
removeMember: (teamId, memberId) => request(`/teams/${teamId}/members/${memberId}`, 'DELETE'),
leave: (teamId) => request(`/teams/${teamId}/leave`, 'POST'),
updateRole: (teamId, memberId, role) => request(`/teams/${teamId}/members/${memberId}/role`, 'PATCH', { role }),
}
export const translateApi = {
@@ -44,6 +138,88 @@ export const translateApi = {
request('/translate', 'POST', { text, target_lang: targetLang, source_lang: sourceLang }),
getReply: (inquiry, tone = 'professional', count = 3) =>
request('/translate/reply', 'POST', { inquiry, tone, count }),
extract: (text, extractType = 'auto') =>
request('/translate/extract', 'POST', { text, extract_type: extractType }),
sendFeedback: (entryId, rating) =>
request('/translate/feedback', 'POST', { entry_id: entryId, rating }),
publicTranslate: (text, targetLang, sourceLang = 'auto') =>
requestWithoutAuth('/translate/public/translate', 'POST', { text, target_lang: targetLang, source_lang: sourceLang }),
publicExtract: (text, extractType = 'auto') =>
requestWithoutAuth('/translate/public/extract', 'POST', { text, extract_type: extractType }),
}
export const notificationApi = {
list: (page = 1, size = 20, unreadOnly = false) =>
request(`/notifications?page=${page}&size=${size}&unread_only=${unreadOnly}`),
unreadCount: () => request('/notifications/unread-count'),
markRead: (id) => request(`/notifications/${id}/read`, 'PATCH'),
markAllRead: () => request('/notifications/read-all', 'POST'),
delete: (id) => request(`/notifications/${id}`, 'DELETE'),
}
export const paymentApi = {
plans: () => request('/payment/plans'),
subscription: () => request('/payment/subscription'),
createOrder: (plan) => request('/payment/create-order', 'POST', { plan }),
}
export const feedbackApi = {
submit: (content, category = 'general', contact = '') =>
request('/feedback', 'POST', { content, category, contact }),
}
export const onboardingApi = {
status: () => request('/onboarding/status'),
createProduct: (name, description, category, target) =>
request('/onboarding/product', 'POST', { name, description, category, target }),
}
export const interactionApi = {
selectSuggestion: (messageId, selectedIndex) =>
request('/interaction/select', 'POST', { message_id: messageId, selected_index: selectedIndex }),
recordEdit: (messageId, editedText) =>
request('/interaction/edit', 'POST', { message_id: messageId, edited_text: editedText }),
analyzePreferences: () => request('/interaction/analyze', 'POST'),
getPreferences: () => request('/interaction/preferences'),
trackMarketingEffect: (data) => request('/interaction/marketing-effect', 'POST', data),
getMarketingEffects: (page = 1, size = 20) =>
request(`/interaction/marketing-effects?page=${page}&size=${size}`),
getMarketingEffectStats: () => request('/interaction/marketing-effects/stats'),
}
export const exchangeApi = {
convert: (fromCurrency = 'USD', toCurrency = 'CNY', amount = 1) =>
request(`/exchange/convert?from_currency=${fromCurrency}&to_currency=${toCurrency}&amount=${amount}`),
rates: (base = 'USD') => request(`/exchange/rates?base=${base}`),
}
export const pushApi = {
register: (clientId, platform = 'weapp', pushToken = null, deviceInfo = null) =>
request('/push/register', 'POST', { client_id: clientId, platform, push_token: pushToken, device_info: deviceInfo }),
unregister: (clientId) =>
request('/push/unregister', 'POST', { client_id: clientId }),
listDevices: () => request('/push/devices'),
}
export const silentPatternApi = {
getRiskAnalysis: () => request('/silent-pattern/risk-analysis'),
getSuggestions: (customerId) => request(`/silent-pattern/${customerId}/suggestions`),
}
export const followupApi = {
strategies: () => request('/followup/strategies'),
pending: (page = 1) => request(`/followup/pending?page=${page}`),
logs: (page = 1) => request(`/followup/logs?page=${page}`),
markSent: (id) => request(`/followup/${id}/send`, 'POST'),
editAndSend: (id, editedText) => request(`/followup/${id}/edit`, 'POST', { edited_text: editedText }),
stats: () => request('/followup/stats'),
scan: () => request('/followup/scan', 'POST'),
}
export const healthApi = {
overview: () => request('/customers/health-overview'),
allScores: () => request('/customers/health-scores'),
customerHealth: (id) => request(`/customers/${id}/health`),
}
export const customerApi = {
@@ -59,30 +235,24 @@ export const customerApi = {
getSilent: (days = 3) => request(`/customers/silent?days=${days}`),
getConversation: (id, page = 1, size = 50) =>
request(`/customers/${id}/conversation?page=${page}&size=${size}`),
}
export const marketingApi = {
generate: (productName, description, category, target = 'US importers', style = 'professional') =>
request('/marketing/generate', 'POST', {
product_name: productName,
description,
category,
target,
style,
}),
}
export const quotationApi = {
list: (page = 1, size = 20) => request(`/quotations?page=${page}&size=${size}`),
get: (id) => request(`/quotations/${id}`),
create: (data) => request('/quotations', 'POST', data),
updateStatus: (id, status) => request(`/quotations/${id}/status`, 'PATCH', { status }),
}
export const productApi = {
list: (page = 1, size = 20) => request(`/products?page=${page}&size=${size}`),
get: (id) => request(`/products/${id}`),
create: (data) => request('/products', 'POST', data),
update: (id, data) => request(`/products/${id}`, 'PATCH', data),
delete: (id) => request(`/products/${id}`, 'DELETE'),
exportCsv: () => `${BASE_URL}/customers/export/csv`,
importCustomers: (file) => {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('token')
uni.uploadFile({
url: `${BASE_URL}/customers/import`,
filePath: file,
name: 'file',
header: token ? { Authorization: `Bearer ${token}` } : {},
success: (res) => {
try {
resolve(JSON.parse(res.data))
} catch (e) {
resolve(res.data)
}
},
fail: reject,
})
})
},
}