Files
Pet3/cloudfunctions/dogManage/index.js
2026-06-25 18:24:29 +08:00

97 lines
3.7 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.
// 云函数 dogManage — 狗狗 create/update/list建档与编辑复用
// 契约见 docs/03-云函数设计.md §2
const cloud = require('wx-server-sdk');
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const db = cloud.database();
// 体型档位 → 步幅模型(与 miniprogram/utils/dogStep.js 保持一致docs/05 R3
const BASE_STRIDE = { xs: 0.20, s: 0.25, m: 0.35, l: 0.45, xl: 0.55 }; // 米/步
const STD_WEIGHT = { xs: 3, s: 7, m: 15, l: 28, xl: 45 }; // 档位标准体重 kg
// 犬种 → 体型档位;未列出的(中华田园犬/串串/其他)需前端让用户手动选 sizeLevel
const BREED_SIZE = {
柯基: 's', 比熊: 'xs', 泰迪: 's', 柴犬: 'm', 金毛: 'l',
拉布拉多: 'l', 哈士奇: 'l', 边境牧羊犬: 'm', 萨摩耶: 'l', 法斗: 's',
};
const resolveSize = (breed, clientSize) => BREED_SIZE[breed] || clientSize || null;
function computeStride(sizeLevel, weight) {
const base = BASE_STRIDE[sizeLevel];
if (!base) return { baseStride: null, stride: null };
let stride = base;
if (weight) {
let f = 1 + (Number(weight) - STD_WEIGHT[sizeLevel]) * 0.005;
f = Math.max(0.85, Math.min(1.15, f));
stride = +(base * f).toFixed(3);
}
return { baseStride: base, stride };
}
// 规范化狗狗字段;返回 { error } 表示校验失败
function normalize(dog) {
const sizeLevel = resolveSize(dog.breed, dog.sizeLevel);
if (!sizeLevel) return { error: '请选择体型档位' }; // 未知犬种必须手动选
const weight = dog.weight != null ? Number(dog.weight) : null;
const { baseStride, stride } = computeStride(sizeLevel, weight);
return {
data: {
name: String(dog.name || '').trim(),
breed: String(dog.breed || '').trim(),
sizeLevel,
baseStride,
stride,
gender: dog.gender || null,
ageStage: dog.ageStage || null,
ageText: dog.ageText || '',
weight,
avatar: dog.avatar || '',
},
};
}
exports.main = async (event, context) => {
const { OPENID } = cloud.getWXContext();
const { action, dog } = event;
const dogsCol = db.collection('dogs');
// ---- list列出我的狗 ----
if (action === 'list') {
const res = await dogsCol.where({ _openid: OPENID }).orderBy('createdAt', 'asc').get();
return { ok: true, data: res.data };
}
// ---- create建档 ----
if (action === 'create') {
if (!dog || !dog.name || !dog.breed) {
return { ok: false, code: 'INVALID', msg: '名字和犬种必填' };
}
const norm = normalize(dog);
if (norm.error) return { ok: false, code: 'INVALID', msg: norm.error };
const now = Date.now();
const doc = {
_openid: OPENID,
...norm.data,
stats: { totalWalks: 0, totalDistance: 0, totalSteps: 0, currentStreak: 0, lastWalkDate: '' },
createdAt: now,
};
const addRes = await dogsCol.add({ data: doc });
return { ok: true, data: { _id: addRes._id, ...doc } };
}
// ---- update编辑校验归属防越权改他人狗----
if (action === 'update') {
if (!dog || !dog._id) return { ok: false, code: 'INVALID', msg: '缺少狗狗ID' };
if (!dog.name || !dog.breed) return { ok: false, code: 'INVALID', msg: '名字和犬种必填' };
const target = await dogsCol.doc(dog._id).get().catch(() => null);
if (!target || !target.data || target.data._openid !== OPENID) {
return { ok: false, code: 'FORBIDDEN', msg: '无权操作' };
}
const norm = normalize(dog);
if (norm.error) return { ok: false, code: 'INVALID', msg: norm.error };
await dogsCol.doc(dog._id).update({ data: norm.data });
return { ok: true, data: { ...target.data, ...norm.data } };
}
return { ok: false, code: 'UNKNOWN_ACTION', msg: '未知操作' };
};