修改分模逻辑为注塑模

This commit is contained in:
2026-05-06 17:20:54 +08:00
parent 1b54f2f7a8
commit 2fb3b0271c
13 changed files with 492 additions and 76 deletions
+2 -1
View File
@@ -76,7 +76,8 @@
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vue-router@4/dist/vue-router.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/air-datepicker@3.5.3/air-datepicker.js"></script>
<script src="/static/vue-app.js?v=20260409-01"></script>
<script src="/static/vue-app.js?v=20260506-01"></script>
</body>
</html>
+143
View File
@@ -1538,6 +1538,149 @@ optgroup {
color: var(--text-tertiary);
}
/* ================================
铝金属价格板块
================================ */
.aluminum-section {
margin-bottom: var(--space-6);
}
.aluminum-price-card {
border-left: 4px solid var(--primary-500);
}
.aluminum-icon {
font-size: 1.2em;
}
.aluminum-source {
font-size: var(--text-xs);
color: var(--text-muted);
}
.aluminum-content {
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.aluminum-price-row {
display: flex;
align-items: baseline;
gap: var(--space-6);
flex-wrap: wrap;
}
.aluminum-current {
display: flex;
align-items: baseline;
gap: var(--space-3);
}
.aluminum-price-value {
font-size: 2.5rem;
font-weight: var(--font-bold);
color: var(--text-primary);
line-height: 1.2;
font-variant-numeric: tabular-nums;
}
.aluminum-price-unit {
font-size: var(--text-sm);
color: var(--text-tertiary);
}
.aluminum-change {
display: flex;
align-items: center;
gap: var(--space-1);
font-weight: var(--font-semibold);
font-size: var(--text-base);
}
.aluminum-change.price-up {
color: #dc2626;
}
.aluminum-change.price-down {
color: #16a34a;
}
.change-arrow {
font-size: var(--text-sm);
}
.aluminum-detail-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: var(--space-3);
padding: var(--space-4);
background: var(--bg-secondary);
border-radius: var(--radius-lg);
}
.aluminum-detail-item {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.detail-label {
font-size: var(--text-xs);
color: var(--text-tertiary);
}
.detail-value {
font-size: var(--text-sm);
font-weight: var(--font-medium);
color: var(--text-primary);
font-variant-numeric: tabular-nums;
}
.price-up-text {
color: #dc2626;
}
.price-down-text {
color: #16a34a;
}
.aluminum-chart-wrapper {
margin-top: var(--space-2);
}
.aluminum-chart-title {
font-size: var(--text-sm);
font-weight: var(--font-medium);
color: var(--text-secondary);
margin-bottom: var(--space-3);
}
.aluminum-chart-container {
position: relative;
width: 100%;
height: 280px;
background: var(--bg-secondary);
border-radius: var(--radius-lg);
padding: var(--space-3);
}
@media (max-width: 768px) {
.aluminum-price-value {
font-size: 1.75rem;
}
.aluminum-price-row {
gap: var(--space-3);
}
.aluminum-detail-row {
grid-template-columns: repeat(2, 1fr);
gap: var(--space-2);
}
.aluminum-chart-container {
height: 220px;
}
}
/* ================================
响应式设计
================================ */
+142 -2
View File
@@ -463,7 +463,10 @@ const HomeView = {
const state = reactive({
stats: null,
loading: true,
backendDbReady: true
backendDbReady: true,
aluminumPrice: null,
aluminumHistory: [],
aluminumLoading: true
});
const loadStats = async () => {
@@ -481,15 +484,94 @@ const HomeView = {
}
};
const loadAluminumPrice = async () => {
try {
const [current, history] = await Promise.all([
apiRequest('/api/aluminum-price/current').catch(() => null),
apiRequest('/api/aluminum-price/history?days=30').catch(() => null)
]);
state.aluminumPrice = current;
state.aluminumHistory = history || [];
} catch (e) {
console.error('铝价数据加载失败:', e);
} finally {
state.aluminumLoading = false;
nextTick(() => {
renderAluminumChart();
});
}
};
let chartInstance = null;
const renderAluminumChart = () => {
const canvas = document.getElementById('aluminumChart');
if (!canvas || !state.aluminumHistory.length) return;
if (chartInstance) chartInstance.destroy();
const ctx = canvas.getContext('2d');
const labels = state.aluminumHistory.map(d => d.date.slice(5));
const prices = state.aluminumHistory.map(d => d.close);
const gradient = ctx.createLinearGradient(0, 0, 0, 280);
gradient.addColorStop(0, 'rgba(59, 130, 246, 0.35)');
gradient.addColorStop(1, 'rgba(59, 130, 246, 0.02)');
chartInstance = new Chart(ctx, {
type: 'line',
data: {
labels,
datasets: [{
label: '铝价 (元/吨)',
data: prices,
borderColor: '#3b82f6',
backgroundColor: gradient,
borderWidth: 2,
fill: true,
tension: 0.3,
pointRadius: 0,
pointHoverRadius: 5,
pointHoverBackgroundColor: '#3b82f6',
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { display: false },
tooltip: {
backgroundColor: 'rgba(23, 23, 23, 0.9)',
titleFont: { size: 12 },
bodyFont: { size: 13 },
padding: 10,
cornerRadius: 8,
displayColors: false,
callbacks: {
label: ctx => '¥' + ctx.parsed.y.toLocaleString() + ' 元/吨'
}
}
},
scales: {
x: {
grid: { display: false },
ticks: { color: '#a3a3a3', font: { size: 10 }, maxTicksLimit: 8 }
},
y: {
grid: { color: 'rgba(0,0,0,0.05)' },
ticks: { color: '#a3a3a3', font: { size: 10 }, callback: v => v.toLocaleString() }
}
}
}
});
};
onMounted(() => {
if (!appState.user) {
router.push('/login');
return;
}
loadStats();
loadAluminumPrice();
});
return { state, formatNumber, formatCurrency, appState };
return { state, formatNumber, formatCurrency, appState, loadAluminumPrice };
},
template: `
<div class="page-container">
@@ -552,6 +634,64 @@ const HomeView = {
</div>
</div>
</div>
<div class="aluminum-section">
<div class="card aluminum-price-card">
<div class="card-header">
<div class="card-title">
<span class="aluminum-icon">🪨</span>
铝金属实时行情
</div>
<div class="aluminum-source">数据来源: SHFE模拟</div>
</div>
<div class="card-body">
<div v-if="state.aluminumLoading" class="loading-state" style="padding: 20px;">
<div class="loading-spinner"></div>
<p>加载铝价数据...</p>
</div>
<div v-else-if="state.aluminumPrice" class="aluminum-content">
<div class="aluminum-price-row">
<div class="aluminum-current">
<div class="aluminum-price-value">¥{{ state.aluminumPrice.price?.toLocaleString() }}</div>
<div class="aluminum-price-unit">{{ state.aluminumPrice.unit }}</div>
</div>
<div class="aluminum-change" :class="state.aluminumPrice.change >= 0 ? 'price-up' : 'price-down'">
<span class="change-arrow">{{ state.aluminumPrice.change >= 0 ? '▲' : '▼' }}</span>
<span class="change-value">{{ Math.abs(state.aluminumPrice.change)?.toLocaleString() }}</span>
<span class="change-percent">({{ state.aluminumPrice.change_percent >= 0 ? '+' : '' }}{{ state.aluminumPrice.change_percent }}%)</span>
</div>
</div>
<div class="aluminum-detail-row">
<div class="aluminum-detail-item">
<span class="detail-label">开盘价</span>
<span class="detail-value">¥{{ state.aluminumPrice.open?.toLocaleString() }}</span>
</div>
<div class="aluminum-detail-item">
<span class="detail-label">最高价</span>
<span class="detail-value price-up-text">¥{{ state.aluminumPrice.high?.toLocaleString() }}</span>
</div>
<div class="aluminum-detail-item">
<span class="detail-label">最低价</span>
<span class="detail-value price-down-text">¥{{ state.aluminumPrice.low?.toLocaleString() }}</span>
</div>
<div class="aluminum-detail-item">
<span class="detail-label">昨收价</span>
<span class="detail-value">¥{{ state.aluminumPrice.prev_close?.toLocaleString() }}</span>
</div>
</div>
<div class="aluminum-chart-wrapper">
<div class="aluminum-chart-title">近30日价格走势</div>
<div class="aluminum-chart-container">
<canvas id="aluminumChart"></canvas>
</div>
</div>
</div>
<div v-else class="empty-state" style="padding: 20px;">
<p>铝价数据暂不可用</p>
</div>
</div>
</div>
</div>
<div v-if="state.stats?.inventory?.low_stock_products?.length" class="section">
<h2 class="section-title">低库存预警</h2>