|
|
@@ -28,85 +28,117 @@
|
|
|
>
|
|
|
</el-date-picker>
|
|
|
</el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="handleQuery">查询</el-button>
|
|
|
+ </el-form-item>
|
|
|
</el-form>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 成本性态分析结果展示 -->
|
|
|
- <el-card v-if="costAnalysisResult" class="cost-analysis-card" id="analysisCard">
|
|
|
+ <el-card v-if="costAnalysisResult || waterElectricityAnalysisResult" class="cost-analysis-card" id="analysisCard">
|
|
|
<div slot="header" class="clearfix">
|
|
|
<span>成本性态分析结果</span>
|
|
|
</div>
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">固定成本(a)</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.fixedCost.toFixed(2) }} <span class="unit">元</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">单位变动成本(b)</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.variableCostPerUnit.toFixed(2) }} <span class="unit">元/米</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">相关系数(R)</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.correlationCoefficient.toFixed(4) }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">R方(R²)</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.rSquared !== undefined ? costAnalysisResult.rSquared.toFixed(4) : 'N/A' }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="20" style="margin-top: 20px;">
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">数据点数量</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.dataPoints }} <span class="unit">个</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">F统计量</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.fStatistic !== undefined ? costAnalysisResult.fStatistic.toFixed(2) : 'N/A' }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">显著性</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.significance !== undefined ? costAnalysisResult.significance : 'N/A' }}
|
|
|
- <div v-if="costAnalysisResult.pValue !== undefined && costAnalysisResult.pValue !== null" class="p-value">
|
|
|
- (P = {{ costAnalysisResult.pValue.toFixed(6) }})
|
|
|
+
|
|
|
+ <div class="analysis-container">
|
|
|
+ <!-- 总成本分析 -->
|
|
|
+ <div class="analysis-column" v-if="costAnalysisResult">
|
|
|
+ <div class="analysis-section">
|
|
|
+ <div class="section-title">总成本模型</div>
|
|
|
+ <div class="metrics-grid">
|
|
|
+ <div class="metric-card primary">
|
|
|
+ <div class="metric-label">固定成本(a)</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.fixedCost.toFixed(2) }} <span class="unit">元</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card primary">
|
|
|
+ <div class="metric-label">单位变动成本(b)</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.variableCostPerUnit.toFixed(2) }} <span class="unit">元/米</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card secondary">
|
|
|
+ <div class="metric-label">相关系数(R)</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.correlationCoefficient.toFixed(4) }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card secondary">
|
|
|
+ <div class="metric-label">R方(R²)</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.rSquared !== undefined ? costAnalysisResult.rSquared.toFixed(4) : 'N/A' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card info">
|
|
|
+ <div class="metric-label">数据点数量</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.dataPoints }} <span class="unit">个</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card info">
|
|
|
+ <div class="metric-label">F统计量</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.fStatistic !== undefined ? costAnalysisResult.fStatistic.toFixed(2) : 'N/A' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card warning">
|
|
|
+ <div class="metric-label">显著性</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.significance }}</div>
|
|
|
+ <div class="p-value" v-if="costAnalysisResult.pValue !== undefined && costAnalysisResult.pValue !== null">
|
|
|
+ (P={{ formatPValue(costAnalysisResult.pValue) }})
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card warning">
|
|
|
+ <div class="metric-label">标准误差</div>
|
|
|
+ <div class="metric-value">{{ costAnalysisResult.standardError !== undefined ? costAnalysisResult.standardError.toFixed(2) : 'N/A' }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="analysis-item">
|
|
|
- <div class="analysis-label">标准误差</div>
|
|
|
- <div class="analysis-value">{{ costAnalysisResult.standardError !== undefined ? costAnalysisResult.standardError.toFixed(2) : 'N/A' }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="20" style="margin-top: 20px;">
|
|
|
- <el-col :span="24">
|
|
|
- <div class="model-display">
|
|
|
- <div class="model-label">成本模型:</div>
|
|
|
- <div class="model-formula">总成本 = {{ costAnalysisResult.fixedCost.toFixed(2) }} + {{ costAnalysisResult.variableCostPerUnit.toFixed(2) }} × 产量(米)</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分隔线 -->
|
|
|
+ <div class="divider"></div>
|
|
|
+
|
|
|
+ <!-- 水电分析 -->
|
|
|
+ <div class="analysis-column" v-if="waterElectricityAnalysisResult">
|
|
|
+ <div class="analysis-section">
|
|
|
+ <div class="section-title">水电费成本模型</div>
|
|
|
+ <div class="metrics-grid">
|
|
|
+ <div class="metric-card primary">
|
|
|
+ <div class="metric-label">固定成本(a)</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.fixedCost.toFixed(2) }} <span class="unit">元</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card primary">
|
|
|
+ <div class="metric-label">单位变动成本(b)</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.variableCostPerUnit.toFixed(2) }} <span class="unit">元/米</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card secondary">
|
|
|
+ <div class="metric-label">相关系数(R)</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.correlationCoefficient.toFixed(4) }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card secondary">
|
|
|
+ <div class="metric-label">R方(R²)</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.rSquared !== undefined ? waterElectricityAnalysisResult.rSquared.toFixed(4) : 'N/A' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card info">
|
|
|
+ <div class="metric-label">数据点数量</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.dataPoints }} <span class="unit">个</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card info">
|
|
|
+ <div class="metric-label">F统计量</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.fStatistic !== undefined ? waterElectricityAnalysisResult.fStatistic.toFixed(2) : 'N/A' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card warning">
|
|
|
+ <div class="metric-label">显著性</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.significance }}</div>
|
|
|
+ <div class="p-value" v-if="waterElectricityAnalysisResult.pValue !== undefined && waterElectricityAnalysisResult.pValue !== null">
|
|
|
+ (P={{ formatPValue(waterElectricityAnalysisResult.pValue) }})
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-card warning">
|
|
|
+ <div class="metric-label">标准误差</div>
|
|
|
+ <div class="metric-value">{{ waterElectricityAnalysisResult.standardError !== undefined ? waterElectricityAnalysisResult.standardError.toFixed(2) : 'N/A' }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</el-card>
|
|
|
|
|
|
<el-card class="table-card">
|
|
|
<div slot="header" class="clearfix">
|
|
|
<span>成本数据明细</span>
|
|
|
<div style="float: right;">
|
|
|
- <el-button type="success" size="mini" @click="handlePredict" :disabled="!costAnalysisResult">成本预测</el-button>
|
|
|
+ <el-button type="success" size="mini" @click="handlePredict" :disabled="!costAnalysisResult || !waterElectricityAnalysisResult">成本预测</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<el-table
|
|
|
@@ -184,17 +216,17 @@
|
|
|
{{ formatNumber(scope.row.otherCost) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="预测成本(元)" align="center" prop="predictedCost" width="120">
|
|
|
+ <el-table-column label="预测总成本(元)" align="center" prop="predictedTotalCost" width="120">
|
|
|
<template #default="scope">
|
|
|
- <span :class="{ 'predicted-high': scope.row.predictedCost > scope.row.totalCost }">
|
|
|
- {{ formatNumber(scope.row.predictedCost) }}
|
|
|
+ <span :class="{ 'predicted-high': scope.row.predictedTotalCost > scope.row.totalCost }">
|
|
|
+ {{ formatNumber(scope.row.predictedTotalCost) }}
|
|
|
</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="实际偏离(元)" align="center" prop="deviation" width="120">
|
|
|
+ <el-table-column label="预测水电费(元)" align="center" prop="predictedWaterElectricity" width="120">
|
|
|
<template #default="scope">
|
|
|
- <span :class="getDeviationClass(scope.row.deviation)">
|
|
|
- {{ formatNumber(scope.row.deviation) }}
|
|
|
+ <span :class="{ 'predicted-high': scope.row.predictedWaterElectricity > scope.row.waterElectricity }">
|
|
|
+ {{ formatNumber(scope.row.predictedWaterElectricity) }}
|
|
|
</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -217,6 +249,7 @@ const total = ref(0);
|
|
|
const originalRows = ref({}); // 用于保存原始数据,便于取消编辑时恢复
|
|
|
const selectedQueryYear = ref(new Date().getFullYear().toString()); // 查询条件中的年份,默认当年,转为字符串
|
|
|
const costAnalysisResult = ref(null); // 成本性态分析结果
|
|
|
+const waterElectricityAnalysisResult = ref(null); // 水电费分析结果
|
|
|
|
|
|
// 获取车间名称
|
|
|
function getWsName(wsValue) {
|
|
|
@@ -244,18 +277,16 @@ function handleYearChange(value) {
|
|
|
|
|
|
// 产量变化处理
|
|
|
function handleLengthChange(row) {
|
|
|
- if (row.length && costAnalysisResult.value) {
|
|
|
- const { fixedCost, variableCostPerUnit } = costAnalysisResult.value;
|
|
|
+ if (row.length && costAnalysisResult.value && waterElectricityAnalysisResult.value) {
|
|
|
+ const { fixedCost: totalFixedCost, variableCostPerUnit: totalVariableCostPerUnit } = costAnalysisResult.value;
|
|
|
+ const { fixedCost: waterElectricityFixedCost, variableCostPerUnit: waterElectricityVariableCostPerUnit } = waterElectricityAnalysisResult.value;
|
|
|
+
|
|
|
const length = parseFloat(row.length);
|
|
|
|
|
|
if (!isNaN(length)) {
|
|
|
- // 计算预测成本
|
|
|
- row.predictedCost = fixedCost + variableCostPerUnit * length;
|
|
|
-
|
|
|
- // 如果没有实际成本,则将预测成本作为显示成本
|
|
|
- if (!row.totalCost) {
|
|
|
- row.displayCost = row.predictedCost;
|
|
|
- }
|
|
|
+ // 计算预测总成本和预测水电费
|
|
|
+ row.predictedTotalCost = totalFixedCost + totalVariableCostPerUnit * length;
|
|
|
+ row.predictedWaterElectricity = waterElectricityFixedCost + waterElectricityVariableCostPerUnit * length;
|
|
|
|
|
|
// 自动执行成本预测
|
|
|
nextTick(() => {
|
|
|
@@ -279,6 +310,21 @@ function formatNumber(value) {
|
|
|
return num.toFixed(2);
|
|
|
}
|
|
|
|
|
|
+// 格式化P值,避免科学计数法
|
|
|
+function formatPValue(pValue) {
|
|
|
+ if (pValue === null || pValue === undefined || isNaN(pValue)) {
|
|
|
+ return 'N/A';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对于非常小的数值,使用toPrecision来避免科学计数法
|
|
|
+ if (pValue < 0.000001) {
|
|
|
+ return pValue.toPrecision(6);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对于一般的数值,保留6位小数
|
|
|
+ return pValue.toFixed(6);
|
|
|
+}
|
|
|
+
|
|
|
// 获取偏离值的样式类
|
|
|
function getDeviationClass(deviation) {
|
|
|
if (deviation === null || deviation === undefined || deviation === '') {
|
|
|
@@ -299,16 +345,16 @@ function getDeviationClass(deviation) {
|
|
|
}
|
|
|
|
|
|
// 成本性态分析函数 - 使用最小二乘法进行线性回归分析
|
|
|
-function performCostAnalysis(data) {
|
|
|
+function performCostAnalysis(data, property = 'totalCost') {
|
|
|
// 过滤掉无效数据
|
|
|
- const validData = data.filter(item =>
|
|
|
- item.length !== null &&
|
|
|
- item.totalCost !== null &&
|
|
|
- !isNaN(parseFloat(item.length)) &&
|
|
|
- !isNaN(parseFloat(item.totalCost))
|
|
|
+ const validData = data.filter(item =>
|
|
|
+ item.length !== null &&
|
|
|
+ item[property] !== null &&
|
|
|
+ !isNaN(parseFloat(item.length)) &&
|
|
|
+ !isNaN(parseFloat(item[property]))
|
|
|
).map(item => ({
|
|
|
x: parseFloat(item.length), // 产量
|
|
|
- y: parseFloat(item.totalCost) // 总成本
|
|
|
+ y: parseFloat(item[property]) // 成本(总成本或水电费)
|
|
|
}));
|
|
|
|
|
|
if (validData.length < 2) {
|
|
|
@@ -329,7 +375,7 @@ function performCostAnalysis(data) {
|
|
|
|
|
|
// 计算回归系数
|
|
|
const denominator = n * sumXX - sumX * sumX;
|
|
|
-
|
|
|
+
|
|
|
if (denominator === 0) {
|
|
|
return null; // 无法计算(分母为零)
|
|
|
}
|
|
|
@@ -341,7 +387,7 @@ function performCostAnalysis(data) {
|
|
|
// 计算相关系数
|
|
|
const numerator = n * sumXY - sumX * sumY;
|
|
|
const denominatorR = Math.sqrt((n * sumXX - sumX * sumX) * (n * sumYY - sumY * sumY));
|
|
|
-
|
|
|
+
|
|
|
const r = denominatorR !== 0 ? numerator / denominatorR : 0; // 相关系数
|
|
|
|
|
|
// 计算R方 (决定系数)
|
|
|
@@ -351,25 +397,25 @@ function performCostAnalysis(data) {
|
|
|
let ssTotal = 0; // 总平方和
|
|
|
let ssResidual = 0; // 残差平方和
|
|
|
let ssRegression = 0; // 回归平方和
|
|
|
-
|
|
|
+
|
|
|
const yMean = sumY / n; // y的均值
|
|
|
-
|
|
|
+
|
|
|
validData.forEach(point => {
|
|
|
const yPredicted = a + b * point.x; // 预测值
|
|
|
ssTotal += Math.pow(point.y - yMean, 2);
|
|
|
ssResidual += Math.pow(point.y - yPredicted, 2);
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
ssRegression = ssTotal - ssResidual;
|
|
|
-
|
|
|
+
|
|
|
// 计算标准误差
|
|
|
const standardError = Math.sqrt(ssResidual / (n - 2));
|
|
|
-
|
|
|
+
|
|
|
// 计算F统计量 (ANOVA F-test)
|
|
|
const msRegression = ssRegression / 1; // 回归均方 (自由度为1)
|
|
|
const msResidual = ssResidual / (n - 2); // 残差均方 (自由度为n-2)
|
|
|
const fStatistic = msRegression / msResidual;
|
|
|
-
|
|
|
+
|
|
|
// 计算 P 值 (使用近似计算)
|
|
|
const pValue = calculatePValue(fStatistic, 1, n - 2);
|
|
|
|
|
|
@@ -542,32 +588,35 @@ function generateFullYearData(data, year) {
|
|
|
|
|
|
// 执行成本预测
|
|
|
function performCostForecast() {
|
|
|
- if (!costAnalysisResult.value) {
|
|
|
+ if (!costAnalysisResult.value || !waterElectricityAnalysisResult.value) {
|
|
|
proxy.$modal.msgWarning("请先进行成本性态分析");
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- const { fixedCost, variableCostPerUnit } = costAnalysisResult.value;
|
|
|
-
|
|
|
- // 为每个数据项计算预测成本和实际偏离
|
|
|
+
|
|
|
+ const { fixedCost: totalFixedCost, variableCostPerUnit: totalVariableCostPerUnit } = costAnalysisResult.value;
|
|
|
+ const { fixedCost: waterElectricityFixedCost, variableCostPerUnit: waterElectricityVariableCostPerUnit } = waterElectricityAnalysisResult.value;
|
|
|
+
|
|
|
+ // 为每个数据项计算预测成本
|
|
|
costList.value = costList.value.map(item => {
|
|
|
// 如果有产量数据,则进行预测
|
|
|
if (item.length !== null && !isNaN(parseFloat(item.length))) {
|
|
|
- const predictedCost = fixedCost + variableCostPerUnit * parseFloat(item.length);
|
|
|
- const totalCost = item.totalCost !== null && !isNaN(parseFloat(item.totalCost)) ? parseFloat(item.totalCost) : null;
|
|
|
- const deviation = totalCost !== null ? totalCost - predictedCost : null;
|
|
|
-
|
|
|
+ const length = parseFloat(item.length);
|
|
|
+
|
|
|
+ // 计算预测总成本和预测水电费
|
|
|
+ const predictedTotalCost = totalFixedCost + totalVariableCostPerUnit * length;
|
|
|
+ const predictedWaterElectricity = waterElectricityFixedCost + waterElectricityVariableCostPerUnit * length;
|
|
|
+
|
|
|
return {
|
|
|
...item,
|
|
|
- predictedCost: predictedCost,
|
|
|
- deviation: deviation
|
|
|
+ predictedTotalCost: predictedTotalCost,
|
|
|
+ predictedWaterElectricity: predictedWaterElectricity
|
|
|
};
|
|
|
} else {
|
|
|
- // 如果没有产量数据,则预测和偏离都为空
|
|
|
+ // 如果没有产量数据,则预测值为空
|
|
|
return {
|
|
|
...item,
|
|
|
- predictedCost: null,
|
|
|
- deviation: null
|
|
|
+ predictedTotalCost: null,
|
|
|
+ predictedWaterElectricity: null
|
|
|
};
|
|
|
}
|
|
|
});
|
|
|
@@ -626,7 +675,7 @@ function getList() {
|
|
|
listCost(queryParam).then(response => {
|
|
|
// 生成完整的12个月数据
|
|
|
const fullYearData = generateFullYearData(response.rows, selectedQueryYear.value);
|
|
|
-
|
|
|
+
|
|
|
costList.value = fullYearData.map(item => ({
|
|
|
...item,
|
|
|
isEditing: true, // 查询出来的数据也默认处于编辑状态
|
|
|
@@ -642,13 +691,21 @@ function getList() {
|
|
|
});
|
|
|
|
|
|
// 执行成本性态分析
|
|
|
- costAnalysisResult.value = performCostAnalysis(costList.value.filter(item =>
|
|
|
- item.length !== null &&
|
|
|
+ costAnalysisResult.value = performCostAnalysis(costList.value.filter(item =>
|
|
|
+ item.length !== null &&
|
|
|
item.totalCost !== null &&
|
|
|
- !isNaN(parseFloat(item.length)) &&
|
|
|
+ !isNaN(parseFloat(item.length)) &&
|
|
|
!isNaN(parseFloat(item.totalCost))
|
|
|
));
|
|
|
|
|
|
+ // 执行水电费分析
|
|
|
+ waterElectricityAnalysisResult.value = performCostAnalysis(costList.value.filter(item =>
|
|
|
+ item.length !== null &&
|
|
|
+ item.waterElectricity !== null &&
|
|
|
+ !isNaN(parseFloat(item.length)) &&
|
|
|
+ !isNaN(parseFloat(item.waterElectricity))
|
|
|
+ ), 'waterElectricity');
|
|
|
+
|
|
|
// 执行成本预测
|
|
|
if (costAnalysisResult.value) {
|
|
|
performCostForecast();
|
|
|
@@ -685,11 +742,11 @@ function handleQuery() {
|
|
|
|
|
|
// 成本预测处理
|
|
|
function handlePredict() {
|
|
|
- if (!costAnalysisResult.value) {
|
|
|
+ if (!costAnalysisResult.value || !waterElectricityAnalysisResult.value) {
|
|
|
proxy.$modal.msgWarning("没有足够的数据进行成本预测,请先查询数据");
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
performCostForecast();
|
|
|
proxy.$modal.msgSuccess("成本预测完成");
|
|
|
}
|
|
|
@@ -733,38 +790,103 @@ onMounted(() => {
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
-.analysis-item {
|
|
|
- background: #f5f7fa;
|
|
|
- border-radius: 4px;
|
|
|
- padding: 15px;
|
|
|
+.analysis-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+
|
|
|
+.analysis-column {
|
|
|
+ flex: 1;
|
|
|
+ padding: 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.divider {
|
|
|
+ width: 1px;
|
|
|
+ background-color: #ebeef5;
|
|
|
+ margin: 0 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 15px;
|
|
|
text-align: center;
|
|
|
- height: 100px;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+}
|
|
|
+
|
|
|
+.metrics-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
+ gap: 15px;
|
|
|
+ margin-top: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-card {
|
|
|
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 15px 10px;
|
|
|
+ text-align: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
|
|
+ border: 1px solid #e9ecef;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: center;
|
|
|
- transition: all 0.3s;
|
|
|
}
|
|
|
|
|
|
-.analysis-item:hover {
|
|
|
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+.metric-card:hover {
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
transform: translateY(-2px);
|
|
|
+ border-color: #adb5bd;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-card.primary {
|
|
|
+ background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
|
|
+ border-color: #90caf9;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-card.secondary {
|
|
|
+ background: linear-gradient(135deg, #f3e5f5 0%, #e1bee7 100%);
|
|
|
+ border-color: #ce93d8;
|
|
|
}
|
|
|
|
|
|
-.analysis-label {
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
+.metric-card.info {
|
|
|
+ background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%);
|
|
|
+ border-color: #a5d6a7;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-card.warning {
|
|
|
+ background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);
|
|
|
+ border-color: #ffcc80;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #495057;
|
|
|
margin-bottom: 8px;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
|
|
|
-.analysis-value {
|
|
|
- font-size: 18px;
|
|
|
+.metric-value {
|
|
|
+ font-size: 16px;
|
|
|
font-weight: bold;
|
|
|
- color: #333;
|
|
|
+ color: #212529;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.unit {
|
|
|
- font-size: 14px;
|
|
|
- color: #999;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #6c757d;
|
|
|
+}
|
|
|
+
|
|
|
+.p-value {
|
|
|
+ font-size: 11px;
|
|
|
+ color: #666;
|
|
|
+ margin-top: 3px;
|
|
|
}
|
|
|
|
|
|
.model-display {
|
|
|
@@ -810,9 +932,25 @@ onMounted(() => {
|
|
|
font-weight: bold;
|
|
|
}
|
|
|
|
|
|
-.p-value {
|
|
|
- font-size: 12px;
|
|
|
- color: #666;
|
|
|
- margin-top: 2px;
|
|
|
+@media (max-width: 1200px) {
|
|
|
+ .metrics-grid {
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .analysis-container {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .divider {
|
|
|
+ width: 100%;
|
|
|
+ height: 1px;
|
|
|
+ margin: 20px 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .metrics-grid {
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|