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