新增小程序后端代码,包括数据库、路由、服务层等。
小程序前后端打通,包括登录、注册、绑定设备、查询绑定信息,修改小朋友名称等功能。
This commit is contained in:
56
banban-mini/src/services/api.ts
Normal file
56
banban-mini/src/services/api.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import Taro from '@tarojs/taro'
|
||||
|
||||
// const BASE_URL = 'http://175.24.73.253:8001' // 改为实际后端IP
|
||||
const BASE_URL = 'http://127.0.0.1:8001'
|
||||
|
||||
class ApiError extends Error {
|
||||
constructor(public status: number, message: string) {
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
async function request<T>(
|
||||
url: string,
|
||||
options: {
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
||||
data?: any
|
||||
headers?: Record<string, string>
|
||||
} = {}
|
||||
): Promise<T> {
|
||||
const token = Taro.getStorageSync('token')
|
||||
console.log(`[API] ${options.method || 'GET'} ${url}`, token ? 'with token' : 'no token')
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
}
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
|
||||
const response = await Taro.request({
|
||||
url: `${BASE_URL}${url}`,
|
||||
method: options.method || 'GET',
|
||||
data: options.data,
|
||||
header: headers,
|
||||
})
|
||||
|
||||
console.log(`[API] Response status:`, response.statusCode)
|
||||
|
||||
if (response.statusCode >= 400) {
|
||||
const detail = response.data?.detail || 'Request failed'
|
||||
throw new ApiError(response.statusCode, detail)
|
||||
}
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
export { request, ApiError, BASE_URL }
|
||||
|
||||
export function getToken(): string {
|
||||
return Taro.getStorageSync('token') || ''
|
||||
}
|
||||
|
||||
export function getCurrentUserId(): number {
|
||||
return Taro.getStorageSync('user_id') || 0
|
||||
}
|
||||
75
banban-mini/src/services/auth.ts
Normal file
75
banban-mini/src/services/auth.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { request, BASE_URL } from './api'
|
||||
|
||||
export interface Parent {
|
||||
user_id: number
|
||||
openid: string
|
||||
unionid?: string
|
||||
nickname?: string
|
||||
avatar_url?: string
|
||||
phone?: string
|
||||
status: number
|
||||
}
|
||||
|
||||
// 微信登录
|
||||
export async function wechatLogin(code: string): Promise<{ token: string; user_id: number }> {
|
||||
// TODO: 实现微信登录 - 通过 code 换取 openid,然后调用后端
|
||||
// 这里先返回 mock 数据
|
||||
const mockParent: Parent = {
|
||||
user_id: 1,
|
||||
openid: 'mock_openid_' + code,
|
||||
nickname: '微信用户',
|
||||
status: 1,
|
||||
}
|
||||
|
||||
// 保存模拟 token
|
||||
const token = 'mock_token_' + Date.now()
|
||||
Taro.setStorageSync('token', token)
|
||||
Taro.setStorageSync('user_id', mockParent.user_id)
|
||||
|
||||
return { token, user_id: mockParent.user_id }
|
||||
}
|
||||
|
||||
// 创建家长
|
||||
export async function createParent(data: {
|
||||
openid: string
|
||||
unionid?: string
|
||||
nickname?: string
|
||||
avatar_url?: string
|
||||
}): Promise<Parent> {
|
||||
return request<Parent>('/parents', {
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取家长信息
|
||||
export async function getParent(userId: number): Promise<Parent> {
|
||||
return request<Parent>(`/parents/${userId}`)
|
||||
}
|
||||
|
||||
// 更新家长信息
|
||||
export async function updateParent(
|
||||
userId: number,
|
||||
data: { nickname?: string; avatar_url?: string; phone?: string }
|
||||
): Promise<Parent> {
|
||||
return request<Parent>(`/parents/${userId}`, {
|
||||
method: 'PATCH',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取 token
|
||||
export function getToken(): string {
|
||||
return Taro.getStorageSync('token')
|
||||
}
|
||||
|
||||
// 清除 token
|
||||
export function clearToken(): void {
|
||||
Taro.removeStorageSync('token')
|
||||
Taro.removeStorageSync('user_id')
|
||||
}
|
||||
|
||||
// 获取当前用户ID
|
||||
export function getCurrentUserId(): number {
|
||||
return Taro.getStorageSync('user_id') || 0
|
||||
}
|
||||
105
banban-mini/src/services/binding.ts
Normal file
105
banban-mini/src/services/binding.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { request } from './api'
|
||||
|
||||
export interface Binding {
|
||||
device_id: string
|
||||
child_id: number
|
||||
status: number
|
||||
bound_at: string
|
||||
}
|
||||
|
||||
export interface BindStartResponse {
|
||||
bind_token: string
|
||||
expires_at: string
|
||||
}
|
||||
|
||||
export interface BindHistoryItem {
|
||||
device_id: string
|
||||
child_id: number
|
||||
bound_at: string
|
||||
unbound_at?: string
|
||||
}
|
||||
|
||||
export interface BindHistoryResponse {
|
||||
items: BindHistoryItem[]
|
||||
total: number
|
||||
next_cursor?: string
|
||||
}
|
||||
|
||||
// 获取当前绑定信息
|
||||
export async function getCurrentBinding(): Promise<Binding | null> {
|
||||
try {
|
||||
return await request<Binding>('/bindings/current')
|
||||
} catch (err: any) {
|
||||
if (err.status === 404) {
|
||||
return null
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// 开始绑定设备
|
||||
export async function startBind(data: {
|
||||
device_id: string
|
||||
child_id: number
|
||||
}): Promise<BindStartResponse> {
|
||||
return request<BindStartResponse>('/bindings/start', {
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 确认绑定设备
|
||||
export async function confirmBind(data: {
|
||||
bind_token: string
|
||||
challenge_code: string
|
||||
}): Promise<{ device_id: string; child_id: number }> {
|
||||
return request('/bindings/confirm', {
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取设备绑定信息
|
||||
export async function getBinding(deviceId: string): Promise<Binding | null> {
|
||||
// If no deviceId, get the first binding for this user
|
||||
if (!deviceId) {
|
||||
try {
|
||||
// Try to get binding list - for now return null if no specific device
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return request<Binding>(`/bindings/${deviceId}`)
|
||||
}
|
||||
|
||||
// 解绑设备
|
||||
export async function unbindDevice(deviceId: string): Promise<void> {
|
||||
return request(`/bindings/${deviceId}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
// 直接绑定设备(手动输入设备码)
|
||||
export async function directBind(data: {
|
||||
device_id: string
|
||||
child_id: number
|
||||
}): Promise<{ device_id: string; child_id: number }> {
|
||||
return request('/bindings/direct', {
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取绑定历史
|
||||
export async function getBindHistory(
|
||||
deviceId: string,
|
||||
cursor?: string,
|
||||
limit: number = 20
|
||||
): Promise<BindHistoryResponse> {
|
||||
const params = new URLSearchParams()
|
||||
if (cursor) params.append('cursor', cursor)
|
||||
params.append('limit', String(limit))
|
||||
|
||||
return request<BindHistoryResponse>(`/bindings/history/${deviceId}?${params.toString()}`)
|
||||
}
|
||||
55
banban-mini/src/services/child.ts
Normal file
55
banban-mini/src/services/child.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { request } from './api'
|
||||
|
||||
export interface Child {
|
||||
child_id: number
|
||||
child_name: string
|
||||
child_gender: number
|
||||
child_birthday?: string
|
||||
status: number
|
||||
}
|
||||
|
||||
export interface ChildListResponse {
|
||||
items: Child[]
|
||||
total: number
|
||||
next_cursor?: number
|
||||
}
|
||||
|
||||
// 创建小孩档案
|
||||
export async function createChild(data: {
|
||||
child_name: string
|
||||
child_gender?: number
|
||||
child_birthday?: string
|
||||
}): Promise<Child> {
|
||||
return request<Child>('/children', {
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取小孩列表
|
||||
export async function getChildren(
|
||||
cursor?: number,
|
||||
limit: number = 20
|
||||
): Promise<ChildListResponse> {
|
||||
const params = new URLSearchParams()
|
||||
if (cursor) params.append('cursor', String(cursor))
|
||||
params.append('limit', String(limit))
|
||||
|
||||
return request<ChildListResponse>(`/children?${params.toString()}`)
|
||||
}
|
||||
|
||||
// 获取单个小孩信息
|
||||
export async function getChild(childId: number): Promise<Child> {
|
||||
return request<Child>(`/children/${childId}`)
|
||||
}
|
||||
|
||||
// 更新小孩信息
|
||||
export async function updateChild(
|
||||
childId: number,
|
||||
data: { child_name?: string; child_gender?: number; child_birthday?: string }
|
||||
): Promise<Child> {
|
||||
return request<Child>(`/children/${childId}`, {
|
||||
method: 'PATCH',
|
||||
data,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user