feat: 小程序连接服务器IP + 同步未提交开发
- miniprogram/config.js: BASE_URL 指向 http://192.227.237.8:3001 - 动作标题中文化(nameZh),搜索匹配 name/nameZh/nameEn - 新增计划/收藏/我的 等页面与组件 - 后端 Docker 化(Dockerfile/.dockerignore)与翻译脚本 - .gitignore 补充 .DS_Store
This commit is contained in:
@@ -1,6 +1,19 @@
|
||||
// 业务服务层:直接映射后端 REST 接口字段,不做多余转换。
|
||||
const { request } = require('../utils/request');
|
||||
|
||||
// 确保动作名称以中文展示(防御层:即使后端意外返回英文也能兜底)
|
||||
function injectDisplayName(item) {
|
||||
if (!item) return item;
|
||||
// 优先级:nameZh > name(后端 normalize 已把 name 设为中文)> nameEn 不展示
|
||||
item.displayName = item.nameZh || item.name || '';
|
||||
return item;
|
||||
}
|
||||
|
||||
function injectDisplayNames(list) {
|
||||
if (!list || !Array.isArray(list)) return list || [];
|
||||
return list.map(injectDisplayName);
|
||||
}
|
||||
|
||||
// 将参数对象序列化为 query string(跳过空值)
|
||||
function buildQuery(params) {
|
||||
const qs = Object.keys(params || {})
|
||||
@@ -12,12 +25,15 @@ function buildQuery(params) {
|
||||
|
||||
// 1) 动作列表(支持多维筛选与排序)
|
||||
function listExercises(params = {}) {
|
||||
return request({ url: '/api/exercises' + buildQuery(params) });
|
||||
return request({ url: '/api/exercises' + buildQuery(params) }).then((res) => {
|
||||
if (res && res.items) res.items = injectDisplayNames(res.items);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
// 2) 动作详情
|
||||
function getExercise(id) {
|
||||
return request({ url: '/api/exercises/' + encodeURIComponent(id) });
|
||||
return request({ url: '/api/exercises/' + encodeURIComponent(id) }).then(injectDisplayName);
|
||||
}
|
||||
|
||||
// 3) 分类维度枚举
|
||||
@@ -27,7 +43,10 @@ function getCategories(type) {
|
||||
|
||||
// 4) 智能推荐
|
||||
function recommend(params = {}) {
|
||||
return request({ url: '/api/recommend' + buildQuery(params) });
|
||||
return request({ url: '/api/recommend' + buildQuery(params) }).then((res) => {
|
||||
if (res && res.items) res.items = injectDisplayNames(res.items);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
// 5) 训练组合列表
|
||||
@@ -37,12 +56,18 @@ function listCollections() {
|
||||
|
||||
// 5) 训练组合下的动作
|
||||
function getCollectionExercises(slug, params = {}) {
|
||||
return request({ url: '/api/collections/' + encodeURIComponent(slug) + '/exercises' + buildQuery(params) });
|
||||
return request({ url: '/api/collections/' + encodeURIComponent(slug) + '/exercises' + buildQuery(params) }).then((res) => {
|
||||
if (res && res.items) res.items = injectDisplayNames(res.items);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
// 6) 搜索
|
||||
function search(q) {
|
||||
return request({ url: '/api/search?q=' + encodeURIComponent(q) });
|
||||
return request({ url: '/api/search?q=' + encodeURIComponent(q) }).then((res) => {
|
||||
if (res && res.items) res.items = injectDisplayNames(res.items);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
// 7) 统计概览
|
||||
|
||||
73
miniprogram/services/favorite.js
Normal file
73
miniprogram/services/favorite.js
Normal file
@@ -0,0 +1,73 @@
|
||||
// 收藏服务:动作收藏 + 官方计划收藏(均受保护)。
|
||||
const { request } = require('../utils/request');
|
||||
|
||||
// 复用 displayName 注入(避免循环依赖,内联轻量版)
|
||||
function injectDisplayName(item) {
|
||||
if (!item) return item;
|
||||
item.displayName = item.nameZh || item.name || '';
|
||||
return item;
|
||||
}
|
||||
|
||||
function injectDisplayNames(list) {
|
||||
if (!list || !Array.isArray(list)) return list || [];
|
||||
return list.map(injectDisplayName);
|
||||
}
|
||||
|
||||
// 收藏的动作列表
|
||||
function listExercises() {
|
||||
return request({ url: '/api/favorites/exercises', method: 'GET' }).then((res) => {
|
||||
const items = (res && Array.isArray(res)) ? res : (res && res.items);
|
||||
if (items) {
|
||||
const injected = injectDisplayNames(items);
|
||||
if (Array.isArray(res)) return injected;
|
||||
res.items = injected;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
// 收藏某个动作
|
||||
function addExercise(id) {
|
||||
return request({ url: '/api/favorites/exercises', method: 'POST', data: { target: id } });
|
||||
}
|
||||
|
||||
// 取消收藏某个动作
|
||||
function removeExercise(id) {
|
||||
return request({ url: '/api/favorites/exercises/' + encodeURIComponent(id), method: 'DELETE' });
|
||||
}
|
||||
|
||||
// 查询某动作收藏状态 { favorited }
|
||||
function exerciseStatus(id) {
|
||||
return request({ url: '/api/favorites/exercises/' + encodeURIComponent(id) + '/status', method: 'GET' });
|
||||
}
|
||||
|
||||
// 收藏的官方计划列表(CollectionDef[])
|
||||
function listPlans() {
|
||||
return request({ url: '/api/favorites/plans', method: 'GET' });
|
||||
}
|
||||
|
||||
// 收藏某个官方计划
|
||||
function addPlan(slug) {
|
||||
return request({ url: '/api/favorites/plans', method: 'POST', data: { target: slug } });
|
||||
}
|
||||
|
||||
// 取消收藏某个官方计划
|
||||
function removePlan(slug) {
|
||||
return request({ url: '/api/favorites/plans/' + encodeURIComponent(slug), method: 'DELETE' });
|
||||
}
|
||||
|
||||
// 查询某官方计划收藏状态 { favorited }
|
||||
function planStatus(slug) {
|
||||
return request({ url: '/api/favorites/plans/' + encodeURIComponent(slug) + '/status', method: 'GET' });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listExercises,
|
||||
addExercise,
|
||||
removeExercise,
|
||||
exerciseStatus,
|
||||
listPlans,
|
||||
addPlan,
|
||||
removePlan,
|
||||
planStatus
|
||||
};
|
||||
92
miniprogram/services/plan.js
Normal file
92
miniprogram/services/plan.js
Normal file
@@ -0,0 +1,92 @@
|
||||
// 训练计划服务:我自己的计划 CRUD + 官方计划分级与导入。
|
||||
const { request } = require('../utils/request');
|
||||
|
||||
function injectDisplayName(item) {
|
||||
if (!item) return item;
|
||||
item.displayName = item.nameZh || item.name || '';
|
||||
return item;
|
||||
}
|
||||
|
||||
function injectDisplayNames(list) {
|
||||
if (!list || !Array.isArray(list)) return list || [];
|
||||
return list.map(injectDisplayName);
|
||||
}
|
||||
|
||||
function buildQuery(params) {
|
||||
const qs = Object.keys(params || {})
|
||||
.filter(k => params[k] !== '' && params[k] !== undefined && params[k] !== null)
|
||||
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
|
||||
.join('&');
|
||||
return qs ? '?' + qs : '';
|
||||
}
|
||||
|
||||
// 我自己的计划列表
|
||||
function listMine() {
|
||||
return request({ url: '/api/plans', method: 'GET' });
|
||||
}
|
||||
|
||||
// 新建计划
|
||||
function create(dto) {
|
||||
return request({ url: '/api/plans', method: 'POST', data: dto });
|
||||
}
|
||||
|
||||
// 计划详情
|
||||
function get(id) {
|
||||
return request({ url: '/api/plans/' + encodeURIComponent(id), method: 'GET' }).then((plan) => {
|
||||
if (plan && plan.exercises) plan.exercises = injectDisplayNames(plan.exercises);
|
||||
return plan;
|
||||
});
|
||||
}
|
||||
|
||||
// 更新计划元信息
|
||||
function update(id, dto) {
|
||||
return request({ url: '/api/plans/' + encodeURIComponent(id), method: 'PATCH', data: dto });
|
||||
}
|
||||
|
||||
// 删除计划
|
||||
function remove(id) {
|
||||
return request({ url: '/api/plans/' + encodeURIComponent(id), method: 'DELETE' });
|
||||
}
|
||||
|
||||
// 向计划添加动作(自动去重)
|
||||
function addExercise(id, exerciseId) {
|
||||
return request({ url: '/api/plans/' + encodeURIComponent(id) + '/exercises', method: 'POST', data: { exerciseId } });
|
||||
}
|
||||
|
||||
// 从计划移除动作
|
||||
function removeExercise(id, exerciseId) {
|
||||
return request({ url: '/api/plans/' + encodeURIComponent(id) + '/exercises/' + encodeURIComponent(exerciseId), method: 'DELETE' });
|
||||
}
|
||||
|
||||
// 导入官方计划为我的副本
|
||||
function importOfficial(slug, name) {
|
||||
return request({ url: '/api/plans/import', method: 'POST', data: { slug, name } });
|
||||
}
|
||||
|
||||
// 官方计划分级分组
|
||||
function officialGroups() {
|
||||
return request({ url: '/api/plans/official', method: 'GET' });
|
||||
}
|
||||
|
||||
// 官方计划下的动作(分页)
|
||||
function officialExercises(slug, page = 1, pageSize = 30) {
|
||||
return request({
|
||||
url: '/api/plans/official/' + encodeURIComponent(slug) + '/exercises' + buildQuery({ page, pageSize })
|
||||
}).then((res) => {
|
||||
if (res && res.items) res.items = injectDisplayNames(res.items);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listMine,
|
||||
create,
|
||||
get,
|
||||
update,
|
||||
remove,
|
||||
addExercise,
|
||||
removeExercise,
|
||||
importOfficial,
|
||||
officialGroups,
|
||||
officialExercises
|
||||
};
|
||||
13
miniprogram/services/user.js
Normal file
13
miniprogram/services/user.js
Normal file
@@ -0,0 +1,13 @@
|
||||
// 用户服务:映射 /api/auth/me 与 /api/users/me。
|
||||
// request 自动携带 token,页面无需手动处理鉴权头。
|
||||
const { request } = require('../utils/request');
|
||||
|
||||
function getMe() {
|
||||
return request({ url: '/api/auth/me', method: 'GET' });
|
||||
}
|
||||
|
||||
function updateProfile(dto) {
|
||||
return request({ url: '/api/users/me', method: 'PATCH', data: dto });
|
||||
}
|
||||
|
||||
module.exports = { getMe, updateProfile };
|
||||
Reference in New Issue
Block a user