AnalysisSystemForRadionucli.../src/views/spectrumAnalysis/gamma-analysis.vue

2195 lines
66 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="gamma-analysis">
<a-spin :spinning="isLoading">
<!-- 二级交互栏 -->
<div class="spectrum-analysis-sub-operators">
<pop-over-with-icon placement="bottomLeft">
Detailed-Information
<detailed-infomation slot="content" :data="detailedInfomation" />
</pop-over-with-icon>
<pop-over-with-icon>
Graph Assistance
<graph-assistance
slot="content"
v-model="graphAssistance"
@change="handleGraphAssistanceChange"
@reset="handleResetChart"
/>
</pop-over-with-icon>
<pop-over-with-icon v-model="subOperatorsState.nuclideLibraryVisible">
Nuclide Library
<a-spin slot="content" :spinning="isLoadingNuclide">
<nuclide-library :list="nuclideLibraryList" @dblclick="handleNuclideDblClick" />
</a-spin>
</pop-over-with-icon>
<div class="peak-info">
<button-with-switch-icon @change="handlePeakInfoChange" @click="handleTogglePeak"></button-with-switch-icon>
</div>
<pop-over-with-icon placement="right" v-model="subOperatorsState.qcFlagsVisible">
QC Flags
<qc-flags slot="content" :data="qcFlags" />
</pop-over-with-icon>
</div>
<!-- 二级交互栏结束 -->
<!-- 主体部分 -->
<div class="gamma-analysis-main">
<div class="gamma-analysis-chart">
<CustomChart
ref="chartRef"
:option="option"
:opts="opts"
@zr:click="handleChartClick"
@zr:dblclick="handleTogglePeak"
@zr:mousedown="handleMouseDown"
@zr:mouseup="handleMouseUp"
@brushEnd="handleBrushEnd"
style="height: 100%"
/>
<!-- 右上角缩略图 -->
<div class="gamma-analysis-thumbnail">
<CustomChart
ref="thumbnailChartRef"
:option="thumbnailOption"
@zr:click="handleThumbnailChartClick"
style="height: 100%"
/>
</div>
<!-- 缩略图结束 -->
<!-- 自定义tooltip用于展示Peak Infomation -->
<div
v-if="peakInfomationTooltip.visible"
class="peak-infomation-tooltip"
:style="{
top: peakInfomationTooltip.top + 'px',
left: peakInfomationTooltip.left + 'px',
}"
>
<div class="peak-infomation-tooltip-content" v-html="peakInfomationTooltip.content"></div>
</div>
<!-- tooltip结束 -->
</div>
</div>
<!-- 主体部分结束 -->
</a-spin>
<nuclide-review-modal
v-model="nuclideReview.visible"
:sampleId="sample.sampleId"
:channel="currChannel"
:nuclide="nuclideReview.nuclide"
:page="`gamma-analysis`"
/>
<compare-file-list-modal v-model="compareFileListModalVisible" @fileSelect="handleFileSelect" />
<!-- Strip 弹窗开始 -->
<strip-modal ref="stripModal" />
<!-- Strip 弹窗结束 -->
<!-- ReProcessing 弹窗开始 -->
<re-processing-modal
v-if="abc"
v-model="reprocessingModalVisible"
:bAnalyed="bAnalyed"
:currStep="currStep"
:checkBoxFlag="checkBox_updateCal"
:newCheckBoxFlag="newCheckBox_updateCal"
@closeModal="handleCloseModal"
/>
<!-- ReProcessing 弹窗结束 -->
</div>
</template>
<script>
import CustomChart from '@/components/CustomChart/index.vue'
import PopOverWithIcon from './components/SubOperators/PopOverWithIcon.vue'
import DetailedInfomation from './components/SubOperators/DetailedInfomation.vue'
import QcFlags from './components/SubOperators/QcFlags.vue'
import GraphAssistance from './components/SubOperators/GraphAssistance/GraphAssistance.vue'
import NuclideLibrary from './components/SubOperators/NuclideLibrary.vue'
import ButtonWithSwitchIcon from './components/SubOperators/ButtonWithSwitchIcon.vue'
import { getAction, postAction } from '@/api/manage'
import Response from './response.json'
import {
buildLineSeries,
findSeriesByName,
getAxisMax,
getXAxisAndYAxisByPosition,
rangeNumber,
} from '@/utils/chartHelper'
import { cloneDeep } from 'lodash'
import axios from 'axios'
import NuclideReviewModal from './components/Modals/AnalyzeInteractiveToolModal/components/NuclideReviewModal.vue'
import CompareFileListModal from './components/Modals/CompareFileListModal.vue'
import ReProcessingModal from './components/Modals/ReProcessingModal/index.vue'
import { GammaOptions, graphAssistance } from './settings'
import store from '@/store/'
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import StripModal from './components/Modals/StripModal.vue'
import { FilePicker } from '@/utils/FilePicker'
import { readFile, zipFile } from '@/utils/file'
import { findNearPeak } from '@/utils/sampleHelper'
import { add, subtract } from 'xe-utils/methods'
import { PHDParser, isSample, getSampleTypeIdentify } from '@/utils/phdHelper'
export default {
props: {
sample: {
type: Object,
},
updateFlag: {
type: String,
},
currSampleDet: {
type: Array,
},
},
components: {
CustomChart,
PopOverWithIcon,
DetailedInfomation,
QcFlags,
GraphAssistance,
NuclideLibrary,
ButtonWithSwitchIcon,
NuclideReviewModal,
CompareFileListModal,
ReProcessingModal,
StripModal,
},
data() {
return {
abc: false,
isLoading: false,
isLoadingNuclide: false,
option: cloneDeep(GammaOptions.option),
opts: {
notMerge: false,
},
thumbnailOption: cloneDeep(GammaOptions.thumbnailOption),
detailedInfomation: [],
qcFlags: [],
graphAssistance: cloneDeep(graphAssistance),
// 子菜单状态
subOperatorsState: {
nuclideLibraryVisible: false,
qcFlagsVisible: false,
},
channelData: {
peakGroup: [],
spectrumLine: null,
baseLine: null,
lcLine: null,
scacLine: null,
all: null,
baseLineCP: [],
compareLine: null,
stripSumOrCutLine: null,
stripReferenceLine: null,
},
energyData: {
peakGroup: [],
spectrumLine: null,
baseLine: null,
lcLine: null,
scacLine: null,
all: null,
baseLineCP: [],
compareLine: null,
stripSumOrCutLine: null,
stripReferenceLine: null,
},
peakList: [], // Peak 列表(非点位)
baseCtrls: {}, // BaseCtrls
nuclideLibraryList: [], // 当前鼠标点击选中的channel
peakInfomationTooltip: {
// Peak Infomation的位置
visible: false,
content: '',
top: 0,
left: 0,
},
nuclideReview: {
visible: false,
nuclide: '',
},
currChannel: -1,
compareFileListModalVisible: false, // Compare 弹窗
isStrip: false,
reprocessingModalVisible: false, // 重新分析弹窗
isProcessing: false, // 正在处理
websock: null,
lockReconnect: false,
bAnalyed: false, //是否重新分析
checkBox_updateCal: false, //update复选框状态
newCheckBox_updateCal: false, //update复选框状态
currStep: '',
isReAnalyed: false,
timerStamp: Date.now(),
}
},
created() {
this.setChartBottomTitle(0, 0, 0)
this.option.tooltip.formatter = this.tooltipFormatter
this.$bus.$on('gammaRefresh', this.handleRefresh)
this.$bus.$on('accept', this.handleAccept)
window.addEventListener('keydown', this.handleKeyboardEvent)
window.addEventListener('click', this.closePeakInfomationTooltip)
},
destroyed() {
this.cancelLastRequest()
this.$bus.$off('gammaRefresh', this.handleRefresh)
this.$bus.$off('accept', this.handleAccept)
window.removeEventListener('keydown', this.handleKeyboardEvent)
window.removeEventListener('click', this.closePeakInfomationTooltip)
if (this.qcFlagsTimer) {
clearTimeout(this.qcFlagsTimer)
}
},
deactivated() {
// Object.keys(this.subOperatorsState).forEach(k => {
// this.subOperatorsState[k] = false
// })
},
mounted() {
this.option.brush = { toolbox: [] }
this.initWebSocket()
this.qcFlagsTimer = setTimeout(() => {
this.subOperatorsState.qcFlagsVisible = true
}, 100)
},
methods: {
// 键盘事件
handleKeyboardEvent(event) {
this.changeRectByKeyBoard(event.key)
this.closePeakInfomationTooltip()
},
/**
* 键盘事件处理
* @param {*} key
* @description 1、xAxis采用按axis值增/减量的方式实现
* 2、而因为yAxis在type=log下分布不平均无法用按axis值增/减量的方式实现平均的增大或缩小
* 所以采用像素增/减量的方式。
* 具体实现则为因为右上角缩略图表是不改变轴最大值最小值的也就是它的每个axis像素数不会
* 随着图表值域的缩小而变大所以将其视作标准参照物将主图表现在的axis值转为像素值增/减
* 去每步像素值得到新的像素值然后再转化为axis值去设置主图表范围和设置右上角缩略图表的
* 框的范围
*/
changeRectByKeyBoard(key) {
if (!['=', '-', 'ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft'].includes(key)) {
return
}
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
const markLineData = spectrumLineSeries.markLine.data[0]
const markLineXAxis = markLineData.xAxis
const thumbnailChart = this.getThumbnailChart()
// 通过thumbnail chart获取最小值和最大值
const maxX = getAxisMax(thumbnailChart, 'xAxis')
const maxY = getAxisMax(thumbnailChart, 'yAxis')
const xStep = Math.ceil(maxX / 100) // x 轴每次走的axis数
const yStep = 5 // y 轴在缩略图表每次走的像素数
// 如果遇到dataMax设为最大值真实值
let { min: currMinX, max: currMaxX } = this.option.xAxis
if (currMaxX == 'dataMax') {
currMaxX = maxX
}
let { min: currMinY, max: currMaxY } = this.option.yAxis
if (currMaxY == 'dataMax') {
currMaxY = maxY
}
const { pixX: currMinXPix } = this.convertToPixel(thumbnailChart, currMinX, currMinY)
const { pixY: currMinYPix } = this.convertToPixel(thumbnailChart, currMinX, currMinY)
const { pixY: currMaxYPix } = this.convertToPixel(thumbnailChart, currMinX, currMaxY)
const { pixY: minYPixel } = this.convertToPixel(thumbnailChart, currMinX, 1)
const { pixY: maxYPixel } = this.convertToPixel(thumbnailChart, currMinX, maxY)
let nextMinX, nextMaxX, nextMinYPix, nextMaxYPix
switch (key) {
case '=': // 在x轴扩大范围
nextMinX = currMinX - xStep
nextMaxX = currMaxX + xStep
if (nextMinX < this.xAxisMin) {
nextMinX = this.xAxisMin
}
if (nextMaxX > maxX) {
nextMaxX = maxX
}
this.setRectRange(nextMinX, nextMaxX, currMinY, currMaxY)
break
case '-': // 在x轴缩小范围
if (currMaxX - currMinX > 2 * xStep) {
nextMinX = currMinX + xStep
nextMaxX = currMaxX - xStep
this.setRectRange(nextMinX, nextMaxX, currMinY, currMaxY)
}
break
case 'ArrowUp': // 在y轴扩大范围
nextMinYPix = currMinYPix + yStep
nextMaxYPix = currMaxYPix - yStep
if (nextMinYPix > minYPixel) {
nextMinYPix = minYPixel
}
if (nextMaxYPix < maxYPixel) {
nextMaxYPix = maxYPixel
}
const nextMinY = getXAxisAndYAxisByPosition(thumbnailChart, currMinXPix, nextMinYPix)[1]
const nextMaxY = getXAxisAndYAxisByPosition(thumbnailChart, currMinXPix, nextMaxYPix)[1]
this.setRectRange(currMinX, currMaxX, nextMinY, nextMaxY)
break
case 'ArrowDown': // 在y轴缩小范围
if (currMinYPix - currMaxYPix > 2 * yStep) {
nextMinYPix = currMinYPix - yStep
nextMaxYPix = currMaxYPix + yStep
const nextMinY = getXAxisAndYAxisByPosition(thumbnailChart, currMinXPix, nextMinYPix)[1]
const nextMaxY = getXAxisAndYAxisByPosition(thumbnailChart, currMinXPix, nextMaxYPix)[1]
this.setRectRange(currMinX, currMaxX, nextMinY, nextMaxY)
}
break
case 'ArrowRight':
if (markLineXAxis == maxX) {
return
}
let rightAxis = -1
if (markLineXAxis == -1) {
rightAxis = this.xAxisMin
} else {
if (this.isEnergy) {
const channel = this.getChannelByEnergy(markLineXAxis)
rightAxis = this.getEnergyByChannel(channel + 1)
} else {
rightAxis = markLineXAxis + 1
}
}
markLineData.xAxis = rightAxis
const {
channel: rightChannel,
energy: rightEnergy,
counts: rightCounts,
} = this.getEnergyAndCountsByXAxis(rightAxis)
this.setChartBottomTitle(rightChannel, rightEnergy, rightCounts)
this.getSelPosNuclide(rightChannel, rightEnergy)
break
case 'ArrowLeft':
if (markLineXAxis <= this.xAxisMin) {
return
}
let leftAxis = 0
if (this.isEnergy) {
const channel = this.getChannelByEnergy(markLineXAxis)
leftAxis = this.getEnergyByChannel(channel - 1)
} else {
leftAxis = markLineXAxis - 1
}
markLineData.xAxis = leftAxis
const {
channel: leftChannel,
energy: leftEnergy,
counts: leftCounts,
} = this.getEnergyAndCountsByXAxis(leftAxis)
this.setChartBottomTitle(leftChannel, leftEnergy, leftCounts)
this.getSelPosNuclide(leftChannel, leftEnergy)
break
}
},
// 图表转化像素值
convertToPixel(chart, xAxis, yAxis) {
const [pixX, pixY] = chart.convertToPixel({ seriesIndex: 0 }, [xAxis, yAxis])
return {
pixX,
pixY,
}
},
// 设置范围
setRectRange(minX, maxX, minY, maxY) {
this.option.xAxis.min = minX
this.option.xAxis.max = maxX
this.option.yAxis.min = minY
this.option.yAxis.max = maxY
this.setThumbnailChartRect(minX, maxY, maxX, minY)
const thumbnailChart = this.getThumbnailChart()
const [, maxYPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, minY]) // 方框的上下两条边的yAxis转为pix
const [, minYPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, maxY])
const rectHeightPixel = maxYPixel - minYPixel // 计算方框的左右边长(pix)
this.halfHeightPixel = rectHeightPixel / 2
},
initWebSocket: function () {
// WebSocket与普通的请求所用协议有所不同ws等同于httpwss等同于https
var userId = store.getters.userInfo.id
var url =
window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://') +
'/websocket/' +
userId +
'_' +
this.timerStamp
//console.log(url);
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
let token = Vue.ls.get(ACCESS_TOKEN)
this.websock = new WebSocket(url, [token])
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
this.websock.onopen = this.websocketOnopen
this.websock.onerror = this.websocketOnerror
this.websock.onmessage = this.websocketOnmessage
this.websock.onclose = this.websocketOnclose
},
websocketOnopen: function () {
// console.log('WebSocket连接成功1231')
//心跳检测重置
//this.heartCheck.reset().start();
},
websocketOnerror: function (e) {
this.reconnect()
},
websocketOnmessage: function (e) {
// console.log('-----接收消息1231-------', e.data)
var data = eval('(' + e.data + ')') //解析对象
// console.log(data)
if (data.cmd === 'analysis-process') {
this.currStep = data.msgTxt
}
},
websocketOnclose: function (e) {
this.reconnect()
},
reconnect() {
var that = this
if (that.lockReconnect) return
that.lockReconnect = true
//没连接上会一直重连,设置延迟避免请求过多
setTimeout(function () {
console.info('尝试重连...')
that.initWebSocket()
that.lockReconnect = false
}, 20000)
},
// 获取样品详情
async getSampleDetail() {
const { dbName, sampleId, analyst } = this.sample
try {
this.isLoading = true
// const { success, result, message } = Response
this.cancelLastRequest()
const cancelToken = this.createCancelToken()
const { success, result, message } = await getAction(
'/gamma/gammaByDB',
{
dbName,
sampleId,
analyst,
},
cancelToken
)
console.log('%c [ result ]-243', 'font-size:13px; background:pink; color:#bf2c9f;', result)
if (success) {
this.dataProcess(result, 'db')
} else {
this.$message.error(message)
this.isLoading = false
}
} catch (error) {
console.error(error)
const isCancel = axios.isCancel(error)
if(!isCancel) {
this.isLoading = false
}
}
},
async getSampleDetail_file() {
const { inputFileName: fileName } = this.sample
try {
this.isLoading = true
// const { success, result, message } = Response
this.cancelLastRequest()
const cancelToken = this.createCancelToken()
const { success, result, message } = await getAction(
'/gamma/gammaByFile',
{
fileName,
},
cancelToken
)
console.log('%c [ result ]-243', 'font-size:13px; background:pink; color:#bf2c9f;', result)
if (success) {
this.dataProcess(result, 'file')
} else {
this.$message.error(message)
this.isLoading = false
}
} catch (error) {
console.error(error)
this.isLoading = false
}
},
cancelLastRequest() {
if (this._cancelToken && typeof this._cancelToken == 'function') {
this._cancelToken()
this._cancelToken = undefined
}
},
createCancelToken() {
const cancelToken = new axios.CancelToken((c) => {
this._cancelToken = c
})
return cancelToken
},
dataProcess(result, flag) {
const { inputFileName } = this.sample
this.$store.commit('ADD_SAMPLE_DATA', {
inputFileName,
data: result,
from: flag,
})
this.isLoading = false
const {
dead_time,
live_time,
real_time,
start_time,
DetailedInformation,
QCFlag,
allData,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
peak,
BaseCtrls,
} = result
if (flag && (flag == 'db' || flag == 'file')) {
this.bAnalyed = result.bAnalyed
this.$emit('reAnalyed', this.bAnalyed)
this.checkBox_updateCal = result.checkBox_updateCal
this.newCheckBox_updateCal = '2'
console.log(this.checkBox_updateCal)
}
this.detailedInfomation = DetailedInformation
this.qcFlags = QCFlag
if (peak) {
this.peakList = peak
}
if (BaseCtrls) {
this.baseCtrls = BaseCtrls
}
const channelPeakGroup = this.getLineData(allData, 'Peak', 'channel', true)
const energyPeakGroup = this.getLineData(allData, 'Peak', 'energy', true)
const channelBaseLine = this.getLineData(allData, 'BaseLine', 'channel')
const energyBaseLine = this.getLineData(allData, 'BaseLine', 'energy')
const channelLcLine = this.getLineData(allData, 'Lc', 'channel')
const energyLcLine = this.getLineData(allData, 'Lc', 'energy')
const channelScacLine = this.getLineData(allData, 'Scac', 'channel')
const energyScacLine = this.getLineData(allData, 'Scac', 'energy')
const allChannel = this.getLineData(allData, 'Count', 'channel')
const allEnergy = this.getLineData(allData, 'Energy', 'energy')
this.channelData = {
peakGroup: channelPeakGroup,
spectrumLine: shadowChannelChart,
baseLine: channelBaseLine,
lcLine: channelLcLine,
scacLine: channelScacLine,
all: allChannel,
baseLineCP: shapeChannelData,
}
this.energyData = {
peakGroup: energyPeakGroup,
spectrumLine: shadowEnergyChart,
baseLine: energyBaseLine,
lcLine: energyLcLine,
scacLine: energyScacLine,
all: allEnergy,
baseLineCP: shapeEnergyData,
}
this.resetThumbnailChartDataMax()
// 设置 Spectrum Line
this.setSeriesData(
this.option.series,
'Spectrum',
this.transformPointListData(shadowChannelChart.pointlist),
shadowChannelChart.color
)
// 设置 BaseLine
this.setSeriesData(
this.option.series,
'BaseLine',
this.transformPointListData(channelBaseLine.pointlist),
channelBaseLine.color
)
// 设置 LcLine
this.setSeriesData(
this.option.series,
'LcLine',
this.transformPointListData(channelLcLine.pointlist),
channelLcLine.color
)
// 设置 ScacLine
this.setSeriesData(
this.option.series,
'ScacLine',
this.transformPointListData(channelScacLine.pointlist),
channelScacLine.color
)
// 设置 基线控制点
this.redrawCtrlPointBySeriesName()
// 设置 Peak Line
this.redrawPeakLine()
// 设置右上角缩略图 Spectrum Line 数据
this.setSeriesData(
this.thumbnailOption.series,
'Spectrum',
this.transformPointListData(shadowChannelChart.pointlist),
shadowChannelChart.color
)
},
// chart 的 tooltip
tooltipFormatter(params) {
let channel = 0
let energy = 0
const value = params[0].value[0]
if (this.isEnergy) {
energy = value.toFixed(2)
channel = this.getChannelByEnergy(value)
} else {
channel = parseInt(value.toFixed())
energy = this.getEnergyByChannel(channel)
energy = energy ? energy.toFixed(2) : undefined
}
return `<div class="channel">Channel: ${channel}</div>
<div class="energy">${energy ? `Energy: ${energy}` : ''}</div>`
},
// Graph Assistance 操作
handleGraphAssistanceChange(key) {
const value = this.graphAssistance[key]
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
const thumbnailSpectrumLineSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
const compareLineSeries = findSeriesByName(this.option.series, 'Compare')
const StripSumOrCutLineSeries = findSeriesByName(this.option.series, 'StripSumOrCut')
const stripReferenceLineSeries = findSeriesByName(this.option.series, 'StripReference')
switch (key) {
// 折线y轴类型变化
case 'chartYAxisType':
if (value == 'Linear') {
this.option.yAxis.type = 'value'
this.thumbnailOption.yAxis.type = 'value'
} else {
this.option.yAxis.type = 'log'
this.thumbnailOption.yAxis.type = 'log'
}
this.handleResetChart()
break
// 红色竖线是否显示
case 'Cursor':
if (value) {
spectrumLineSeries.markLine.lineStyle.width = 2
} else {
spectrumLineSeries.markLine.lineStyle.width = 0
}
break
// 基线是否显示
case 'Baseline':
this.redrawLineBySeriesName('BaseLine', this.energyData.baseLine, this.channelData.baseLine, value)
break
// Lc 线是否显示
case 'Lc':
this.redrawLineBySeriesName('LcLine', this.energyData.lcLine, this.channelData.lcLine, value)
break
// Channel和Energy的切换
case 'axisType':
// 如果Energy没有值则不进行切换
if (!this.energyData.all.pointlist) {
if (value == 'Energy') {
this.graphAssistance[key] = 'Channel'
}
this.$message.warn('Has No Energy Yet')
return
}
this.option.xAxis.name = value
if (this.isEnergy) {
this.option.xAxis.axisLabel.formatter = (value) => {
return value.toFixed(2)
}
} else {
this.option.xAxis.axisLabel.formatter = (value) => {
return value
}
}
this.handleResetChart()
this.thumbnailOption.xAxis.min = this.xAxisMin
this.redrawLineBySeriesName(
'BaseLine',
this.energyData.baseLine,
this.channelData.baseLine,
this.graphAssistance.Baseline
)
this.redrawLineBySeriesName(
'LcLine',
this.energyData.lcLine,
this.channelData.lcLine,
this.graphAssistance.Lc
)
this.redrawLineBySeriesName(
'ScacLine',
this.energyData.scacLine,
this.channelData.scacLine,
this.graphAssistance.SCAC
)
this.redrawLineBySeriesName('Spectrum', this.energyData.spectrumLine, this.channelData.spectrumLine)
this.redrawCtrlPointBySeriesName()
this.redrawPeakLine()
this.redrawThumbnailChart()
if (this.channelData.compareLine) {
this.redrawLineBySeriesName('Compare', this.energyData.compareLine, this.channelData.compareLine)
}
if (this.channelData.stripSumOrCutLine) {
this.redrawLineBySeriesName(
'StripSumOrCut',
this.energyData.stripSumOrCutLine,
this.channelData.stripSumOrCutLine
)
}
if (this.channelData.stripReferenceLine) {
this.redrawLineBySeriesName(
'StripReference',
this.energyData.stripReferenceLine,
this.channelData.stripReferenceLine
)
}
break
// Lines 和 Scatter 的切换
case 'spectrumType':
if (value == 'Lines') {
spectrumLineSeries.type = 'line'
spectrumLineSeries.symbol = 'none'
thumbnailSpectrumLineSeries.type = 'line'
thumbnailSpectrumLineSeries.symbol = 'none'
compareLineSeries.type = 'line'
compareLineSeries.symbol = 'none'
StripSumOrCutLineSeries.type = 'line'
StripSumOrCutLineSeries.symbol = 'none'
stripReferenceLineSeries.type = 'line'
stripReferenceLineSeries.symbol = 'none'
this.redrawLineBySeriesName('Spectrum', this.energyData.spectrumLine, this.channelData.spectrumLine)
if (this.channelData.compareLine) {
this.redrawLineBySeriesName('Compare', this.energyData.compareLine, this.channelData.compareLine)
}
if (this.channelData.stripSumOrCutLine) {
this.redrawLineBySeriesName(
'StripSumOrCut',
this.energyData.stripSumOrCutLine,
this.channelData.stripSumOrCutLine
)
}
if (this.channelData.stripReferenceLine) {
this.redrawLineBySeriesName(
'StripReference',
this.energyData.stripReferenceLine,
this.channelData.stripReferenceLine
)
}
} else {
spectrumLineSeries.type = 'scatterGL'
spectrumLineSeries.symbol = 'circle'
thumbnailSpectrumLineSeries.type = 'scatterGL'
thumbnailSpectrumLineSeries.symbol = 'circle'
compareLineSeries.type = 'scatterGL'
compareLineSeries.symbol = 'circle'
StripSumOrCutLineSeries.type = 'scatterGL'
StripSumOrCutLineSeries.symbol = 'circle'
stripReferenceLineSeries.type = 'scatterGL'
stripReferenceLineSeries.symbol = 'circle'
this.$nextTick(() => {
this.rangeScatter()
})
}
break
// SCAC 线是否显示
case 'SCAC':
this.redrawLineBySeriesName('ScacLine', this.energyData.scacLine, this.channelData.scacLine, value)
break
}
},
changeSeriesType() {},
handleChangeNuclideVisible() {
this.subOperatorsState.nuclideLibraryVisible = !this.subOperatorsState.nuclideLibraryVisible
},
// 根据seriesName重绘线
redrawLineBySeriesName(seriesName, energyData, channelData, isShow = true, color) {
if (isShow) {
const data = this.isEnergy ? energyData : channelData
this.setSeriesData(this.option.series, seriesName, this.transformPointListData(data.pointlist), color)
} else {
this.setSeriesData(this.option.series, seriesName, [])
}
},
// 重绘控制点
redrawCtrlPointBySeriesName() {
const series = findSeriesByName(this.option.series, 'BaseLine_Ctrl_Point')
const data = this.isEnergy ? this.energyData.baseLineCP : this.channelData.baseLineCP
series.data = data.map(({ size, color, point: { x, y } }) => {
return {
value: [x, y],
itemStyle: {
color: 'transparent',
borderColor: color,
borderWidth: size / 2,
},
}
})
},
clearPeakLine() {
this.opts.notMerge = true
this.option.series.splice(8)
this.$nextTick(() => {
this.resetChartOpts()
})
},
// 重绘Peak Line
redrawPeakLine() {
this.clearPeakLine()
const data = this.isEnergy ? this.energyData.peakGroup : this.channelData.peakGroup
const peakLines = []
data.forEach((item, index) => {
peakLines.push(
buildLineSeries(`Peak_${index}`, this.transformPointListData(item.pointlist), item.color, {
z: 6,
})
)
})
this.option.series.push(...peakLines)
},
// 重绘右上角的缩略图
redrawThumbnailChart() {
const series = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
const data = this.isEnergy ? this.energyData.spectrumLine : this.channelData.spectrumLine
series.data = this.transformPointListData(data.pointlist)
},
// 点击图表,设置红线
handleChartClick(param) {
const { offsetX, offsetY } = param
const point = getXAxisAndYAxisByPosition(this.getChart(), offsetX, offsetY)
if (point) {
const xAxis = point[0]
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
spectrumLineSeries.markLine.data[0].xAxis = xAxis
const { channel, energy, counts } = this.getEnergyAndCountsByXAxis(xAxis)
this.setChartBottomTitle(channel, energy, counts)
this.getSelPosNuclide(channel, energy)
}
},
// 设置图表底部的标题
setChartBottomTitle(channel, energy, counts) {
const { index, find } = findNearPeak(channel, this.peakList)
this.option.title.text = `{a|Channel:${channel}} {a|Energy:${energy.toFixed(2) || '0.00'}} {a|Counts:${
counts || '0.0'
}} {a|Significance:${find ? this.peakList[index].significance.toFixed(2) : '0.00'}}`
},
// 根据xAixs值找channel、energy和counts
getEnergyAndCountsByXAxis(xAxis) {
if (-1 == xAxis) {
return {
channel: -1,
energy: 0,
counts: 0,
}
}
let channel, energy, counts
if (this.isEnergy) {
channel = this.getChannelByEnergy(xAxis)
energy = xAxis
counts = this.energyData.all.pointlist[channel - 1].y
} else {
channel = Math.round(xAxis)
energy = this.getEnergyByChannel(channel)
counts = this.channelData.all.pointlist[channel - 1].y
}
return {
channel,
energy,
counts,
}
},
// 获取 Nuclide Library 数据
async getSelPosNuclide(channel, energy) {
this.currChannel = channel
try {
this.isLoadingNuclide = true
const { sampleId, inputFileName: fileName } = this.sample
const { success, result, message } = await getAction('/gamma/getGammaSelPosNuclide', {
sampleId,
channel,
fileName,
energy,
})
if (success) {
const { possible } = result
this.nuclideLibraryList = possible
} else {
this.$message.error(message)
}
} catch (error) {
this.nuclideLibraryList = []
console.error(error)
} finally {
this.isLoadingNuclide = false
}
},
// Nuclide Library 单项双击
handleNuclideDblClick(nuclide) {
this.subOperatorsState.nuclideLibraryVisible = false
this.nuclideReview.nuclide = nuclide
this.nuclideReview.visible = true
},
resize() {
this.$refs.chartRef.resize()
this.$refs.thumbnailChartRef.resize()
this.closePeakInfomationTooltip()
},
// peak info 点击左右方向
handlePeakInfoChange(direction) {
this.moveMarkLine(direction)
},
// 触发Peak Infomation
handleTogglePeak() {
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
const xAxis = spectrumLineSeries.markLine.data[0].xAxis
const channel = this.isEnergy ? this.getChannelByEnergy(xAxis) : parseInt(xAxis.toFixed())
const index = this.channelData.peakGroup.findIndex((peakItem) => {
const allX = peakItem.pointlist.map((item) => item.x)
const max = Math.max(...allX)
const min = Math.min(...allX)
return channel >= min && channel <= max
})
if (-1 !== index) {
this.getPeakInfo(index)
} else {
this.closePeakInfomationTooltip()
}
},
// 获取 Peak 峰顶 信息
async getPeakInfo(index) {
try {
const { inputFileName: fileName } = this.sample
const { success, result, message } = await getAction('/gamma/clickPeakInformation', {
fileName,
index,
})
if (success) {
const html = result.replaceAll('\n', '<br>')
const currPeak = this.channelData.peakGroup[index]
const { x, y } = currPeak.pointlist.reduce((prev, curr) => {
return prev && prev.y > curr.y ? prev : curr
})
const [xPix, yPix] = this.getChart().convertToPixel({ seriesIndex: 0 }, [x, y])
this.peakInfomationTooltip.content = html
this.peakInfomationTooltip.visible = true
this.peakInfomationTooltip.left = xPix
this.peakInfomationTooltip.top = yPix < 0 ? 20 : yPix - 20
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
// 关闭Peak Infomation
closePeakInfomationTooltip() {
this.peakInfomationTooltip.visible = false
},
/**
* 向某一个方向移动标记线
* @param { 'left'| 'right' } direction
*/
moveMarkLine(direction) {
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
const prevAxis = spectrumLineSeries.markLine.data[0].xAxis
const { channel: prevChannel } = this.getEnergyAndCountsByXAxis(prevAxis)
let i,
size = this.peakList.length
if (direction == 'right') {
for (i = 0; i < size; i++) {
const centroid = Math.round(this.peakList[i].peakCentroid)
if (centroid > prevChannel) {
const energy = this.getEnergyByChannel(centroid)
this.setMarkLineXAxis(this.isEnergy ? energy : centroid, i)
this.getSelPosNuclide(centroid, energy)
const { counts } = this.getEnergyAndCountsByXAxis(this.isEnergy ? energy : centroid)
this.setChartBottomTitle(centroid, energy, counts)
return
}
}
} else if (direction == 'left') {
for (i = size - 1; i >= 0; i--) {
const centroid = Math.round(this.peakList[i].peakCentroid)
if (Math.round(centroid) < prevChannel) {
const energy = this.getEnergyByChannel(centroid)
this.setMarkLineXAxis(this.isEnergy ? energy : centroid, i)
this.getSelPosNuclide(centroid, energy)
const { counts } = this.getEnergyAndCountsByXAxis(this.isEnergy ? energy : centroid)
this.setChartBottomTitle(centroid, energy, counts)
return
}
}
}
},
// 设置红色标记线的位置
setMarkLineXAxis(xAxis, index) {
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
const markLineOption = spectrumLineSeries.markLine.data[0]
markLineOption.xAxis = xAxis
const {
xAxis: { max: xAxisMax, min: xAxisMin },
yAxis: { max: yAxisMax, min: yAxisMin },
} = this.option
// 如果不在范围内
if (xAxis >= xAxisMax || xAxis <= xAxisMin) {
let nextMaxX = xAxisMax,
nextMinX = xAxisMin,
nextMaxY = yAxisMax,
nextMinY = yAxisMin
const halfDiff = (xAxisMax - xAxisMin) / 2
const dataSource = this.isEnergy ? this.energyData : this.channelData
const lastChannel = dataSource.spectrumLine.pointlist[dataSource.spectrumLine.pointlist.length - 1].x
const tmpNextMaxX = xAxis + halfDiff
const tmpNextMinX = xAxis - halfDiff
nextMaxX = tmpNextMaxX > lastChannel ? lastChannel : tmpNextMaxX
nextMinX = tmpNextMinX < this.xAxisMin ? this.xAxisMin : tmpNextMinX
const peak = this.channelData.peakGroup[index]
const peakCountMax = Math.max(...peak.pointlist.map(({ y }) => y))
const peakCountMin = Math.min(...peak.pointlist.map(({ y }) => y))
const chart = this.$refs.thumbnailChartRef.getChartInstance()
const yDataMax = getAxisMax(chart, 'yAxis')
if (yAxisMax !== 'dataMax' && peakCountMin >= yAxisMax) {
nextMaxY = yDataMax
}
if (peakCountMax <= yAxisMin) {
nextMinY = 1
}
this.setRectRange(nextMinX, nextMaxX, nextMinY, nextMaxY)
}
},
// 鼠标按下时开启可刷选状态
handleMouseDown() {
this.getChart().dispatchAction({
type: 'takeGlobalCursor',
// 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
key: 'brush',
brushOption: {
// 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
brushType: 'rect',
},
})
},
handleMouseUp() {
this.$nextTick(() => {
this.clearBrush()
})
},
clearBrush() {
const chart = this.getChart()
// 清理刷选的范围
chart.dispatchAction({
type: 'brush',
areas: [],
})
// 改为不可刷选状态
chart.dispatchAction({
type: 'takeGlobalCursor',
})
},
// 刷选完毕时
handleBrushEnd(param) {
this.closePeakInfomationTooltip()
const chart = this.$refs.chartRef.getChartInstance()
const areas = param.areas[0]
if (areas) {
const range = areas.range
const [[minX, maxX], [minY, maxY]] = range
const point1 = chart.convertFromPixel({ seriesIndex: 0 }, [minX, minY]).map((num) => parseInt(num.toFixed()))
const point2 = chart.convertFromPixel({ seriesIndex: 0 }, [maxX, maxY]).map((num) => parseInt(num.toFixed()))
// 拿到之前的最大值
const xAxisMax = getAxisMax(chart, 'xAxis')
const yAxisMax = getAxisMax(chart, 'yAxis')
// 拿到之前的最小值
const xAxisMin = this.option.xAxis.min
const yAxisMin = this.option.yAxis.min
let [x1, y2, x2, y1] = [...point1, ...point2] // 根据解析出的数据确定真实的范围
const xAxisLimit = rangeNumber(xAxisMin, xAxisMax)
const yAxisLimit = rangeNumber(yAxisMin, yAxisMax)
x1 = xAxisLimit(x1)
x2 = xAxisLimit(x2)
y1 = yAxisLimit(y1)
y2 = yAxisLimit(y2)
this.option.xAxis.min = x1
this.option.xAxis.max = x2
this.option.yAxis.min = y1
this.option.yAxis.max = y2
this.setThumbnailChartRect(x1, y2, x2, y1)
const thumbnailChart = this.getThumbnailChart()
const [, maxYPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, y1]) // 方框的上下两条边的yAxis转为pix
const [, minYPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, y2])
const rectHeightPixel = maxYPixel - minYPixel // 计算方框的左右边长(pix)
this.halfHeightPixel = rectHeightPixel / 2
}
this.$nextTick(() => {
this.rangeScatter()
})
},
/**
* 因scatterGL 不受axis中max和min的控制手动处理溢出部分
* @param {Boolean} isReset 是否重置到初始状态
*/
rangeScatter(isReset) {
if (!this.isScatter()) {
return
}
const {
xAxis: { min: x1 },
yAxis: { min: y1 },
} = this.option
const chart = this.getChart()
const x2 = getAxisMax(chart, 'xAxis')
const y2 = getAxisMax(chart, 'yAxis')
const channelSpectrumData = {
...this.channelData.spectrumLine,
pointlist: isReset
? this.pointlistLimitY(this.channelData.spectrumLine.pointlist)
: this.pointlistLimit(this.channelData.spectrumLine.pointlist, x1, x2, y1, y2),
}
const energySpectrumData = {
...this.energyData.spectrumLine,
pointlist: isReset
? this.pointlistLimitY(this.energyData.spectrumLine.pointlist)
: this.pointlistLimit(this.energyData.spectrumLine.pointlist, x1, x2, y1, y2),
}
this.redrawLineBySeriesName('Spectrum', energySpectrumData, channelSpectrumData)
if (this.channelData.compareLine) {
const channelCompareLine = {
...this.channelData.compareLine,
pointlist: isReset
? this.pointlistLimitY(this.channelData.compareLine.pointlist)
: this.pointlistLimit(this.channelData.compareLine.pointlist, x1, x2, y1, y2),
}
let energyCompareLine = []
if (this.energyData.compareLine) {
energyCompareLine = {
...this.energyData.compareLine,
pointlist: isReset
? this.pointlistLimitY(this.energyData.compareLine.pointlist)
: this.pointlistLimit(this.energyData.compareLine.pointlist, x1, x2, y1, y2),
}
}
this.redrawLineBySeriesName('Compare', energyCompareLine, channelCompareLine)
}
if (this.channelData.stripReferenceLine) {
const channelStripReferenceLine = {
...this.channelData.stripReferenceLine,
pointlist: isReset
? this.pointlistLimitY(this.channelData.stripReferenceLine.pointlist)
: this.pointlistLimit(this.channelData.stripReferenceLine.pointlist, x1, x2, y1, y2),
}
if (this.channelData.stripSumOrCutLine) {
const channelStripSumOrCutLine = {
...this.channelData.stripSumOrCutLine,
pointlist: isReset
? this.pointlistLimitY(this.channelData.stripSumOrCutLine.pointlist)
: this.pointlistLimit(this.channelData.stripSumOrCutLine.pointlist, x1, x2, y1, y2),
}
let energyStripSumOrCutLine = []
if (this.energyData.stripSumOrCutLine) {
energyStripSumOrCutLine = {
...this.energyData.stripSumOrCutLine,
pointlist: isReset
? this.pointlistLimitY(this.energyData.stripSumOrCutLine.pointlist)
: this.pointlistLimit(this.energyData.stripSumOrCutLine.pointlist, x1, x2, y1, y2),
}
}
this.redrawLineBySeriesName('StripSumOrCut', energyStripSumOrCutLine, channelStripSumOrCutLine)
}
let energyStripReferenceLine = []
if (this.energyData.stripReferenceLine) {
energyStripReferenceLine = {
...this.energyData.stripReferenceLine,
pointlist: isReset
? this.pointlistLimitY(this.energyData.stripReferenceLine.pointlist)
: this.pointlistLimit(this.energyData.stripReferenceLine.pointlist, x1, x2, y1, y2),
}
}
this.redrawLineBySeriesName('StripReference', energyStripReferenceLine, channelStripReferenceLine)
}
},
/**
* 筛选范围内的点
* @param {*} pointlist
* @param {*} x1
* @param {*} x2
* @param {*} y1
* @param {*} y2
*/
pointlistLimit(pointlist, x1, x2, y1, y2) {
return pointlist.filter(({ x, y }) => x >= x1 && x <= x2 && y >= y1 && y <= y2)
},
pointlistLimitY(pointlist) {
return pointlist.filter(({ y }) => y >= 1)
},
// 在右上角缩略图中设置范围
setThumbnailChartRect(x1, y2, x2, y1) {
this.thumbnailChartRect = [x1, y2, x2, y1]
const thumbnailSpectrumLineSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
const { markLine } = thumbnailSpectrumLineSeries
const pointList = [
[
[x1, y1],
[x2, y1],
],
[
[x2, y1],
[x2, y2],
],
[
[x2, y2],
[x1, y2],
],
[
[x1, y2],
[x1, y1],
],
]
const lines = pointList.map((point) => {
return this.generateLineDataByTwoPoints(point[0], point[1])
})
markLine.data = lines
},
// 缩略图点击
handleThumbnailChartClick(param) {
const { offsetX, offsetY } = param
const thumbnailChart = this.getThumbnailChart()
const point = getXAxisAndYAxisByPosition(thumbnailChart, offsetX, offsetY)
if (point && this.thumbnailChartRect && this.thumbnailChartRect.length) {
const [x1, y2, x2, y1] = this.thumbnailChartRect
const halfWidth = (x2 - x1) / 2
// 缩略图最大值转为pix
const { pixY: maxYAxisPixel } = this.convertToPixel(thumbnailChart, 0, getAxisMax(thumbnailChart, 'yAxis'))
const { pixY: minYAxisPixel } = this.convertToPixel(thumbnailChart, 0, 1)
let [xAxis, yAxis] = point
const xAxisMax = getAxisMax(thumbnailChart, 'xAxis')
const xAxisLimit = rangeNumber(add(this.xAxisMin, halfWidth), subtract(xAxisMax, halfWidth))
const halfHeightPixel = this.halfHeightPixel
const yAxisLimit = rangeNumber(add(maxYAxisPixel, halfHeightPixel), subtract(minYAxisPixel, halfHeightPixel))
xAxis = xAxisLimit(xAxis)
let { pixY: yAxisPixel } = this.convertToPixel(thumbnailChart, 0, yAxis)
yAxisPixel = yAxisLimit(yAxisPixel)
const minYAxis = thumbnailChart.convertFromPixel({ seriesIndex: 0 }, [0, add(yAxisPixel, halfHeightPixel)])[1] // 再把y轴最小值从pix转为yAxis
const maxYAxis = thumbnailChart.convertFromPixel({ seriesIndex: 0 }, [
0,
subtract(yAxisPixel, halfHeightPixel),
])[1]
const nextXAxisMin = subtract(xAxis, halfWidth)
const nextXAxisMax = add(xAxis, halfWidth)
this.setThumbnailChartRect(nextXAxisMin, maxYAxis, nextXAxisMax, minYAxis)
this.option.xAxis.min = nextXAxisMin
this.option.xAxis.max = nextXAxisMax
this.option.yAxis.min = minYAxis
this.option.yAxis.max = maxYAxis
this.$nextTick(() => {
this.rangeScatter()
})
}
},
/**
* 重置图表
*/
handleResetChart() {
this.option.xAxis.min = this.xAxisMin
this.option.xAxis.max = 'dataMax'
this.option.yAxis.min = 1
this.option.yAxis.max = 'dataMax'
const thumbnailSpectrumLineSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
thumbnailSpectrumLineSeries.markLine.data = []
this.thumbnailChartRect = []
this.closePeakInfomationTooltip()
this.$nextTick(() => {
this.rangeScatter(true)
})
},
// 从分析工具刷新部分数据
handleRefresh(data) {
Object.assign(data, {
DetailedInformation: this.detailedInfomation,
QCFlag: this.qcFlags,
BaseCtrls: this.baseCtrls,
bAnalyed: this.bAnalyed,
})
this.clearCompareLine()
this.redrawPeakLine()
this.dataProcess(data)
},
// 分析工具Accept时刷新部分数据
handleAccept(data) {
const {
allData,
peak,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
barChart,
BaseCtrls,
} = data
const result = {
DetailedInformation: this.detailedInfomation,
QCFlag: this.qcFlags,
allData,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
peak,
BaseCtrls,
bAnalyed: this.bAnalyed,
barChart,
}
this.clearCompareLine()
this.redrawPeakLine()
this.dataProcess(result)
},
// 显示比较弹窗
showCompareModal(isStrip) {
if (this.isLoading) {
this.$message.warn('Sample is Loading')
return
}
this.handleResetChart()
this.clearCompareLine()
this.isStrip = isStrip
if (FilePicker.canUse()) {
this.chooseFileFromFS()
} else {
this.compareFileListModalVisible = true
}
},
// 从文件系统中选择文件
async chooseFileFromFS() {
try {
const [fileHandle] = await FilePicker.chooseFile(false, [{ accept: { 'text/phd': ['.phd'] } }])
const file = await fileHandle.getFile()
const text = await readFile(file)
const parser = new PHDParser(text)
const { sampleFilePrefix, qualify, dataType, liveTime } = parser
const hide = this.$message.loading('Uploading...', 0)
const zipedFiles = await zipFile([file], 'test.zip')
try {
const formData = new FormData()
formData.append('file', zipedFiles)
const { success, message } = await postAction('/spectrumFile/upload', formData)
if (success) {
this.handleFileSelect(`${sampleFilePrefix}${getSampleTypeIdentify(dataType)}_${qualify}_${liveTime}.PHD`)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
hide()
}
} catch (error) {
console.error(error)
}
},
// 文件之间对比
async handleFileSelect(selectedFileName) {
const { inputFileName: fileName } = this.sample
const hide = this.$message.loading(this.isStrip ? 'Stripping...' : 'Comparing...', 0)
try {
let param = {
fileName,
compareFileName: selectedFileName,
},
url = '/gamma/Compare'
// 如果是Strip
if (this.isStrip) {
this.ratio = await this.$refs.stripModal.getRatio()
param = {
fileName,
stripFileName: selectedFileName,
ratioRate: this.ratio,
}
url = '/gamma/Strip'
}
const { success, result, message } = await getAction(url, param)
if (success) {
if (this.isStrip) {
const { reference: referenceLine, result: compareLine } = result
this.channelData.stripSumOrCutLine = compareLine[0]
this.energyData.stripSumOrCutLine = compareLine[1]
this.redrawLineBySeriesName(
'StripSumOrCut',
this.energyData.stripSumOrCutLine,
this.channelData.stripSumOrCutLine,
true,
this.channelData.stripSumOrCutLine.color
)
this.channelData.stripReferenceLine = referenceLine[0]
this.energyData.stripReferenceLine = referenceLine[1]
this.redrawLineBySeriesName(
'StripReference',
this.energyData.stripReferenceLine,
this.channelData.stripReferenceLine,
true,
this.channelData.stripReferenceLine.color
)
this.$nextTick(() => {
this.thumbnailOption.yAxis.max = getAxisMax(this.getChart(), 'yAxis')
})
} else {
const [channelData, energyData] = result
this.channelData.compareLine = channelData
this.energyData.compareLine = energyData
this.redrawLineBySeriesName('Compare', energyData, channelData, true, channelData.color)
this.$nextTick(() => {
this.thumbnailOption.yAxis.max = getAxisMax(this.getChart(), 'yAxis')
})
}
this.$emit('compareSuccess', this.isStrip)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
hide()
}
},
// 从DB选择的文件之间对比
async handleDBFileSelect(sampleId, isStrip, isOperating) {
if (this.isLoading) {
this.$message.warn('Sample is Loading')
return
}
this.handleResetChart()
this.clearCompareLine()
if (isOperating) {
return
}
this.isStrip = isStrip
const { inputFileName: fileName } = this.sample
const hide = this.$message.loading(isStrip ? 'Stripping...' : 'Comparing...', 0)
try {
let param = {
fileName,
sampleId,
},
url = '/gamma/CompareDB'
// 如果是Strip
if (isStrip) {
this.ratio = await this.$refs.stripModal.getRatio()
param = {
fileName,
sampleId,
ratioRate: this.ratio,
}
url = '/gamma/StripDB'
}
const { success, result, message } = await getAction(url, param)
if (success) {
if (isStrip) {
const { reference: referenceLine, result: compareLine } = result
this.channelData.stripSumOrCutLine = compareLine[0]
this.energyData.stripSumOrCutLine = compareLine[1]
this.redrawLineBySeriesName(
'StripSumOrCut',
this.energyData.stripSumOrCutLine,
this.channelData.stripSumOrCutLine,
true,
this.channelData.stripSumOrCutLine.color
)
this.channelData.stripReferenceLine = referenceLine[0]
this.energyData.stripReferenceLine = referenceLine[1]
this.redrawLineBySeriesName(
'StripReference',
this.energyData.stripReferenceLine,
this.channelData.stripReferenceLine,
true,
this.channelData.stripReferenceLine.color
)
this.$nextTick(() => {
this.thumbnailOption.yAxis.max = getAxisMax(this.getChart(), 'yAxis')
})
} else {
const [channelData, energyData] = result
this.channelData.compareLine = channelData
this.energyData.compareLine = energyData
this.redrawLineBySeriesName('Compare', energyData, channelData, true, channelData.color)
this.$nextTick(() => {
this.thumbnailOption.yAxis.max = getAxisMax(this.getChart(), 'yAxis')
})
}
this.$emit('compareSuccess', isStrip)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
hide()
}
},
// 移除 Compare 线
clearCompareLine() {
const compareLine = findSeriesByName(this.option.series, 'Compare')
if (compareLine) {
compareLine.data = []
}
this.channelData.compareLine = undefined
this.energyData.compareLine = undefined
const stripStripSumOrCutLine = findSeriesByName(this.option.series, 'StripSumOrCut')
if (stripStripSumOrCutLine) {
stripStripSumOrCutLine.data = []
}
this.channelData.stripSumOrCutLine = undefined
this.energyData.stripSumOrCutLine = undefined
const stripReferenceLine = findSeriesByName(this.option.series, 'StripReference')
if (stripReferenceLine) {
stripReferenceLine.data = []
}
this.channelData.stripReferenceLine = undefined
this.energyData.stripReferenceLine = undefined
this.resetThumbnailChartDataMax()
},
// 重新分析
async reProcessing(showMessage = true) {
var userId = store.getters.userInfo.id
if (this.isProcessing) {
return
}
if (this.isLoading) {
this.$message.warn('Sample is Loading')
return
}
try {
this.isLoading = true
const str = `&processKey=${userId}_${this.timerStamp}`
const { inputFileName: fileName } = this.sample
const { success, result, message } = await postAction(
`/gamma/Reprocessing?fileName=${fileName}${showMessage ? str : ''}`
)
if (success) {
this.reprocessingModalVisible = false //如果分析成功了,分析进度的弹窗即便是没有接收到后面的 ws 消息也要关闭弹窗
this.isReAnalyed = true
this.bAnalyed = result.bAnalyed
this.$emit('reAnalyed', this.isReAnalyed)
this.handleResetState()
result.DetailedInformation = this.detailedInfomation
this.dataProcess(result)
return success
} else {
this.isLoading = false
this.reprocessingModalVisible = false
if (showMessage) {
const arr = message.split('\n')
this.$warning({
title: 'Warning',
content: () => arr.map((text) => <div>{text}</div>),
})
}
return message
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
handleCloseModal() {
this.reprocessingModalVisible = false
this.abc = false
},
/**
* 重置缩略图表y轴最大值
*/
resetThumbnailChartDataMax() {
this.thumbnailOption.yAxis.max = 'dataMax'
},
/**
* 重置图表配置
*/
resetChartOpts() {
this.opts.notMerge = false
this.option.brush = { toolbox: [] }
},
/**
* 根据两个点生成一个markLine直线
*/
generateLineDataByTwoPoints(point1, point2) {
return [
{
xAxis: point1[0],
yAxis: point1[1],
},
{
xAxis: point2[0],
yAxis: point2[1],
},
]
},
/**
* 根据energy获取channel
* @param {number} energy
*/
getChannelByEnergy(energy) {
let channel = 0
const pointlist = this.energyData.all.pointlist
for (let index = 1; index < pointlist.length; index++) {
const currEnergy = pointlist[index].x
if (currEnergy >= energy) {
const prevEnergy = pointlist[index - 1].x
if (currEnergy - energy > energy - prevEnergy.x) {
channel = index
} else {
channel = index + 1
}
break
}
}
return channel
},
/**
* 根据channel获取energy
* @param {number} channel
*/
getEnergyByChannel(channel) {
const energyItem = this.energyData.all.pointlist ? this.energyData.all.pointlist[channel - 1] : {}
return energyItem ? energyItem.x : 0
},
/**
* 重置页面信息
*/
handleResetState() {
this.handleResetChart()
this.selectedChannel = -1
this.nuclideLibraryList = []
this.closePeakInfomationTooltip()
this.clearPeakLine()
this.option.xAxis.name = 'Channel'
this.option.yAxis.type = 'log'
this.thumbnailOption.yAxis.type = 'log'
this.option.series[0].markLine.data[0].xAxis = -1
this.setChartBottomTitle(0, 0, 0)
},
/**
* 颜色改变
* @param {*} colorConfig
*/
handleColorChange(colorConfig) {
// 如果还没加载完,加载新的
if (this.isLoading) {
this.getSampleDetail()
}
// 否则修改已有颜色
else {
this.changeColor(colorConfig)
}
},
// 修改颜色
changeColor(colorConfig) {
const {
Color_Spec,
Color_Peak,
Color_Lc,
Color_Base,
Color_Scac,
Color_Compare,
Color_Reference,
Color_SpecSum,
Color_SpecCut,
} = colorConfig
this.channelData.spectrumLine.color = Color_Spec
this.energyData.spectrumLine.color = Color_Spec
for (let i = 0; i < this.channelData.peakGroup.length; i++) {
this.channelData.peakGroup[i].color = Color_Peak
this.energyData.peakGroup[i].color = Color_Peak
}
this.channelData.lcLine.color = Color_Lc
this.energyData.lcLine.color = Color_Lc
this.channelData.baseLine.color = Color_Base
this.energyData.baseLine.color = Color_Base
this.channelData.scacLine.color = Color_Scac
this.energyData.scacLine.color = Color_Scac
if (this.channelData.compareLine) {
this.channelData.compareLine.color = Color_Compare
if (this.energyData.compareLine) {
this.energyData.compareLine.color = Color_Compare
}
}
this.changeColorBySeriesName('Spectrum', Color_Spec)
this.changePeakLineColor(Color_Peak)
this.changeColorBySeriesName('LcLine', Color_Lc)
this.changeColorBySeriesName('BaseLine', Color_Base)
this.changeColorBySeriesName('ScacLine', Color_Scac)
if (this.isStrip) {
this.changeColorBySeriesName('StripSumOrCut', this.ratio >= 0 ? Color_SpecSum : Color_SpecCut)
this.changeColorBySeriesName('StripReference', Color_Reference)
} else {
this.changeColorBySeriesName('Compare', Color_Compare)
}
const thumbnailChartSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
thumbnailChartSeries.itemStyle.color = Color_Spec
},
/**
* 根据series名修改颜色
* @param {*} seriesName
* @param {*} color
*/
changeColorBySeriesName(seriesName, color) {
const series = findSeriesByName(this.option.series, seriesName)
series.itemStyle.color = color
},
// 改变Peak的颜色
changePeakLineColor(color) {
this.option.series
.filter((item) => item.name.includes('Peak_'))
.forEach((item) => {
item.itemStyle.color = color
})
},
isScatter() {
return this.graphAssistance.spectrumType == 'Scatter'
},
getChart() {
return this.$refs.chartRef.getChartInstance()
},
getThumbnailChart() {
return this.$refs.thumbnailChartRef.getChartInstance()
},
/**
* 设置图表数据和颜色
*/
setSeriesData(series, seriesName, data, color) {
const find = findSeriesByName(series, seriesName)
find.data = data
if (color) {
find.itemStyle.color = color
}
},
/**
* 转换pointlist类型数据到series的data可用的数据
*/
transformPointListData(pointlist) {
if (!pointlist) {
return []
}
return pointlist.map(({ x, y }) => [x, y])
},
/**
* 在返回的allData中查找指定的数据
* @param {Array} allData
* @param {*} name
* @param {*} group
*/
getLineData(allData, name, group, isList = false) {
const arrFunc = isList ? Array.prototype.filter : Array.prototype.find
return arrFunc.call(allData, (item) => item.name == name && item.group == group) || {}
},
},
watch: {
currStep: {
handler(val) {
if (val && val == '0') {
this.abc = true
this.reprocessingModalVisible = true
}
},
immediate: true,
},
sample: {
async handler(newVal, oldVal) {
console.log('newValnewVal', newVal)
this.graphAssistance.axisType = 'Channel'
this.handleResetState()
const sampleData = await this.$store.dispatch('GET_SAMPLE_DATA', newVal.inputFileName)
if (sampleData) {
this.cancelLastRequest()
this.isLoading = false
this.dataProcess(sampleData.data, sampleData.from)
} else {
if (newVal.sampleId) {
this.getSampleDetail()
} else {
this.getSampleDetail_file()
}
}
},
immediate: true,
},
updateFlag: {
handler(val) {
this.newCheckBox_updateCal = val
},
immediate: true,
},
currSampleDet: {
handler(val) {
this.detailedInfomation = [...val]
},
},
},
computed: {
// 是不是Energy
isEnergy() {
return this.graphAssistance.axisType == 'Energy'
},
// 获取x轴最小值
xAxisMin() {
return this.isEnergy ? 0.01 : 1
},
},
}
</script>
<style lang="less" scoped>
.gamma-analysis {
height: 100%;
.ant-spin-nested-loading {
height: 100%;
::v-deep {
.ant-spin-container {
height: 100%;
}
}
}
// 二级操作栏开始
.spectrum-analysis-sub-operators {
flex-shrink: 0;
margin-bottom: 19px;
display: flex;
gap: 11px;
flex-wrap: nowrap;
overflow: auto;
height: 46px;
align-items: center;
.pop-over-with-icon {
height: 32px;
&:nth-child(1) {
width: 216px;
}
&:nth-child(2) {
width: 182px;
}
&:nth-child(3) {
width: 170px;
}
&:nth-child(5) {
width: 156px;
}
}
.peak-info {
width: 226px;
height: 32px;
display: inline-block;
}
}
// 二级操作栏结束
&-main {
height: calc(100% - 65px);
display: flex;
overflow: auto hidden;
position: relative;
}
&-chart {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
outline: none;
}
&-thumbnail {
position: absolute;
top: 50px;
right: 10px;
width: 500px;
height: 20%;
background-color: #153e44;
}
}
</style>
<style lang="less">
.peak-infomation-tooltip {
position: absolute;
border-style: solid;
white-space: nowrap;
z-index: 9;
box-shadow: rgba(0, 0, 0, 0.2) 1px 2px 10px;
border-width: 1px;
border-radius: 4px;
padding: 10px;
border-color: rgb(255, 255, 255);
pointer-events: none;
background-color: #55a9fe;
border-color: #55a9fe;
}
</style>