4755cc75ba
- 管理后台用户/统计/日志/配置四页签全部对接真实后端API - auth注册/登录/游客/微信登录事件写入usage_logs表 - 提取信息结果从原始JSON改为卡片式字段列表(中文标签) - 管理后台搜索按钮增加加载态和结果数提示 - 配置WECHAT_APP_ID/WECHAT_APP_SECRET - 客户/产品/报价单CRUD页面完整(导出导入批量操作)
325 lines
12 KiB
JavaScript
325 lines
12 KiB
JavaScript
export const BASE_URL = '/api/v1'
|
|
|
|
const getAuthHeader = () => {
|
|
const token = uni.getStorageSync('token')
|
|
return token ? { Authorization: `Bearer ${token}` } : {}
|
|
}
|
|
|
|
const request = (url, method = 'GET', data = {}) => {
|
|
return new Promise((resolve, reject) => {
|
|
uni.request({
|
|
url: `${BASE_URL}${url}`,
|
|
method,
|
|
data,
|
|
header: {
|
|
'Content-Type': 'application/json',
|
|
...getAuthHeader(),
|
|
},
|
|
success: (res) => {
|
|
if (res.statusCode === 200) {
|
|
resolve(res.data)
|
|
} else if (res.statusCode === 401) {
|
|
uni.removeStorageSync('token')
|
|
uni.reLaunch({ url: '/pages/login/login' })
|
|
reject(new Error('Unauthorized'))
|
|
} else {
|
|
reject(new Error(res.data?.detail || 'Request failed'))
|
|
}
|
|
},
|
|
fail: (err) => {
|
|
reject(err)
|
|
},
|
|
})
|
|
})
|
|
}
|
|
|
|
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 }),
|
|
wechatConfig: () => request('/auth/wechat/config'),
|
|
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`,
|
|
exportXlsx: () => `${BASE_URL}/quotations/export/xlsx`,
|
|
generateFromInquiry: (inquiryText, customerId = null) =>
|
|
request('/quotations/generate-from-inquiry', 'POST', { inquiry_text: inquiryText, customer_id: customerId }),
|
|
importQuotations: (file) => {
|
|
return new Promise((resolve, reject) => {
|
|
const token = uni.getStorageSync('token')
|
|
uni.uploadFile({
|
|
url: `${BASE_URL}/quotations/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,
|
|
})
|
|
})
|
|
},
|
|
}
|
|
|
|
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}/products/export/csv`,
|
|
exportXlsx: () => `${BASE_URL}/products/export/xlsx`,
|
|
importProducts: (file) => {
|
|
return new Promise((resolve, reject) => {
|
|
const token = uni.getStorageSync('token')
|
|
uni.uploadFile({
|
|
url: `${BASE_URL}/products/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,
|
|
})
|
|
})
|
|
},
|
|
}
|
|
|
|
export const adminApi = {
|
|
getDashboard: () => request('/admin/dashboard'),
|
|
listUsers: (page = 1, size = 20, role) => {
|
|
let url = `/admin/users?page=${page}&size=${size}`
|
|
if (role) url += `&role=${role}`
|
|
return request(url)
|
|
},
|
|
updateUserTier: (userId, tier) => request(`/admin/users/${userId}/tier`, 'PATCH', { tier }),
|
|
updateUserRole: (userId, role) => request(`/admin/users/${userId}/role`, 'PATCH', { role }),
|
|
toggleUserActive: (userId) => request(`/admin/users/${userId}/toggle-active`, 'POST'),
|
|
getUserDetail: (userId) => request(`/admin/users/${userId}`),
|
|
searchUsers: (q) => request(`/admin/users/search?q=${encodeURIComponent(q)}`),
|
|
getUsageStats: () => request('/admin/usage-stats'),
|
|
getLogs: (page = 1, size = 50, filters = {}) => {
|
|
let url = `/admin/logs?page=${page}&size=${size}`
|
|
if (filters.action) url += `&action=${encodeURIComponent(filters.action)}`
|
|
if (filters.user_id) url += `&user_id=${encodeURIComponent(filters.user_id)}`
|
|
if (filters.date_from) url += `&date_from=${filters.date_from}`
|
|
if (filters.date_to) url += `&date_to=${filters.date_to}`
|
|
return request(url)
|
|
},
|
|
getConfig: () => request('/admin/config'),
|
|
updateConfig: (key, value) => request(`/admin/config/${key}`, 'PUT', { value }),
|
|
}
|
|
|
|
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 = {
|
|
translate: (text, targetLang, sourceLang = 'auto') =>
|
|
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 whatsappApi = {
|
|
send: (to, text, templateName = null, templateParams = null, mediaUrl = null, mediaType = null) =>
|
|
request('/whatsapp/send', 'POST', { to, text, template_name: templateName, template_params: templateParams, media_url: mediaUrl, media_type: mediaType }),
|
|
}
|
|
|
|
export const customerApi = {
|
|
list: (page = 1, size = 20, status) => {
|
|
let params = `page=${page}&size=${size}`
|
|
if (status) params += `&status=${status}`
|
|
return request(`/customers?${params}`)
|
|
},
|
|
get: (id) => request(`/customers/${id}`),
|
|
create: (data) => request('/customers', 'POST', data),
|
|
update: (id, data) => request(`/customers/${id}`, 'PATCH', data),
|
|
delete: (id) => request(`/customers/${id}`, 'DELETE'),
|
|
getSilent: (days = 3) => request(`/customers/silent?days=${days}`),
|
|
getConversation: (id, page = 1, size = 50) =>
|
|
request(`/customers/${id}/conversation?page=${page}&size=${size}`),
|
|
exportCsv: () => `${BASE_URL}/customers/export/csv`,
|
|
exportXlsx: () => `${BASE_URL}/customers/export/xlsx`,
|
|
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,
|
|
})
|
|
})
|
|
},
|
|
} |