feat: 商业核算+个人库存+认证优化 #23

Merged
hera merged 14 commits from feat/inventory-commercial into main 2026-04-11 10:47:08 +00:00
Showing only changes of commit a5178f83f9 - Show all commits

View File

@@ -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%;