Files
jiapuapp/utils/api.js
T

219 lines
9.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { currentUser, genealogies, treeMembers, familyFeeds, familyContent, notifications, joinApplications } from '@/data/mock.js'
import { hasRemoteConfig, isMockMode, runtimeConfig } from '@/utils/config.js'
import { session } from '@/utils/session.js'
const successCodes = [0, 200]
export const unwrapResponse = (response) => {
if (!response || typeof response !== 'object' || Array.isArray(response)) return response
if (!Object.prototype.hasOwnProperty.call(response, 'code')) return response
if (!successCodes.includes(Number(response.code))) {
throw new Error(response.msg || '请求未成功')
}
return Object.prototype.hasOwnProperty.call(response, 'data') ? response.data : response
}
const request = (options, { authenticated = true } = {}) => new Promise((resolve, reject) => {
const token = session.getToken()
uni.request({
...options,
url: `${runtimeConfig.baseUrl}${options.url}`,
header: {
clientid: runtimeConfig.clientId,
...(authenticated && token ? { Authorization: `Bearer ${token}` } : {}),
...(options.header || {})
},
success: ({ data, statusCode }) => {
if (statusCode < 200 || statusCode >= 300) {
reject(new Error(data?.msg || `请求失败(${statusCode}`))
return
}
try {
resolve(unwrapResponse(data))
} catch (error) {
reject(error)
}
},
fail: (error) => reject(new Error(error.errMsg || '网络连接失败'))
})
})
const authPayload = (payload) => ({
clientId: runtimeConfig.clientId,
tenantId: runtimeConfig.tenantId,
...payload
})
const saveLogin = (loginResult) => {
const token = loginResult?.token || loginResult?.accessToken || loginResult?.tokenValue
if (!token) throw new Error('登录响应未包含会话令牌')
session.saveToken(token)
return loginResult
}
const toTreeNode = (person, index = 0) => {
const generation = Number(person.generationNo || person.generation || 1)
return {
...person,
id: person.id || person.personId,
name: person.personName || person.name || '未命名族人',
relation: person.relation || (generation === 1 ? '始祖' : '族人'),
generation,
years: person.years || [person.birthDate, person.deathDate].filter(Boolean).join('—') || '生卒待补',
branch: person.branch || '主支',
x: person.x ?? (20 + (index % 4) * 20),
y: person.y ?? (generation * 31 - 24)
}
}
export const appApi = {
async sendSmsCode({ phone, validToken = '' }) {
if (isMockMode()) return { success: true }
return request({
url: '/genealogy/app/auth/sms/code',
method: 'POST',
data: authPayload({ grantType: 'sms', sceneCode: 'APP_LOGIN', phone, validToken })
}, { authenticated: false })
},
async loginWithPassword({ phone, passwordHash }) {
if (isMockMode()) {
session.saveToken('mock-session-token')
return { token: 'mock-session-token', userId: currentUser.id }
}
const result = await request({
url: '/genealogy/app/auth/login',
method: 'POST',
data: authPayload({ grantType: 'password', phone, password: passwordHash })
}, { authenticated: false })
return saveLogin(result)
},
async loginWithSms({ phone, smsCode }) {
if (isMockMode()) {
session.saveToken('mock-session-token')
return { token: 'mock-session-token', userId: currentUser.id }
}
const result = await request({
url: '/genealogy/app/auth/login/sms',
method: 'POST',
data: authPayload({ grantType: 'sms', phone, smsCode })
}, { authenticated: false })
return saveLogin(result)
},
async getProfile() {
return hasRemoteConfig() ? request({ url: '/genealogy/app/auth/profile' }) : currentUser
},
async getMyGenealogies() {
return hasRemoteConfig() ? request({ url: '/genealogy/app/genealogies/mine' }) : genealogies
},
async createGenealogy(payload) {
if (hasRemoteConfig()) return request({ url: '/genealogy/app/genealogies', method: 'POST', data: payload })
const created = { ...payload, id: Date.now(), memberCount: 0, activeCount: 0, motto: '敦亲睦族,敬祖传家。', visibility: '仅成员可见' }
genealogies.unshift(created)
return created
},
async getGenealogy(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}` }) : genealogies.find((item) => String(item.id) === String(genealogyId))
},
async getOverview(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/overview` }) : await this.getGenealogy(genealogyId)
},
async getTree(genealogyId) {
if (hasRemoteConfig()) {
const tree = await request({ url: `/genealogy/app/genealogies/${genealogyId}/lineage/tree` })
return (tree || []).map(toTreeNode)
}
return treeMembers.filter((item) => String(item.genealogyId || 1001) === String(genealogyId)).map(toTreeNode)
},
async getPerson(genealogyId, personId) {
if (hasRemoteConfig()) {
const person = await request({ url: `/genealogy/app/genealogies/${genealogyId}/lineage/persons/${personId}` })
return toTreeNode(person)
}
const person = treeMembers.find((item) => String(item.id) === String(personId) && String(item.genealogyId || 1001) === String(genealogyId))
return person ? toTreeNode(person) : null
},
async createPerson(genealogyId, payload) {
if (hasRemoteConfig()) {
const person = await request({ url: `/genealogy/app/genealogies/${genealogyId}/lineage/persons`, method: 'POST', data: payload })
return toTreeNode(person)
}
const person = toTreeNode({
...payload,
id: Date.now(),
genealogyId,
relation: Number(payload.generationNo) === 1 ? '始祖' : '族人',
x: 50,
y: 7
})
treeMembers.push(person)
const genealogy = genealogies.find((item) => String(item.id) === String(genealogyId))
if (genealogy) {
genealogy.memberCount = (genealogy.memberCount || 0) + 1
genealogy.activeCount = (genealogy.activeCount || 0) + 1
}
return person
},
async getFeeds(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/feeds` }) : familyFeeds
},
async createFeed(genealogyId, payload) {
if (hasRemoteConfig()) return request({ url: `/genealogy/app/genealogies/${genealogyId}/feeds`, method: 'POST', data: payload })
const feed = { id: Date.now(), genealogyId, author: currentUser.name, title: '家族动态', content: payload.feedContent, date: '刚刚', type: '族务' }
familyFeeds.unshift(feed)
return feed
},
async getArticles(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/articles` }) : familyContent.article
},
async getAlbums(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/albums` }) : familyContent.album
},
async getCeremonies(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/ceremonies` }) : familyContent.ceremony
},
async getGrowthRecords(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/growth-records` }) : familyContent.record
},
async getContent(type, genealogyId) {
const loaders = { article: this.getArticles, album: this.getAlbums, ceremony: this.getCeremonies, record: this.getGrowthRecords }
if (!loaders[type]) throw new Error('未知内容类型')
return loaders[type].call(this, genealogyId)
},
async getNotifications() {
return hasRemoteConfig() ? request({ url: '/genealogy/app/notifications' }) : notifications
},
async markNotificationRead(notificationId) {
if (hasRemoteConfig()) return request({ url: `/genealogy/app/notifications/${notificationId}/read`, method: 'POST' })
const notification = notifications.find((item) => String(item.id) === String(notificationId))
if (notification) notification.unread = false
return { success: true }
},
async markAllNotificationsRead() {
if (hasRemoteConfig()) return request({ url: '/genealogy/app/notifications/read-all', method: 'POST' })
notifications.forEach((item) => { item.unread = false })
return { success: true }
},
async getPublicGenealogies() {
return hasRemoteConfig() ? request({ url: '/genealogy/app/genealogies/public' }) : genealogies.filter((item) => item.visibility === '公开可申请')
},
async applyToJoin(genealogyId, payload) {
if (hasRemoteConfig()) return request({ url: `/genealogy/app/genealogies/${genealogyId}/join-applies`, method: 'POST', data: payload })
joinApplications.unshift({
id: Date.now(),
genealogyId,
name: currentUser.name,
phone: currentUser.phone,
relation: payload.message || '申请加入家谱',
appliedAt: '刚刚',
status: 'PENDING'
})
return { success: true }
},
async getPendingApplications(genealogyId) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/join-applies/pending` }) : joinApplications.filter((item) => String(item.genealogyId || 1001) === String(genealogyId))
},
async auditApplication(genealogyId, applicationId, approved) {
return hasRemoteConfig() ? request({ url: `/genealogy/app/genealogies/${genealogyId}/join-applies/${applicationId}/audit`, method: 'PUT', data: { approved } }) : { success: true }
}
}