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

1529 lines
45 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 placement="bottomLeft">
QC Flags
<qc-flags slot="content" :data="qcFlags" />
</pop-over-with-icon>
<pop-over-with-icon>
Graph Assistance
<graph-assistance
v-if="!isLoading"
slot="content"
@change="handleGraphAssistanceChange"
@reset="handleResetChart"
/>
</pop-over-with-icon>
<a-popover
overlayClassName="popover-with-icon"
:visible="nuclideLibraryVisible"
@click="handleChangeNuclideVisible"
placement="bottom"
>
<div class="pop-over-with-icon">
<span class="text"> Nuclide Library </span>
<img src="@/assets/images/global/select-down.png" alt="" />
</div>
<a-spin slot="content" :spinning="isLoadingNuclide">
<nuclide-library :list="nuclideLibraryList" @dblclick="handleNuclideDblClick" />
</a-spin>
</a-popover>
<div class="peak-info">
<button-with-switch-icon @change="handlePeakInfoChange" @click="handleTogglePeak"></button-with-switch-icon>
</div>
</div>
<!-- 二级交互栏结束 -->
<!-- 主体部分 -->
<div class="gamma-analysis-main">
<div class="gamma-analysis-chart">
<CustomChart
ref="chartRef"
:option="option"
:opts="opts"
@zr:click="handleChartClick"
@zr:dblclick="handleChartDblClick"
@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"
/>
<compare-file-list-modal v-model="compareFileListModalVisible" @compareWithFile="handleCompareWithFile" />
<!-- ReProcessing 弹窗开始 -->
<re-processing-modal
v-if="abc"
v-model="reprocessingModalVisible"
:bAnalyed="bAnalyed"
:currStep="currStep"
:checkBoxFlag="checkBox_updateCal"
:newCheckBoxFlag="newCheckBox_updateCal"
@closeModal="haCndleCloseModal"
/>
<!-- 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.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'
export default {
props: {
sample: {
type: Object,
},
updateFlag: {
type: String,
},
},
components: {
CustomChart,
PopOverWithIcon,
DetailedInfomation,
QcFlags,
GraphAssistance,
NuclideLibrary,
ButtonWithSwitchIcon,
NuclideReviewModal,
CompareFileListModal,
ReProcessingModal,
},
data() {
return {
abc: false,
isLoading: false,
isLoadingNuclide: false,
option: cloneDeep(GammaOptions.option),
opts: {
notMerge: false,
},
thumbnailOption: cloneDeep(GammaOptions.thumbnailOption),
detailedInfomation: [],
qcFlags: [],
graphAssistance: cloneDeep(graphAssistance),
nuclideLibraryVisible: false,
channelData: {
peakGroup: [],
spectrumLine: null,
baseLine: null,
lcLine: null,
scacLine: null,
all: null,
baseLineCP: [],
},
energyData: {
peakGroup: [],
spectrumLine: null,
baseLine: null,
lcLine: null,
scacLine: null,
all: null,
baseLineCP: [],
},
nuclideLibraryList: [], // 当前鼠标点击选中的channel
peakInfomationTooltip: {
// Peak Infomation的位置
visible: false,
content: '',
top: 0,
left: 0,
},
nuclideReview: {
visible: false,
nuclide: '',
},
currChannel: -1,
compareFileListModalVisible: false, // Compare 弹窗
reprocessingModalVisible: false, // 重新分析弹窗
isProcessing: false, // 正在处理
websock: null,
lockReconnect: false,
bAnalyed: false, //是否重新分析
checkBox_updateCal: false, //update复选框状态
newCheckBox_updateCal: false, //update复选框状态
currStep: '',
}
},
created() {
this.setChartBottomTitle(0, 0, 0)
this.option.tooltip.formatter = this.tooltipFormatter
this.$bus.$on('colorChange', this.handleColorChange)
this.$bus.$on('gammaRefresh', this.handleRefresh)
this.$bus.$on('accept', this.handleAccept)
},
destroyed() {
this.cancelLastRequest()
this.$bus.$off('colorChange', this.handleColorChange)
this.$bus.$off('gammaRefresh', this.handleRefresh)
this.$bus.$off('accept', this.handleAccept)
},
mounted() {
this.option.brush = { toolbox: [] }
this.initWebSocket()
},
methods: {
initWebSocket: function () {
console.log('qweqwerq')
// WebSocket与普通的请求所用协议有所不同ws等同于httpwss等同于https
var userId = store.getters.userInfo.id
var url =
window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://') + '/websocket/' + userId
//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 } = this.sample
try {
this.isLoading = true
this.handleResetState()
// const { success, result, message } = Response
this.cancelLastRequest()
const cancelToken = this.createCancelToken()
const { success, result, message } = await getAction(
'/gamma/gammaByDB',
{
dbName,
sampleId,
},
cancelToken
)
console.log('%c [ result ]-243', 'font-size:13px; background:pink; color:#bf2c9f;', result)
if (success) {
this.dataProsess(result, 'db')
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
async getSampleDetail_file() {
const { inputFileName: fileName } = this.sample
try {
this.isLoading = true
this.handleResetState()
// 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.dataProsess(result, 'file')
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
cancelLastRequest() {
if (this._cancelToken && typeof this._cancelToken == 'function') {
this._cancelToken()
}
},
createCancelToken() {
const cancelToken = new axios.CancelToken((c) => {
this._cancelToken = c
})
return cancelToken
},
dataProsess(result, flag) {
this.isLoading = false
const {
dead_time,
live_time,
real_time,
start_time,
DetailedInformation,
QCFlag,
allData,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
} = result
if (flag && (flag == 'dab' || flag == 'file')) {
this.bAnalyed = result.bAnalyed
this.checkBox_updateCal = result.checkBox_updateCal
this.newCheckBox_updateCal = '2'
console.log(this.checkBox_updateCal)
}
this.detailedInfomation = DetailedInformation
this.qcFlags = QCFlag
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()
const series = []
// 推入Spectrum Line
series.push(
buildLineSeries(
'Spectrum',
this.transformPointListData(shadowChannelChart.pointlist),
shadowChannelChart.color,
{
symbolSize: 2,
markLine: {
silent: true,
symbol: 'none',
label: {
show: false,
},
lineStyle: {
color: 'red',
width: 1,
},
data: [{ xAxis: -1 }],
},
}
)
)
// 右上角缩略图设置Spectrum Line 数据
this.setSeriesData(
this.thumbnailOption.series,
'Spectrum',
this.transformPointListData(shadowChannelChart.pointlist),
shadowChannelChart.color
)
// 推入BaseLine
series.push(
buildLineSeries('BaseLine', this.transformPointListData(channelBaseLine.pointlist), channelBaseLine.color, {
zlevel: 2,
})
)
// 推入LcLine线
series.push(
buildLineSeries('LcLine', this.transformPointListData(channelLcLine.pointlist), channelLcLine.color, {
zlevel: 3,
})
)
// 推入Scac线
series.push(
buildLineSeries('ScacLine', this.transformPointListData(channelScacLine.pointlist), channelScacLine.color, {
zlevel: 4,
})
)
// 推入基线控制点
series.push({
name: 'BaseLine_Ctrl_Point',
type: 'scatter',
data: shapeChannelData.map(({ size, color, point: { x, y } }) => {
return {
value: [x, y],
itemStyle: {
color: 'transparent',
borderColor: color,
borderWidth: size / 2,
},
}
}),
emphasis: {
disabled: true,
},
animation: false,
zlevel: 5,
})
// 推入Peak Line
const peakLines = []
channelPeakGroup.forEach((item, index) => {
peakLines.push(
buildLineSeries(`Peak_${index}`, this.transformPointListData(item.pointlist), item.color, {
zlevel: 6,
})
)
})
series.push(...peakLines)
// 推入Compare Line
series.push(
buildLineSeries('Compare', [], '#fff', {
symbolSize: 2,
})
)
this.option.series = series
},
// 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(energy)
} else {
const allPointList = this.energyData.all.pointlist
channel = parseInt(value.toFixed())
energy = allPointList && allPointList[channel - 1]
energy = energy ? energy.x.toFixed(2) : undefined
}
return `<div class="channel">Channel: ${channel}</div>
<div class="energy">${energy ? `Energy: ${energy}` : ''}</div>`
},
// Graph Assistance 操作
handleGraphAssistanceChange({ type, label, value }) {
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
const thumbnailSpectrumLineSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
const compareLineSeries = findSeriesByName(this.option.series, 'Compare')
// 类型变化
if (type == 'labelChange') {
switch (label) {
case 'Linear':
this.option.yAxis.type = 'value'
this.thumbnailOption.yAxis.type = 'value'
this.handleResetChart()
break
case 'Log10':
this.option.yAxis.type = 'log'
this.thumbnailOption.yAxis.type = 'log'
this.handleResetChart()
break
case 'Channel':
case 'Energy':
this.graphAssistance.axisType = label
this.option.xAxis.name = label
this.handleResetChart()
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.channelCompareLine) {
this.redrawLineBySeriesName('Compare', this.energyCompareLine, this.channelCompareLine)
}
break
case 'Lines':
this.graphAssistance.spectrumType = 'Lines'
spectrumLineSeries.type = 'line'
spectrumLineSeries.symbol = 'none'
thumbnailSpectrumLineSeries.type = 'line'
thumbnailSpectrumLineSeries.symbol = 'none'
compareLineSeries.type = 'line'
compareLineSeries.symbol = 'none'
this.redrawLineBySeriesName('Spectrum', this.energyData.spectrumLine, this.channelData.spectrumLine)
if (this.channelCompareLine) {
this.redrawLineBySeriesName('Compare', this.energyCompareLine, this.channelCompareLine)
}
break
case 'Scatter':
this.graphAssistance.spectrumType = 'Scatter'
spectrumLineSeries.type = 'scatterGL'
spectrumLineSeries.symbol = 'circle'
thumbnailSpectrumLineSeries.type = 'scatterGL'
thumbnailSpectrumLineSeries.symbol = 'circle'
compareLineSeries.type = 'scatterGL'
compareLineSeries.symbol = 'circle'
this.$nextTick(() => {
this.rangeScatter()
})
break
}
}
// 值变化
else if (type == 'valueChange') {
this.graphAssistance[label] = value
switch (label) {
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
case 'Lc':
this.redrawLineBySeriesName('LcLine', this.energyData.lcLine, this.channelData.lcLine, value)
break
case 'SCAC':
this.redrawLineBySeriesName('ScacLine', this.energyData.scacLine, this.channelData.scacLine, value)
break
}
}
},
handleChangeNuclideVisible() {
this.nuclideLibraryVisible = !this.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,
},
}
})
},
// 重绘Peak Line
redrawPeakLine() {
this.option.series = this.option.series.filter((item) => {
return !item.name.includes('Peak_')
})
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, {
zlevel: 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)
}
},
// 设置图表底部的标题
setChartBottomTitle(channel, energy, counts) {
this.option.title.text = `{a|Channel:${channel}} {a|Energy:${energy}} {a|Counts:${counts}} {a|Detectability:0}`
},
// 根据xAixs值找channel、energy和counts
getEnergyAndCountsByXAxis(xAxis) {
let channel, energy, counts
if (this.isEnergy()) {
channel = this.getChannelByEnergy(xAxis)
energy = xAxis.toFixed(2)
counts = this.energyData.all.pointlist[channel - 1]
} else {
channel = parseInt(xAxis.toFixed())
energy = this.energyData.all.pointlist && this.energyData.all.pointlist[channel - 1].x.toFixed(2)
counts = this.channelData.all.pointlist[channel - 1]
}
return {
channel,
energy,
counts: counts.y,
}
},
// 双击还原
handleChartDblClick() {
this.handleResetChart()
},
// 获取 Nuclide Library 数据
async getSelPosNuclide(channel) {
this.currChannel = channel
try {
this.isLoadingNuclide = true
const { sampleId, inputFileName: fileName } = this.sample
const { success, result, message } = await getAction('/gamma/getSelPosNuclide', {
sampleId,
channel,
fileName,
})
if (success) {
const { possible } = result
this.nuclideLibraryList = possible
} else {
this.$message.error(message)
}
} catch (error) {
this.list = []
console.error(error)
} finally {
this.isLoadingNuclide = false
}
},
// Nuclide Library 单项双击
handleNuclideDblClick(nuclide) {
this.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 - 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
// 获取每一段 Channel 中的最大值
const maxXAxises = this.channelData.peakGroup.map((item) => {
const allY = item.pointlist.map((item) => item.y)
const max = item.pointlist.find((point) => point.y == Math.max(...allY))
return max.x
})
let find = null
if (direction == 'right') {
// 找到第一个比prevAxis大的xAxis
find = maxXAxises.find((xAxis) => xAxis > prevAxis)
if (find) {
spectrumLineSeries.markLine.data[0].xAxis = find
}
} else if (direction == 'left') {
// 找到第一个比prevAxis小的xAxis
find = maxXAxises.reverse().find((xAxis) => xAxis < prevAxis)
if (find) {
spectrumLineSeries.markLine.data[0].xAxis = find
}
}
if (find) {
this.getSelPosNuclide(find)
const { channel, energy, counts } = this.getEnergyAndCountsByXAxis(find)
this.setChartBottomTitle(channel, energy, counts)
}
},
// 鼠标按下时开启可刷选状态
handleMouseDown() {
this.getChart().dispatchAction({
type: 'takeGlobalCursor',
// 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
key: 'brush',
brushOption: {
// 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
brushType: 'rect',
},
})
},
handleMouseUp() {
if (this.timer) {
window.clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
this.clearBrush()
}, 0)
},
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
if (this.isEnergy()) {
const channel1 = this.getChannelByEnergy(x1)
const channel2 = this.getChannelByEnergy(x2)
this.setThumbnailChartRect(channel1, y2, channel2, y1)
} else {
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.channelCompareLine) {
const channelCompareLine = {
...this.channelCompareLine,
pointlist: isReset
? this.pointlistLimitY(this.channelCompareLine.pointlist)
: this.pointlistLimit(this.channelCompareLine.pointlist, x1, x2, y1, y2),
}
const energyCompareLine = {
...this.energyCompareLine,
pointlist: isReset
? this.pointlistLimitY(this.energyCompareLine.pointlist)
: this.pointlistLimit(this.energyCompareLine.pointlist, x1, x2, y1, y2),
}
this.redrawLineBySeriesName('Compare', energyCompareLine, channelCompareLine)
}
},
/**
* 筛选范围内的点
* @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 = Math.ceil((x2 - x1) / 2)
// 缩略图最大值转为pix
const [, maxYAxisPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [
0,
getAxisMax(thumbnailChart, 'yAxis'),
])
const [, minYAxisPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, 1])
let [xAxis, yAxis] = point
const xAxisMax = getAxisMax(thumbnailChart, 'xAxis')
const xAxisLimit = rangeNumber(1 + halfWidth, xAxisMax - halfWidth)
const halfHeightPixel = this.halfHeightPixel
const yAxisLimit = rangeNumber(maxYAxisPixel + halfHeightPixel, minYAxisPixel - halfHeightPixel)
xAxis = xAxisLimit(xAxis)
let [, yAxisPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, yAxis])
yAxisPixel = yAxisLimit(yAxisPixel)
const minYAxis = thumbnailChart.convertFromPixel({ seriesIndex: 0 }, [0, yAxisPixel + halfHeightPixel])[1] // 再把y轴最小值从pix转为yAxis
const maxYAxis = thumbnailChart.convertFromPixel({ seriesIndex: 0 }, [0, yAxisPixel - halfHeightPixel])[1]
this.setThumbnailChartRect(xAxis - halfWidth, maxYAxis, xAxis + halfWidth, minYAxis)
if (this.isEnergy()) {
const x1 = parseInt(this.energyData.spectrumLine.pointlist[xAxis - halfWidth].x)
const x2 = parseInt(this.energyData.spectrumLine.pointlist[xAxis + halfWidth].x)
this.option.xAxis.min = x1
this.option.xAxis.max = x2
} else {
this.option.xAxis.min = xAxis - halfWidth
this.option.xAxis.max = xAxis + halfWidth
}
this.option.yAxis.min = minYAxis
this.option.yAxis.max = maxYAxis
this.$nextTick(() => {
this.rangeScatter()
})
}
},
/**
* 重置图表
*/
handleResetChart() {
this.option.xAxis.min = 1
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) {
this.handleResetState()
data.DetailedInformation = this.detailedInfomation
this.dataProsess(data)
},
// 分析工具Accept时刷新部分数据
handleAccept() {
console.log('%c [ 分析工具Accept时刷新部分数据 ]-1046', 'font-size:13px; background:pink; color:#bf2c9f;')
this.clearCompareLine()
},
// 显示比较弹窗
showCompareModal() {
if (this.isLoading) {
this.$message.warn('Sample is Loading')
return
}
this.handleResetChart()
this.clearCompareLine()
this.compareFileListModalVisible = true
},
// 文件之间对比
handleCompareWithFile([channelData, energyData]) {
this.channelCompareLine = channelData
this.energyCompareLine = energyData
this.redrawLineBySeriesName('Compare', energyData, channelData, true, channelData.color)
if (this.isScatter()) {
lineSeries.type = 'scatterGL'
}
this.$nextTick(() => {
this.thumbnailOption.yAxis.max = getAxisMax(this.getChart(), 'yAxis')
})
},
// 移除 Compare 线
clearCompareLine() {
const compareLine = findSeriesByName(this.option.series, 'Compare')
if (compareLine) {
compareLine.data = []
this.resetThumbnailChartDataMax()
}
this.channelCompareLine = undefined
this.energyCompareLine = undefined
},
// 重新分析
async reProcessing() {
if (this.isProcessing) {
return
}
if (this.isLoading) {
this.$message.warn('Sample is Loading')
return
}
try {
this.isLoading = true
this.handleResetState()
const { inputFileName: fileName } = this.sample
const { success, result, message } = await postAction(`/gamma/Reprocessing?fileName=${fileName}`)
if (success) {
result.DetailedInformation = this.detailedInfomation
this.dataProsess(result)
} else {
this.isLoading = false
const arr = message.split('\n')
this.$warning({
title: 'Warning',
content: () => arr.map((text) => <div>{text}</div>),
})
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
haCndleCloseModal() {
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
},
/**
* 重置页面信息
*/
handleResetState() {
this.handleResetChart()
this.selectedChannel = -1
this.nuclideLibraryList = []
this.closePeakInfomationTooltip()
this.option.series = []
this.option.xAxis.name = 'Channel'
this.option.yAxis.type = 'value'
this.thumbnailOption.yAxis.type = 'value'
if (this.option.series.length) {
const spectrumLineSeries = findSeriesByName(this.option.series, 'Spectrum')
spectrumLineSeries.type = 'line'
spectrumLineSeries.symbol = 'none'
spectrumLineSeries.markLine.lineStyle.width = 2
}
const thumbnailSpectrumLineSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
thumbnailSpectrumLineSeries.type = 'line'
thumbnailSpectrumLineSeries.symbol = 'none'
this.graphAssistance = cloneDeep(graphAssistance)
},
/**
* 颜色改变
* @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_Strip, Color_Fitbase } =
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.channelCompareLine) {
this.channelCompareLine.color = Color_Compare
this.energyCompareLine.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)
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
})
},
isEnergy() {
return this.graphAssistance.axisType == 'Energy'
},
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) {
console.log('dfad', val)
if (val && val == '0') {
this.abc = true
this.reprocessingModalVisible = true
}
},
immediate: true,
},
sample: {
handler(newVal, oldVal) {
console.log('newValnewVal', newVal)
if (newVal.sampleId) {
this.getSampleDetail()
} else {
this.getSampleDetail_file()
}
},
immediate: true,
},
updateFlag: {
handler(val) {
console.log('dfad', val)
this.newCheckBox_updateCal = val
},
immediate: true,
},
},
}
</script>
<style lang="less" scoped>
.gamma-analysis {
height: 100%;
.ant-spin-nested-loading {
height: 100%;
::v-deep {
.ant-spin-container {
height: 100%;
}
}
}
&-main {
height: calc(100% - 51px);
display: flex;
overflow: auto hidden;
position: relative;
}
&-chart {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
&-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>