2026-09-11 20:23:10 +08:00
|
|
|
|
/** Mobile API adapter with deterministic local mocks. */
|
2026-09-18 12:59:43 +08:00
|
|
|
|
import { demoProducts, parseProduct, FinanceProduct } from '@/services/finance.uts'
|
2026-09-11 20:23:10 +08:00
|
|
|
|
export const API_BASE_URL = ''
|
|
|
|
|
|
const REQUEST_TIMEOUT = 10000
|
|
|
|
|
|
const SESSION_KEY = 'aiFinanceSession'
|
2026-09-10 10:57:40 +08:00
|
|
|
|
|
2026-09-11 20:23:10 +08:00
|
|
|
|
const wait = (duration: number) => new Promise<void>((resolve) => {
|
|
|
|
|
|
setTimeout(() => resolve(), duration)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
export function saveSession(token: string, phone: string): void {
|
|
|
|
|
|
uni.setStorageSync(SESSION_KEY, { token, phone, loggedInAt: Date.now() })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getSession(): UTSJSONObject | null {
|
|
|
|
|
|
const value = uni.getStorageSync(SESSION_KEY)
|
2026-09-15 16:16:55 +08:00
|
|
|
|
if (value == null || typeof value != 'object') return null
|
2026-09-11 20:23:10 +08:00
|
|
|
|
return value as UTSJSONObject
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function isLoggedIn(): boolean {
|
|
|
|
|
|
return getSession() != null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function clearSession(): void {
|
|
|
|
|
|
uni.removeStorageSync(SESSION_KEY)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-15 16:16:55 +08:00
|
|
|
|
const apiMessage = (error: any | null, fallback: string): string => {
|
2026-09-11 20:23:10 +08:00
|
|
|
|
if (error == null) return fallback
|
|
|
|
|
|
const text = error.toString()
|
|
|
|
|
|
return text.length > 0 ? text : fallback
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const requestJson = (path: string, method: RequestMethod, payload: UTSJSONObject): Promise<UTSJSONObject> => {
|
|
|
|
|
|
return new Promise<UTSJSONObject>((resolve, reject) => {
|
|
|
|
|
|
uni.request({
|
|
|
|
|
|
url: API_BASE_URL + path,
|
|
|
|
|
|
method,
|
|
|
|
|
|
data: payload,
|
|
|
|
|
|
timeout: REQUEST_TIMEOUT,
|
|
|
|
|
|
success: (response) => {
|
|
|
|
|
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
|
|
|
|
|
if (response.data == null) resolve(new UTSJSONObject())
|
|
|
|
|
|
else resolve(response.data as UTSJSONObject)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
reject('请求失败(' + response.statusCode.toString() + ')')
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (error) => {
|
|
|
|
|
|
reject(apiMessage(error, '网络请求失败,请稍后重试'))
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-09-10 10:57:40 +08:00
|
|
|
|
|
|
|
|
|
|
export async function requestSmsCode(phone: string): Promise<boolean> {
|
2026-09-11 20:23:10 +08:00
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(350)
|
|
|
|
|
|
return phone.length == 11
|
|
|
|
|
|
}
|
|
|
|
|
|
await requestJson('/auth/sms-code', 'POST', { phone })
|
2026-09-10 10:57:40 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-11 20:23:10 +08:00
|
|
|
|
export async function loginWithSms(phone: string, code: string): Promise<string> {
|
|
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(300)
|
2026-09-15 16:16:55 +08:00
|
|
|
|
if (code.length != 6) throw new Error('验证码应为 6 位数字')
|
2026-09-11 20:23:10 +08:00
|
|
|
|
return 'demo-sms-token'
|
|
|
|
|
|
}
|
|
|
|
|
|
const result = await requestJson('/auth/sms-login', 'POST', { phone, code })
|
|
|
|
|
|
const token = result['token'] as string | null
|
2026-09-15 16:16:55 +08:00
|
|
|
|
if (token == null || token.length == 0) throw new Error('登录响应缺少 token')
|
2026-09-11 20:23:10 +08:00
|
|
|
|
return token
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function loginWithPassword(phone: string, password: string): Promise<string> {
|
|
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(300)
|
|
|
|
|
|
return 'demo-password-token'
|
|
|
|
|
|
}
|
|
|
|
|
|
const result = await requestJson('/auth/password-login', 'POST', { phone, password })
|
|
|
|
|
|
const token = result['token'] as string | null
|
2026-09-15 16:16:55 +08:00
|
|
|
|
if (token == null || token.length == 0) throw new Error('登录响应缺少 token')
|
2026-09-11 20:23:10 +08:00
|
|
|
|
return token
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-10 10:57:40 +08:00
|
|
|
|
export async function submitAssessment(payload: UTSJSONObject): Promise<string> {
|
|
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(650)
|
|
|
|
|
|
uni.setStorageSync('latestAssessment', payload)
|
|
|
|
|
|
return 'ASSESSMENT-DEMO-001'
|
|
|
|
|
|
}
|
2026-09-11 20:23:10 +08:00
|
|
|
|
const result = await requestJson('/assessments', 'POST', payload)
|
|
|
|
|
|
const id = result['id'] as string | null
|
2026-09-15 16:16:55 +08:00
|
|
|
|
if (id == null || id.length == 0) throw new Error('评估提交成功但未返回编号')
|
2026-09-11 20:23:10 +08:00
|
|
|
|
return id
|
2026-09-10 10:57:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-18 12:59:43 +08:00
|
|
|
|
export async function fetchMatches(): Promise<FinanceProduct[]> {
|
2026-09-11 20:23:10 +08:00
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(320)
|
2026-09-18 12:59:43 +08:00
|
|
|
|
return demoProducts.slice()
|
2026-09-11 20:23:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
const result = await requestJson('/matches', 'GET', new UTSJSONObject())
|
|
|
|
|
|
const items = result['items'] as UTSJSONObject[] | null
|
2026-09-18 12:59:43 +08:00
|
|
|
|
return items == null ? [] : items.map((item: UTSJSONObject): FinanceProduct => parseProduct(item))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function fetchProduct(id: string): Promise<FinanceProduct | null> {
|
|
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(180)
|
|
|
|
|
|
const products = demoProducts.filter((item: FinanceProduct): boolean => item.id == id)
|
|
|
|
|
|
return products.length > 0 ? products[0] : null
|
|
|
|
|
|
}
|
|
|
|
|
|
const result = await requestJson('/products/' + encodeURIComponent(id), 'GET', new UTSJSONObject())
|
|
|
|
|
|
return parseProduct(result)
|
2026-09-10 10:57:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function sendAssistantMessage(message: string): Promise<string> {
|
2026-09-11 20:23:10 +08:00
|
|
|
|
if (API_BASE_URL.length == 0) {
|
|
|
|
|
|
await wait(600)
|
|
|
|
|
|
return '结合您的评估结果,建议优先选择年化利率较低、可随借随还的产品,并重点确认提前还款规则。'
|
|
|
|
|
|
}
|
|
|
|
|
|
const result = await requestJson('/assistant/messages', 'POST', { message })
|
|
|
|
|
|
const reply = result['reply'] as string | null
|
2026-09-15 16:16:55 +08:00
|
|
|
|
if (reply == null || reply.length == 0) throw new Error('助手暂时没有返回内容')
|
2026-09-11 20:23:10 +08:00
|
|
|
|
return reply
|
2026-09-10 10:57:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-11 20:23:10 +08:00
|
|
|
|
export { apiMessage }
|