feat: 购油方案 — 会员请求+老师定制+购油清单
Some checks failed
Test / unit-test (push) Successful in 5s
Test / build-check (push) Failing after 4s
PR Preview / teardown-preview (pull_request) Has been skipped
Test / e2e-test (push) Failing after 3m5s
PR Preview / test (pull_request) Successful in 6s
PR Preview / deploy-preview (pull_request) Failing after 10s

后端:
- oil_plans/oil_plan_recipes 表
- 7个API: teachers列表、方案CRUD、配方增删、购油清单计算
- 购油清单自动算月消耗、瓶数、费用,交叉比对库存

前端:
- 会员端(库存页): 请求方案→选老师→描述需求;查看购油清单
- 老师端(用户管理): 接收请求→选配方+频率→激活方案
- plans store 管理状态

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 21:38:07 +00:00
parent e0ee1cba8c
commit 7ae2e73ee5
5 changed files with 608 additions and 2 deletions

View File

@@ -0,0 +1,62 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { requestJSON, api } from '../composables/useApi'
export const usePlansStore = defineStore('plans', () => {
const plans = ref([])
const teachers = ref([])
const shoppingList = ref([])
const activePlan = computed(() => plans.value.find(p => p.status === 'active'))
const pendingPlans = computed(() => plans.value.filter(p => p.status === 'pending'))
async function loadPlans() {
plans.value = await requestJSON('/api/oil-plans')
}
async function loadTeachers() {
teachers.value = await requestJSON('/api/teachers')
}
async function createPlan(healthDesc, teacherId) {
const res = await api('/api/oil-plans', {
method: 'POST',
body: JSON.stringify({ health_desc: healthDesc, teacher_id: teacherId }),
})
if (!res.ok) throw new Error('创建失败')
await loadPlans()
return res.json()
}
async function updatePlan(planId, data) {
await api(`/api/oil-plans/${planId}`, {
method: 'PUT',
body: JSON.stringify(data),
})
await loadPlans()
}
async function addRecipe(planId, recipeName, ingredients, timesPerMonth) {
await api(`/api/oil-plans/${planId}/recipes`, {
method: 'POST',
body: JSON.stringify({ recipe_name: recipeName, ingredients, times_per_month: timesPerMonth }),
})
await loadPlans()
}
async function removeRecipe(planId, recipeId) {
await api(`/api/oil-plans/${planId}/recipes/${recipeId}`, { method: 'DELETE' })
await loadPlans()
}
async function loadShoppingList(planId) {
shoppingList.value = await requestJSON(`/api/oil-plans/${planId}/shopping-list`)
}
return {
plans, teachers, shoppingList,
activePlan, pendingPlans,
loadPlans, loadTeachers, createPlan, updatePlan,
addRecipe, removeRecipe, loadShoppingList,
}
})