+
+
-
+
@@ -281,6 +291,30 @@ async function loadProjects() {
}
}
+// Demo = first project (芳香调理技术), managed by admin
+const demoProject = computed(() => projects.value.find(p => p.name && p.name.includes('芳香调理')) || projects.value[0] || null)
+const userProjects = computed(() => {
+ const demoId = demoProject.value?._id || demoProject.value?.id
+ return projects.value.filter(p => (p._id || p.id) !== demoId)
+})
+const isDemoMode = computed(() => selectedProject.value?._demo === true)
+
+function selectDemoProject() {
+ const p = demoProject.value
+ if (!p) return
+ selectedProject.value = {
+ ...p,
+ _demo: true,
+ ingredients: (p.ingredients || []).map(i => ({ ...i })),
+ packaging_cost: p.packaging_cost || 0,
+ labor_cost: p.labor_cost || 0,
+ other_cost: p.other_cost || 0,
+ selling_price: p.selling_price || 0,
+ quantity: p.quantity || 1,
+ notes: p.notes || '',
+ }
+}
+
function handleCreateProject() {
if (!auth.isBusiness && !auth.isAdmin) {
showCertPrompt()
@@ -289,23 +323,6 @@ function handleCreateProject() {
createProject()
}
-function openDemo() {
- // Find the real 芳香调理技术 recipe
- const recipe = recipeStore.recipes.find(r => r.name.includes('芳香调理技术') || r.name === '芳香调理')
- const ings = recipe ? recipe.ingredients.map(i => ({ ...i })) : [{ oil: '芳香调理', drops: 12 }, { oil: '椰子油', drops: 186 }]
- selectedProject.value = {
- _demo: true,
- name: recipe ? recipe.name : '芳香调理技术',
- ingredients: ings,
- packaging_cost: 5,
- labor_cost: 30,
- other_cost: 10,
- selling_price: 198,
- quantity: 1,
- notes: '体验项目:修改数字不会影响其他用户',
- }
-}
-
async function createProject() {
const name = await showPrompt('项目名称:', '新项目')
if (!name) return
@@ -353,7 +370,10 @@ function selectProject(p) {
async function saveProject() {
if (!selectedProject.value) return
+ // Demo mode for non-admin: only save locally, don't hit API
+ if (isDemoMode.value && !auth.isAdmin) return
const id = selectedProject.value._id || selectedProject.value.id
+ if (!id) return
try {
await api(`/api/projects/${id}`, {
method: 'PUT',
@@ -476,6 +496,10 @@ function formatDate(d) {
.commercial-icon { font-size: 48px; margin-bottom: 8px; }
.commercial-desc { font-size: 14px; color: var(--text-light, #999); }
.demo-card { border-style: dashed !important; opacity: 0.85; }
+.readonly-row { background: #f8f7f5; }
+.readonly-oil { font-size: 13px; color: #6b6375; }
+.readonly-drops { font-size: 13px; color: #3e3a44; font-weight: 500; }
+
.consumption-section { margin-bottom: 20px; padding: 14px; background: #f8f7f5; border-radius: 12px; border: 1.5px solid #e5e4e7; }
.consumption-section h4 { margin: 0 0 12px; font-size: 14px; color: #3e3a44; }
.consumption-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 10px; }