feat: 养护模板/社区运营/体重趋势/计划日历 + 雪花ID重构 + 文件表与图片上传

后端
- 主键改雪花字符串 ID(pkg/idgen + Base.BeforeCreate),全表外键/JWT/中间件随之调整
- 新增 files 表:/api/upload 按 MD5 去重,返回 {id,url,md5},服务端只收图片
- 头像/记录附图/帖子图改 file_id 关联,读取解析为 URL
- 养护模板(物种×阶段)后台可配 + AI 生成草稿;建档按模板生成任务/计划/提醒
- 社区 AI 运营:虚拟账号池 + 每日定时/手动生成,帖子带 AI 标
- 计划路线图节点带真实日期;首页周历与计划日历同源;新增 day-plan 当日安排
- 体重趋势接口带备注;记录列表分页

小程序
- 公共图片上传 utils/upload.js(仅图片);记录拍照/我的头像/社区发图三处接入
- 首页日历点选查当日任务;记录页体重趋势可点看备注 + 时间轴分页折叠
- 计划页日历点选查当日计划;自定义 tabBar 高度调整

后台(React)
- 新增「养护模板」「社区运营」页;用户管理加机器人筛选

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-06 08:48:15 +08:00
parent 609f7d06cf
commit 2f5dd6eefc
83 changed files with 2253 additions and 355 deletions
+19 -2
View File
@@ -11,7 +11,8 @@ import { Pager } from '@/components/Pager'
export default function Users() {
const [keyword, setKeyword] = useState('')
const [query, setQuery] = useState('')
const { page, setPage, data, totalPages, reload } = usePaged<any>(api.users, { keyword: query })
const [type, setType] = useState('')
const { page, setPage, data, totalPages, reload } = usePaged<any>(api.users, { keyword: query, type })
async function toggle(u: any) {
await api.setUserDisabled(u.id, !u.disabled)
@@ -30,6 +31,15 @@ export default function Users() {
onKeyDown={(e) => e.key === 'Enter' && (setPage(1), setQuery(keyword))}
/>
<Button onClick={() => (setPage(1), setQuery(keyword))}></Button>
<select
className="h-9 rounded-md border border-input bg-card px-3 text-sm"
value={type}
onChange={(e) => (setPage(1), setType(e.target.value))}
>
<option value=""></option>
<option value="real"></option>
<option value="bot">(AI)</option>
</select>
</div>
<Card>
<CardContent className="pt-6">
@@ -48,7 +58,14 @@ export default function Users() {
{data?.list?.map((u) => (
<TableRow key={u.id}>
<TableCell>{u.id}</TableCell>
<TableCell className="font-medium">{u.nickname}</TableCell>
<TableCell className="font-medium">
{u.nickname}
{u.is_bot && (
<Badge variant="muted" className="ml-2">
AI
</Badge>
)}
</TableCell>
<TableCell>{u.phone || '—'}</TableCell>
<TableCell>{u.onboarded ? '已建档' : '未建档'}</TableCell>
<TableCell>