Files
msh-system/msh_single_uniapp/api/tool.js

565 lines
16 KiB
JavaScript
Raw Normal View History

// +----------------------------------------------------------------------
// | Tool模块API接口
// +----------------------------------------------------------------------
// | 包含食谱计算器、AI营养师、饮食打卡、食物百科、营养知识等接口
// +----------------------------------------------------------------------
import request from "@/utils/request.js";
import { HTTP_REQUEST_URL, TOKENNAME } from "@/config/app.js";
import store from "@/store";
// ==================== 食谱计算器相关 ====================
/**
* 计算营养方案
* @param {Object} data - 计算参数
* @param {String} data.gender - 性别male/female
* @param {Number} data.age - 年龄
* @param {Number} data.height - 身高(cm)
* @param {Boolean} data.dialysis - 是否透析true/false
* @param {String} data.dialysisType - 透析类型hemodialysis/peritoneal (可选)
* @param {Number} data.dryWeight - 干体重(kg)
* @param {Number} data.creatinine - 血肌酐(μmol/L)
*/
export function calculateNutrition(data) {
return request.post('tool/calculator/calculate', data);
}
/**
* 获取计算结果详情
* @param {Number} id - 计算结果ID
*/
export function getCalculatorResult(id) {
return request.get('tool/calculator/result/' + id);
}
/**
* 采纳营养计划
* @param {Number} resultId - 计算结果ID
*/
export function adoptNutritionPlan(resultId) {
return request.post('tool/calculator/adopt', { resultId });
}
// ==================== AI营养师相关 ====================
/**
* 发送消息给AI营养师
* @param {Object} data - 消息数据
* @param {String} data.content - 消息内容
* @param {String} data.type - 消息类型text/image/voice
* @param {String} data.imageUrl - 图片URL当type为image时
* @param {String} data.voiceUrl - 语音URL当type为voice时
* @param {String} data.conversationId - 会话ID可选用于继续对话
*/
export function sendAIMessage(data) {
return request.post('tool/ai-nutritionist/message', data);
}
/**
* 获取AI回复
* @param {String} messageId - 消息ID
*/
export function getAIResponse(messageId) {
return request.get('tool/ai-nutritionist/response/' + messageId);
}
/**
* 获取对话历史
* @param {Object} data - 查询参数
* @param {String} data.conversationId - 会话ID可选
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getConversationHistory(data) {
return request.get('tool/ai-nutritionist/history', data);
}
/**
* 清空对话历史
* @param {String} conversationId - 会话ID可选
*/
export function clearConversation(conversationId) {
return request.post('tool/ai-nutritionist/clear', { conversationId });
}
// ==================== 饮食打卡相关 ====================
/**
* 提交打卡记录
* @param {Object} data - 打卡数据
* @param {String} data.mealType - 餐次breakfast/lunch/dinner/snack
* @param {String} data.date - 打卡日期YYYY-MM-DD
* @param {Array} data.images - 图片URL数组
* @param {String} data.remark - 备注
* @param {String} data.voiceUrl - 语音备注URL可选
* @param {String} data.taskId - 语音识别任务ID可选
* @param {String} data.dishes - 菜品清单JSON字符串
* @param {Object} data.nutrition - 营养数据可选
* @param {Boolean} data.enableAIVideo - 是否生成AI视频
* @param {Boolean} data.enableAIAnalysis - 是否开启AI识别
*/
export function submitCheckin(data) {
return request.post('tool/checkin/submit', data);
}
/**
* 获取打卡记录列表
* @param {Object} data - 查询参数
* @param {String} data.date - 日期YYYY-MM-DD可选
* @param {String} data.mealType - 餐次可选
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getCheckinList(data) {
return request.get('tool/checkin/list', data);
}
/**
* 获取打卡记录详情
* @param {Number} id - 打卡记录ID
*/
export function getCheckinDetail(id) {
return request.get('tool/checkin/detail/' + id);
}
/**
* 获取连续打卡统计
*/
export function getCheckinStreak() {
return request.get('tool/checkin/streak');
}
/**
* 获取打卡日历数据
* @param {String} yearMonth - 年月YYYY-MM
*/
export function getCheckinCalendar(yearMonth) {
return request.get('tool/checkin/calendar', { yearMonth });
}
/**
* 获取打卡任务列表
*/
export function getCheckinTasks() {
return request.get('tool/checkin/tasks');
}
/**
* 查询视频任务状态
* @param {String} taskId - 任务ID
*/
export function getVideoTaskStatus(taskId) {
return request.get(`kieai/video/task/${taskId}`);
}
/**
* 一键复制打卡
* @param {Number} sourceRecordId - 源打卡记录ID
* @param {Object} data - 修改后的数据可选
*/
export function copyCheckin(sourceRecordId, data) {
return request.post('tool/checkin/copy', {
sourceRecordId,
...data
});
}
/**
* 一键借鉴打卡
* @param {Number} sourcePostId - 源社区内容ID
* @param {Object} data - 修改后的数据可选
*/
export function learnCheckin(sourcePostId, data) {
return request.post('tool/checkin/learn', {
sourcePostId,
...data
});
}
// ==================== 食物百科相关 ====================
/**
* 搜索食物
* @param {Object} data - 搜索参数
* @param {String} data.keyword - 搜索关键词
* @param {String} data.category - 分类可选
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function searchFood(data) {
return request.get('tool/food/search', data);
}
/**
* 获取食物列表按分类
* @param {Object} data - 查询参数
* @param {String} data.category - 分类all/grain/vegetable/fruit/meat/seafood
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getFoodList(data) {
return request.get('tool/food/list', data);
}
/**
* 获取食物详情后端仅接受 Long 类型 id name 400
* @param {Number|String} id - 食物ID必须为数字不能传名称
*/
export function getFoodDetail(id) {
const numId = typeof id === 'number' && !isNaN(id) ? id : parseInt(String(id), 10);
// 打印请求参数便于确认(后端仅接受 Long 类型 id传 name 会 400
console.log('[api/tool] getFoodDetail 请求参数:', { id, numId, type: typeof id });
if (isNaN(numId)) {
return Promise.reject(new Error('食物详情接口需要数字ID当前传入: ' + id));
}
return request.get('tool/food/detail/' + numId);
}
/**
* 获取相似食物推荐
* @param {String} foodId - 食物ID
*/
export function getSimilarFoods(foodId) {
return request.get('tool/food/similar/' + foodId);
}
// ==================== 营养知识相关 ====================
/**
* 获取营养知识列表
* @param {Object} data - 查询参数
* @param {String} data.type - 类型nutrients/guide/article
* @param {String} data.category - 分类可选
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getKnowledgeList(data) {
return request.get('tool/knowledge/list', data);
}
/**
* 获取营养知识详情
* @param {Number} id - 知识ID
*/
export function getKnowledgeDetail(id) {
return request.get('tool/knowledge/detail/' + id);
}
/**
* 获取营养素详情
* @param {String} name - 营养素名称
*/
export function getNutrientDetail(name) {
return request.get('tool/knowledge/nutrient/' + name);
}
/**
* AI 营养估算根据饮食描述文本返回估算的热量蛋白质T06-T09
* @param {String} text - 饮食描述
* @returns {Promise<{data: {energyKcal?, proteinG?, potassiumMg?, phosphorusMg?}}>}
*/
export function getAiNutritionFill(text) {
return request.post('tool/nutrition/fill-ai', { text: text || '' });
}
// ==================== 打卡社区相关 ====================
/**
* 获取社区内容列表
* @param {Object} data - 查询参数
* @param {String} data.tab - Tab类型recommend/latest/follow/hot
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getCommunityList(data) {
return request.get('tool/community/list', data);
}
/**
* 获取社区内容详情
* @param {Number} id - 内容ID
*/
export function getCommunityDetail(id) {
return request.get('tool/community/detail/' + id);
}
/**
* 发布社区内容
* @param {Object} data - 内容数据
* @param {String} data.title - 标题
* @param {String} data.content - 内容
* @param {Array} data.images - 图片URL数组
* @param {Array} data.tags - 标签数组
* @param {Number} data.checkInRecordId - 关联的打卡记录ID可选
*/
export function publishCommunityPost(data) {
return request.post('tool/community/publish', data);
}
/**
* 点赞/取消点赞
* @param {Number} postId - 内容ID会被转为数字以匹配后端 Long
* @param {Boolean} isLike - 是否点赞true/false
*/
export function toggleLike(postId, isLike) {
const id = typeof postId === 'number' && !isNaN(postId) ? postId : parseInt(postId, 10);
return request.post('tool/community/like', { postId: id, isLike: !!isLike });
}
/**
* 收藏/取消收藏
* @param {Number} postId - 内容ID会被转为数字以匹配后端 Long
* @param {Boolean} isCollect - 是否收藏true/false
*/
export function toggleCollect(postId, isCollect) {
const id = typeof postId === 'number' && !isNaN(postId) ? postId : parseInt(postId, 10);
return request.post('tool/community/collect', { postId: id, isCollect: !!isCollect });
}
/**
* 发表评论
* @param {Object} data - 评论数据
* @param {Number} data.postId - 内容ID
* @param {String} data.content - 评论内容
* @param {Number} data.parentCommentId - 父评论ID可选用于回复
* @param {Number} data.replyToUserId - 回复的用户ID可选
*/
export function addComment(data) {
return request.post('tool/community/comment', data);
}
/**
* 获取评论列表
* @param {Number} postId - 内容ID
* @param {Object} data - 查询参数
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getCommentList(postId, data) {
return request.get('tool/community/comment/list/' + postId, data);
}
/**
* 关注/取消关注用户
* @param {Number} userId - 用户ID
* @param {Boolean} isFollow - 是否关注true/false
*/
export function toggleFollow(userId, isFollow) {
return request.post('tool/community/follow', { userId, isFollow });
}
/**
* 分享内容
* @param {Number} postId - 内容ID
*/
export function sharePost(postId) {
return request.post('tool/community/share', { postId });
}
/**
* 填充帖子营养数据服务端根据帖子内容/打卡补充营养并回写
* @param {Number|String} postId - 帖子ID
* @returns {Promise<{data?: object}>} 返回更新后的帖子或营养数据
*/
export function fillPostNutrition(postId) {
const id = typeof postId === 'number' && !isNaN(postId) ? postId : parseInt(postId, 10);
return request.post('tool/community/post/' + id + '/fill-nutrition');
}
// ==================== 积分系统相关 ====================
/**
* 获取用户积分信息
*/
export function getUserPoints() {
return request.get('tool/points/info');
}
/**
* 获取积分规则
*/
export function getPointsRules() {
return request.get('tool/points/rules');
}
/**
* 获取积分流水
* @param {Object} data - 查询参数
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
* @param {String} data.type - 类型earn/consume可选
*/
export function getPointsHistory(data) {
return request.get('tool/points/history', data);
}
/**
* 获取积分兑换列表
*/
export function getPointsExchangeList() {
return request.get('tool/points/exchange/list');
}
/**
* 积分兑换
* @param {Number} exchangeId - 兑换项ID
*/
export function exchangePoints(exchangeId) {
return request.post('tool/points/exchange', { exchangeId });
}
// ==================== 首页数据相关 ====================
/**
* 获取首页数据
*/
export function getHomeData() {
return request.get('tool/home/data');
}
/**
* 获取推荐食谱列表首页展示无需登录即可浏览
* @param {Object} data - 查询参数
* @param {Number} data.limit - 数量限制
*/
export function getRecommendedRecipes(data) {
return request.get('tool/home/recipes', data, { noAuth: true });
}
/**
* 获取推荐营养知识首页展示无需登录即可浏览
* @param {Object} data - 查询参数
* @param {Number} data.limit - 数量限制
*/
export function getRecommendedKnowledge(data) {
return request.get('tool/home/knowledge', data, { noAuth: true });
}
/**
* 获取用户健康档案状态首页展示未登录时返回默认状态
*/
export function getUserHealthStatus() {
return request.get('tool/home/health-status', {}, { noAuth: true });
}
/**
* 获取首页展示配置如四大功能入口是否显示由系统配置 field01 控制1=显示
*/
export function getHomeDisplayConfig() {
return request.get('tool/home/display-config', {}, { noAuth: true });
}
// ==================== 食谱相关 ====================
/**
* 获取食谱列表
* @param {Object} data - 查询参数
* @param {String} data.mealType - 餐次可选
* @param {Number} data.page - 页码
* @param {Number} data.limit - 每页数量
*/
export function getRecipeList(data) {
return request.get('tool/recipe/list', data);
}
/**
* 获取食谱详情
* @param {Number} id - 食谱ID
*/
export function getRecipeDetail(id) {
return request.get('tool/recipe/detail/' + id);
}
/**
* 收藏/取消收藏食谱
* @param {Number} recipeId - 食谱ID
* @param {Boolean} isFavorite - 是否收藏true/false
*/
export function toggleRecipeFavorite(recipeId, isFavorite) {
return request.post('tool/recipe/favorite', { recipeId, isFavorite });
}
// T09: 食谱营养 AI 回填
export function fillRecipeNutrition(recipeId) {
return request.post("tool/recipe/" + recipeId + "/fill-nutrition")
}
// ==================== 文件上传相关 ====================
/**
* 上传图片
* @param {String} filePath - 图片临时路径
* @param {String} type - 上传类型checkin/community/avatar
*/
export function uploadImage(filePath, type = 'checkin') {
return new Promise((resolve, reject) => {
const token = store.state.app.token || '';
const header = {};
if (token) {
header[TOKENNAME] = token;
}
uni.uploadFile({
url: HTTP_REQUEST_URL + '/api/front/tool/upload/image',
filePath: filePath,
name: 'file',
formData: {
type: type
},
header: header,
success: (res) => {
try {
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
if (data.code === 200) {
resolve(data.data);
} else {
reject(data.message || '上传失败');
}
} catch (e) {
reject('解析响应失败');
}
},
fail: (err) => {
reject('上传失败:' + (err.errMsg || '网络错误'));
}
});
});
}
/**
* 上传语音
* @param {String} filePath - 语音临时路径
*/
export function uploadVoice(filePath) {
return new Promise((resolve, reject) => {
const token = store.state.app.token || '';
const header = {};
if (token) {
header[TOKENNAME] = token;
}
uni.uploadFile({
url: HTTP_REQUEST_URL + '/api/front/tool/upload/voice',
filePath: filePath,
name: 'file',
header: header,
success: (res) => {
try {
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
if (data.code === 200) {
resolve(data.data);
} else {
reject(data.message || '上传失败');
}
} catch (e) {
reject('解析响应失败');
}
},
fail: (err) => {
reject('上传失败:' + (err.errMsg || '网络错误'));
}
});
});
}