640 lines
16 KiB
Vue
640 lines
16 KiB
Vue
<template>
|
||
<custom-modal v-model="visible" :width="1280" title="Efficiency Calibration" :footer="null" destroy-on-close>
|
||
<a-spin :spinning="isLoading">
|
||
<div class="energy-calibration">
|
||
<div class="left">
|
||
<!-- Calibration Data -->
|
||
<title-over-border title="Calibration Data">
|
||
<div class="calibration-data">
|
||
<a-form-model
|
||
:colon="false"
|
||
:labelCol="{
|
||
style: {
|
||
width: '70px',
|
||
textAlign: 'left',
|
||
flexShrink: 0
|
||
}
|
||
}"
|
||
:wrapperCol="{
|
||
style: {
|
||
flex: 1
|
||
}
|
||
}"
|
||
>
|
||
<a-form-model-item label="Energy">
|
||
<a-input type="number" v-model="model.energy"></a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item label="Efficiency">
|
||
<a-input type="number" v-model="model.efficiency"></a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item :label="' '">
|
||
<a-button type="primary" @click="handleInsert">Insert</a-button>
|
||
</a-form-model-item>
|
||
<a-form-model-item :label="' '">
|
||
<a-button type="primary" @click="handleModify">Modify</a-button>
|
||
</a-form-model-item>
|
||
<a-form-model-item :label="' '">
|
||
<a-button type="primary" @click="handleDelete">Delete</a-button>
|
||
</a-form-model-item>
|
||
</a-form-model>
|
||
<!-- 表格 -->
|
||
<custom-table
|
||
:columns="columns"
|
||
:list="list"
|
||
:pagination="false"
|
||
size="small"
|
||
:class="list.length ? 'has-data' : ''"
|
||
:scroll="{ y: 182 }"
|
||
:selectedRowKeys.sync="selectedRowKeys"
|
||
:canDeselect="false"
|
||
@rowClick="handleRowClick"
|
||
></custom-table>
|
||
<!-- 表格结束 -->
|
||
<div class="operators">
|
||
<div>
|
||
<a-button type="primary">Call</a-button>
|
||
<a-button type="primary">Save</a-button>
|
||
</div>
|
||
<div>
|
||
<a-select v-model="funcId" @change="recalculate">
|
||
<a-select-option v-for="(func, index) in functions" :key="index" :value="func.value">
|
||
{{ func.label }}
|
||
</a-select-option>
|
||
</a-select>
|
||
<a-button type="primary" @click="handleApply">Apply</a-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</title-over-border>
|
||
<!-- Equation -->
|
||
<title-over-border class="mt-20" title="Equation">
|
||
<div class="equation" v-html="equation"></div>
|
||
</title-over-border>
|
||
<!-- curve -->
|
||
<title-over-border class="mt-20" title="curve">
|
||
<div class="curve">
|
||
<custom-chart :option="option" :opts="opts" />
|
||
</div>
|
||
</title-over-border>
|
||
</div>
|
||
<div class="right">
|
||
<title-over-border title="Data Source" style="height: 100%">
|
||
<div class="data-source">
|
||
<div class="content">
|
||
<div
|
||
class="item"
|
||
:class="item == currSelectedDataSource ? 'active' : ''"
|
||
v-for="(item, index) in dataSourceList"
|
||
:key="index"
|
||
@click="handleDataSourceClick(item)"
|
||
>
|
||
{{ item }}
|
||
</div>
|
||
</div>
|
||
<div class="footer mt-20">
|
||
<a-button type="primary" @click="handleSetToCurrent">Set to Current</a-button>
|
||
<div class="mt-20">{{ appliedDataSource }}</div>
|
||
</div>
|
||
</div>
|
||
</title-over-border>
|
||
</div>
|
||
</div>
|
||
</a-spin>
|
||
</custom-modal>
|
||
</template>
|
||
|
||
<script>
|
||
import ModalMixin from '@/mixins/ModalMixin'
|
||
import TitleOverBorder from '../TitleOverBorder.vue'
|
||
import CustomChart from '@/components/CustomChart/index.vue'
|
||
import { getAction, postAction } from '@/api/manage'
|
||
import { cloneDeep } from 'lodash'
|
||
import { buildLineSeries } from '@/utils/chartHelper'
|
||
import SampleDataMixin from '../../SampleDataMixin'
|
||
|
||
const columns = [
|
||
{
|
||
title: 'Energy(keV)',
|
||
dataIndex: 'energy'
|
||
},
|
||
{
|
||
title: 'Efficiency',
|
||
dataIndex: 'efficiency'
|
||
},
|
||
{
|
||
title: 'Fit(keV)',
|
||
dataIndex: 'fit'
|
||
},
|
||
{
|
||
title: 'Delta(%)',
|
||
dataIndex: 'delta'
|
||
}
|
||
]
|
||
|
||
const initialOption = {
|
||
grid: {
|
||
top: 20,
|
||
right: 20,
|
||
bottom: 50,
|
||
left: 70
|
||
},
|
||
title: {
|
||
text: 'Channel',
|
||
textStyle: {
|
||
color: '#8FD4F8',
|
||
fontSize: 14,
|
||
fontWeight: 'normal'
|
||
},
|
||
right: 10,
|
||
bottom: 0
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
formatter: params => {
|
||
const [x, y] = params[0].value
|
||
const energy = parseInt(x)
|
||
const efficiency = y.toFixed(3)
|
||
return `<div class="channel">Energy: ${energy}</div>
|
||
<div class="energy">Efficiency: ${efficiency}</div>`
|
||
},
|
||
className: 'figure-chart-option-tooltip'
|
||
},
|
||
xAxis: {
|
||
min: 1,
|
||
max: 'dataMax',
|
||
axisLabel: {
|
||
color: '#fff'
|
||
},
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#fff'
|
||
}
|
||
},
|
||
splitLine: {
|
||
show: false
|
||
}
|
||
},
|
||
yAxis: {
|
||
axisLabel: {
|
||
color: '#fff'
|
||
},
|
||
axisTick: {
|
||
show: false
|
||
},
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#fff'
|
||
}
|
||
},
|
||
splitLine: {
|
||
show: false
|
||
},
|
||
name: 'keV',
|
||
nameLocation: 'center',
|
||
nameGap: 50,
|
||
nameTextStyle: {
|
||
color: '#8FD4F8',
|
||
fontSize: 14
|
||
}
|
||
},
|
||
series: []
|
||
}
|
||
|
||
const functions = [
|
||
{
|
||
label: 'Interpolation',
|
||
value: 1
|
||
},
|
||
{
|
||
label: 'HT Efficiency',
|
||
value: 5
|
||
},
|
||
{
|
||
label: 'Log Polynomial',
|
||
value: 6
|
||
},
|
||
{
|
||
label: 'Invlog Polynomial',
|
||
value: 8
|
||
},
|
||
{
|
||
label: 'HAE Efficiency(1-3)',
|
||
value: 93
|
||
},
|
||
{
|
||
label: 'HAE Efficiency(1-2)',
|
||
value: 94
|
||
},
|
||
{
|
||
label: 'HAE Efficiency(1-2-3)',
|
||
value: 95
|
||
}
|
||
]
|
||
|
||
export default {
|
||
components: { TitleOverBorder, CustomChart },
|
||
mixins: [ModalMixin, SampleDataMixin],
|
||
data() {
|
||
this.columns = columns
|
||
this.functions = functions
|
||
|
||
return {
|
||
isLoading: false,
|
||
equation: '',
|
||
dataSourceList: [],
|
||
list: [],
|
||
option: cloneDeep(initialOption),
|
||
selectedRowKeys: [],
|
||
model: {},
|
||
currSelectedDataSource: '',
|
||
appliedDataSource: '',
|
||
opts: {
|
||
notMerge: true
|
||
},
|
||
ECutAnalysis_Low: -1,
|
||
G_energy_span: -1,
|
||
funcId: 1
|
||
}
|
||
},
|
||
methods: {
|
||
async getData(currentText) {
|
||
try {
|
||
this.isLoading = true
|
||
const { sampleId, inputFileName: fileName } = this.sampleData
|
||
const { success, result, message } = await getAction('/gamma/EfficiencyCalibration', {
|
||
sampleId,
|
||
fileName,
|
||
currentText
|
||
})
|
||
this.isLoading = false
|
||
if (success) {
|
||
console.log('%c [ ]-220', 'font-size:13px; background:pink; color:#bf2c9f;', result)
|
||
const { list_dataSource, ECutAnalysis_Low, G_energy_span } = result
|
||
this.dataSourceList = list_dataSource
|
||
if (!currentText) {
|
||
this.currSelectedDataSource = list_dataSource[list_dataSource.length - 1]
|
||
this.appliedDataSource = list_dataSource[list_dataSource.length - 1]
|
||
}
|
||
|
||
this.ECutAnalysis_Low = ECutAnalysis_Low
|
||
this.G_energy_span = G_energy_span
|
||
|
||
this.handleResult(result)
|
||
} else {
|
||
this.$message.error(message)
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
}
|
||
},
|
||
|
||
handleResult(result) {
|
||
const { AllData, equation, param, table, uncert } = result
|
||
// 有数据
|
||
if (AllData) {
|
||
const [linePoint, scatterPoint] = AllData
|
||
this.equation = equation
|
||
this.param = param
|
||
this.uncert = uncert
|
||
|
||
this.list = table
|
||
this.generateTableId()
|
||
|
||
const series = []
|
||
series.push(
|
||
buildLineSeries(
|
||
'LineSeries',
|
||
linePoint.pointlist.map(({ x, y }) => [x, y]),
|
||
`rgb(${linePoint.color})`
|
||
)
|
||
)
|
||
series.push({
|
||
type: 'scatter',
|
||
data: scatterPoint.pointlist.map(({ x, y }) => {
|
||
return {
|
||
value: [x, y],
|
||
itemStyle: {
|
||
color: scatterPoint.color,
|
||
borderWidth: 0
|
||
}
|
||
}
|
||
}),
|
||
emphasis: {
|
||
disabled: true
|
||
},
|
||
animation: false,
|
||
zlevel: 20
|
||
})
|
||
this.option.series = series
|
||
}
|
||
// 没数据
|
||
else {
|
||
this.option.series = []
|
||
}
|
||
},
|
||
|
||
beforeModalOpen() {
|
||
this.selectedRowKeys = []
|
||
this.funcId = 1
|
||
this.getData()
|
||
},
|
||
|
||
// 表格单行点击
|
||
handleRowClick(row) {
|
||
this.model = cloneDeep(row)
|
||
},
|
||
|
||
// 插入
|
||
handleInsert() {
|
||
const energy = parseFloat(this.model.energy)
|
||
const efficiency = parseFloat(this.model.efficiency)
|
||
|
||
if (Number.isNaN(energy) || Number.isNaN(efficiency)) {
|
||
this.$message.warn('Format is invalid.')
|
||
return
|
||
}
|
||
|
||
if (energy <= this.ECutAnalysis_Low || energy >= this.G_energy_span) {
|
||
this.$message.warn('Energy is out of analysis range.')
|
||
return
|
||
}
|
||
|
||
let i,
|
||
num = this.list.length
|
||
for (i = 0; i < num; ++i) {
|
||
const currEnergy = this.list[i].energy
|
||
if (Math.abs(currEnergy - energy) < 0.001) {
|
||
this.$message.warn('The centroid has already existed!')
|
||
return
|
||
} else if (currEnergy > energy) {
|
||
break
|
||
}
|
||
}
|
||
|
||
this.list.splice(i, 0, {
|
||
energy: energy,
|
||
efficiency
|
||
})
|
||
|
||
this.uncert.splice(i, 0, 0.5)
|
||
|
||
this.selectedRowKeys = [i]
|
||
this.generateTableId()
|
||
|
||
this.recalculate()
|
||
},
|
||
|
||
// 生成table中数据的id,用以选中
|
||
generateTableId() {
|
||
this.list.forEach((item, index) => {
|
||
item.id = index
|
||
})
|
||
},
|
||
|
||
// 修改
|
||
handleModify() {
|
||
if (this.selectedRowKeys.length) {
|
||
const energy = parseFloat(this.model.energy)
|
||
const efficiency = parseFloat(this.model.efficiency)
|
||
|
||
if (Number.isNaN(energy) || Number.isNaN(efficiency)) {
|
||
this.$message.warn('Format is invalid.')
|
||
return
|
||
}
|
||
|
||
if (energy <= this.ECutAnalysis_Low || energy >= this.G_energy_span) {
|
||
this.$message.warn('Energy is out of analysis range.')
|
||
return
|
||
}
|
||
|
||
const [currSelectedIndex] = this.selectedRowKeys
|
||
|
||
this.list[currSelectedIndex].energy = energy
|
||
this.list[currSelectedIndex].efficiency = efficiency
|
||
|
||
this.uncert[currSelectedIndex] = 0
|
||
|
||
this.recalculate()
|
||
}
|
||
},
|
||
|
||
// 删除
|
||
handleDelete() {
|
||
if (this.selectedRowKeys.length) {
|
||
const [currSelectedIndex] = this.selectedRowKeys
|
||
|
||
this.list.splice(currSelectedIndex, 1)
|
||
this.uncert.splice(currSelectedIndex, 1)
|
||
this.generateTableId()
|
||
if (this.list.length) {
|
||
const selectedKey = this.selectedRowKeys[0]
|
||
if (selectedKey > this.list.length - 1) {
|
||
this.selectedRowKeys[0] = selectedKey - 1
|
||
}
|
||
} else {
|
||
this.selectedRowKeys = []
|
||
}
|
||
this.recalculate()
|
||
}
|
||
},
|
||
|
||
// 重新计算
|
||
async recalculate() {
|
||
try {
|
||
this.isLoading = true
|
||
const { sampleId, inputFileName: fileName } = this.sampleData
|
||
const { success, result, message } = await postAction('/gamma/changeDataEfficiency', {
|
||
sampleId,
|
||
fileName,
|
||
m_vCurEnergy: this.list.map(item => item.energy),
|
||
m_vCurEffi: this.list.map(item => item.efficiency),
|
||
m_vCurUncert: this.uncert,
|
||
m_curParam: this.param,
|
||
funcId: this.funcId
|
||
})
|
||
if (success) {
|
||
this.handleResult(result)
|
||
} else {
|
||
this.$message.error(message)
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
this.isLoading = false
|
||
}
|
||
},
|
||
|
||
// 应用
|
||
async handleApply() {
|
||
try {
|
||
let curCalName = this.currSelectedDataSource
|
||
// 如果沒选中以Input开头的,也就是选中了PHD之类的
|
||
if (!curCalName.includes('Input')) {
|
||
curCalName = `Input ${this.dataSourceList.filter(item => item.includes('Input')).length + 1}`
|
||
}
|
||
|
||
const { sampleId, inputFileName: fileName } = this.sampleData
|
||
const { success, result, message } = await postAction('/gamma/applyDataEfficiency', {
|
||
m_vCurEnergy: this.list.map(item => item.energy),
|
||
m_vCurEffi: this.list.map(item => item.efficiency),
|
||
m_vCurUncert: this.uncert,
|
||
m_curParam: this.param,
|
||
curCalName,
|
||
sampleId,
|
||
fileName
|
||
})
|
||
if (success) {
|
||
this.handleDataSourceClick(curCalName)
|
||
} else {
|
||
this.$message.error(message)
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
}
|
||
},
|
||
|
||
// 右侧DataSource中的选项点击
|
||
handleDataSourceClick(item) {
|
||
this.currSelectedDataSource = item
|
||
this.getData(item)
|
||
},
|
||
|
||
handleSetToCurrent() {
|
||
this.appliedDataSource = this.currSelectedDataSource
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.energy-calibration {
|
||
display: flex;
|
||
margin-top: 5px;
|
||
|
||
.left {
|
||
flex: 1;
|
||
|
||
.calibration-data {
|
||
display: flex;
|
||
gap: 20px;
|
||
|
||
.ant-form {
|
||
width: 25%;
|
||
|
||
::v-deep {
|
||
.ant-form-item {
|
||
margin-bottom: 15px;
|
||
|
||
&-label,
|
||
&-control {
|
||
line-height: 32px;
|
||
}
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
.ant-btn {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
.ant-table-wrapper {
|
||
width: 50%;
|
||
|
||
&.has-data {
|
||
::v-deep {
|
||
.ant-table-body {
|
||
height: 182px;
|
||
background-color: #06282a;
|
||
}
|
||
}
|
||
}
|
||
|
||
::v-deep {
|
||
.ant-table-placeholder {
|
||
height: 183px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
.operators {
|
||
width: 25%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
|
||
.ant-select {
|
||
width: 100%;
|
||
}
|
||
.ant-btn {
|
||
width: 100%;
|
||
|
||
&:last-child {
|
||
margin-top: 10px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.equation {
|
||
height: 40px;
|
||
background-color: #1b5465;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.curve {
|
||
height: 400px;
|
||
}
|
||
}
|
||
|
||
.right {
|
||
width: 20%;
|
||
margin-left: 20px;
|
||
|
||
.data-source {
|
||
.content {
|
||
height: 330px;
|
||
background-color: #275466;
|
||
overflow: auto;
|
||
|
||
.item {
|
||
height: 32px;
|
||
line-height: 32px;
|
||
padding: 0 5px;
|
||
cursor: pointer;
|
||
|
||
&.active {
|
||
background-color: #296d81;
|
||
}
|
||
}
|
||
}
|
||
|
||
.footer {
|
||
.ant-btn {
|
||
width: 100%;
|
||
}
|
||
|
||
> div {
|
||
text-align: center;
|
||
height: 32px;
|
||
line-height: 32px;
|
||
background-color: #285367;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.mt-20 {
|
||
margin-top: 20px;
|
||
}
|
||
</style>
|