Files
Blizzard 15adfb76ac feat(fe): 身份卡重绘成正面+照护信息+证件三段式 + 手机号验证
- 正面:头像/名字/物种性别 + 品种·毛色 / 出生·星座 / 体重 + 性格标签chips
- 照护信息:主人 / 联系电话 / 疫苗情况 / 备注(去掉驱虫、过敏)
- 证件区:居民身份卡 + 身份ID / 发证机构 / 有效期 + 小程序码
- 未验证手机号时页面出现「用微信验证手机号」(getPhoneNumber),
  拿到 code 换手机号后重取卡重画;表单去掉过敏输入

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 17:28:26 +08:00

168 lines
8.4 KiB
JavaScript
Raw Permalink 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.
const { request, uploadFile, setToken, setRefreshToken } = require('./request.js');
// 登录成功后统一落盘 access + refresh 两个令牌
function saveTokens(data) {
setToken(data.token);
setRefreshToken(data.refresh_token);
return data;
}
// wx.login 取 code
function wxLogin() {
return new Promise((resolve, reject) => {
wx.login({
success: (r) => (r.code ? resolve(r.code) : reject(new Error('wx.login 未返回 code'))),
fail: reject,
});
});
}
// 登录:优先微信 code2session,失败回退开发态 Mock 登录(后端 dev_login=true
async function login() {
try {
const code = await wxLogin();
// noAuthRetry:登录接口失败时也会返回 40100,不能再触发「续期→重新登录」,否则会自己套自己
const data = await request({ url: '/api/auth/wechat', method: 'POST', data: { code }, noAuthRetry: true });
return saveTokens(data);
} catch (e) {
console.warn('[api] 微信登录失败,回退 Mock 登录:', e && e.message);
const data = await request({
url: '/api/auth/login',
method: 'POST',
data: { nickname: '开发用户' },
noAuthRetry: true,
});
return saveTokens(data);
}
}
const api = {
login,
uploadFile,
// 用户
getProfile: () => request({ url: '/api/user/profile' }),
bindPhone: (code) => request({ url: '/api/user/phone', method: 'POST', data: { code } }),
updateProfile: (body) => request({ url: '/api/user/profile', method: 'PUT', data: body }),
// 用户
userSummary: () => request({ url: '/api/user/summary' }),
// 记录类型(后台可配)。分组好的,前端直接渲染
recordTypes: () => request({ url: '/api/record-types' }),
updateDecoration: (body) => request({ url: '/api/user/decoration', method: 'PUT', data: body }),
// 宠物
getPets: () => request({ url: '/api/pets' }),
homeSummary: (id) => request({ url: `/api/pets/${id}/home-summary` }),
getPet: (id) => request({ url: `/api/pets/${id}` }),
// 养护方案:可选列表 + 套用到某个月
careTemplates: (species, stage) =>
request({ url: '/api/care-templates?species=' + species + '&stage=' + encodeURIComponent(stage) }),
applyTemplate: (petId, templateID, monthOffset) =>
request({ url: `/api/pets/${petId}/apply-template`, method: 'POST',
data: { template_id: templateID, month_offset: monthOffset || 0 } }),
// 生命阶段的划分标准。判定和展示用同一份数据 —— 不另写一份说明文案,
// 否则改了阈值忘了改文案,用户看到的依据和实际行为对不上
lifeStages: (species, size) =>
request({ url: `/api/life-stages?species=${species}&size=${size || ''}` }),
petIDCard: (id) => request({ url: `/api/pets/${id}/id-card` }),
petStageDrift: (petId) => request({ url: `/api/pets/${petId}/stage-drift` }),
// 品种(后台可配),按首字母分组
breeds: (species) => request({ url: '/api/breeds?species=' + species }),
createPet: (body) => request({ url: '/api/pets', method: 'POST', data: body }),
updatePet: (id, body) => request({ url: `/api/pets/${id}`, method: 'PUT', data: body }),
deletePet: (id) => request({ url: `/api/pets/${id}`, method: 'DELETE' }),
onboarding: (body) => request({ url: '/api/onboarding', method: 'POST', data: body }),
// 记录
getRecords: (id, { type, page, pageSize } = {}) => {
const qs = [];
if (type) qs.push(`type=${type}`);
if (page) qs.push(`page=${page}`);
if (pageSize) qs.push(`page_size=${pageSize}`);
return request({ url: `/api/pets/${id}/records${qs.length ? '?' + qs.join('&') : ''}` });
},
createRecord: (id, body) => request({ url: `/api/pets/${id}/records`, method: 'POST', data: body }),
deleteRecord: (recordId) => request({ url: `/api/records/${recordId}`, method: 'DELETE' }),
petInsights: (id) => request({ url: `/api/pets/${id}/insights` }),
weightTrend: (id) => request({ url: `/api/pets/${id}/records/weight-trend` }),
// 任务
getTasks: (id, date) => request({ url: `/api/pets/${id}/tasks${date ? `?date=${date}` : ''}` }),
createTask: (id, body) => request({ url: `/api/pets/${id}/tasks`, method: 'POST', data: body }),
updateTask: (taskId, body) => request({ url: `/api/tasks/${taskId}`, method: 'PUT', data: body }),
deleteTask: (taskId) => request({ url: `/api/tasks/${taskId}`, method: 'DELETE' }),
toggleTask: (taskId) => request({ url: `/api/tasks/${taskId}/toggle`, method: 'POST' }),
completeAllTasks: (id) => request({ url: `/api/pets/${id}/tasks/complete-all`, method: 'POST' }),
// 计划
getPlan: (id) => request({ url: `/api/pets/${id}/plan` }),
planCalendar: (id, month) =>
request({ url: `/api/pets/${id}/plan/calendar${month ? `?month=${month}` : ''}` }),
dayPlan: (id, date) => request({ url: `/api/pets/${id}/day-plan?date=${date}` }),
// AI 相关:用户端入口已全部下掉,后端 10 个路由和配额配置都还在。
// 想开回来把这几行解注释、再把入口接上就行,不用重写。
// createAIPlan: (id, input) => request({ url: `/api/pets/${id}/ai-plan`, method: 'POST', data: { input } }),
// applyAIPlan: (planId) => request({ url: `/api/ai-plan/${planId}/apply`, method: 'POST' }),
// 用户自己管理计划节点
planMonthStatus: (petId) => request({ url: `/api/pets/${petId}/plan/month-status` }),
addPlanTask: (petId, body) => request({ url: `/api/pets/${petId}/plan-tasks`, method: 'POST', data: body }),
updatePlanTask: (taskId, body) => request({ url: `/api/plan-tasks/${taskId}`, method: 'PUT', data: body }),
deletePlanTask: (taskId) => request({ url: `/api/plan-tasks/${taskId}`, method: 'DELETE' }),
togglePlanTask: (taskId) => request({ url: `/api/plan-tasks/${taskId}/toggle`, method: 'POST' }),
// 提醒
getReminders: (id) => request({ url: `/api/pets/${id}/reminders` }),
createReminder: (id, body) => request({ url: `/api/pets/${id}/reminders`, method: 'POST', data: body }),
updateReminder: (remId, body) => request({ url: `/api/reminders/${remId}`, method: 'PUT', data: body }),
deleteReminder: (remId) => request({ url: `/api/reminders/${remId}`, method: 'DELETE' }),
// 报告
weeklyReport: (id) => request({ url: `/api/pets/${id}/report/weekly` }),
getBill: (id, period) => request({ url: `/api/pets/${id}/bill?period=${period || 'month'}` }),
healthSummary: (id) => request({ url: `/api/pets/${id}/health-summary` }),
getPoster: (id) => request({ url: `/api/pets/${id}/poster` }),
// 社区
listPosts: (tab, page) =>
request({ url: `/api/posts?tab=${encodeURIComponent(tab || '')}&page=${page || 1}&page_size=10` }),
createPost: (body) => request({ url: '/api/posts', method: 'POST', data: body }),
likePost: (id) => request({ url: `/api/posts/${id}/like`, method: 'POST' }),
userCard: (userId) => request({ url: `/api/users/${userId}/profile` }),
userPosts: (userId, page) => request({ url: `/api/users/${userId}/posts?page=${page || 1}&page_size=10` }),
relations: (userId, kind, page) =>
request({ url: `/api/users/${userId}/relations?kind=${kind}&page=${page || 1}&page_size=20` }),
followUser: (userId) => request({ url: `/api/users/${userId}/follow`, method: 'POST' }),
unfollowUser: (userId) => request({ url: `/api/users/${userId}/follow`, method: 'DELETE' }),
deletePost: (id) => request({ url: `/api/posts/${id}`, method: 'DELETE' }),
deleteComment: (id) => request({ url: `/api/comments/${id}`, method: 'DELETE' }),
listComments: (id) => request({ url: `/api/posts/${id}/comments` }),
createComment: (id, content, images, parentId) =>
request({
url: `/api/posts/${id}/comments`,
method: 'POST',
data: { content, images: images || [], parent_id: parentId || '' },
}),
listReplies: (commentId) => request({ url: `/api/comments/${commentId}/replies` }),
// 文章
listArticles: () => request({ url: '/api/articles' }),
submitFeedback: (body) => request({ url: '/api/feedback', method: 'POST', data: body }),
getArticle: (id) => request({ url: `/api/articles/${id}` }),
// Pro
getPro: () => request({ url: '/api/pro' }),
activatePro: () => request({ url: '/api/pro/activate', method: 'POST' }),
// AI
// aiMessages: (session, limit) =>
// request({ url: `/api/ai/messages?session=${session || ''}&limit=${limit || 30}` }),
// aiChat: (body) => request({ url: '/api/ai/chat', method: 'POST', data: body }),
// assessSymptom: (id, body) =>
// request({ url: `/api/pets/${id}/ai/assess-symptom`, method: 'POST', data: body }),
};
module.exports = api;