UI: 价格+利润左右并排,总成本对齐表格列
All checks were successful
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 5s
PR Preview / deploy-preview (pull_request) Successful in 15s
Test / e2e-test (push) Successful in 51s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 10:16:56 +00:00
parent cfe93125ac
commit a5178f83f9

View File

@@ -105,17 +105,22 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div class="total-row"> <table class="ingredients-table total-table">
<span class="total-label">配方总成本</span> <tr>
<span class="total-price">{{ oils.fmtPrice(materialCost) }}</span> <td class="total-label-cell">配方总成本</td>
</div> <td></td>
<td></td>
<td class="total-price-cell">{{ oils.fmtPrice(materialCost) }}</td>
<td></td>
</tr>
</table>
<!-- Consumption Analysis --> <!-- Consumption Analysis -->
<div v-if="consumptionData.length" class="consumption-section" style="margin-top:12px"> <div v-if="consumptionData.length" class="consumption-section" style="margin-top:12px">
<h4>🧪 消耗分析</h4> <h4>🧪 消耗分析</h4>
<table class="consumption-table"> <table class="ingredients-table">
<thead> <thead>
<tr><th>精油</th><th>单次用量</th><th>瓶装容量</th><th>可做次数</th></tr> <tr><th>精油</th><th>单次用量</th><th>瓶装容量</th><th>可做次数</th><th></th></tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="c in consumptionData" :key="c.oil" :class="{ 'limit-oil': c.isLimit }"> <tr v-for="c in consumptionData" :key="c.oil" :class="{ 'limit-oil': c.isLimit }">
@@ -123,6 +128,7 @@
<td>{{ c.drops }}</td> <td>{{ c.drops }}</td>
<td>{{ c.bottleDrops }}</td> <td>{{ c.bottleDrops }}</td>
<td>{{ c.sessions }}</td> <td>{{ c.sessions }}</td>
<td></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -133,76 +139,56 @@
</div> </div>
</div> </div>
<!-- Pricing Section --> <!-- Pricing + Profit side by side -->
<div class="pricing-section"> <div class="price-profit-row">
<h4>💰 价格计算</h4> <div class="pricing-col">
<div class="price-row"> <h4>💰 价格计算</h4>
<span class="price-label">原料成本</span> <div class="price-row">
<span class="price-value cost">{{ oils.fmtPrice(materialCost) }}</span> <span class="price-label">原料成本</span>
</div> <span class="price-value cost">{{ oils.fmtPrice(materialCost) }}</span>
</div>
<div class="price-row"> <div class="price-row">
<span class="price-label">包装费用</span> <span class="price-label">包装费用</span>
<div class="price-input-wrap"> <div class="price-input-wrap"><span>¥</span><input v-model.number="selectedProject.packaging_cost" type="number" class="form-input-inline" @change="saveProject" /></div>
<span>¥</span> </div>
<input v-model.number="selectedProject.packaging_cost" type="number" class="form-input-inline" @change="saveProject" /> <div class="price-row">
<span class="price-label">人工费用</span>
<div class="price-input-wrap"><span>¥</span><input v-model.number="selectedProject.labor_cost" type="number" class="form-input-inline" @change="saveProject" /></div>
</div>
<div class="price-row">
<span class="price-label">其他成本</span>
<div class="price-input-wrap"><span>¥</span><input v-model.number="selectedProject.other_cost" type="number" class="form-input-inline" @change="saveProject" /></div>
</div>
<div class="price-row total">
<span class="price-label">总成本</span>
<span class="price-value cost">{{ oils.fmtPrice(totalCost) }}</span>
</div>
<div class="price-row">
<span class="price-label">售价</span>
<div class="price-input-wrap"><span>¥</span><input v-model.number="selectedProject.selling_price" type="number" class="form-input-inline" @change="saveProject" /></div>
</div>
<div class="price-row">
<span class="price-label">批量数量</span>
<input v-model.number="selectedProject.quantity" type="number" min="1" class="form-input-inline" @change="saveProject" />
</div> </div>
</div> </div>
<div class="profit-col">
<div class="price-row"> <h4>📊 利润分析</h4>
<span class="price-label">人工费用</span> <div class="profit-item">
<div class="price-input-wrap"> <span class="profit-label">单件利润</span>
<span>¥</span> <span class="profit-value" :class="{ negative: unitProfit < 0 }">{{ oils.fmtPrice(unitProfit) }}</span>
<input v-model.number="selectedProject.labor_cost" type="number" class="form-input-inline" @change="saveProject" />
</div> </div>
</div> <div class="profit-item">
<span class="profit-label">利润率</span>
<div class="price-row"> <span class="profit-value" :class="{ negative: profitMargin < 0 }">{{ profitMargin.toFixed(1) }}%</span>
<span class="price-label">其他成本</span>
<div class="price-input-wrap">
<span>¥</span>
<input v-model.number="selectedProject.other_cost" type="number" class="form-input-inline" @change="saveProject" />
</div> </div>
</div> <div class="profit-item">
<span class="profit-label">批量总利润</span>
<div class="price-row total"> <span class="profit-value" :class="{ negative: batchProfit < 0 }">{{ oils.fmtPrice(batchProfit) }}</span>
<span class="price-label">总成本</span>
<span class="price-value cost">{{ oils.fmtPrice(totalCost) }}</span>
</div>
<div class="price-row">
<span class="price-label">售价</span>
<div class="price-input-wrap">
<span>¥</span>
<input v-model.number="selectedProject.selling_price" type="number" class="form-input-inline" @change="saveProject" />
</div> </div>
</div> <div class="profit-item">
<span class="profit-label">批量总收入</span>
<div class="price-row"> <span class="profit-value">{{ oils.fmtPrice(batchRevenue) }}</span>
<span class="price-label">批量数量</span>
<input v-model.number="selectedProject.quantity" type="number" min="1" class="form-input-inline" @change="saveProject" />
</div>
</div>
<!-- Profit Analysis -->
<div class="profit-section">
<h4>📊 利润分析</h4>
<div class="profit-grid">
<div class="profit-card">
<div class="profit-label">单件利润</div>
<div class="profit-value" :class="{ negative: unitProfit < 0 }">{{ oils.fmtPrice(unitProfit) }}</div>
</div>
<div class="profit-card">
<div class="profit-label">利润率</div>
<div class="profit-value" :class="{ negative: profitMargin < 0 }">{{ profitMargin.toFixed(1) }}%</div>
</div>
<div class="profit-card">
<div class="profit-label">批量总利润</div>
<div class="profit-value" :class="{ negative: batchProfit < 0 }">{{ oils.fmtPrice(batchProfit) }}</div>
</div>
<div class="profit-card">
<div class="profit-label">批量总收入</div>
<div class="profit-value">{{ oils.fmtPrice(batchRevenue) }}</div>
</div> </div>
</div> </div>
</div> </div>
@@ -681,12 +667,10 @@ function formatDate(d) {
.remove-btn { border: none; background: none; color: #ccc; cursor: pointer; font-size: 14px; padding: 2px; } .remove-btn { border: none; background: none; color: #ccc; cursor: pointer; font-size: 14px; padding: 2px; }
.remove-btn:hover { color: #c0392b; } .remove-btn:hover { color: #c0392b; }
.total-row { .total-table { background: #e8f5e9; border-radius: 10px; margin-bottom: 0; }
background: #e8f5e9; border-radius: 12px; padding: 14px 18px; .total-table td { border: none; padding: 10px 8px; }
display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; .total-label-cell { font-size: 14px; color: #3e3a44; font-weight: 600; }
} .total-price-cell { font-size: 18px; font-weight: 700; color: #2e7d5a; text-align: center; }
.total-label { font-size: 14px; color: #3e3a44; font-weight: 500; }
.total-price { font-size: 20px; font-weight: 700; color: #2e7d5a; }
.pricing-inline { margin-top: 12px; } .pricing-inline { margin-top: 12px; }
.price-field { display: flex; align-items: center; gap: 8px; } .price-field { display: flex; align-items: center; gap: 8px; }
@@ -769,35 +753,21 @@ function formatDate(d) {
border-color: #7ec6a4; border-color: #7ec6a4;
} }
.profit-grid { .price-profit-row {
display: grid; display: flex; gap: 16px; margin-bottom: 20px;
grid-template-columns: 1fr 1fr;
gap: 8px;
} }
.pricing-col, .profit-col {
.profit-card { flex: 1; padding: 14px; background: #f8f7f5; border-radius: 12px; border: 1.5px solid #e5e4e7;
padding: 12px;
background: #fff;
border-radius: 10px;
text-align: center;
border: 1.5px solid #e5e4e7;
} }
.pricing-col h4, .profit-col h4 { margin: 0 0 10px; font-size: 14px; color: #3e3a44; }
.profit-label { .profit-item {
font-size: 12px; display: flex; justify-content: space-between; align-items: center;
color: #6b6375; padding: 8px 0; border-bottom: 1px solid #eae8e5; font-size: 14px;
margin-bottom: 4px;
}
.profit-value {
font-size: 18px;
font-weight: 700;
color: #4a9d7e;
}
.profit-value.negative {
color: #ef5350;
} }
.profit-item:last-child { border-bottom: none; }
.profit-label { color: #6b6375; font-size: 13px; }
.profit-value { font-size: 16px; font-weight: 700; color: #4a9d7e; }
.profit-value.negative { color: #ef5350; }
.notes-textarea { .notes-textarea {
width: 100%; width: 100%;