自建台站增加交互分析,并修改相关逻辑;修复部分BUG;

This commit is contained in:
Xu Zhimeng 2024-07-25 19:00:53 +08:00
parent 3ab8daa875
commit ffb75d9b35
13 changed files with 3499 additions and 26 deletions

View File

@ -170,13 +170,14 @@ export default {
this.sampleDetail = data
this.emitGetFiles(data)
}
// this.ROIAnalyzeLists = data.ROIAnalyzeLists
this.ROIAnalyzeLists = data.ROIAnalyzeLists
} else {
if (newVal.sampleId) {
this.getSampleDetail()
} else {
this.getSelfStationSampleDetail()
}
this.ROIAnalyzeLists = []
}
await this.$nextTick()
this.$refs.betaChartRef.handleUnzoom()
@ -185,6 +186,15 @@ export default {
deep: true,
},
},
created() {
this.$bus.$on('selfRefresh', this.handleRefresh)
this.$bus.$on('selfAccept', this.handleAccept)
},
beforeDestroy() {
this.cancelLastRequest()
this.$bus.$on('selfRefresh', this.handleRefresh)
this.$bus.$off('selfAccept', this.handleAccept)
},
methods: {
async getAnalyzeCurrentSpectrum() {
try {
@ -478,6 +488,8 @@ export default {
]
this.roiParamList = cloneDeep(this.boundaryList)
this.$bus.$emit('selfAnalyzeSampleTypeChange', val)
},
cancelLastRequest() {
if (this._cancelToken && typeof this._cancelToken == 'function') {
@ -507,9 +519,50 @@ export default {
this.$set(this.boundaryList, index, [start, end])
this.$set(this.roiParamList, index, [start, end])
},
},
destroyed() {
this.cancelLastRequest()
//
handleRefresh(data, index) {
this.ROIAnalyzeLists[index] = this.$set(this.ROIAnalyzeLists, index, data)
const { inputFileName } = this.sample
updateSampleData({
inputFileName,
key: 'ROIAnalyzeLists',
data: this.ROIAnalyzeLists,
})
},
// Accept
handleAccept(data, index) {
const {
allData,
peak,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
barChart,
BaseCtrls,
} = data
this.ROIAnalyzeLists[index] = this.$set(this.ROIAnalyzeLists, index, {
allData,
peak,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
barChart,
BaseCtrls,
})
const { inputFileName } = this.sample
updateSampleData({
inputFileName,
key: 'ROIAnalyzeLists',
data: this.ROIAnalyzeLists,
})
},
},
}
</script>

View File

@ -0,0 +1,60 @@
<template>
<custom-modal v-model="visible" :title="'Slope at ' + (index + 1)" :width="250">
<a-input-number v-model="value"></a-input-number>
<template slot="custom-footer">
<div class="footer">
<a-button type="primary" @click="handleOK">Ok</a-button>
<a-button @click="visible = false">Cancel</a-button>
</div>
</template>
</custom-modal>
</template>
<script>
export default {
data() {
return {
index: -1,
value: 0,
prevValue: 0,
allowNaN: false,
visible: false
}
},
methods: {
/**
* 打开弹窗
* @param {{ index: number; value: number; allowNaN: boolean; }} config
*/
open(config) {
this.index = config.index
this.value = config.value
this.prevValue = config.value
this.allowNaN = config.allowNaN
this.visible = true
},
handleOK() {
if (this.allowNaN || this.value) {
this.$emit('change', this.value, this.index, this.prevValue)
this.visible = false
} else {
this.$message.warn('Input value invalid.')
}
}
}
}
</script>
<style lang="less" scoped>
.ant-input-number {
width: 100%;
}
.footer {
display: flex;
justify-content: center;
gap: 10px;
}
</style>

View File

@ -0,0 +1,246 @@
<template>
<custom-modal centered v-model="visible" :width="1200" title="Fit Peaks and Baseline">
<a-spin :spinning="isLoading">
<custom-table :columns="columns" :list="list" :canSelect="false">
<template v-for="(slot, index) in slots" :slot="slot.slotName" slot-scope="{ record }">
<a-checkbox v-if="slot.isCheckbox" :key="index" v-model="record[slot.dataIndex]"> Fixed </a-checkbox>
<a-input
v-else
:key="index"
v-model="record[slot.dataIndex]"
:readOnly="slot.isStatic"
@change="handleInput(record, slot.dataIndex)"
></a-input>
</template>
</custom-table>
</a-spin>
<div slot="custom-footer">
<a-space>
<a-button type="primary" :disabled="isLoading" :loading="isAcceptting" @click="handlePeaks(true)">
Peaks
</a-button>
<a-button @click="visible = false">Cancel</a-button>
</a-space>
</div>
</custom-modal>
</template>
<script>
import { getAction, postAction } from '@/api/manage'
import ModalMixin from '@/mixins/ModalMixin'
import SampleDataMixin from '@/views/spectrumAnalysis/SampleDataMixin'
import { cloneDeep } from 'lodash'
const columns = [
{
title: 'Peak',
dataIndex: 'lab',
width: 100,
scopedSlots: {
customRender: 'lab',
},
isStatic: true,
},
{
title: 'Nuclide',
dataIndex: 'nuclide',
width: 100,
scopedSlots: {
customRender: 'nuclide',
},
isStatic: true,
},
{
title: 'Energy',
dataIndex: 'energy',
width: 100,
scopedSlots: {
customRender: 'Energy',
},
},
{
title: 'NetArea',
dataIndex: 'netArea',
width: 100,
scopedSlots: {
customRender: 'netArea',
},
},
{
title: 'FWHM',
dataIndex: 'fwhm',
width: 100,
scopedSlots: {
customRender: 'fwhm',
},
},
{
title: 'Step',
dataIndex: 'step',
width: 100,
scopedSlots: {
customRender: 'Step',
},
},
{
title: 'BWGamma',
dataIndex: 'bwGamma',
width: 100,
scopedSlots: {
customRender: 'BWGamma',
},
},
{
title: 'NetArea',
dataIndex: 'netAreaB',
width: 100,
scopedSlots: {
customRender: 'netAreaB',
},
isCheckbox: true,
},
{
title: 'Centroid',
dataIndex: 'centroid',
width: 100,
scopedSlots: {
customRender: 'Centroid',
},
isCheckbox: true,
},
{
title: 'FWHM',
dataIndex: 'fwhmB',
width: 100,
scopedSlots: {
customRender: 'fwhmB',
},
isCheckbox: true,
},
]
export default {
mixins: [ModalMixin, SampleDataMixin],
props: {
channel_1: {
type: Number,
},
channel_2: {
type: Number,
},
isInsertPeak: {
type: Boolean,
},
},
data() {
this.columns = columns
return {
list: [],
originalTablePeaksList: [],
isAcceptting: false,
}
},
methods: {
async handlePeaks(accept) {
try {
this.isAcceptting = true
const { inputFileName: fileName } = this.sampleData
const { success, result, message } = await postAction('/selfStation/acceptResults', {
fileName,
accept,
oldPeak: this.oldPeaks,
newPeak: this.newPeaks,
flag: this.isInsertPeak ? 'insert' : 'fit',
tablePeaksList: this.list,
})
if (success) {
this.visible = false
this.$emit(accept ? 'result' : 'cancel', result)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isAcceptting = false
}
},
//
handleInput(record, index) {
const find = this.originalTablePeaksList.find((item) => item.index == record.lab)
if (find) {
const table2NewPeakMap = {
energy: 'energy',
netArea: 'area',
fwhm: 'fwhm',
}
find[table2NewPeakMap[index]] = record[index]
}
},
async getData() {
const { sampleId, inputFileName: fileName } = this.sampleData
try {
let url = '/selfStation/fitPeak'
let params = {
left: this.channel_1,
right: this.channel_2,
fileName,
}
// Insert Peak
if (this.isInsertPeak) {
url = '/selfStation/insertPeak'
params = {
sampleId,
fileName,
curChan: Math.ceil(this.channel_1),
}
}
this.isLoading = true
const { success, result, message } = await getAction(url, params)
if (success) {
const { newPeaks, oldPeaks, tablePeaksList } = result
this.originalTablePeaksList = cloneDeep(tablePeaksList)
tablePeaksList.forEach((item) => {
item.energy = Number(item.energy).toPrecision(6)
item.netArea = Number(item.netArea).toPrecision(6)
item.fwhm = Number(item.fwhm).toPrecision(6)
})
this.list = tablePeaksList
this.newPeaks = newPeaks
this.oldPeaks = oldPeaks
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
beforeModalOpen() {
this.getData()
},
},
computed: {
slots() {
return columns.map((column) => {
return {
isCheckbox: column.isCheckbox,
isStatic: column.isStatic,
dataIndex: column.dataIndex,
slotName: column.scopedSlots.customRender,
}
})
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,69 @@
<template>
<custom-modal v-model="visible" title="General Comment" :okHandler="handleOk">
<a-spin :spinning="isLoading">
<a-textarea :rows="10" v-model="content"></a-textarea>
</a-spin>
</custom-modal>
</template>
<script>
import { getAction, postAction } from '@/api/manage'
import ModalMixin from '@/mixins/ModalMixin'
import SampleDataMixin from '@/views/spectrumAnalysis/SampleDataMixin'
export default {
mixins: [ModalMixin, SampleDataMixin],
data() {
return {
content: ''
}
},
methods: {
async handleOk() {
if (!this.content) {
this.$message.warn('Please Input Comment')
throw new Error('Comment is Empty')
}
try {
this.isSubmitting = true
const { inputFileName: fileName } = this.sampleData
const { success, message } = await postAction('/selfStation/addGeneralComment', {
fileName,
comments: this.content
})
if (!success) {
this.$message.error(message)
throw new Error(message)
}
} catch (error) {
console.error(error)
}
},
async getComment() {
try {
this.isLoading = true
const { inputFileName: fileName } = this.sampleData
const { success, result, message } = await getAction('/selfStation/viewGeneralComment', {
fileName
})
if (success) {
this.content = result
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
beforeModalOpen() {
this.content = ''
this.getComment()
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,149 @@
<template>
<custom-chart :option="option" />
</template>
<script>
import { cloneDeep } from 'lodash'
import CustomChart from '@/components/CustomChart/index.vue'
const initialOption = {
grid: {
top: 40,
bottom: 50,
right: 30,
left: 50,
},
title: {
text: 'Energy',
textStyle: {
color: '#8FD4F8',
fontSize: 14,
fontWeight: 'normal',
},
right: 10,
bottom: 5,
},
xAxis: {
axisLine: {
lineStyle: {
color: 'rgb(119, 181, 213, 0.5)',
},
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(119, 181, 213, .2)',
},
},
axisLabel: {
color: '#ade6ee',
},
min: 'dataMin',
max: 'dataMax',
animation: false,
},
yAxis: {
axisLine: {
show: true,
lineStyle: {
color: 'rgb(119, 181, 213, 0.5)',
},
},
splitLine: {
lineStyle: {
color: 'rgba(119, 181, 213, .2)',
},
},
axisLabel: {
color: '#ade6ee',
},
axisTick: {
show: false,
},
name: 'Counts',
nameTextStyle: {
color: '#8FD4F8',
fontSize: 14,
},
animation: false,
},
series: [],
}
export default {
components: {
CustomChart,
},
props: {
data: {
type: Object,
default: () => ({}),
},
},
data() {
return {
option: cloneDeep(initialOption),
}
},
watch: {
data: {
handler() {
const { chartData, selPos } = this.data
console.log(chartData);
const series = []
chartData.forEach(({ pointlist, color, name }) => {
console.log(color);
// line yAxis
if (name === 'Energy') {
this.option.yAxis.max = Math.ceil(Math.max(...pointlist.map(({ y }) => y)))
this.option.yAxis.min = Math.floor(Math.min(...pointlist.map(({ y }) => y)))
}
series.push({
type: 'line',
data: pointlist.map(({ x, y }) => [x, y]),
itemStyle: {
color,
},
lineStyle: {
width: 1
},
symbol: 'none',
animation: false,
// markLine: {
// silent: true,
// symbol: 'none',
// data: [],
// animation: false,
// lineStyle: {
// type: 'solid',
// width: 2
// }
// }
})
})
series[0].markLine = {
data: [
{
xAxis: selPos,
label: {
formatter: '{c} keV',
color: '#f00',
fontWeight: 'bold',
fontSize: 14,
},
},
],
symbol: 'none',
lineStyle: {
color: '#f00',
},
emphasis: {
disabled: true,
},
}
this.option.series = series
},
immediate: true,
},
},
}
</script>

View File

@ -0,0 +1,587 @@
<template>
<custom-modal v-model="visible" :width="1280" title="Nuclide Review" :footer="null">
<a-spin :spinning="isLoading">
<div class="nuclide-review-search">
<span @click="handleNuclideChange('prev')">&lt;</span>
<a-form-model layout="inline">
<a-form-model-item label="Energy">
<a-input-number v-model="model.energy"></a-input-number>
</a-form-model-item>
<a-form-model-item label="Tolerance">
<a-input-number v-model="model.tolerance"></a-input-number>
</a-form-model-item>
<a-button type="primary" @click="handleSearch">Search</a-button>
</a-form-model>
<span @click="handleNuclideChange('next')">&gt;</span>
</div>
<!-- 以下是表格部分 -->
<div class="nuclide-review-table">
<div class="nuclide-review-table-nuclide">
<div class="nuclide-review-table-nuclide-header">Nuclide</div>
<div class="nuclide-review-table-nuclide-content">
<div
class="nuclide-review-table-nuclide-item"
:class="currNuclide == item ? 'active' : ''"
v-for="(item, index) in nuclideList"
:key="item"
@click="handleNuclideClick(index)"
>
{{ item }}
</div>
</div>
</div>
<div class="nuclide-review-table-table">
<div class="title">
<a-form-model>
<a-row>
<a-col :span="6">
<a-form-model-item label="Name">
{{ info.name }}
</a-form-model-item>
</a-col>
<a-col :span="6">
<a-form-model-item label="Half Life">
{{ info.halfLife }}
</a-form-model-item>
</a-col>
<a-col :span="6">
<a-form-model-item label="Half Life Err">
{{ info.halfLifeErr }}
</a-form-model-item>
</a-col>
<a-col :span="6">
<a-form-model-item label="Lines">
{{ info.lines }}
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</div>
<a-table
ref="tableRef"
:class="list.length ? 'has-data' : ''"
:columns="columns"
:dataSource="list"
:scroll="{ y: 180 }"
:customRow="customRow"
:pagination="false"
size="small"
>
<template slot="keyLine" slot-scope="text">
<span v-if="text == 1" class="green-check-mark"> </span>
</template>
</a-table>
</div>
</div>
<!-- 表格部分结束 -->
<!-- 以下是图表部分 -->
<div class="nuclide-review-chart">
<div class="nuclide-review-chart-prev">
<span @click="handleChangeChart('prev')"> &lt; </span>
</div>
<a-row class="nuclide-review-chart-list">
<a-col class="nuclide-review-chart-item" :span="8" v-for="(chartItem, index) in currChartList" :key="index">
<p>{{ chartItem.title }}</p>
<div
class="nuclide-review-chart-item-chart"
:class="currSelectedTableIndex == chartItem._index ? 'active' : ''"
>
<nuclide-review-chart :data="chartItem" />
</div>
<p>{{ chartItem.bottom }}</p>
</a-col>
</a-row>
<div class="nuclide-review-chart-next">
<span @click="handleChangeChart('next')"> &gt; </span>
</div>
</div>
<!-- 图表部分结束 -->
</a-spin>
</custom-modal>
</template>
<script>
import { getAction } from '@/api/manage'
import NuclideReviewChart from './NuclideReviewChart.vue'
import ModalMixin from '@/mixins/ModalMixin'
import SampleDataMixin from '@/views/spectrumAnalysis/SampleDataMixin'
const columns = [
{
title: 'Id',
width: '5%',
customRender: (_, __, index) => {
return index + 1
},
},
{
title: 'Full Name',
dataIndex: 'fullName',
width: '15%',
},
{
title: 'Energy',
dataIndex: 'energy',
width: '15%',
sorter: (a, b) => a.energy - b.energy,
},
{
title: 'Energy Err',
dataIndex: 'energyUncert',
width: '15%',
},
{
title: 'Abundance(%)',
dataIndex: 'yield',
width: '15%',
sorter: (a, b) => a.yield - b.yield,
},
{
title: 'Abundance Err(%)',
dataIndex: 'yieldUncert',
width: '15%',
},
{
title: 'KeyLine',
dataIndex: 'keyFlag',
width: '15%',
align: 'center',
scopedSlots: {
customRender: 'keyLine',
},
},
]
export default {
components: { NuclideReviewChart },
mixins: [ModalMixin, SampleDataMixin],
props: {
channel: {
type: Number,
},
nuclide: {
type: String,
},
page: {
type: String,
default: 'AnalyzeInteractiveToolModal'
},
},
data() {
this.columns = columns
return {
nuclideList: [],
list: [], //
currNuclide: '',
currSelectedTableIndex: 0, //
chartList: [],
currChartList: [], // ,3
model: {},
info: {},
}
},
methods: {
// /
handleNuclideChange(direction) {
const currIndex = this.nuclideList.findIndex((item) => item == this.currNuclide)
if (direction == 'prev' && currIndex > 0) {
this.handleNuclideClick(currIndex - 1)
} else if (direction == 'next' && currIndex !== this.nuclideList.length - 1) {
this.handleNuclideClick(currIndex + 1)
}
},
scrollIntoView(index) {
const tableEle = this.$refs.tableRef.$el
const tableBodyEle = tableEle.querySelector('.ant-table-body')
const prevEle = tableBodyEle.querySelector(`.ant-table-row:nth-child(${index + 1})`)
tableBodyEle.scrollTop = prevEle.offsetTop
},
//
handleNuclideClick(index) {
this.currNuclide = this.nuclideList[index]
this.getInfoByNuclide()
},
selectTableRow(index) {
this.currSelectedTableIndex = index
let startIndex = 0
let endIndex = 0
if (index == 0) {
//
endIndex = startIndex + 3
} else if (index == this.list.length - 1) {
//
endIndex = index + 1
startIndex = endIndex - 3
} else {
startIndex = index - 1
endIndex = index + 2
}
if (startIndex < 0) {
startIndex = 0
}
this.currChartList = this.chartList.slice(startIndex, endIndex)
},
// /
handleChangeChart(direction) {
const currIndex = this.currSelectedTableIndex
if (direction == 'prev') {
const willJumpIndex = currIndex - 3
if (willJumpIndex >= 0) {
this.selectTableRow(willJumpIndex)
this.scrollIntoView(willJumpIndex)
} else {
this.selectTableRow(0)
this.scrollIntoView(0)
}
} else if (direction == 'next') {
const willJumpIndex = currIndex + 3
if (willJumpIndex <= this.list.length - 2) {
this.selectTableRow(willJumpIndex)
this.scrollIntoView(willJumpIndex)
} else {
this.selectTableRow(this.list.length - 1)
this.scrollIntoView(this.list.length - 1)
}
}
},
// /
customRow(record, index) {
return {
class: 'custom-table-row' + (this.currSelectedTableIndex == index ? ' ant-table-row-selected' : ''),
on: {
click: () => {
this.selectTableRow(index)
},
},
}
},
//
async getInfo() {
try {
this.isLoading = true
const { sampleId, inputFileName: fileName } = this.sampleData
let url = '/selfStation/nuclideReview'
// 20231219:xiao
if(this.page === 'gamma-analysis'){
url = '/selfStation/nuclideReviewGamma'
}
const { success, result, message } = await getAction(url, {
sampleId: sampleId,
channel: this.channel,
fileName,
})
if (success) {
this.model = {
energy: result ? result.energy : undefined,
tolerance: 0.5,
}
this.handleResData(result)
if (this.nuclide && this.nuclideList.length) {
this.currNuclide = this.nuclide
this.getInfoByNuclide()
}
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
//
handleResData(result) {
if (!result) {
result = {
chart: [],
halfLife: null,
halfLifeErr: null,
lines: null,
list: [],
name: '',
table: [],
}
}
const { chart, halfLife, halfLifeErr, lines, list, name, table } = result
this.info = {
halfLife,
halfLifeErr,
lines,
name,
}
this.list = table
this.nuclideList = list
chart.forEach((chartItem, index) => (chartItem._index = index))
this.chartList = chart
this.currNuclide = this.nuclideList[0]
this.selectTableRow(table.length > 1 ? 1 : 0)
},
// Nuclide
async getInfoByNuclide() {
try {
this.isLoading = true
const { sampleId, inputFileName } = this.sampleData
let url = '/selfStation/changeNuclide'
// 20231219:xiao
if(this.page === 'gamma-analysis'){
url = '/selfStation/changeNuclideGamma'
}
const { success, result, message } = await getAction(url, {
sampleId,
nuclideName: this.currNuclide,
fileName: inputFileName,
})
if (success) {
const { chart, halfLife, halfLifeErr, lines, name, table } = result
this.info = {
halfLife,
halfLifeErr,
lines,
name,
}
this.list = table
chart.forEach((chartItem, index) => (chartItem._index = index))
this.chartList = chart
this.selectTableRow(table.length > 1 ? 1 : 0)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
beforeModalOpen() {
this.getInfo()
},
//
async handleSearch() {
try {
this.isLoading = true
const { sampleId, inputFileName: fileName } = this.sampleData
const { success, result, message } = await getAction('/selfStation/searchNuclide', {
sampleId,
fileName,
...this.model,
})
if (success) {
this.handleResData(result)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
},
}
</script>
<style lang="less" scoped>
.nuclide-review {
&-search {
display: flex;
justify-content: center;
align-items: center;
border-top: 1px solid rgba(12, 235, 201, 0.3);
border-bottom: 1px solid rgba(12, 235, 201, 0.3);
background-color: rgba(12, 235, 201, 0.05);
> span {
color: @primary-color;
width: 30px;
height: 30px;
border: 1px solid @primary-color;
border-radius: 50%;
margin: 0 10px;
text-align: center;
font-size: 20px;
cursor: pointer;
user-select: none;
}
.ant-form {
display: flex;
align-items: center;
}
}
&-table {
display: flex;
height: 250px;
margin-top: 10px;
&-nuclide {
width: 150px;
display: flex;
flex-direction: column;
&-header {
height: 32px;
line-height: 32px;
text-align: center;
background-color: #126b82;
}
&-content {
background-color: #275466;
flex: 1;
padding: 5px;
overflow: auto;
}
&-item {
padding: 0 5px;
height: 30px;
line-height: 30px;
cursor: pointer;
user-select: none;
&.active {
background-color: #296d81;
}
}
}
&-table {
margin-left: 20px;
flex: 1;
overflow: hidden;
.title {
::v-deep {
.ant-form {
&-item {
margin-bottom: 0;
&-label,
&-control {
line-height: 32px;
}
}
}
}
}
.ant-table-wrapper {
&.has-data {
::v-deep {
.ant-table-body {
height: 180px;
background-color: #06282a;
}
}
}
::v-deep {
.ant-table-placeholder {
height: 181px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
}
&-chart {
margin-top: 20px;
height: 300px;
//background-color: #05354c;
display: flex;
align-items: center;
&-list {
flex: 1;
height: 100%;
}
&-item {
height: 100%;
p {
height: 30px;
line-height: 30px;
font-size: 16px;
text-align: center;
margin-bottom: 0;
}
&-chart {
height: calc(100% - 60px);
border: 4px solid transparent;
&.active {
background-color: #0a6f82;
border-color: #0d8696;
}
}
}
&-prev,
&-next {
width: 40px;
text-align: center;
span {
display: inline-block;
color: @primary-color;
width: 30px;
height: 30px;
border: 1px solid @primary-color;
border-radius: 50%;
text-align: center;
font-size: 20px;
cursor: pointer;
user-select: none;
}
}
}
}
.custom-table-row {
cursor: pointer;
}
.green-check-mark {
&::after {
@color: #3df9a7;
content: '';
border-radius: 0px;
width: 16px;
height: 9px;
display: inline-block;
border-bottom: 3px solid @color;
border-left: 3px solid @color;
transform: rotate(-45deg);
}
}
</style>

View File

@ -0,0 +1,76 @@
<template>
<custom-modal v-model="visible" title="Peak Comment" :okHandler="handleOk">
<a-spin :spinning="isLoading">
<a-textarea :rows="10" v-model="content"></a-textarea>
</a-spin>
</custom-modal>
</template>
<script>
import { getAction, postAction } from '@/api/manage'
import ModalMixin from '@/mixins/ModalMixin'
import SampleDataMixin from '@/views/spectrumAnalysis/SampleDataMixin'
export default {
mixins: [ModalMixin, SampleDataMixin],
props: {
curRow: {
type: Number
}
},
data() {
return {
content: ''
}
},
methods: {
async handleOk() {
if (!this.content) {
this.$message.warn('Please Input Comment')
throw new Error('Comment is Empty')
}
try {
this.isSubmitting = true
const { inputFileName: fileName } = this.sampleData
const { success, message } = await postAction('/selfStation/addPeakComment', {
fileName,
comments: this.content,
curRow: this.curRow
})
if (!success) {
this.$message.error(message)
throw new Error(message)
}
} catch (error) {
console.error(error)
}
},
async getComment() {
try {
this.isLoading = true
const { inputFileName: fileName } = this.sampleData
const { success, result, message } = await getAction('/selfStation/viewPeakComment', {
fileName,
curRow: this.curRow
})
if (success) {
this.content = result
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isLoading = false
}
},
beforeModalOpen() {
this.content = ''
this.getComment()
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,149 @@
<template>
<div class="rect-list" :class="isMoving ? 'draggable' : ''" @mousemove="handleMouseMove" @mouseup="handleMouseUp">
<div
class="rect-list-item"
:class="draggable && !isMoving ? 'draggable' : ''"
v-for="(item, index) in list"
:key="index"
@mousedown="handleMouseDown(item, index)"
>
<div
class="plus"
:class="isMoving ? 'will-change' : ''"
v-if="item.yslope"
:style="getPosition(item.xAxis - 2, item.yAxis - 2 * item.yslope)"
>
+
</div>
<div class="rect" :class="isMoving ? 'will-change' : ''" :style="getPosition(item.xAxis, item.yAxis)"></div>
<div
class="plus"
:class="isMoving ? 'will-change' : ''"
v-if="item.yslope"
:style="getPosition(item.xAxis + 2, item.yAxis + 2 * item.yslope)"
>
+
</div>
</div>
</div>
</template>
<script>
import { getXAxisAndYAxisByPosition } from '@/utils/chartHelper'
export default {
props: {
chartRef: {
type: Object,
},
baseControls: {
type: Object,
},
draggable: {
type: Boolean,
},
},
data() {
return {
list: [],
isMoving: false,
}
},
methods: {
init() {
this.chart = this.chartRef.getChartInstance()
const { xctrl: xctrlList, yctrl: yctrlList, yslope: yslopeList } = this.baseControls
this.list = xctrlList.map((xAxis, index) => {
const yAxis = yctrlList[index]
const yslope = yslopeList[index]
return {
xAxis,
yAxis,
yslope,
}
})
},
clear() {
this.list = []
},
getPosition(xAxis, yAxis) {
const [xPix, yPix] = this.chart.convertToPixel('grid', [xAxis, yAxis])
return {
position: 'absolute',
left: xPix + 'px',
top: yPix + 'px',
}
},
handleMouseDown(item, index) {
this.isMoving = true
this.currItem = item
this.prevYAxis = item.yAxis
this.currItemIndex = index
},
handleMouseMove(event) {
if (this.isMoving) {
const { offsetX, offsetY } = event
const position = getXAxisAndYAxisByPosition(this.chart, offsetX, offsetY)
if (position) {
this.currItem.yAxis = position[1]
this.$emit('move', this.list.map((item) => item.yAxis))
}
}
},
handleMouseUp() {
if (this.isMoving) {
this.isMoving = false
this.$emit('moveEnd', this.prevYAxis, this.currItemIndex)
}
},
},
}
</script>
<style lang="less" scoped>
.rect-list {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
overflow: hidden;
&.draggable {
pointer-events: all;
}
&-item {
user-select: none;
pointer-events: none;
&.draggable {
pointer-events: all;
}
}
.rect {
width: 10px;
height: 10px;
border: 2px solid red;
transform: translate(-50%, -50%);
}
.plus {
font-size: 20px;
color: #0f0;
width: 12px;
height: 12px;
line-height: 12px;
transform: translate(-50%, -50%);
}
}
.will-change {
will-change: top;
}
</style>

View File

@ -305,8 +305,8 @@ const initialGammaGatedChartOption = {
},
xAxis: {
min: 0,
max: 256,
interval: 64,
max: 512,
interval: 128,
axisLine: {
lineStyle: {
color: 'rgb(119, 181, 213, 0.5)',
@ -360,7 +360,7 @@ const initialGammaGatedChartOption = {
fontSize: 14,
color: '#5b9cba',
},
nameGap: 25,
nameGap: 40,
},
series: {
type: 'line',
@ -429,8 +429,8 @@ const initialFigureChartOption = {
},
xAxis: {
min: 0,
max: 256,
interval: 64,
max: 0,
interval: 0,
axisLine: {
lineStyle: {
color: 'rgb(119, 181, 213, 0.5)',
@ -670,9 +670,11 @@ export default {
oldScatterSeries,
newCToE,
newEToC,
tableWidgets,
} = res.result
this.c2e = CToE
this.e2c = EToC
this.list = tableWidgets
this.oldScatterSeries = oldScatterSeries
this.count = oldScatterSeries.length
@ -686,7 +688,19 @@ export default {
const gammaEnergyMax = Math.max(...gammaEnergyValue)
const gammaEnergyMin = Math.min(...gammaEnergyValue)
const { max, min, interval } = splitAxis(gammaEnergyMax, gammaEnergyMin, 4)
const tableWidgetsEnergyMax = Math.min(...tableWidgets.map((item) => item.energy))
const tableWidgetsChannelMax = Math.min(...tableWidgets.map((item) => item.channel))
const { max, min, interval } = splitAxis(Math.max(gammaEnergyMax, tableWidgetsEnergyMax), gammaEnergyMin, 4)
const { max: xMax, xInterval } = splitAxis(
Math.max(gammaEnergyValue.length - 1, tableWidgetsChannelMax),
0,
4,
1
)
this.figureChartOption.xAxis.max = xMax
this.figureChartOption.xAxis.interval = xInterval
this.figureChartOption.yAxis.max = max
this.figureChartOption.yAxis.min = min
@ -697,10 +711,15 @@ export default {
this.oldChartOption = cloneDeep(this.figureChartOption)
this.figureChartOption.series[1].markPoint.data = tableWidgets.map((item) => ({
xAxis: item.channel,
yAxis: item.energy,
}))
// reanalyzefittingReanalyze 20231101xiao
// todo fitting
if (this.getCache('CALIBRATION_BETA_' + this.newSampleData.inputFileName)) {
this.setFirringResult(this.getCache('CALIBRATION_BETA_' + this.newSampleData.inputFileName))
if (this.getCache('SELF_STATION_CALIBRATION_BETA_' + this.newSampleData.inputFileName)) {
this.setFirringResult(this.getCache('SELF_STATION_CALIBRATION_BETA_' + this.newSampleData.inputFileName))
return false
}
@ -736,8 +755,8 @@ export default {
this.currEnergy = this.gammaEnergy[yAxis][0].toPrecision(6) // Energy
this.channelAndEnergyModel = {
channel: yAxis,
energy: this.currEnergy,
channel: undefined,
energy: undefined,
}
this.getGammaGated(yAxis)
@ -830,7 +849,7 @@ export default {
this.tooltipChannel = xAxis
this.tooltipPosition.top = offsetY
if (xAxis > 187) {
if (xAxis > 424) {
this.tooltipPosition.left = offsetX - 125
} else {
this.tooltipPosition.left = offsetX + 20
@ -934,7 +953,7 @@ export default {
// Reset Button
async handleReset() {
this.$emit('isFitting', false)
this.removeCache('CALIBRATION_BETA_' + this.newSampleData.inputFileName) // fitting 20231101:xiao
this.removeCache('SELF_STATION_CALIBRATION_BETA_' + this.newSampleData.inputFileName) // fitting 20231101:xiao
this.newCalibrationFuncModel = cloneDeep(newCalibrationFuncModel)
this.list = []
this.newE2C = []
@ -978,7 +997,7 @@ export default {
this.betaIsFitting = true
this.$emit('isFitting', true) // reAnalyzeisFirstFittingtrue 20231101xiao
this.setCache('CALIBRATION_BETA_' + this.newSampleData.inputFileName, result) // ReAnalyze 20231101xiao
this.setCache('SELF_STATION_CALIBRATION_BETA_' + this.newSampleData.inputFileName, result) // ReAnalyze 20231101xiao
this.setFirringResult(result)
} else {
@ -1090,7 +1109,7 @@ export default {
computed: {
rectHeight() {
const { top, bottom } = initialBetaGammaChartOption.grid
const totalHeight = 427 - top - bottom
const totalHeight = 549 - top - bottom
return (totalHeight / 4096) * this.gammaChannelWidth
},
},

View File

@ -545,8 +545,8 @@ export default {
// reanalyzefittingReanalyze 20231101xiao
// todo fitting
if (this.getCache('CALIBRATION_GAMMA_' + this.newSampleData.inputFileName)) {
this.setFirringResult(this.getCache('CALIBRATION_GAMMA_' + this.newSampleData.inputFileName))
if (this.getCache('SELF_STATION_CALIBRATION_GAMMA_' + this.newSampleData.inputFileName)) {
this.setFirringResult(this.getCache('SELF_STATION_CALIBRATION_GAMMA_' + this.newSampleData.inputFileName))
return false
}
@ -680,7 +680,7 @@ export default {
// Reset Button
async handleReset() {
this.$ls.remove('CALIBRATION_GAMMA_' + this.newSampleData.inputFileName) // fitting 20231101:xiao
this.$ls.remove('SELF_STATION_CALIBRATION_GAMMA_' + this.newSampleData.inputFileName) // fitting 20231101:xiao
this.newCalibrationFuncModel = cloneDeep(newCalibrationFuncModel)
this.list = []
this.newE2C = []
@ -727,7 +727,7 @@ export default {
this.gammaIsFitting = true
this.$emit('isFitting', true) // reAnalyzeisFirstFittingtrue 20231101xiao
this.setCache('CALIBRATION_GAMMA_' + this.newSampleData.inputFileName, result) // ReAnalyze 20231101xiao
this.setCache('SELF_STATION_CALIBRATION_GAMMA_' + this.newSampleData.inputFileName, result) // ReAnalyze 20231101xiao
this.setFirringResult(result)

View File

@ -169,11 +169,13 @@ export default {
created() {
this.option.tooltip.formatter = this.handleTooltipFormat
this.option.series[0].itemStyle.color = 'yellow'
this.option.brush = { toolbox: [] }
this.$bus.$on('changeROILimitsYAxisType', this.changeYAxisType)
this.$bus.$on('roiLimitItemUnzoom', this.handleUnZoom)
this.$bus.$on('roiLimitItemChange', this.handleLimitItemChange)
},
mounted() {
this.option.brush = { toolbox: [] }
},
beforeDestroy() {
this.$bus.$off('changeROILimitsYAxisType', this.changeYAxisType)
this.$bus.$off('roiLimitItemUnzoom', this.handleUnZoom)
@ -435,6 +437,8 @@ export default {
handler(val) {
if (val && Object.keys(val).length) {
this.handleAnalyzeResult()
console.log('%c [ ]-441', 'font-size:13px; background:pink; color:#bf2c9f;', )
}
},
immediate: true,
@ -489,6 +493,7 @@ export default {
img {
width: 100%;
height: 100%;
display: block;
}
}
}

View File

@ -127,6 +127,14 @@
/>
<!-- 分析工具弹窗结束 -->
<!-- Beta的 分析工具弹窗开始 -->
<beta-analyze-interactive-tool-modal
ref="betaAnalyzeInteractiveToolRef"
:sampleId="sampleData.sampleId"
:colorConfig="colorConfig"
/>
<!-- 分析工具弹窗结束 -->
<!-- Korsum 弹窗开始 -->
<korsum-modal v-model="korsumModalShow" />
<!-- Korsum 弹窗结束 -->
@ -301,6 +309,7 @@ import BGLogViewer from './components/Modals/BetaGammaModals/BGLogViewer.vue'
import { saveAs } from 'file-saver'
import CompareFromDbModal from './components/Modals/CompareFromDBModal.vue'
import { clearSampleData, getSampleData, updateSampleDataAnaly } from '@/utils/SampleStore'
import BetaAnalyzeInteractiveToolModal from './components/Modals/BetaAnalyzeInteractiveToolModal/index.vue'
//
const ANALYZE_TYPE = {
@ -357,6 +366,7 @@ export default {
BgLogViewer: BGLogViewer,
CompareFromDbModal,
CalibrationModal,
BetaAnalyzeInteractiveToolModal,
},
provide() {
@ -616,14 +626,23 @@ export default {
dbName,
fileName,
analyst,
status
status,
}
getAction('/gamma/initValue', params)
})
willAddList
.filter(({ sampleType, inputFileName }) => sampleType == 'B' && inputFileName !== this.sampleData.inputFileName)
.forEach(
({ inputFileName: sampleFileName, gasFileName, detFileName, qcFileName, dbName, sampleId, analyst, status }) => {
({
inputFileName: sampleFileName,
gasFileName,
detFileName,
qcFileName,
dbName,
sampleId,
analyst,
status,
}) => {
const params = {
sampleId,
dbName,
@ -632,7 +651,7 @@ export default {
gasFileName,
detFileName,
qcFileName,
status
status,
}
getAction('/spectrumAnalysis/initValue', params)
}
@ -1382,6 +1401,12 @@ export default {
if (this.isBeta) this.$refs.betaAnalysisRef.getAnalyzeAllSpectrum()
},
},
{
type: 'a-menu-item',
title: 'Interactive Tool',
show: this.isBeta,
handler: () => this.$refs.betaAnalyzeInteractiveToolRef.open(),
},
],
},
],