diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index a152b0d..3d83aee 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -1109,21 +1109,26 @@ async function rejectRecipe(recipe) { } } -async function exportExcel() { - try { - const res = await api('/api/recipes/export-excel') - if (!res.ok) throw new Error('Export failed') - const blob = await res.blob() - const url = URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = '配方导出.xlsx' - a.click() - URL.revokeObjectURL(url) - ui.showToast('导出成功') - } catch { - ui.showToast('导出失败') +function exportExcel() { + const recipes = recipeStore.recipes + if (!recipes.length) { ui.showToast('没有配方可导出'); return } + // BOM for UTF-8 Excel compatibility + let csv = '\uFEFF配方名称,标签,精油成分,滴数,成本\n' + for (const r of recipes) { + const tags = (r.tags || []).join('/') + const ings = r.ingredients.map(i => i.oil).join('、') + const drops = r.ingredients.map(i => `${i.oil}${i.drops}滴`).join('、') + const cost = oils.fmtPrice(oils.calcCost(r.ingredients)) + csv += `"${r.name}","${tags}","${ings}","${drops}","${cost}"\n` } + const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = '配方导出.csv' + a.click() + URL.revokeObjectURL(url) + ui.showToast('导出成功') } function onTagPickerSave(tags) { @@ -1598,8 +1603,8 @@ watch(() => recipeStore.recipes, () => { } .tag-delete { margin-left: 4px; cursor: pointer; font-size: 12px; color: #ccc; } .tag-delete:hover { color: #c0392b; } -.tag-add-row { display: flex; gap: 4px; align-items: center; width: 100%; margin-top: 4px; } -.tag-add-input { flex: 1; padding: 4px 8px; border: 1px solid #e5e4e7; border-radius: 8px; font-size: 12px; outline: none; font-family: inherit; } +.tag-add-row { display: inline-flex; gap: 4px; align-items: center; } +.tag-add-input { width: 80px; padding: 4px 8px; border: 1px solid #e5e4e7; border-radius: 8px; font-size: 12px; outline: none; font-family: inherit; } .tag-add-input:focus { border-color: #7ec6a4; } .tag-add-btn { border: none; background: #e8f5e9; color: #4a9d7e; border-radius: 6px; padding: 4px 10px; font-size: 12px; cursor: pointer; font-family: inherit; } .tag-add-btn:disabled { opacity: 0.4; }