迁移鹰眼模块
This commit is contained in:
36
docs/功能测试-鹰眼.md
Normal file
36
docs/功能测试-鹰眼.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 鹰眼功能测试任务列表
|
||||
|
||||
## 基础入口
|
||||
|
||||
- [ ] 进入 `数据中台 / 相关性分析 / 鹰眼`,页面正常加载,无控制台报错。
|
||||
- [ ] 左侧分析条件区域显示生产批次、工序、NG 码三个筛选项和分析按钮。
|
||||
- [ ] 页面右侧显示分析详情区域,未查询时为空状态。
|
||||
|
||||
## 查询条件
|
||||
|
||||
- [ ] 选择生产批次后,工序下拉框自动加载该批次下的不良工序列。
|
||||
- [ ] 选择工序后,NG 码下拉框自动切换为该工序对应的不良代码。
|
||||
- [ ] 点击重置后,批次、工序、NG 码、相关性结果和图表全部清空。
|
||||
|
||||
## 相关性分析
|
||||
|
||||
- [ ] 未选择生产批次时点击分析,系统提示需要选择批次。
|
||||
- [ ] 未选择工序时点击分析,系统提示需要选择工序。
|
||||
- [ ] 选择有效批次、工序和 NG 码后点击分析,Pearson 相关性散点图正常渲染。
|
||||
- [ ] PCC 表格显示工序参数、样本量、相关系数、P 值和相关性判断。
|
||||
- [ ] 卡方表格显示工序参数、样本量、卡方值、P 值和相关性判断。
|
||||
- [ ] 有不能参与分析的数据列时,顶部折叠区域展示对应参数名称。
|
||||
|
||||
## 图表与交互
|
||||
|
||||
- [ ] 散点图鼠标悬停时显示参数名称、相关系数和 P 值。
|
||||
- [ ] P 值大于 0.05 的记录以蓝色相关状态显示。
|
||||
- [ ] P 值小于或等于 0.05 的记录以红色不相关状态显示。
|
||||
- [ ] 已选择 NG 码时点击表格中的相关性文字,弹出分析报告弹窗。
|
||||
- [ ] 分析报告弹窗内按分类展示折线分布图,关闭后再次打开能正常刷新。
|
||||
|
||||
## 兼容性
|
||||
|
||||
- [ ] 页面在 1366px 宽度下表格和图表不重叠。
|
||||
- [ ] 浏览器窗口缩放后图表能自动适配。
|
||||
- [ ] 切换不同批次再次分析,旧批次结果不会残留。
|
||||
@@ -3,8 +3,8 @@
|
||||
> 根据 `后台Webman界面截图对照表.md` 生成。状态以当前 V2 项目中已落地的页面目录为准。
|
||||
|
||||
- 总功能数:79
|
||||
- 已迁移:34
|
||||
- 未迁移:45
|
||||
- 已迁移:35
|
||||
- 未迁移:44
|
||||
|
||||
| 状态 | 一级模块 | 二级模块 | 三级模块 | 功能说明 | V2 目标路径 |
|
||||
|:---:|---|---|---|---|---|
|
||||
@@ -86,7 +86,7 @@
|
||||
| ✅ | 数据中台 (Data Platform) | 基础追溯 (Traceability) | 电池追溯 (Battery Traceability) | 电池追溯 | `src/views/data-platform/traceability/battery/` |
|
||||
| ✅ | 数据中台 (Data Platform) | 生产报表 (Production Reports) | 设备履历报表 (Equipment History Report) | 设备履历报表 | `src/views/data-platform/production-reports/equipment-history/` |
|
||||
| ✅ | 数据中台 (Data Platform) | 生产报表 (Production Reports) | 电池详情报表 (Battery Detail Report) | 电池详情报表 | `src/views/data-platform/production-reports/battery-detail/` |
|
||||
| ⬜ | 数据中台 (Data Platform) | 相关性分析 (Correlation Analysis) | 鹰眼 (Hawkeye) | | 待确认 |
|
||||
| ✅ | 数据中台 (Data Platform) | 相关性分析 (Correlation Analysis) | 鹰眼 (Hawkeye) | 鹰眼 | `src/views/data-platform/correlation-analysis/hawkeye/` |
|
||||
|
||||
## 状态说明
|
||||
|
||||
|
||||
43
src/api/data-platform/correlation-analysis/hawkeye.js
Normal file
43
src/api/data-platform/correlation-analysis/hawkeye.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { request } from '@/api/_service'
|
||||
|
||||
const BASE = 'data_middleground/eagle_eyes/'
|
||||
|
||||
function apiParams (method, data = {}) {
|
||||
return {
|
||||
method,
|
||||
platform: 'admin',
|
||||
...data
|
||||
}
|
||||
}
|
||||
|
||||
export function getNGWorkstationBatch (data) {
|
||||
return request({
|
||||
url: BASE + 'getNGWorkstationBatch',
|
||||
method: 'get',
|
||||
params: apiParams('data_middleground_eagle_eyes_getNGWorkstationBatch', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function getBatchResultParam (data) {
|
||||
return request({
|
||||
url: BASE + 'getBatchResultParam',
|
||||
method: 'get',
|
||||
params: apiParams('data_middleground_eagle_eyes_getBatchResultParam', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function analyzeHawkeyeCorrelation (data) {
|
||||
return request({
|
||||
url: BASE + 'saveCsvFile',
|
||||
method: 'get',
|
||||
params: apiParams('data_middleground_eagle_eyes_saveCsvFile', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function getDataClassificationByNGCode (data) {
|
||||
return request({
|
||||
url: BASE + 'getDataClassificationByNGCode',
|
||||
method: 'get',
|
||||
params: apiParams('data_middleground_eagle_eyes_get_data_classification_by_ng_code', data)
|
||||
})
|
||||
}
|
||||
@@ -1378,6 +1378,42 @@
|
||||
"prompt": "Prompt",
|
||||
"create_download_task_success": "Download task created successfully"
|
||||
}
|
||||
},
|
||||
"correlation_analysis": {
|
||||
"hawkeye": {
|
||||
"analysis_condition": "Analysis Conditions",
|
||||
"analyze": "Analyze",
|
||||
"reset": "Reset",
|
||||
"production_batch": "Production Batch",
|
||||
"select_production_batch": "Select production batch",
|
||||
"process": "Process",
|
||||
"select_ng_column": "Select NG column",
|
||||
"ng_code": "NG Code",
|
||||
"select_ng_code": "Select NG code",
|
||||
"analysis_detail": "Analysis Detail",
|
||||
"correlated": "Correlated",
|
||||
"not_correlated": "Not Correlated",
|
||||
"correlated_short": "Related",
|
||||
"not_correlated_short": "Not Related",
|
||||
"no_analysis_data_hint": "Columns skipped because values are all identical or all different",
|
||||
"process_param": "Process Parameter",
|
||||
"sample_size": "Sample Size",
|
||||
"correlation_coeff": "Correlation Coeff.",
|
||||
"chi_square_value": "Chi-square Value",
|
||||
"p_value": "P Value",
|
||||
"correlation": "Correlation",
|
||||
"p_value_hint": "P value greater than 0.05 is considered correlated",
|
||||
"p_value_hint2": "P value greater than 0.05 is considered correlated",
|
||||
"scientific_notation_hint": "Value may be shown in scientific notation",
|
||||
"tooltip_dependent_var": "Dependent Variable",
|
||||
"tooltip_corr_coeff": "Correlation Coeff.",
|
||||
"tooltip_p_value": "P Value",
|
||||
"analysis_report": "Analysis Report",
|
||||
"total": "Total",
|
||||
"no_data": "No analysis data",
|
||||
"please_select_batch": "Select production batch",
|
||||
"please_select_process": "Select process"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1378,6 +1378,42 @@
|
||||
"prompt": "提示",
|
||||
"create_download_task_success": "创建下载任务成功"
|
||||
}
|
||||
},
|
||||
"correlation_analysis": {
|
||||
"hawkeye": {
|
||||
"analysis_condition": "分析条件",
|
||||
"analyze": "分析",
|
||||
"reset": "重置",
|
||||
"production_batch": "生产批次",
|
||||
"select_production_batch": "请选择生产批次",
|
||||
"process": "工序",
|
||||
"select_ng_column": "请选择NG列",
|
||||
"ng_code": "NG码",
|
||||
"select_ng_code": "请选择NG码",
|
||||
"analysis_detail": "分析详情",
|
||||
"correlated": "相关",
|
||||
"not_correlated": "不相关",
|
||||
"correlated_short": "相关",
|
||||
"not_correlated_short": "不相关",
|
||||
"no_analysis_data_hint": "因列中数据完全相同或完全不相同,而不进行分析的数据列",
|
||||
"process_param": "工序参数",
|
||||
"sample_size": "样本量",
|
||||
"correlation_coeff": "相关系数",
|
||||
"chi_square_value": "卡方值",
|
||||
"p_value": "P值",
|
||||
"correlation": "相关性",
|
||||
"p_value_hint": "P值大于0.05时判定为相关",
|
||||
"p_value_hint2": "P值大于0.05时判定为相关",
|
||||
"scientific_notation_hint": "数值可能以科学计数法显示",
|
||||
"tooltip_dependent_var": "因变量",
|
||||
"tooltip_corr_coeff": "相关系数",
|
||||
"tooltip_p_value": "P值",
|
||||
"analysis_report": "分析报告",
|
||||
"total": "总数",
|
||||
"no_data": "暂无分析数据",
|
||||
"please_select_batch": "请选择生产批次",
|
||||
"please_select_process": "请选择工序"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -55,6 +55,12 @@ export default {
|
||||
name: `${pre}report-battery-detail`,
|
||||
meta: { ...meta, cache: true, title: '电池详情报表' },
|
||||
component: _import('data-platform/production-reports/battery-detail')
|
||||
},
|
||||
{
|
||||
path: 'pancake/eagle_eyes',
|
||||
name: `${pre}formation-data-record`,
|
||||
meta: { ...meta, cache: true, title: '鹰眼' },
|
||||
component: _import('data-platform/correlation-analysis/hawkeye')
|
||||
}
|
||||
])('data_middleground-')
|
||||
}
|
||||
|
||||
403
src/views/data-platform/correlation-analysis/hawkeye/index.vue
Normal file
403
src/views/data-platform/correlation-analysis/hawkeye/index.vue
Normal file
@@ -0,0 +1,403 @@
|
||||
<template>
|
||||
<d2-container class="hawkeye-page">
|
||||
<div class="hawkeye-layout">
|
||||
<aside class="condition-panel">
|
||||
<div class="panel-header">
|
||||
<span>{{ $t(key('analysis_condition')) }}</span>
|
||||
<el-button type="primary" size="mini" icon="el-icon-data-analysis" :loading="loading" @click="onAnalyze">{{ $t(key('analyze')) }}</el-button>
|
||||
</div>
|
||||
<el-form ref="searchForm" :model="search" label-position="top" size="mini" class="condition-form">
|
||||
<el-form-item :label="$t(key('production_batch'))" prop="table">
|
||||
<el-select v-model="search.table" filterable clearable :placeholder="$t(key('select_production_batch'))" @change="onBatchChange">
|
||||
<el-option v-for="item in batchOptions" :key="item.id || item.batch" :label="item.batch" :value="item.batch" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('process'))" prop="ng_colnum">
|
||||
<el-select v-model="search.ng_colnum" filterable clearable :placeholder="$t(key('select_ng_column'))" value-key="process_code" @change="onProcessChange">
|
||||
<el-option v-for="(item, index) in processOptions" :key="index" :label="formatProcessOption(item)" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('ng_code'))" prop="ng_code">
|
||||
<el-select v-model="search.ng_code" filterable clearable :placeholder="$t(key('select_ng_code'))">
|
||||
<el-option v-for="(item, index) in ngCodeOptions" :key="index" :label="item.explain || item.name || item.code || item" :value="item.explain || item.code || item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-button icon="el-icon-refresh" size="mini" :disabled="loading" @click="onReset">{{ $t(key('reset')) }}</el-button>
|
||||
</el-form>
|
||||
</aside>
|
||||
|
||||
<main class="result-panel">
|
||||
<div class="panel-header">
|
||||
<span>{{ $t(key('analysis_detail')) }}</span>
|
||||
<div class="legend">
|
||||
<span><i class="legend-dot is-related" />{{ $t(key('correlated')) }}</span>
|
||||
<span><i class="legend-dot is-unrelated" />{{ $t(key('not_correlated')) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-collapse v-if="noCorrColumns.length" class="excluded-panel">
|
||||
<el-collapse-item :title="$t(key('no_analysis_data_hint'))" name="excluded">
|
||||
<el-tag v-for="item in noCorrColumns" :key="item" size="mini" type="warning">{{ getParamName(item) }}</el-tag>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<div v-loading="loading" class="analysis-content">
|
||||
<el-empty v-if="!hasAnalysis" :description="$t(key('no_data'))" :image-size="90" />
|
||||
<template v-else>
|
||||
<section class="chart-row">
|
||||
<div ref="pccChart" class="chart-box" />
|
||||
<el-table :data="tableData.pcc" size="mini" border height="100%">
|
||||
<el-table-column prop="process" :label="$t(key('process_param'))" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="sample_size" :label="$t(key('sample_size'))" width="90" />
|
||||
<el-table-column prop="corr_data" :label="$t(key('correlation_coeff'))" width="120" />
|
||||
<el-table-column prop="pv" :label="$t(key('p_value'))" width="110" />
|
||||
<el-table-column :label="$t(key('correlation'))" width="110">
|
||||
<template slot="header">
|
||||
{{ $t(key('correlation')) }}
|
||||
<el-tooltip :content="$t(key('p_value_hint'))" placement="top">
|
||||
<i class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" :class="relationClass(scope.row.pv)" @click="showDistribution(scope.row)">{{ relationText(scope.row.pv) }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section v-if="tableData.chi.length" class="table-section">
|
||||
<el-table :data="tableData.chi" size="mini" border height="100%">
|
||||
<el-table-column prop="process" :label="$t(key('process_param'))" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="sample_size" :label="$t(key('sample_size'))" width="120" />
|
||||
<el-table-column prop="corr_data" :label="$t(key('chi_square_value'))" width="150" />
|
||||
<el-table-column prop="pv" width="140">
|
||||
<template slot="header">
|
||||
{{ $t(key('p_value')) }}
|
||||
<el-tooltip :content="$t(key('scientific_notation_hint'))" placement="top">
|
||||
<i class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="120">
|
||||
<template slot="header">
|
||||
{{ $t(key('correlation')) }}
|
||||
<el-tooltip :content="$t(key('p_value_hint2'))" placement="top">
|
||||
<i class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" :class="relationClass(scope.row.pv)" @click="showDistribution(scope.row)">{{ relationText(scope.row.pv) }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<el-dialog :title="$t(key('analysis_report'))" :visible.sync="distributionDialog.visible" width="80%" @closed="closeDistribution">
|
||||
<div ref="distributionChart" class="distribution-chart" />
|
||||
</el-dialog>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { i18nMixin } from '@/composables/useI18n'
|
||||
import { getBatchAll } from '@/api/planning-production/batch-list'
|
||||
import { analyzeHawkeyeCorrelation, getBatchResultParam, getDataClassificationByNGCode, getNGWorkstationBatch } from '@/api/data-platform/correlation-analysis/hawkeye'
|
||||
|
||||
export default {
|
||||
name: 'data-platform-correlation-analysis-hawkeye',
|
||||
mixins: [i18nMixin('page.data_platform.correlation_analysis.hawkeye')],
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
search: { table: '', ng_colnum: '', ng_code: undefined },
|
||||
batchOptions: [],
|
||||
processOptions: [],
|
||||
ngCodeOptions: [],
|
||||
processParamNames: {},
|
||||
noCorrColumns: [],
|
||||
tableData: { pcc: [], chi: [] },
|
||||
pccChart: null,
|
||||
distributionChart: null,
|
||||
distributionDialog: { visible: false, data: {} }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasAnalysis () {
|
||||
return this.tableData.pcc.length > 0 || this.tableData.chi.length > 0
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.loadBatchOptions()
|
||||
window.addEventListener('resize', this.resizeCharts)
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('resize', this.resizeCharts)
|
||||
if (this.pccChart) this.pccChart.dispose()
|
||||
if (this.distributionChart) this.distributionChart.dispose()
|
||||
},
|
||||
methods: {
|
||||
responseData (res) { return res && res.data !== undefined ? res.data : res },
|
||||
async loadBatchOptions () {
|
||||
const res = await getBatchAll({})
|
||||
this.batchOptions = this.responseData(res) || []
|
||||
},
|
||||
async onBatchChange (batch) {
|
||||
this.search.ng_colnum = ''
|
||||
this.search.ng_code = undefined
|
||||
this.processOptions = []
|
||||
this.ngCodeOptions = []
|
||||
this.processParamNames = {}
|
||||
if (!batch) return
|
||||
const [processRes, paramRes] = await Promise.all([
|
||||
getNGWorkstationBatch({ batch }),
|
||||
getBatchResultParam({ batch })
|
||||
])
|
||||
this.processOptions = this.responseData(processRes) || []
|
||||
const paramData = this.responseData(paramRes) || {}
|
||||
this.processParamNames = paramData.result_param_names || {}
|
||||
},
|
||||
onProcessChange (value) {
|
||||
this.search.ng_code = undefined
|
||||
this.ngCodeOptions = Array.isArray(value) ? value : []
|
||||
},
|
||||
formatProcessOption (item) {
|
||||
const first = Array.isArray(item) ? item[0] : item
|
||||
return (first && (first.name || first.process_name || first.process_code)) || ''
|
||||
},
|
||||
buildAnalyzeParams () {
|
||||
const ngColumn = Array.isArray(this.search.ng_colnum) ? this.search.ng_colnum[0] : this.search.ng_colnum
|
||||
return {
|
||||
...this.search,
|
||||
corr_code: [],
|
||||
ng_colnum: ngColumn && ngColumn.process_code ? ngColumn.process_code : ngColumn
|
||||
}
|
||||
},
|
||||
async onAnalyze () {
|
||||
if (!this.search.table) { this.$message.warning(this.$t(this.key('please_select_batch'))); return }
|
||||
if (!this.search.ng_colnum) { this.$message.warning(this.$t(this.key('please_select_process'))); return }
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await analyzeHawkeyeCorrelation(this.buildAnalyzeParams())
|
||||
this.applyAnalysisData(this.responseData(res) || {})
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
applyAnalysisData (data) {
|
||||
const x2 = Array.isArray(data.X2) ? data.X2 : []
|
||||
const pcc = Array.isArray(data.PCC) ? data.PCC : []
|
||||
this.noCorrColumns = Array.isArray(data.no_corr_colnum) ? data.no_corr_colnum : []
|
||||
this.tableData.pcc = pcc.map(item => ({
|
||||
process: this.getParamName(item.independent_variable_name),
|
||||
dependent_variable: item.independent_variable_name,
|
||||
sample_size: this.formatNumber(item.value && item.value[3]),
|
||||
corr_data: this.formatNumber(item.value && item.value[0]),
|
||||
pv: item.value && item.value[2]
|
||||
}))
|
||||
this.tableData.chi = x2.map(item => ({
|
||||
process: this.getParamName(item.independent_variable_name),
|
||||
dependent_variable: item.independent_variable_name,
|
||||
sample_size: this.formatNumber(item.value && item.value[0]),
|
||||
corr_data: this.formatNumber(item.value && item.value[1]),
|
||||
pv: item.value && item.value[2]
|
||||
}))
|
||||
this.$nextTick(() => this.renderPccChart(pcc))
|
||||
},
|
||||
renderPccChart (pcc) {
|
||||
const chartDom = this.$refs.pccChart
|
||||
if (!chartDom) return
|
||||
if (!this.pccChart) this.pccChart = echarts.init(chartDom)
|
||||
const points = pcc.map(item => ({
|
||||
name: this.getParamName(item.independent_variable_name),
|
||||
value: [Number(item.value && item.value[0]) || 0, Number(item.value && item.value[2]) || 0],
|
||||
sampleSize: item.value && item.value[3]
|
||||
}))
|
||||
this.pccChart.setOption({
|
||||
title: { text: this.$t(this.key('tooltip_corr_coeff')), left: 'center', textStyle: { fontSize: 14 } },
|
||||
grid: { left: 52, right: 28, top: 58, bottom: 42 },
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: params => {
|
||||
const item = params.data
|
||||
return `${this.$t(this.key('tooltip_dependent_var'))}: ${item.name}<br>${this.$t(this.key('tooltip_corr_coeff'))}: ${this.formatNumber(item.value[0])}<br>${this.$t(this.key('tooltip_p_value'))}: ${this.formatNumber(item.value[1])}`
|
||||
}
|
||||
},
|
||||
xAxis: { type: 'value', name: this.$t(this.key('tooltip_corr_coeff')) },
|
||||
yAxis: { type: 'value', name: this.$t(this.key('tooltip_p_value')) },
|
||||
series: [{
|
||||
type: 'scatter',
|
||||
data: points,
|
||||
symbolSize: 9,
|
||||
itemStyle: { color: params => (Number(params.data.value[1]) > 0.05 ? '#409EFF' : '#F56C6C') }
|
||||
}]
|
||||
}, true)
|
||||
this.pccChart.resize()
|
||||
},
|
||||
async showDistribution (row) {
|
||||
if (!this.search.ng_code || !row.dependent_variable) return
|
||||
const res = await getDataClassificationByNGCode({ ng_code: this.search.ng_code, dependent_variable: row.dependent_variable })
|
||||
this.distributionDialog.data = this.responseData(res) || {}
|
||||
this.distributionDialog.visible = true
|
||||
this.$nextTick(this.renderDistributionChart)
|
||||
},
|
||||
renderDistributionChart () {
|
||||
const chartDom = this.$refs.distributionChart
|
||||
if (!chartDom) return
|
||||
if (!this.distributionChart) this.distributionChart = echarts.init(chartDom)
|
||||
const raw = Array.isArray(this.distributionDialog.data.col3) ? this.distributionDialog.data.col3 : []
|
||||
const grouped = this.groupDistribution(raw)
|
||||
const xAxis = grouped.values
|
||||
this.distributionChart.setOption({
|
||||
legend: { data: grouped.classNames, left: 10 },
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 48, right: 28, top: 48, bottom: 42 },
|
||||
xAxis: { type: 'category', data: xAxis },
|
||||
yAxis: { type: 'value', name: this.$t(this.key('total')) },
|
||||
series: grouped.classNames.map(name => ({ name, type: 'line', smooth: true, symbol: 'none', data: xAxis.map(value => grouped.map[name][value] || 0) }))
|
||||
}, true)
|
||||
this.distributionChart.resize()
|
||||
},
|
||||
groupDistribution (raw) {
|
||||
const classNames = Array.from(new Set(raw.map(item => item.classname))).filter(Boolean)
|
||||
const values = Array.from(new Set(raw.map(item => String(item.value)))).sort((a, b) => Number(a) - Number(b))
|
||||
const map = {}
|
||||
classNames.forEach(name => { map[name] = {}; values.forEach(value => { map[name][value] = 0 }) })
|
||||
raw.forEach(item => {
|
||||
const className = item.classname
|
||||
const value = String(item.value)
|
||||
if (map[className] && Object.prototype.hasOwnProperty.call(map[className], value)) map[className][value] += 1
|
||||
})
|
||||
return { classNames, values, map }
|
||||
},
|
||||
getParamName (code) {
|
||||
return this.processParamNames[code] || code || ''
|
||||
},
|
||||
relationClass (pv) {
|
||||
return Number(pv) > 0.05 ? 'relation-related' : 'relation-unrelated'
|
||||
},
|
||||
relationText (pv) {
|
||||
return Number(pv) > 0.05 ? this.$t(this.key('correlated_short')) : this.$t(this.key('not_correlated_short'))
|
||||
},
|
||||
formatNumber (value) {
|
||||
if (value === undefined || value === null || value === '') return ''
|
||||
const number = Number(value)
|
||||
if (!Number.isFinite(number)) return value
|
||||
return Math.abs(number) < 0.001 && number !== 0 ? number.toExponential(2) : Number(number.toFixed(4))
|
||||
},
|
||||
resizeCharts () {
|
||||
if (this.pccChart) this.pccChart.resize()
|
||||
if (this.distributionChart) this.distributionChart.resize()
|
||||
},
|
||||
closeDistribution () {
|
||||
this.distributionDialog.data = {}
|
||||
},
|
||||
onReset () {
|
||||
this.search = { table: '', ng_colnum: '', ng_code: undefined }
|
||||
this.processOptions = []
|
||||
this.ngCodeOptions = []
|
||||
this.noCorrColumns = []
|
||||
this.tableData = { pcc: [], chi: [] }
|
||||
if (this.pccChart) this.pccChart.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hawkeye-page {
|
||||
::v-deep .d2-container-full__body { padding: 0; }
|
||||
}
|
||||
.hawkeye-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 300px minmax(0, 1fr);
|
||||
height: calc(100vh - 132px);
|
||||
min-height: 640px;
|
||||
background: #fff;
|
||||
}
|
||||
.condition-panel {
|
||||
border-right: 1px solid #e5e9f2;
|
||||
overflow: auto;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 44px;
|
||||
padding: 8px 14px;
|
||||
background: #f5f7fa;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
}
|
||||
.condition-form {
|
||||
padding: 14px;
|
||||
::v-deep .el-select { width: 100%; }
|
||||
}
|
||||
.result-panel {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.legend {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.legend-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.is-related { background: #409eff; }
|
||||
.is-unrelated { background: #f56c6c; }
|
||||
.excluded-panel {
|
||||
padding: 0 12px;
|
||||
::v-deep .el-tag { margin: 0 6px 6px 0; }
|
||||
}
|
||||
.analysis-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 14px;
|
||||
}
|
||||
.chart-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(360px, 1fr) minmax(420px, 46%);
|
||||
gap: 14px;
|
||||
height: 360px;
|
||||
min-width: 860px;
|
||||
}
|
||||
.chart-box {
|
||||
height: 100%;
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
.table-section {
|
||||
height: 300px;
|
||||
min-width: 860px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
.relation-related { color: #409eff; }
|
||||
.relation-unrelated { color: #f56c6c; }
|
||||
.distribution-chart {
|
||||
height: 560px;
|
||||
width: 100%;
|
||||
}
|
||||
@media (max-width: 1100px) {
|
||||
.hawkeye-layout {
|
||||
grid-template-columns: 1fr;
|
||||
height: auto;
|
||||
}
|
||||
.condition-panel {
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #e5e9f2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user