Merge branch 'feature-particulate-renpy' of http://git.hivekion.com:3000/xiaoguangbin/AnalysisSystemForRadionuclide_vue into feature-particulate-renpy

This commit is contained in:
orgin 2023-08-02 13:44:29 +08:00
commit 0678934296
57 changed files with 7894 additions and 34 deletions

View File

@ -24,6 +24,7 @@
"dayjs": "^1.8.0",
"dom-align": "1.12.0",
"echarts": "^5.4.2",
"echarts-gl": "^2.0.9",
"enquire.js": "^2.1.6",
"file-saver": "^2.0.5",
"js-cookie": "^2.2.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,51 @@
<template>
<div class="custom-chart" ref="containerRef" :style="{ height: height + 'px' }"></div>
</template>
<script>
import * as echarts from 'echarts'
import 'echarts-gl'
export default {
props: {
option: {
type: Object,
default: () => ({})
},
height: {
type: Number,
default: 0
}
},
data() {
return {}
},
mounted() {
this.chart = echarts.init(this.$refs.containerRef)
this.chart.setOption(this.option)
},
methods: {
resize() {
this.chart && this.chart.resize()
}
},
watch: {
option: {
handler() {
if (this.chart) {
this.chart.setOption(this.option)
}
},
deep: true
},
height() {
this.$nextTick(() => {
this.chart && this.chart.resize()
})
}
}
}
</script>
<style lang="less" scoped>
.custom-chart {
height: 100% !important;
}
</style>

View File

@ -3,6 +3,10 @@
</template>
<script>
import * as echarts from 'echarts'
const events = ['brushEnd']
const zrEvents = ['mousemove', 'mousedown', 'mouseup']
export default {
props: {
option: {
@ -18,27 +22,51 @@ export default {
return {}
},
mounted() {
this.chart = echarts.init(this.$refs.containerRef)
this.chart.setOption(this.option)
this._chart = echarts.init(this.$refs.containerRef)
this._chart.setOption(this.option)
this.initEventListener()
},
methods: {
initEventListener() {
events.forEach(eventName => {
this._chart.on(eventName, (params) => {
this.$emit(eventName, params)
})
})
const zr = this.getZRender()
zrEvents.forEach(eventName => {
zr.on(eventName, params => {
this.$emit(`zr:${eventName}`, params)
})
})
},
resize() {
this.chart && this.chart.resize()
this._chart && this._chart.resize()
},
// echart
getChartInstance() {
return this._chart
},
getZRender() {
return this._chart.getZr()
}
},
watch : {
watch: {
option: {
handler() {
if(this.chart) {
this.chart.clear()
this.chart.setOption(this.option)
if (this._chart) {
this._chart.setOption(this.option)
}
},
deep: true
},
height() {
this.$nextTick(() => {
this.chart && this.chart.resize()
this._chart && this._chart.resize()
})
}
}
@ -46,6 +74,6 @@ export default {
</script>
<style lang="less" scoped>
.custom-chart {
height: 100%;
height: 100% !important;
}
</style>

View File

@ -1,10 +1,5 @@
<template>
<a-modal
:class="'custom-modal' + (innerFullscreen ? ' fullscreen' : '')"
v-bind="_attrs"
v-model="visible"
:footer="null"
>
<a-modal :class="'custom-modal' + (innerFullscreen ? ' fullscreen' : '')" v-bind="_attrs" v-model="visible">
<img slot="closeIcon" src="@/assets/images/global/close.png" />
<div slot="title">
<div class="custom-modal-title">
@ -16,10 +11,13 @@
</div>
</div>
<slot></slot>
<a-space v-if="showFooter" class="operators" :size="20">
<a-button type="success" @click="onSave" :loading="confirmLoading">Save</a-button>
<a-button type="warn" @click="onCancel">Cancel</a-button>
</a-space>
<template slot="footer">
<slot name="custom-footer"></slot>
<a-space v-if="!hasCustomFooter" class="operators" :size="20">
<a-button type="success" @click="onSave" :loading="confirmLoading">Save</a-button>
<a-button type="warn" @click="onCancel">Cancel</a-button>
</a-space>
</template>
</a-modal>
</template>
<script>
@ -34,10 +32,6 @@ export default {
title: {
type: String
},
showFooter: {
type: Boolean,
default: true
},
enableFullScreen: {
type: Boolean,
default: false
@ -92,6 +86,11 @@ export default {
attrs['width'] = '100%'
}
return attrs
},
// footer
hasCustomFooter() {
return !!this.$slots['custom-footer']
}
}
}

View File

@ -41,7 +41,16 @@ export default {
methods: {
onMenuSelect({ key }) {
const childPath = this.getChildrenPath(this.menuItems.find(menu => menu.name === key))
this.$router.push(childPath)
if (key == "abnormal-alarm" || key == "istatistics") {
const selectedKeys = window.sessionStorage.getItem('currMenu')
if (selectedKeys) {
this.$router.push(selectedKeys)
} else {
this.$router.push(childPath)
}
} else {
this.$router.push(childPath)
}
},
getChildrenPath(menuItem) {
if (menuItem.children) {

17
src/mixins/ModalMixin.js Normal file
View File

@ -0,0 +1,17 @@
export default {
props: {
value: {
type: Boolean
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}

View File

@ -18,8 +18,15 @@
@modal-footer-border-color-split: @formInputBorderColor;
@disabled-color: rgba(255, 255, 255, .25);
@background-color-base: darken(@primary-color, 20);
@border-color-base: darken(@primary-color, 20);
@text-color: #fff;
.ant-btn:hover,
.ant-btn:active {
.ant-btn:active,
.ant-btn:focus {
color: #fff !important;
border-color: transparent;
}
@ -61,6 +68,8 @@ body {
.ant-table {
color: #ade6ee;
font-size: 16px;
border: 1px solid rgba(65,111,127, .5);
&-thead {
> tr {
th {
@ -299,6 +308,41 @@ body {
}
}
// 时间选择器
@time-picker-selected-bg: @primary-color;
@item-hover-bg: @primary-color;
.ant-time-picker {
&-input {
background: @modalBg;
border-radius: 0;
&::placeholder {
color: #fff;
}
}
&-clear,
&-clock-icon {
background-color: @modalBg !important;
color: #01B6E3 !important;
}
&-panel {
&-input {
background-color: transparent;
}
&-inner {
background-color: @modalBg;
border: 1px solid @formInputBorderColor;
border-radius: 0;
}
&-select li:focus {
color: #fff;
}
}
}
// 输入框样式
.ant-input {
background-color: @formInputBgColor !important;
@ -679,6 +723,16 @@ input[type='number']::-webkit-outer-spin-button {
background-color: #b98326 !important;
}
}
&-grey {
// 自定义warn样式
background-color: #406979 !important;
color: #fff !important;
border-color: #406979 !important;
&:hover {
background-color: #406979 !important;
}
}
}
// 空状态
@ -869,6 +923,7 @@ input[type='number']::-webkit-outer-spin-button {
&-arrow {
border-left-color: #03353f !important;
border-top-color: #03353f !important;
z-index: -1;
}
}

20
src/utils/chartHelper.js Normal file
View File

@ -0,0 +1,20 @@
/**
* 根据位置获取这个点在图表的哪个轴线上
* @param offsetX
* @param offsetY
*/
export function getXAxisAndYAxisByPosition(chart, offsetX, offsetY, seriesIndex = 0) {
const pointInPixel = [offsetX, offsetY]
if (
chart.containPixel(
{
seriesIndex: 0
},
pointInPixel
)
) {
const [xAxis, yAxis] = chart.convertFromPixel({ seriesIndex }, pointInPixel)
return [xAxis, yAxis]
}
return null
}

View File

@ -55,7 +55,7 @@
</custom-table>
</div>
<!-- 日志列表结束 -->
<custom-modal title="Log" :width="950" v-model="visible" :show-footer="false">
<custom-modal title="Log" :width="950" v-model="visible" :footer="null">
<a-spin class="log-detail" :spinning="isGettingDetail">
<div v-for="(logItem, index) in logInfo" :key="index">
{{ logItem }}

View File

@ -0,0 +1,315 @@
<template>
<div class="beta-gamma-analysis">
<!-- 二级交互栏 -->
<div class="spectrum-analysis-sub-operators">
<pop-over-with-icon placement="bottomLeft">
Detailed-Information
<detailed-infomation slot="content" />
</pop-over-with-icon>
<pop-over-with-icon placement="bottomLeft">
QC Flags
<qc-flags slot="content" :data="{ collectionTime: '123' }" />
</pop-over-with-icon>
<pop-over-with-icon placement="bottomLeft" style="width: 159px" v-model="spectraVisible">
Spectra
<spectra slot="content" v-model="spectraType" @input="spectraVisible = false" />
</pop-over-with-icon>
</div>
<!-- 二级交互栏结束 -->
<!-- 主体部分 -->
<div class="beta-gamma-analysis-main">
<!-- 左侧图表 -->
<div class="beta-gamma-spectrum-sample">
<beta-gamma-chart-container>
<template slot="title">
Beta-Gamma Spectrum: Sample
</template>
<beta-gamma-spectrum-chart
ref="betaGammaChartRef"
:data="histogramDataList"
@positionChange="handlePositionChange"
@rangeChange="handleRangeChange"
/>
</beta-gamma-chart-container>
</div>
<!-- 左侧图表结束 -->
<!-- 右侧 -->
<div class="beta-and-gamma-spectrum">
<!-- 四个图表开始 -->
<div class="spectrum-charts">
<div class="gamma-spectrum">
<div class="gamma-spectrum-item">
<beta-gamma-chart-container>
<template slot="title">
Gamma Spectrum: Original
</template>
<spectrum-line-chart
ref="lineChart1Ref"
:data="gammaOriginalData"
@rangeChange="handleLineChartRangeChange($event, 'y')"
/>
</beta-gamma-chart-container>
</div>
<div class="gamma-spectrum-item">
<beta-gamma-chart-container>
<template slot="title">
Gamma Spectrum: Projected
</template>
<spectrum-line-chart
ref="lineChart2Ref"
:data="betaProjectedData"
@rangeChange="handleLineChartRangeChange($event, 'y')"
/>
</beta-gamma-chart-container>
</div>
</div>
<div class="gamma-spectrum">
<div class="gamma-spectrum-item">
<beta-gamma-chart-container>
<template slot="title">
Beta Spectrum: Original
</template>
<spectrum-line-chart
ref="lineChart3Ref"
:data="betaOriginalData"
title="Beta"
color="#00ff1e"
@rangeChange="handleLineChartRangeChange($event, 'x')"
/>
</beta-gamma-chart-container>
</div>
<div class="gamma-spectrum-item">
<beta-gamma-chart-container>
<template slot="title">
Beta Spectrum: Projected
</template>
<spectrum-line-chart
ref="lineChart4Ref"
:data="gammaProjectedData"
title="Beta"
color="#00ff1e"
@rangeChange="handleLineChartRangeChange($event, 'x')"
/>
</beta-gamma-chart-container>
</div>
</div>
</div>
<!-- 四个图表结束 -->
<!-- 结果显示开始 -->
<div class="result-display">
<beta-gamma-chart-container>
<template slot="title">
Result display
</template>
<result-display :data="resultDisplay"></result-display>
</beta-gamma-chart-container>
</div>
<!-- 结果显示结束 -->
</div>
<!-- 右侧结束 -->
<!-- Comparison Modal 开始 -->
<comparison-modal v-model="comparisonModalVisible" />
<!-- Comparison Modal 结束 -->
</div>
<!-- 主体部分结束 -->
</div>
</template>
<script>
import BetaGammaChartContainer from './components/BetaGammaChartContainer.vue'
import BetaGammaSpectrumChart from './components/BetaGammaSpectrumChart.vue'
import ComparisonModal from './components/Modals/ComparisonModal.vue'
import ResultDisplay from './components/ResultDisplay.vue'
import SpectrumLineChart from './components/SpectrumLineChart.vue'
import DetailedInfomation from './components/SubOperators/DetailedInfomation.vue'
import PopOverWithIcon from './components/SubOperators/PopOverWithIcon.vue'
import QcFlags from './components/SubOperators/QcFlags.vue'
import Spectra from './components/SubOperators/Spectra.vue'
export default {
components: {
BetaGammaChartContainer,
SpectrumLineChart,
ResultDisplay,
BetaGammaSpectrumChart,
ComparisonModal,
DetailedInfomation,
PopOverWithIcon,
QcFlags,
Spectra
},
props: {
data: {
type: Object
}
},
data() {
return {
spectraVisible: false,
spectraType: 'Sample Data',
resultDisplay: [
{
id: 1,
isotope: 'Xe131m',
concentration: '0.03464',
uncertainty: '+/-0.01988',
mdc: '0.03464'
},
{
id: 2,
isotope: 'Xe131m',
concentration: '0.03464',
uncertainty: '+/-0.01988',
mdc: '0.03464'
},
{
id: 3,
isotope: 'Xe131m',
concentration: '0.03464',
uncertainty: '+/-0.01988',
mdc: '0.03464'
},
{
id: 4,
isotope: 'Xe131m',
concentration: '0.03464',
uncertainty: '+/-0.01988',
mdc: '0.03464'
}
],
histogramDataList: [],
gammaOriginalData: [],
betaOriginalData: [],
betaProjectedData: [],
gammaProjectedData: [],
comparisonModalVisible: false
}
},
methods: {
resize() {
this.$refs.betaGammaChartRef && this.$refs.betaGammaChartRef.resize()
this.$refs.lineChart1Ref && this.$refs.lineChart1Ref.resize()
this.$refs.lineChart2Ref && this.$refs.lineChart2Ref.resize()
this.$refs.lineChart3Ref && this.$refs.lineChart3Ref.resize()
this.$refs.lineChart4Ref && this.$refs.lineChart4Ref.resize()
},
// 2d
handlePositionChange([xAxis, yAxis]) {
// Gamma Spectrumbata-gammagamma channely
this.$refs.lineChart1Ref.setLinePosition(yAxis)
this.$refs.lineChart2Ref.setLinePosition(yAxis)
// Beta Spectrumbata-gammabata channelx
this.$refs.lineChart3Ref.setLinePosition(xAxis)
this.$refs.lineChart4Ref.setLinePosition(xAxis)
},
// 2d
handleRangeChange([x1, x2, y1, y2]) {
this.$refs.lineChart1Ref.setRange(y1, y2)
this.$refs.lineChart2Ref.setRange(y1, y2)
this.$refs.lineChart3Ref.setRange(x1, x2)
this.$refs.lineChart4Ref.setRange(x1, x2)
},
/**
* 右侧折线图表刷选时
* @param {number[]} range 范围
* @param {'x'|'y'} type 类型
**/
handleLineChartRangeChange([x1, x2], type) {
if (type == 'y') {
// gamma channel
this.$refs.lineChart1Ref.setRange(x1, x2)
this.$refs.lineChart2Ref.setRange(x1, x2)
} else if (type == 'x') {
this.$refs.lineChart3Ref.setRange(x1, x2)
this.$refs.lineChart4Ref.setRange(x1, x2)
}
this.$refs.betaGammaChartRef.setRange(x1, x2, type)
}
},
watch: {
data: {
handler(newVal) {
const {
betaOriginalData,
betaProjectedData,
gammaOriginalData,
gammaProjectedData,
histogramDataList, // Beta-Gamma Spectrum: Sample
spectrumData
} = newVal
console.log('%c [ spectrumData ]-246', 'font-size:13px; background:pink; color:#bf2c9f;', spectrumData)
this.histogramDataList = histogramDataList
this.gammaOriginalData = gammaOriginalData
this.betaOriginalData = betaOriginalData
this.betaProjectedData = betaProjectedData
this.gammaProjectedData = gammaProjectedData
},
immediate: true
}
}
}
</script>
<style lang="less" scoped>
.beta-gamma-analysis {
height: 100%;
&-main {
height: calc(100% - 51px);
display: flex;
overflow: auto hidden;
}
.beta-gamma-spectrum-sample {
width: calc(100% - 1078px);
}
.beta-and-gamma-spectrum {
width: 1048px;
margin-left: 30px;
flex-direction: column;
.spectrum-charts {
display: flex;
flex-direction: column;
height: calc(100% - 208px);
.gamma-spectrum {
display: flex;
height: 50%;
&-item {
flex: 509px;
&:first-child {
margin-right: 30px;
}
}
}
}
.result-display {
flex-shrink: 0;
}
}
}
</style>

View File

@ -0,0 +1,98 @@
<template>
<div class="betagamma-chart">
<div class="betagamma-chart-title">
<div class="title">
<slot name="title"> </slot>
</div>
<div class="square">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="betagamma-chart-content">
<slot></slot>
</div>
</div>
</template>
<script>
export default {}
</script>
<style lang="less" scoped>
.betagamma-chart {
height: 100%;
overflow: hidden;
&-title {
display: flex;
justify-content: space-between;
padding-right: 20px;
height: 45px;
border-top: 1px solid rgba(12, 235, 201, 0.3);
border-bottom: 4px solid rgba(12, 235, 201, 0.2);
.title {
padding: 0 20px;
line-height: 40px;
background-color: rgba(12, 235, 201, 0.05);
color: #0cebc9;
font-size: 18px;
font-weight: bold;
font-family: MicrogrammaD-MediExte;
letter-spacing: 1px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.square {
display: flex;
align-items: center;
span {
background-color: rgba(12, 235, 201, 0.2);
vertical-align: middle;
&:first-child {
width: 4px;
height: 4px;
}
&:nth-child(2) {
width: 6px;
height: 6px;
margin-right: 6px;
}
&:nth-child(3) {
width: 4px;
height: 4px;
margin-right: 9px;
}
&:nth-child(4) {
width: 1px;
height: 16px;
margin-right: 23px;
}
&:nth-child(5) {
width: 2px;
height: 2px;
margin-right: 24px;
}
&:nth-child(6) {
width: 4px;
height: 4px;
}
}
}
}
&-content {
height: calc(100% - 45px);
overflow: hidden;
padding-top: 15px;
padding-bottom: 12px;
}
}
</style>

View File

@ -0,0 +1,506 @@
<template>
<div class="beta-gamma-spectrum-chart">
<div class="beta-gamma-spectrum-chart-operators">
<span
v-for="(item, index) in buttons"
:key="item"
:class="active == index ? 'active' : ''"
@click="handleChange(index)"
>
{{ item }}
</span>
<span @click="handleUnzoom">Unzoom</span>
</div>
<div class="beta-gamma-spectrum-chart-main">
<!-- 2D 图表 -->
<div class="_2d-chart" v-show="active == 0">
<custom-chart
ref="chartRef"
:option="twoDOption"
@zr:mousemove="handleMouseMove"
@zr:mousedown="handleMouseDown"
@zr:mouseup="handleMouseUp"
@brushEnd="handleBrushEnd"
/>
<div class="bar">
<color-palette v-model="currCount" :maxValue="4" />
<div>{{ currCount + 1 }}</div>
<div class="bar-main"></div>
<div>0</div>
</div>
</div>
<!-- 2D图表结束 -->
<!-- 3D Surface开始 -->
<Custom3DChart v-if="active == 1" key="1" ref="_3dSurfaceRef" :option="threeDSurfaceOption" />
<!-- 3D Surface结束 -->
<!-- 3D Scatter -->
<Custom3DChart v-if="active == 2" key="2" ref="_3dScannerRef" :option="threeDScatterOption" />
<!-- 3D Scatter结束 -->
</div>
</div>
</template>
<script>
import CustomChart from '@/components/CustomChart/index.vue'
import Custom3DChart from '@/components/Custom3DChart/index.vue'
import ColorPalette from './ColorPalette.vue'
import { getXAxisAndYAxisByPosition } from '@/utils/chartHelper.js'
const buttons = ['2D', '3D Surface', '3D Scatter']
// 2D
const twoDOption = {
grid: {
top: 15,
left: 55,
right: 10,
bottom: 45
},
tooltip: {
trigger: 'item',
formatter: params => {
const [b, g, c] = params.value
return `Beta: ${b}<br>Gamma: ${g}<br>Count: ${c}`
},
axisPointer: {
animation: false,
type: 'cross',
lineStyle: {
type: 'dashed'
}
}
},
xAxis: {
name: 'Beta Channel',
nameTextStyle: {
color: '#5b9cba',
fontSize: 16
},
nameLocation: 'center',
nameGap: 30,
axisLabel: {
color: '#ade6ee',
fontSize: 12
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(119, 181, 213, .3)'
}
},
axisTick: {
show: false
},
min: 0,
max: 256,
interval: 64
},
yAxis: {
name: 'Gamma Channel',
nameTextStyle: {
color: '#5b9cba',
fontSize: 16
},
nameLocation: 'center',
nameGap: 35,
axisLabel: {
color: '#ade6ee',
fontSize: 12
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(119, 181, 213, .3)'
}
},
axisTick: {
show: false
},
min: 0,
max: 256,
interval: 64
},
series: {
xAxisIndex: 0,
yAxisIndex: 0,
type: 'scatter',
symbolSize: 5,
data: [],
itemStyle: {
color: '#fff'
}
},
brush: {}
}
//3D Surface
const threeDSurfaceOption = {
visualMap: {
show: false,
dimension: 2,
min: 0,
max: 0,
inRange: ['#47C134', '#f00']
},
grid3D: {
axisLabel: {
color: '#C4E5A6'
},
axisPointer: {
show: false
},
axisLine: {
lineStyle: {
color: '#fff'
}
},
splitLine: {
lineStyle: {
color: '#fff'
}
}
},
xAxis3D: {
name: 'Beta Channel',
nameTextStyle: {
color: '#C4E5A6',
fontSize: 14
},
min: 0,
max: 256,
interval: 64
},
yAxis3D: {
name: 'Gamma Channel',
nameTextStyle: {
color: '#C4E5A6',
fontSize: 14
},
min: 0,
max: 256,
interval: 64
},
zAxis3D: {
name: 'Count',
nameTextStyle: {
color: '#C4E5A6',
fontSize: 14
},
max: 0
},
series: {
type: 'surface',
data: []
}
}
// 3D Scatter
const threeDScatterOption = {
grid3D: {
axisLabel: {
color: '#C4E5A6'
},
axisPointer: {
show: false
},
axisLine: {
lineStyle: {
color: '#fff'
}
},
splitLine: {
lineStyle: {
color: '#fff'
}
}
},
xAxis3D: {
name: 'Beta Channel',
nameTextStyle: {
color: '#C4E5A6',
fontSize: 14
},
min: 0,
max: 256,
interval: 64
},
yAxis3D: {
name: 'Gamma Channel',
nameTextStyle: {
color: '#C4E5A6',
fontSize: 14
},
min: 0,
max: 256,
interval: 64
},
zAxis3D: {
name: 'Count',
nameTextStyle: {
color: '#C4E5A6',
fontSize: 14
},
max: 6
},
series: {
type: 'scatter3D',
symbolSize: 2.5,
itemStyle: {
color: '#a2d092'
},
data: new Array(512)
.fill(0)
.map(() => [parseInt(Math.random() * 256), parseInt(Math.random() * 256), 4.5 + Math.random() * 0.1])
}
}
export default {
props: {
data: {
type: Array,
default: () => []
}
},
components: {
CustomChart,
Custom3DChart,
ColorPalette
},
data() {
this.buttons = buttons
return {
active: 0,
maxCount: 15, // count
currCount: 15,
twoDOption,
threeDSurfaceOption,
threeDScatterOption
}
},
mounted() {
this.twoDOption.brush = { toolbox: [] }
},
methods: {
// Beta-Gamma Spectrum: Sample
handleChange(index) {
this.active = index
},
// unzoom
handleUnzoom() {
this.twoDOption.xAxis.min = 0
this.twoDOption.xAxis.max = 256
this.twoDOption.yAxis.min = 0
this.twoDOption.yAxis.max = 256
this.emitRangeChange([0, 256, 0, 256])
},
resize() {
this.$refs.chartRef && this.$refs.chartRef.resize()
this.$refs._3dSurfaceRef && this.$refs._3dSurfaceRef.resize()
this.$refs._3dScannerRef && this.$refs._3dScannerRef.resize()
},
//
handleMouseMove(param) {
const { offsetX, offsetY } = param
const point = getXAxisAndYAxisByPosition(this.$refs.chartRef.getChartInstance(), offsetX, offsetY)
this.$emit('positionChange', point ? [point[0].toFixed(), point[1].toFixed()] : [null, null])
},
//
handleMouseDown() {
const chart = this.$refs.chartRef.getChartInstance()
chart.dispatchAction({
type: 'takeGlobalCursor',
//
key: 'brush',
brushOption: {
// brush brushType false
brushType: 'rect'
}
})
},
handleMouseUp() {
setTimeout(() => {
const chart = this.$refs.chartRef.getChartInstance()
//
chart.dispatchAction({
type: 'brush',
areas: []
})
//
chart.dispatchAction({
type: 'takeGlobalCursor'
})
}, 0)
},
//
handleBrushEnd(param) {
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 [x1, y2, x2, y1] = [...point1, ...point2] //
this.twoDOption.xAxis.min = x1
this.twoDOption.xAxis.max = x2
this.twoDOption.yAxis.min = y1
this.twoDOption.yAxis.max = y2
this.emitRangeChange([x1, x2, y1, y2])
}
//
chart.dispatchAction({
type: 'brush',
areas: []
})
//
chart.dispatchAction({
type: 'takeGlobalCursor'
})
},
//
emitRangeChange(range) {
this.$emit('rangeChange', range)
},
/**
* 设置范围
* @param {number} x1
* @param {number} x2
* @param {'x' | 'y'} type 要改变哪条轴
*/
setRange(x1, x2, type) {
if (type == 'x') {
this.twoDOption.xAxis.min = x1
this.twoDOption.xAxis.max = x2
} else if (type == 'y') {
this.twoDOption.yAxis.min = x1
this.twoDOption.yAxis.max = x2
}
},
//
interpolateColor(color1, color2, percentage) {
const r = color1.r + (color2.r - color1.r) * percentage
const g = color1.g + (color2.g - color1.g) * percentage
const b = color1.b + (color2.b - color1.b) * percentage
return { r, g, b }
}
},
watch: {
data: {
handler(newVal) {
this.twoDOption.series.data = newVal.filter(item => item.c).map(item => [item.b, item.g, item.c]) // 2D Scatter
const treeDSurfaceZMax = Math.max(...newVal.map(item => item.c))
this.threeDSurfaceOption.zAxis3D.max = Math.ceil(treeDSurfaceZMax * 1.2)
this.threeDSurfaceOption.series.data = newVal.map(item => [item.b, item.g, item.c]) // 3D surface
},
immediate: true
},
currCount: {
handler(val) {
if (val <= this.maxCount) {
const { r, g, b } = this.interpolateColor(
{ r: 255, g: 0, b: 0 },
{ r: 255, g: 255, b: 255 },
val / this.maxCount
)
this.twoDOption.series.itemStyle.color = `rgb(${r}, ${g}, ${b})`
} else {
this.twoDOption.series.itemStyle.color = '#fff'
}
},
immediate: true
}
}
}
</script>
<style lang="less" scoped>
.beta-gamma-spectrum-chart {
height: 100%;
&-operators {
text-align: right;
overflow: auto;
height: 26px;
display: flex;
justify-content: flex-end;
gap: 9px;
.ant-space-item:first-child {
span {
width: 70px;
}
}
span {
text-align: center;
height: 100%;
line-height: 26px;
width: 100px;
background-color: #406979;
cursor: pointer;
user-select: none;
&.active {
background-color: #1397a3;
}
}
}
&-main {
height: calc(100% - 40px);
margin-top: 15px;
._2d-chart {
height: 100%;
display: flex;
.custom-chart {
width: calc(100% - 45px);
}
.bar {
width: 30px;
margin-left: 15px;
height: 100%;
color: #ade6ee;
padding-top: 5px;
padding-bottom: 38px;
text-align: center;
&-main {
display: inline-block;
width: 14px;
height: calc(100% - 70px);
background: linear-gradient(to bottom, #ff0000 0, #fff 100%);
}
}
}
}
}
</style>

View File

@ -0,0 +1,163 @@
<template>
<div
ref="containerElemRef"
class="color-palette"
:style="{ width: circleWidth + 'px', height: circleWidth + 'px' }"
@click="handleClick"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseout="handleMouseOut"
>
<span
ref="dotElemRef"
class="dot"
:style="{
width: dotWidth + 'px',
height: dotWidth + 'px',
left: this.dotPosition.x,
top: this.dotPosition.y
}"
></span>
</div>
</template>
<script>
export default {
props: {
value: {
type: Number,
default: 1
},
maxValue: {
type: Number,
default: 0
},
circleWidth: {
type: Number,
default: 26
},
dotWidth: {
type: Number,
default: 5
}
},
data() {
return {
dotPosition: {
x: 0,
y: 0
},
isMouseDown: false
}
},
methods: {
handleClick({ offsetX, offsetY }) {
this.setPositionByMouseEvent(offsetX, offsetY)
},
//
handleMouseDown({ offsetX, offsetY }) {
this.setPositionByMouseEvent(offsetX, offsetY)
this.isMouseDown = true
},
handleMouseMove({ offsetX, offsetY }) {
if (this.isMouseDown) {
this.setPositionByMouseEvent(offsetX, offsetY)
}
},
//
handleMouseUp() {
this.isMouseDown = false
},
//
handleMouseOut() {
this.isMouseDown = false
},
setPositionByMouseEvent(offsetX, offsetY) {
const { degree, radian } = this.getDegree([offsetX, offsetY])
for (let index = 0; index < this.range; index++) {
if (degree >= this.perDegree * index && degree < this.perDegree * (index + 1)) {
this.$emit('input', index)
break
}
}
this.setDotPosition(radian)
},
setDotPosition(radian) {
const circleRadius = this.circleWidth / 2 //
const dotRadius = circleRadius - this.dotWidth //
this.dotPosition = {
x: circleRadius - dotRadius * Math.sin(radian) - this.dotWidth / 2 + 'px',
y: circleRadius + dotRadius * Math.cos(radian) - this.dotWidth / 2 + 'px'
}
},
//
/**
* 根据圆心和某个点计算从圆心到该点的角度
*/
getDegree(point) {
// x y
const circleRadius = this.circleWidth / 2 //
const [pointX, pointY] = point
const deltaX = circleRadius - pointX
const deltaY = pointY - circleRadius
// 使
const radian = Math.atan2(deltaX, deltaY)
let degree = radian * (180 / Math.PI)
if (degree < 0) {
degree = 360 + degree
}
return {
radian,
degree
}
}
},
watch: {
value: {
handler(newVal) {
const degree = newVal * this.perDegree
const radian = (degree * Math.PI) / 180 //
this.setDotPosition(radian)
},
immediate: true
}
},
computed: {
range() {
return this.maxValue > 50 ? this.maxValue : 50
},
perDegree() {
return 360 / this.range
}
}
}
</script>
<style lang="less" scoped>
.color-palette {
border-radius: 50%;
background-color: #ff5858;
margin: 0 auto;
position: relative;
.dot {
position: absolute;
pointer-events: none;
border-radius: 50%;
background-color: #f00;
}
}
</style>

View File

@ -0,0 +1,48 @@
<template>
<custom-modal v-model="visible" :title="type + ' Comment'" :okHandler="handleOk">
<a-textarea :rows="10" v-model="content"></a-textarea>
</custom-modal>
</template>
<script>
export default {
props: {
value: {
type: Boolean
},
type: {
type: String
}
},
data() {
return {
content: ''
}
},
methods: {
async handleOk() {
if (!this.content) {
this.$message.warn('Please Input Comment')
throw new Error('Content Is Empty')
}
console.log('%c [ ]-29', 'font-size:13px; background:pink; color:#bf2c9f;', this.type, this.content)
}
},
computed: {
visible: {
get() {
if (this.value) {
this.content = ''
}
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,162 @@
<template>
<custom-modal centered v-model="visible" :width="1200" title="Fit Peaks and Baseline">
<custom-table :columns="columns" :list="list">
<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]"></a-input>
</template>
</custom-table>
<div slot="custom-footer">
<a-space>
<a-button type="primary" @click="handlePeaks">Peaks</a-button>
<a-button>Cancel</a-button>
</a-space>
</div>
</custom-modal>
</template>
<script>
const columns = [
{
title: 'Peak',
dataIndex: 'peak',
width: 100,
scopedSlots: {
customRender: 'Peak'
}
},
{
title: 'Nuclide',
dataIndex: 'nuclide',
width: 100,
scopedSlots: {
customRender: 'Nuclide'
}
},
{
title: 'Energy',
dataIndex: 'energy',
width: 100,
scopedSlots: {
customRender: 'Energy'
}
},
{
title: 'NetArea',
dataIndex: 'netAreaInput',
width: 100,
scopedSlots: {
customRender: 'NetAreaInput'
}
},
{
title: 'FWHM',
dataIndex: 'fwhmInput',
width: 100,
scopedSlots: {
customRender: 'FWHMInput'
}
},
{
title: 'Step',
dataIndex: 'Step',
width: 100,
scopedSlots: {
customRender: 'Step'
}
},
{
title: 'BWGamma',
dataIndex: 'bwGamma',
width: 100,
scopedSlots: {
customRender: 'BWGamma'
}
},
{
title: 'NetArea',
dataIndex: 'netAreaCheckbox',
width: 100,
scopedSlots: {
customRender: 'NetAreaCheckbox'
},
isCheckbox: true
},
{
title: 'Centroid',
dataIndex: 'centroid',
width: 100,
scopedSlots: {
customRender: 'Centroid'
},
isCheckbox: true
},
{
title: 'FWHM',
dataIndex: 'fwhmCheckbox',
width: 100,
scopedSlots: {
customRender: 'FWHMCheckbox'
},
isCheckbox: true
}
]
export default {
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
return {
list: [
{
peak: 'peak',
nuclide: 'nuclide',
energy: 'energy',
netAreaInput: 'netAreaInput',
fwhmInput: 'fwhmInput',
Step: 'Step',
bwGamma: 'bwGamma',
netAreaCheckbox: false,
centroid: false,
fwhmCheckbox: false
}
]
}
},
methods: {
handlePeaks() {
console.log('%c [ ]-134', 'font-size:13px; background:pink; color:#bf2c9f;', this.list)
this.visible = false
}
},
computed: {
visible: {
get() {
if (this.value) {
this.content = ''
}
return this.value
},
set(val) {
this.$emit('input', val)
}
},
slots() {
return columns.map(column => {
return {
isCheckbox: column.isCheckbox,
dataIndex: column.dataIndex,
slotName: column.scopedSlots.customRender
}
})
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,128 @@
<template>
<custom-chart :option="option" />
</template>
<script>
import CustomChart from '@/components/CustomChart/index.vue'
const initialOption = {
grid: {
top: 40,
bottom: 50,
right: 30
},
title: {
text: 'Energy',
textStyle: {
color: '#8FD4F8',
fontSize: 14,
fontWeight: 'normal'
},
right: 10,
bottom: 5
},
xAxis: {
min: 620.68,
max: 629.16,
splitNumber: 3,
axisLine: {
lineStyle: {
color: '#fff'
}
},
splitLine: {
show: false
},
axisLabel: {
color: '#fff'
}
},
yAxis: {
min: 417,
max: 327,
interval: 90,
axisLine: {
lineStyle: {
color: '#fff'
}
},
splitLine: {
show: false
},
axisLabel: {
color: '#fff'
},
axisTick: {
show: false
},
name: 'Counts',
nameTextStyle: {
color: '#8FD4F8',
fontSize: 14
}
},
series: [
{
type: 'line',
data: [
[620.68, 410],
[621.98, 390],
[622.12, 337],
[623.53, 400],
[624.37, 410],
[625.37, 410],
[626.37, 410],
[627.37, 410],
[628.37, 410]
],
itemStyle: {
color: '#8BB93C'
},
symbol: 'none',
markLine: {
data: [
{
xAxis: 625.14,
label: {
formatter: '{c} keV',
color: '#f00',
fontWeight: 'bold',
fontSize: 14
}
}
],
symbol: 'none',
lineStyle: {
color: '#f00'
}
}
},
{
type: 'line',
data: [
[620.68, 367],
[622, 367],
[623, 367],
[624, 367],
[625, 367],
[626, 367],
[627, 367],
[628, 367],
[629, 367]
],
itemStyle: {
color: '#8FD4F8'
},
symbol: 'none'
}
]
}
export default {
components: {
CustomChart
},
data() {
return {
option: initialOption
}
}
}
</script>

View File

@ -0,0 +1,564 @@
<template>
<custom-modal v-model="visible" :width="1200" title="Nuclide Review" :footer="null">
<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></a-input-number>
</a-form-model-item>
<a-form-model-item label="Tolerance">
<a-input-number></a-input-number>
</a-form-model-item>
<a-button type="primary">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.id"
@click="handleNuclideClick(index)"
>
{{ item.title }}
</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">
{{ currNuclide.title }}
</a-form-model-item>
</a-col>
<a-col :span="6">
<a-form-model-item label="Half Life">
2
</a-form-model-item>
</a-col>
<a-col :span="6">
<a-form-model-item label="Half Life Err">
3
</a-form-model-item>
</a-col>
<a-col :span="6">
<a-form-model-item label="Lines">
4
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</div>
<a-table
:class="list.length ? 'has-data' : ''"
:columns="columns"
:dataSource="list"
:scroll="{ y: 180 }"
:customRow="customRow"
:pagination="false"
/>
</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>Line{{ chartItem.id }}</p>
<div class="nuclide-review-chart-item-chart" :class="currTableItem.id == chartItem.id ? 'active' : ''">
<nuclide-review-chart />
</div>
<p>Abundance: {{ chartItem.abundance }}</p>
</a-col>
</a-row>
<div class="nuclide-review-chart-next">
<span @click="handleChangeChart('next')">
&gt;
</span>
</div>
</div>
<!-- 图表部分结束 -->
</custom-modal>
</template>
<script>
import NuclideReviewChart from './NuclideReviewChart.vue'
const columns = [
{
title: 'Id',
dataIndex: 'id',
width: '5%'
},
{
title: 'Full Name',
dataIndex: 'fullName',
width: '15%'
},
{
title: 'Energy',
dataIndex: 'energy',
width: '15%'
},
{
title: 'Energy Err',
dataIndex: 'energyErr',
width: '15%'
},
{
title: 'Abundance(%)',
dataIndex: 'abundance',
width: '15%'
},
{
title: 'Abundance Err(%)',
dataIndex: 'abundanceErr',
width: '15%'
},
{
title: 'KeyLine',
dataIndex: 'keyLine',
width: '15%'
}
]
export default {
components: { NuclideReviewChart },
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
return {
nuclideList: [
{
id: 1,
title: 'Ag111',
data: [
{
id: '1',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
}
]
},
{
id: 2,
title: 'Eu157',
data: [
{
id: '1',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '2',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
}
]
},
{
id: 3,
title: 'Mo99',
data: [
{
id: '1',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '2',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '3',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
}
]
},
{
id: 4,
title: 'Pb204M',
data: [
{
id: '1',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '2',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '3',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '4',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '5',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '6',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '7',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
},
{
id: '8',
fullName: 'fullName',
energy: 'energy',
energyErr: 'energyErr',
abundance: 'abundance',
abundanceErr: 'abundanceErr',
keyLine: 'keyLine'
}
]
}
],
list: [], //
currNuclide: {},
currTableItem: {}, //
currChartList: [] // ,3
}
},
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)
}
},
handleNuclideClick(index) {
this.currNuclide = this.nuclideList[index]
this.list = this.currNuclide.data
this.selectTableRow(0)
},
selectTableRow(index) {
const record = this.list[index]
this.currTableItem = record
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.list.slice(startIndex, endIndex)
},
// /
handleChangeChart(direction) {
const currIndex = this.list.findIndex(item => item == this.currTableItem)
if (direction == 'prev') {
const willJumpIndex = currIndex - 3
if (willJumpIndex >= 0) {
this.selectTableRow(willJumpIndex)
}
else {
this.selectTableRow(0)
}
}
else if (direction == 'next') {
const willJumpIndex = currIndex + 3
if (willJumpIndex <= this.list.length - 2) {
this.selectTableRow(willJumpIndex)
}
else {
this.selectTableRow(this.list.length - 1)
}
}
},
// /
customRow(record, index) {
return {
class: 'custom-table-row' + (this.currTableItem == record ? ' ant-table-row-selected' : ''),
on: {
click: () => {
this.selectTableRow(index)
}
}
}
}
},
computed: {
visible: {
get() {
if (this.value) {
this.content = ''
}
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</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;
}
</style>

View File

@ -0,0 +1,489 @@
<template>
<custom-modal v-model="visible" :width="1280" title="Interactive Analyse Tools" :footer="null">
<div class="interactive-analysis-tools">
<div class="interactive-analysis-tools-left">
<div class="chart">
<custom-chart :option="option" />
</div>
<div class="thumbnail"></div>
<div class="table">
<p class="title">
<span @click="handleChangeMarkLine('prev')">&lt; </span>
6 Peaks with Anthro.Nuclides
<span @click="handleChangeMarkLine('next')">&gt;</span>
</p>
<custom-table
:class="list.length ? 'has-data' : ''"
:list="list"
:columns="columns"
:scroll="{ y: 288 }"
:selectedRowKeys.sync="selectedKeys"
>
</custom-table>
<div class="operators">
<a-button type="primary" @click="nuclideReviewModalVisible = true">Nuclide Review Window</a-button>
<a-button type="primary" @click="handleAddComment('Peak')">Add Peak Comment</a-button>
<a-button type="primary" @click="handleAddComment('General')">Add General Comment</a-button>
</div>
</div>
</div>
<div class="interactive-analysis-tools-right">
<title-over-boarder title="Peak">
<div class="peak-box">
<!-- 按钮组1 -->
<template v-if="btnGroupType == 1">
<div class="peak-box-item">
<a-button type="primary">Insert</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">Delete</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">Fit</a-button>
</div>
<div class="peak-box-item symbol" :key="4">
<a-button type="primary" @click="handleChangeMarkLine('prev')">&lt;</a-button>
<a-button type="primary" @click="handleChangeMarkLine('next')">&gt;</a-button>
</div>
<div class="peak-box-item base-line">
<a-button type="primary" @click="btnGroupType = 2">BaseLine</a-button>
</div>
</template>
<!-- 按钮组2 -->
<template v-if="btnGroupType == 2">
<div class="peak-box-item">
<a-button type="primary">(A)dd CP</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">(R)emove CP</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">(M)odify CP</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">Edit (S)lope</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">Undo</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary">Replot</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary" @click="btnGroupType = 1">Accept</a-button>
</div>
<div class="peak-box-item">
<a-button type="primary" @click="btnGroupType = 1">Cancel</a-button>
</div>
</template>
</div>
</title-over-boarder>
<div class="reset-btn-box">
<a-button type="primary">Reset Chart</a-button>
</div>
<div class="identify-box">
<title-over-boarder title="Nuclide Identify">
<a-form-model class="tolerance">
<a-form-model-item label="Tolerance">
<a-input-number></a-input-number>
</a-form-model-item>
</a-form-model>
<div class="identify-item">
<div class="title">
Possible Nuclide
</div>
<div class="content"></div>
</div>
<div class="identify-item">
<div class="title">
Nuclide Identified
</div>
<div class="content"></div>
</div>
<div class="identify-operators">
<a-space>
<a-input></a-input>
<a-button type="primary">Add</a-button>
<a-button type="primary" @click="handleDel">Del</a-button>
</a-space>
</div>
</title-over-boarder>
</div>
</div>
</div>
<!-- Comment弹窗 开始 -->
<comment-modal v-model="commentModalVisible" :type="commentType" />
<!-- Comment弹窗 结束 -->
<!-- Fit Peaks and Baseline弹窗 开始 -->
<fit-peaks-and-base-line-modal v-model="fitPeaksAndBaselineModalVisible" />
<!-- Fit Peaks and Baseline弹窗 结束 -->
<!-- Nuclide Review 弹窗开始 -->
<nuclide-review-modal v-model="nuclideReviewModalVisible" />
<!-- Nuclide Review 弹窗结束 -->
</custom-modal>
</template>
<script>
import CustomChart from '@/components/CustomChart/index.vue'
import TitleOverBoarder from '../../TitleOverBoarder.vue'
import CommentModal from './components/CommentModal.vue'
import FitPeaksAndBaseLineModal from './components/FitPeaksAndBaselineModal.vue'
import NuclideReviewModal from './components/NuclideReviewModal.vue'
const initialOption = {
grid: {
top: 20,
bottom: 20,
left: 100,
right: 20
},
xAxis: {
min: 1,
max: 8192,
interval: 1143,
axisLabel: {
color: '#fff'
},
splitLine: {
show: false
},
axisTick: {
show: false
}
},
yAxis: {
min: 1,
max: 994914,
axisLabel: {
color: '#fff'
},
name: 'Counts',
nameLocation: 'center',
nameGap: 60,
nameTextStyle: {
fontSize: 16,
color: '#5b9cba'
},
splitLine: {
show: false
},
axisTick: {
show: false
}
},
series: [
{
type: 'line',
data: [],
itemStyle: {
color: '#FCFE02'
},
markLine: {
data: [
{
xAxis: 1000
}
],
symbol: 'none',
lineStyle: {
color: '#f00'
},
label: {
show: false
}
}
},
{
type: 'line',
data: [],
itemStyle: {
color: '#F87E28'
}
},
{
type: 'line',
data: [],
itemStyle: {
color: '#01F6FE'
}
}
]
}
const columns = [
{
title: 'ID',
dataIndex: 'id',
width: 60
},
{
title: 'Energy (keV)',
dataIndex: 'energy',
width: 120
},
{
title: 'Centroid (C)',
dataIndex: 'centroid',
width: 120
},
{
title: 'FWHM (keV)',
dataIndex: 'fwhm',
width: 120
},
{
title: 'Area',
dataIndex: 'area',
width: 120
},
{
title: 'Detectability',
dataIndex: 'detectability',
width: 120
},
{
title: 'Cmnt',
dataIndex: 'cmnt',
width: 120
},
{
title: 'Nuclides',
dataIndex: 'nuclides',
width: 120
}
]
export default {
props: {
value: {
type: Boolean
}
},
components: {
CustomChart,
TitleOverBoarder,
CommentModal,
FitPeaksAndBaseLineModal,
NuclideReviewModal
},
data() {
this.columns = columns
return {
option: initialOption,
list: [],
commentModalVisible: false, // Comment
commentType: 'Peak',
btnGroupType: 1, // Peak
selectedKeys: [], //
fitPeaksAndBaselineModalVisible: false, // Fit Peaks And Base Line
nuclideReviewModalVisible: false // Nuclide Review
}
},
methods: {
// 线
handleChangeMarkLine(direction) {
if (direction == 'prev') {
this.option.series[0].markLine.data[0].xAxis = 900
} else if (direction == 'next') {
this.option.series[0].markLine.data[0].xAxis = 1100
}
this.list = new Array(20).fill(0).map((_, index) => ({
id: index.toString(),
energy: 'energy',
centroid: 'centroid',
fwhm: 'fwhm',
area: 'area',
detectability: 'detectability',
cmnt: 'cmnt',
nuclides: 'nuclides'
}))
},
// comment
handleAddComment(type) {
this.commentType = type
this.commentModalVisible = true
},
//
handleDel() {
if (!this.selectedKeys.length) {
this.$message.warn('Please Select At Least 1 Peak To Delete')
return
}
this.$warning({
title: 'Warning',
content: 'Are you sure to delete this peak?',
onOk: () => {
console.log('%c [ ]-294', 'font-size:13px; background:pink; color:#bf2c9f;', this.selectedKeys)
}
})
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
.interactive-analysis-tools {
display: flex;
&-left {
width: 75%;
margin-right: 20px;
.chart {
height: 331px;
}
.thumbnail {
height: 50px;
margin-top: 10px;
margin-bottom: 35px;
background-color: #255369;
}
.table {
.title {
color: #0cebc9;
font-size: 20px;
text-align: center;
margin-bottom: 10px;
span {
cursor: pointer;
margin: 0 5px;
}
}
.custom-table {
&.has-data {
::v-deep {
.ant-table-body {
height: 288px;
background-color: #06282a;
}
}
}
::v-deep {
.ant-table-placeholder {
height: 289px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
.operators {
display: flex;
margin-top: 10px;
gap: 10px;
.ant-btn {
flex: 1;
}
}
}
}
&-right {
.peak-box {
height: 326px;
&-item:not(:last-child) {
margin-bottom: 10px;
}
.symbol {
display: flex;
.ant-btn {
flex: 1;
&:first-child {
margin-right: 10px;
}
}
}
}
.base-line {
margin-top: 136px;
}
.reset-btn-box {
margin-top: 20px;
margin-bottom: 30px;
}
.identify-box {
.tolerance {
::v-deep {
.ant-form-item {
margin-bottom: 10px;
&-control-wrapper {
flex: 1;
}
&-control {
width: 100%;
}
}
}
.ant-input-number {
width: 100%;
}
}
.identify-item {
.title {
background-color: #497e9d;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 16px;
}
.content {
height: 80px;
background-color: #275466;
margin: 10px 0;
}
}
.identify-operators {
display: flex;
.ant-btn {
width: 50px;
padding-left: 5px;
padding-right: 5px;
}
}
}
}
.ant-btn {
width: 100%;
}
}
</style>

View File

@ -0,0 +1,193 @@
<template>
<custom-modal
v-model="visible"
:width="900"
title="Analysis Settings"
class="analysis-settings"
:okHanlder="handleOk"
>
<!-- 第一行 -->
<div class="analysis-settings-item">
<title-over-boarder title="Peak Searching">
<a-form-model :colon="false" :labelCol="{ style: { width: '160px' } }">
<a-form-model-item label="ECutAnalysis_Low">
<div class="input-with-unit">
<a-input></a-input>
KeV
</div>
</a-form-model-item>
<a-form-model-item label="ECutAnalysis_High">
<div class="input-with-unit">
<a-input></a-input>
KeV
</div>
</a-form-model-item>
<a-form-model-item label="EnergyTolerance">
<div class="input-with-unit">
<a-input></a-input>
KeV
</div>
</a-form-model-item>
<a-form-model-item label="PSS_low">
<a-input></a-input>
</a-form-model-item>
</a-form-model>
</title-over-boarder>
<title-over-boarder title="Calibration Peak Searching">
<a-form-model :colon="false" :labelCol="{ style: { width: '170px' } }">
<a-form-model-item label="CalibrationPSS_low">
<a-input></a-input>
</a-form-model-item>
<a-form-model-item label="CalibrationPSS_high">
<a-input></a-input>
</a-form-model-item>
<a-form-model-item>
<a-checkbox>
Update Calibration
</a-checkbox>
</a-form-model-item>
<a-form-model-item>
<a-checkbox>
Keep Calibration Peak Search Peaks
</a-checkbox>
</a-form-model-item>
</a-form-model>
</title-over-boarder>
</div>
<!-- 第二行 -->
<div class="analysis-settings-item">
<title-over-boarder title="Baseline Param">
<a-form-model :colon="false" :labelCol="{ style: { width: '90px' } }">
<a-form-model-item label="k_back">
<a-input></a-input>
</a-form-model-item>
<a-form-model-item label="k_alpha">
<a-input></a-input>
</a-form-model-item>
<a-form-model-item label="k_beta">
<a-input></a-input>
</a-form-model-item>
</a-form-model>
</title-over-boarder>
<div>
<a-form-model :colon="false" :labelCol="{ style: { width: '150px' } }">
<title-over-boarder title="BaseImprove">
<a-form-model-item label="BaseImprovePSS">
<a-input></a-input>
</a-form-model-item>
</title-over-boarder>
<title-over-boarder title="LC Computing" style="margin-top: 20px">
<a-form-model-item label="RiskLevelK">
<a-input></a-input>
</a-form-model-item>
</title-over-boarder>
</a-form-model>
</div>
</div>
<!-- 第三行 -->
<div class="analysis-settings-item">
<title-over-boarder title="Activity Reference Time">
<custom-date-picker show-time v-model="formModel.activityReferenceTime"></custom-date-picker>
</title-over-boarder>
<title-over-boarder title="Concentration Reference Time">
<custom-date-picker show-time v-model="formModel.concentrationReferenceTime"></custom-date-picker>
</title-over-boarder>
</div>
</custom-modal>
</template>
<script>
import TitleOverBoarder from '../TitleOverBoarder.vue'
export default {
components: { TitleOverBoarder },
props: {
value: {
type: Boolean
}
},
data() {
return {
formModel: {
activityReferenceTime: undefined,
concentrationReferenceTime: undefined
}
}
},
methods: {
handleOk() {
console.log('%c [ handleOk ]-121', 'font-size:13px; background:pink; color:#bf2c9f;')
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
.analysis-settings {
&-item {
display: flex;
&:not(:first-child) {
margin-top: 20px;
}
> div {
flex: 1;
&:first-child {
margin-right: 20px;
}
}
.ant-form {
&-item {
margin-bottom: 0;
&:not(:last-child) {
margin-bottom: 10px;
}
::v-deep {
.ant-form-item {
&-label {
text-align: left;
label {
font-size: 16px;
}
}
&-control-wrapper {
flex: 1;
}
}
}
.ant-input {
height: 26px;
}
.input-with-unit {
display: flex;
align-items: center;
.ant-input {
margin-right: 10px;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,130 @@
<template>
<custom-modal v-model="visible" title="Comparison" :width="800" :footer="null" class="comparison-modal">
<div class="comparison-list">
<div class="comparison-list-item" v-for="(item, index) in compareList" :key="index">
<div class="comparison-list-item-title">{{ item.title }}</div>
<custom-table :list="item.list" :columns="columns"></custom-table>
</div>
</div>
</custom-modal>
</template>
<script>
const columns = [
{
title: 'Isotope',
dataIndex: 'isotope'
},
{
title: 'Concentration',
dataIndex: 'concentration'
},
{
title: 'Uncertainty',
dataIndex: 'uncertainty'
},
{
title: 'MDC[mBq / m3 ]',
dataIndex: 'mdc'
}
]
export default {
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
return {
compareList: [
{
title: 'ARMD',
list: [
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
},
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
},
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
}
]
},
{
title: 'IDC',
list: [
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
},
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
},
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
},
{
isotope: 'isotope',
concentration: 'concentration',
uncertainty: 'uncertainty',
mdc: 'mdc'
}
]
}
]
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
.comparison-modal {
::v-deep {
.ant-modal-body {
padding: 16px;
}
}
}
.comparison-list {
&-item {
&-title {
color: #0cebc9;
}
&:last-child {
margin-top: 12px;
}
}
}
</style>

View File

@ -0,0 +1,333 @@
<template>
<custom-modal v-model="visible" :width="1280" title="Efficiency Calibration" :footer="null">
<div class="efficiency-calibration">
<div class="left">
<!-- Calibration Data -->
<title-over-boarder 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></a-input>
</a-form-model-item>
<a-form-model-item label="Efficiency">
<a-input></a-input>
</a-form-model-item>
<a-form-model-item :label="' '">
<a-button type="primary">Insert</a-button>
</a-form-model-item>
<a-form-model-item :label="' '">
<a-button type="primary">Modify</a-button>
</a-form-model-item>
<a-form-model-item :label="' '">
<a-button type="primary">Delete</a-button>
</a-form-model-item>
</a-form-model>
<!-- 表格 -->
<a-table
:columns="columns"
:dataSource="list"
:pagination="false"
:class="list.length ? 'has-data' : ''"
:scroll="{ y: 182 }"
></a-table>
<!-- 表格结束 -->
<div class="operators">
<div>
<a-button type="primary">Call</a-button>
<a-button type="primary">Save</a-button>
</div>
<div>
<a-select :value="''">
<a-select-option value="">
Interpolation
</a-select-option>
</a-select>
<a-button type="primary">Apply</a-button>
</div>
</div>
</div>
</title-over-boarder>
<!-- Equation -->
<title-over-boarder class="mt-20" title="Equation">
<div class="equation">
Efficiency = 59.541 + (88.034 - 59.541) * (E - 1)/ (0.058243 - 1)
</div>
</title-over-boarder>
<!-- curve -->
<title-over-boarder class="mt-20" title="curve">
<div class="curve">
<custom-chart :option="option" />
</div>
</title-over-boarder>
</div>
<div class="right">
<title-over-boarder title="Data Source" style="height: 100%">
<div class="data-source">
<div class="data-source-main">
<div class="title">PHD</div>
<div class="content"></div>
</div>
<div class="footer mt-20">
<a-button type="primary">Set to Current</a-button>
<div class="mt-20">PHD</div>
</div>
</div>
</title-over-boarder>
</div>
</div>
</custom-modal>
</template>
<script>
import ModalMixin from '@/mixins/ModalMixin'
import TitleOverBoarder from '../TitleOverBoarder.vue'
import CustomChart from '@/components/CustomChart/index.vue'
const columns = [
{
title: 'Energy(keV)',
dataIndex: 'energy'
},
{
title: 'Efficiency',
dataIndex: 'efficiency'
},
{
title: 'Fit',
dataIndex: 'fit'
},
{
title: 'Delta(%)',
dataIndex: 'delta'
}
]
const initialOption = {
grid: {
top: 20,
right: 20,
bottom: 50,
left: 70
},
title: {
text: 'Energy(keV)',
textStyle: {
color: '#8FD4F8',
fontSize: 14,
fontWeight: 'normal'
},
right: 10,
bottom: 0
},
xAxis: {
min: 42,
max: 2740,
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: 'Efficiency',
nameLocation: 'center',
nameGap: 50,
nameTextStyle: {
color: '#8FD4F8',
fontSize: 14
}
},
series: [
{
type: 'line',
itemStyle: {
color: '#EDF005'
},
data: [
[42, 0],
[100, 0.2],
[978, 0.1]
],
color: 'red'
}
]
}
export default {
components: { TitleOverBoarder, CustomChart },
mixins: [ModalMixin],
data() {
this.columns = columns
return {
list: [
{
energy: 'energy',
efficiency: 'efficiency',
fit: 'fit',
delta: 'delta'
}
],
option: initialOption
}
}
}
</script>
<style lang="less" scoped>
.efficiency-calibration {
display: flex;
.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: 32px;
line-height: 32px;
text-align: center;
background-color: #1b5465;
}
.curve {
height: 300px;
}
}
.right {
width: 20%;
margin-left: 20px;
.data-source {
.title {
height: 32px;
line-height: 32px;
background-color: #296d81;
padding: 0 5px;
}
.content {
height: 300px;
background-color: #275466;
}
.footer {
.ant-btn {
width: 100%;
}
> div {
text-align: center;
height: 32px;
line-height: 32px;
background-color: #285367;
}
}
}
}
}
.mt-20 {
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,465 @@
<template>
<custom-modal v-model="visible" title="Korsum" :width="1120" :footer="null">
<div class="korsum">
<!-- 输入开始 -->
<title-over-boarder title="Input">
<div class="korsum-input">
<!-- 公式部分 -->
<a-form-model
class="korsum-input-formula"
:labelCol="{
style: {
width: '110px'
}
}"
>
<a-form-model-item label="Total Effi = exp(">
<!-- 第一行 -->
<div>
<a-input-number v-model="formula.totalEffi[0]"></a-input-number>
<span class="operator">* Er + </span>
<a-input-number v-model="formula.totalEffi[1]"></a-input-number>
<span class="operator">+ </span>
</div>
<!-- 第二行 -->
<div>
<a-input-number v-model="formula.totalEffi[2]"></a-input-number>
<span class="operator">/ Er + </span>
<a-input-number v-model="formula.totalEffi[3]"></a-input-number>
<span class="operator">/ Er <sup>2</sup> + </span>
</div>
<!-- 第三行 -->
<div>
<a-input-number v-model="formula.totalEffi[4]"></a-input-number>
<span class="operator"> / Er <sup>3</sup> + </span>
<a-input-number v-model="formula.totalEffi[5]"></a-input-number>
<span class="operator">/ Er <sup>4</sup> ) </span>
</div>
</a-form-model-item>
<a-form-model-item label="Efficiency = exp(">
<!-- 第一行 -->
<div>
<a-input-number v-model="formula.efficiency[0]"></a-input-number>
<span class="operator">* Er + </span>
<a-input-number v-model="formula.efficiency[1]"></a-input-number>
<span class="operator">+ </span>
</div>
<!-- 第二行 -->
<div>
<a-input-number v-model="formula.efficiency[2]"></a-input-number>
<span class="operator">/ Er + </span>
<a-input-number v-model="formula.efficiency[3]"></a-input-number>
<span class="operator">/ Er <sup>2</sup> + </span>
</div>
<!-- 第三行 -->
<div>
<a-input-number v-model="formula.efficiency[4]"></a-input-number>
<span class="operator"> / Er <sup>3</sup> + </span>
<a-input-number v-model="formula.efficiency[5]"></a-input-number>
<span class="operator">/ Er <sup>4</sup> ) </span>
</div>
</a-form-model-item>
</a-form-model>
<!-- 公式结束 -->
<!-- 标题 -->
<p class="korsum-input-title">
Input
</p>
<!-- 标题结束 -->
<!-- 表格开始 -->
<a-table
class="korsum-input-table"
:class="list.length ? 'has-data' : ''"
:columns="columns"
:dataSource="list"
:scroll="{ y: 288 }"
:pagination="false"
>
<template slot="energy" slot-scope="text, record">
<a-input-number v-model="record.energy"></a-input-number>
</template>
<template slot="totalEfficiency" slot-scope="text, record">
<a-input-number v-model="record.totalEfficiency"></a-input-number>
</template>
<template slot="peakEfficiency" slot-scope="text, record">
<a-input-number v-model="record.peakEfficiency"></a-input-number>
</template>
<template slot="uncertainty" slot-scope="text, record">
<a-input-number v-model="record.uncertainty"></a-input-number>
</template>
</a-table>
<!-- 表格结束 -->
<!-- 按钮开始 -->
<div class="korsum-input-buttons">
<a-button type="primary" @click="handleAnalyze">Analyse</a-button>
<a-button type="primary" @click="handleExit">Exit</a-button>
</div>
<!-- 按钮结束 -->
</div>
</title-over-boarder>
<!-- 输入结束 -->
<!-- 输出开始 -->
<title-over-boarder title="Output">
<div class="korsum-output">
<div class="korsum-output-main">
<div class="korsum-output-list">
<div
class="korsum-output-list-item"
:class="selectedItem == item ? 'active' : ''"
v-for="(item, index) in outputList"
:key="index"
@click="handleOutputItemClick(item)"
>
{{ item.title }}
</div>
</div>
<a-table
class="korsum-output-table"
:columns="outputColumns"
:dataSource="outputTableList"
:class="outputTableList.length ? 'has-data' : ''"
:scroll="{ y: 584 }"
:pagination="false"
></a-table>
</div>
<div class="korsum-output-operation">
<div class="left">
<a-input v-model="filterWord"></a-input>
</div>
<div class="right">
<a-button type="primary" @click="handleExport">Export to Excel</a-button>
</div>
</div>
</div>
</title-over-boarder>
<!-- 输出结束 -->
</div>
</custom-modal>
</template>
<script>
import TitleOverBoarder from '../TitleOverBoarder.vue'
const columns = [
{
title: 'Energy',
dataIndex: 'energy',
scopedSlots: {
customRender: 'energy'
}
},
{
title: 'Total Efficiency',
dataIndex: 'totalEfficiency',
scopedSlots: {
customRender: 'totalEfficiency'
}
},
{
title: 'Peak Efficiency',
dataIndex: 'peakEfficiency',
scopedSlots: {
customRender: 'peakEfficiency'
}
},
{
title: 'Uncertainty(%)',
dataIndex: 'uncertainty',
scopedSlots: {
customRender: 'uncertainty'
}
}
]
const outputColumns = [
{
title: 'Energy',
dataIndex: 'energy'
},
{
title: 'Correct Factor',
dataIndex: 'correctFactor'
},
{
title: 'Uncertainty(%)',
dataIndex: 'uncertainty'
}
]
export default {
components: { TitleOverBoarder },
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
this.outputColumns = outputColumns
return {
formula: {
totalEffi: [0, 0, 0, 0, 0, 0],
efficiency: [0, 0, 0, 0, 0, 0]
},
list: [
{
id: 1,
energy: 10,
totalEfficiency: 0.005,
peakEfficiency: 0.002,
uncertainty: 10.0
},
{
id: 2,
energy: 10,
totalEfficiency: 0.005,
peakEfficiency: 0.002,
uncertainty: 10.0
}
],
selectedItem: {}, // output
outputTableList: [], // output
filterWord: '' //
}
},
methods: {
//
handleAnalyze() {
console.log('%c [ 分析 ]-178', 'font-size:13px; background:pink; color:#bf2c9f;')
},
// 退
handleExit() {
this.visible = false
},
// output
handleOutputItemClick(item) {
this.selectedItem = item
this.outputTableList = item.list
},
// excel
handleExport() {
console.log('%c [ 导出到excel ]-246', 'font-size:13px; background:pink; color:#bf2c9f;')
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
outputList() {
const list = [
{
id: 1,
title: 'SN-125',
list: [
{
id: 12,
energy: 'energy',
correctFactor: 'correctFactor',
uncertainty: 'uncertainty'
}
]
},
{
id: 2,
title: 'EU-157',
list: [
{
id: 12,
energy: 'energy',
correctFactor: 'correctFactor',
uncertainty: 'uncertainty'
}
]
}
]
return list.filter(item => item.title.toLowerCase().includes(this.filterWord.toLowerCase()))
}
}
}
</script>
<style lang="less" scoped>
::v-deep {
.title-over-border-content {
height: 711px;
}
}
.korsum {
display: flex;
gap: 20px;
.title-over-border {
flex: 1;
}
&-input {
&-formula {
::v-deep {
.ant-form-item {
margin-bottom: 10px;
&-label {
::after {
content: ' ';
margin: 0 2px;
}
> label {
color: #fff;
}
}
}
}
.ant-input-number {
width: 120px;
}
.operator {
display: inline-block;
width: 46px;
margin: 0 5px;
}
}
&-title {
height: 32px;
line-height: 32px;
text-align: center;
background-color: @primary-color;
}
&-table {
&.has-data {
::v-deep {
.ant-table-body {
height: 288px;
background-color: #06282a;
}
}
}
::v-deep {
.ant-table {
font-size: 14px;
}
.ant-table-placeholder {
height: 289px;
display: flex;
justify-content: center;
align-items: center;
}
}
.ant-input-number {
height: 26px;
::v-deep {
.ant-input-number-input {
height: 26px;
}
}
}
}
&-buttons {
margin-top: 10px;
display: flex;
gap: 20px;
.ant-btn {
flex: 1;
}
}
}
&-output {
height: 100%;
display: flex;
flex-direction: column;
&-main {
display: flex;
gap: 20px;
flex: 1;
}
&-list {
width: 120px;
height: 619px;
background: #275466;
padding: 5px;
overflow: auto;
&-item {
height: 32px;
line-height: 32px;
padding: 0 4px;
cursor: pointer;
&.active {
background-color: @primary-color;
}
}
}
&-table {
flex: 1;
&.has-data {
::v-deep {
.ant-table-body {
height: 584px;
background-color: #06282a;
}
}
}
::v-deep {
.ant-table {
font-size: 14px;
}
.ant-table-placeholder {
height: 585px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
&-operation {
margin-top: 20px;
display: flex;
gap: 20px;
.left {
width: 120px;
}
.right {
flex: 1;
.ant-btn {
width: 100%;
}
}
}
}
}
</style>

View File

@ -0,0 +1,448 @@
<template>
<custom-modal v-model="visible" :width="1280" title="Load From Database" class="load-from-db-modal">
<search-form ref="searchFormRef" :items="formItems" v-model="queryParam">
<a-space slot="additional">
<a-button @click="handleReset">Reset</a-button>
<a-button type="primary" @click="searchQuery">Search</a-button>
</a-space>
</search-form>
<custom-table
size="middle"
rowKey="sampleId"
:columns="columns"
:list="dataSource"
:pagination="ipagination"
:loading="loading"
@change="handleTableChange"
:selectedRowKeys.sync="selectedRowKeys"
:selectionRows.sync="selectionRows"
:multiple="true"
>
</custom-table>
<!-- 底部操作栏 -->
<template slot="custom-footer">
<a-space>
<a-radio-group v-model="queryParam.dbName">
<a-radio value="auto">From Auto DB</a-radio>
<a-radio value="man">From Interactive DB</a-radio>
</a-radio-group>
<a-button type="primary" @click="handleLoad">Load</a-button>
</a-space>
</template>
</custom-modal>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import { getAction } from '../../../../api/manage'
import moment from 'moment'
const columns = [
{
title: 'SampleID',
align: 'left',
dataIndex: 'sampleId'
},
{
title: 'Station',
align: 'left',
dataIndex: 'stationName'
},
{
title: 'Detector',
align: 'left',
dataIndex: 'detectorsName'
},
{
title: 'Sample',
align: 'left',
dataIndex: 'sampleType'
},
{
title: 'DataType',
align: 'left',
dataIndex: 'dataType'
},
{
title: 'Qualifier',
align: 'left',
dataIndex: 'spectralQualifie'
},
{
title: 'Col.Stop',
align: 'left',
dataIndex: 'collectStop'
},
{
title: 'Acq.Start',
align: 'left',
dataIndex: 'acquisitionStart'
},
{
title: 'Acq.real',
align: 'left',
dataIndex: 'acquisitionRealSec'
},
{
title: 'Acq.live',
align: 'left',
dataIndex: 'acquisitionLiveSec'
},
{
title: 'Status',
align: 'left',
dataIndex: 'status'
}
]
export default {
props: {
value: {
type: Boolean
}
},
mixins: [JeecgListMixin],
data() {
this.columns = columns
this.disableMixinCreated = true
return {
queryParam: {
menuTypes: undefined,
startDate: moment()
.add(-7, 'd')
.format('YYYY-MM-DD'),
endDate: moment().format('YYYY-MM-DD'),
dbName: 'auto'
},
selectedRowKeys: [],
selectionRows: [],
stationList: [],
detectorList: [],
url: {
list: '/spectrumAnalysis/getDBSpectrumList'
}
}
},
methods: {
loadData(arg) {
const params = this.getQueryParams() //
const { startDate, endDate, menuTypes } = params
if (!menuTypes) {
this.$message.warn('Please Select SampleType First')
return
}
if(!startDate || !endDate) {
this.$message.warn(`'From' Date And 'To' Date Cannot Be Null`)
return
}
if(moment(startDate).isAfter(moment(endDate))) {
this.$message.warn(`'From' Date Cannot Be Late Than 'To' Date`)
return
}
// 1
if (arg === 1) {
this.ipagination.current = 1
}
if (params.checkboxGroup) {
params.checkboxGroup.forEach(item => {
params[item] = true
})
delete params.checkboxGroup
}
this.onClearSelected()
this.loading = true
getAction(this.url.list, params)
.then(res => {
if (res.success) {
this.dataSource = res.result.records || res.result
if (res.result.total) {
this.ipagination.total = res.result.total
} else {
this.ipagination.total = 0
}
} else {
this.$message.warning(res.message)
}
})
.finally(() => {
this.loading = false
})
},
/**
* 加载
*/
async handleLoad() {
if (!this.selectedRowKeys.length) {
this.$message.warn('Please Select Databases To Load')
return
}
this.selectedRowKeys = []
this.visible = false
this.$emit('loadSample', this.selectionRows)
},
//
async getStationAndDetectorList(value) {
if (!value) {
return
}
try {
const { success, result, message } = await getAction('/spectrumAnalysis/getDBSearchList', {
menuTypes: value
})
if (success) {
this.stationList = result.stationCode.map(item => ({ label: item, value: item }))
this.detectorList = result.detectorCode.map(item => ({ label: item, value: item }))
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
//
handleReset() {
this.$refs.searchFormRef.$refs.form.resetFields()
},
filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
formItems() {
return [
{
label: 'SampleType',
type: 'custom-select',
name: 'menuTypes',
props: {
options: [
{
label: 'All',
value: 'G,B'
},
{
label: 'Gamma',
value: 'G'
},
{
label: 'Beta',
value: 'B'
}
],
allowClear: true
},
style: {
width: '18%'
},
on: {
change: event => {
this.getStationAndDetectorList(event)
}
}
},
{
label: 'Station',
type: 'custom-select',
name: 'stationName',
props: {
options: this.stationList,
showSearch: true,
filterOption: this.filterOption,
allowClear: true
},
style: {
width: '19%'
}
},
{
label: 'Detector',
type: 'custom-select',
name: 'detectorsName',
props: {
options: this.detectorList,
showSearch: true,
filterOption: this.filterOption,
allowClear: true
},
style: {
width: '19%'
}
},
{
label: 'Sample',
type: 'custom-select',
name: 'sampleType',
props: {
options: [
{
label: 'P',
value: 'P'
},
{
label: 'B',
value: 'B'
},
{
label: 'G',
value: 'G'
}
],
allowClear: true
},
style: {
width: '14%'
}
},
{
label: 'DataType',
type: 'custom-select',
name: 'dataType',
props: {
options: [
{
label: 'S',
value: 'S'
},
{
label: 'G',
value: 'G'
},
{
label: 'D',
value: 'D'
},
{
label: 'Q',
value: 'Q'
},
{
label: 'B',
value: 'B'
},
{
label: 'C',
value: 'C'
}
],
allowClear: true
},
style: {
width: '14%'
}
},
{
label: 'Qualifier',
type: 'custom-select',
name: 'spectralQualifie',
props: {
options: [
{
label: 'FULL',
value: 'FULL'
},
{
label: 'PREL',
value: 'PREL'
}
],
allowClear: true
},
style: {
width: '16%',
paddingRight: 0
}
},
{
label: 'SampleID',
type: 'a-input',
name: 'sampleId',
props: {
allowClear: true
},
style: {
width: '264px'
}
},
{
label: '',
type: 'a-checkbox-group',
name: 'checkboxGroup',
props: {
options: [
{ label: 'All User', value: 'allUser' },
{ label: 'Collect Stop', value: 'CollectStop' },
{ label: 'Acq.Start', value: 'AcqStart' }
]
},
style: {
width: '305px',
paddingRight: 0
}
},
{
label: 'From',
type: 'custom-date-picker',
name: 'startDate',
props: {
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
style: {
minWidth: 'auto'
}
},
style: {
width: '19%'
}
},
{
label: 'To',
type: 'custom-date-picker',
name: 'endDate',
props: {
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
style: {
minWidth: 'auto'
}
},
style: {
paddingRight: 0,
marginRight: '22px',
width: '19%'
}
}
]
}
}
}
</script>
<style lang="less" scoped>
.load-from-db-modal {
::v-deep {
.search-btn {
display: none;
}
}
}
</style>

View File

@ -0,0 +1,172 @@
<template>
<custom-modal v-model="visible" :width="1200" title="Load Data From File">
<a-table :data-source="list" :columns="columns" :pagination="false" bordered>
<template slot="sampleData" slot-scope="text, record">
<phd-select type="file" @change="handleFileChange(record, 'sampleData', $event)" :title="text && text.name">
{{ text && text.name }}
</phd-select>
</template>
<template slot="gasBkData" slot-scope="text, record">
<phd-select type="file" @change="handleFileChange(record, 'gasBkData', $event)" :title="text && text.name">
{{ text && text.name }}
</phd-select>
</template>
<template slot="detBkData" slot-scope="text, record">
<phd-select type="file" @change="handleFileChange(record, 'detBkData', $event)" :title="text && text.name">
{{ text && text.name }}
</phd-select>
</template>
<template slot="qcData" slot-scope="text, record">
<phd-select type="file" @change="handleFileChange(record, 'qcData', $event)" :title="text && text.name">
{{ text && text.name }}
</phd-select>
</template>
<template slot="status" slot-scope="text">
<span class="status"></span>
</template>
</a-table>
<!-- 底部按钮 -->
<template slot="custom-footer">
<a-space>
<a-button type="primary" @click="handleReset">Reset</a-button>
<a-button type="primary" @click="handleLoad">Load</a-button>
<a-button type="primary" @click="handleCancel">Cancel</a-button>
</a-space>
</template>
<!-- 底部按钮结束 -->
</custom-modal>
</template>
<script>
import PhdSelect from '../PHDSelect.vue'
const columns = [
{
title: 'SampleData',
dataIndex: 'sampleData',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'sampleData'
}
},
{
title: 'GasBkData',
dataIndex: 'gasBkData',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'gasBkData'
}
},
{
title: 'DetBkData',
dataIndex: 'detBkData',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'detBkData'
}
},
{
title: 'QCData',
dataIndex: 'qcData',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'qcData'
}
},
{
title: 'Status',
align: 'center',
scopedSlots: {
customRender: 'status'
}
}
]
export default {
components: { PhdSelect },
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
return {
list: this.getInitialList()
}
},
methods: {
// 10*4
getInitialList() {
return new Array(10).fill(0).map(() => ({
sampleData: undefined,
gasBkData: undefined,
detBkData: undefined,
qcData: undefined
}))
},
handleFileChange(record, key, fileInfo) {
record[key] = fileInfo
},
handleReset() {
this.list = this.getInitialList()
},
handleLoad() {
console.log('%c [ handleLoad ]-123', 'font-size:13px; background:pink; color:#bf2c9f;', this.list)
},
handleCancel() {
this.visible = false
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
.status {
display: inline-block;
width: 25px;
height: 25px;
border-radius: 50%;
margin-top: 8px;
background-color: #00e170;
}
::v-deep {
@tableBorderColor: #000;
.ant-table-bordered .ant-table-thead > tr > th,
.ant-table-bordered .ant-table-tbody > tr > td {
border-right-color: @tableBorderColor;
}
.ant-table-thead > tr th {
border-bottom: 1px solid @tableBorderColor;
}
.ant-table-bordered .ant-table-body > table {
border-color: @tableBorderColor;
}
.ant-table-tbody tr td {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
}
</style>

View File

@ -0,0 +1,239 @@
<template>
<custom-modal
v-model="visible"
:width="1231"
title="Nuclide Activity and MDC"
class="nuclide-activity-and-mdc-modal"
:footer="null"
>
<!-- 顶部搜索栏 -->
<a-form-model class="search-form">
<div class="time-pickers">
<a-form-model-item label="Activity reference time">
<custom-date-picker show-time v-model="queryParam.activityReferenceTime" />
</a-form-model-item>
<a-form-model-item label="Concentration reference time">
<custom-date-picker show-time v-model="queryParam.concentrationReferenceTime" />
</a-form-model-item>
</div>
<a-space class="operators" :size="20">
<a-button :type="compareVisible ? 'grey' : 'primary'" @click="handleComparision">
<img src="@/assets/images/spectrum/comparation.png" />
{{ compareVisible ? 'Cancel comparison' : 'Comparison' }}
</a-button>
<a-button type="primary" @click="handleExportToExcel">
<img src="@/assets/images/spectrum/download.png" />
Export to Excel
</a-button>
</a-space>
</a-form-model>
<!-- 顶部搜索栏结束 -->
<!-- 主体部分 -->
<div v-if="compareVisible" class="comparison-list">
<div class="comparison-list-item" v-for="(item, index) in compareList" :key="index">
<div class="comparison-list-item-title">{{ item.title }}</div>
<custom-table :list="item.list" :columns="columns"></custom-table>
</div>
</div>
<custom-table v-else :list="list" :columns="columns"></custom-table>
</custom-modal>
</template>
<script>
const columns = [
{
title: 'Nuclide',
dataIndex: 'nuclide'
},
{
title: 'HalfLife',
dataIndex: 'halfLife'
},
{
title: 'Energy (keV)',
dataIndex: 'energy'
},
{
title: 'Yield (%)',
dataIndex: 'yield'
},
{
title: 'Efficiency',
dataIndex: 'efficiency'
},
{
title: 'Activity (Bq)',
dataIndex: 'activity'
},
{
title: 'Act Err (%)',
dataIndex: 'actErr'
},
{
title: 'MDA (Bq)',
dataIndex: 'mda'
},
{
title: 'Conc (uBq/m3)',
dataIndex: 'conc'
},
{
title: 'MDC (uBq/m3)',
dataIndex: 'mdc'
}
]
export default {
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
return {
queryParam: {
activityReferenceTime: undefined,
concentrationReferenceTime: undefined
},
compareVisible: false,
list: [
{
nuclide: 'nuclide',
halfLife: 'halfLife',
energy: 'energy',
yield: 'yield',
efficiency: 'efficiency',
activity: 'activity',
actErr: 'actErr',
mda: 'mda',
conc: 'conc',
mdc: 'mdc'
}
],
compareList: [
{
title: 'ARMD',
list: [
{
nuclide: 'nuclide',
halfLife: 'halfLife',
energy: 'energy',
yield: 'yield',
efficiency: 'efficiency',
activity: 'activity',
actErr: 'actErr',
mda: 'mda',
conc: 'conc',
mdc: 'mdc'
}
]
},
{
title: 'IDC',
list: [
{
nuclide: 'nuclide',
halfLife: 'halfLife',
energy: 'energy',
yield: 'yield',
efficiency: 'efficiency',
activity: 'activity',
actErr: 'actErr',
mda: 'mda',
conc: 'conc',
mdc: 'mdc'
}
]
}
]
}
},
methods: {
//
handleComparision() {
this.compareVisible = !this.compareVisible
},
// Excel
handleExportToExcel() {}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
.nuclide-activity-and-mdc-modal {
::v-deep {
.ant-modal-body {
padding: 16px;
}
}
}
.search-form {
display: flex;
justify-content: space-between;
margin-bottom: 15px;
.time-pickers {
display: flex;
.ant-form-item {
margin-bottom: 0;
&:nth-child(2) {
margin-left: 20px;
}
::v-deep {
.ant-form-item {
&-label {
> label {
color: #ade6ee;
}
}
&-control-wrapper {
width: 210px;
}
}
}
}
}
.operators {
.ant-btn {
display: flex;
align-items: center;
img {
margin-right: 10px;
}
}
}
}
.comparison-list {
padding-top: 15px;
border-top: 1px solid rgba(13, 109, 118, 0.5);
&-item {
&-title {
color: #0cebc9;
}
&:last-child {
margin-top: 12px;
}
}
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<span class="status" :style="{ background: currStatus.color }">{{ currStatus.title }}</span>
</template>
<script>
const statusList = {
0: {
title: 'Done',
color: '#008000'
},
1: {
title: '==>',
color: '#FFAA00'
},
2: {
title: 'Pending',
color: '#FF0000'
}
}
export default {
props: {
status: {
type: Number,
default: 0
}
},
computed: {
currStatus() {
return statusList[this.status]
}
}
}
</script>
<style lang="less" scoped>
.status {
width: 80px;
text-align: center;
}
</style>

View File

@ -0,0 +1,108 @@
<template>
<custom-modal v-model="visible" :width="400" title="Processing Monitor" :footer="null">
<div class="processing">
<div>
<!-- 标题 -->
<div class="processing-title">Calibration Updates</div>
<!-- 列表 -->
<div class="processing-list">
<div class="processing-list-item">
<status :status="0" />
<div class="description">Energy - Mariscotti Centroids</div>
</div>
<div class="processing-list-item">
<status :status="0" />
<div class="description">Resolution</div>
</div>
<div class="processing-list-item">
<status :status="0" />
<div class="description">Energy - Fitted Centroids</div>
</div>
</div>
</div>
<div style="margin-top: 20px;">
<!-- 标题 -->
<div class="processing-title">Spectrum Analysis</div>
<!-- 列表 -->
<div class="processing-list">
<div class="processing-list-item">
<status :status="0" />
<div class="description">Peak Search</div>
</div>
<div class="processing-list-item">
<status :status="0" />
<div class="description">Baseline Fitting</div>
</div>
<div class="processing-list-item">
<status :status="1" />
<div class="description">Net Area Fitting</div>
</div>
<div class="processing-list-item">
<status :status="2" />
<div class="description">Nuclide Identification</div>
</div>
<div class="processing-list-item">
<status :status="2" />
<div class="description">Activity and MDA</div>
</div>
<div class="processing-list-item">
<status :status="2" />
<div class="description">QC Test</div>
</div>
</div>
</div>
</div>
</custom-modal>
</template>
<script>
import Status from './components/status.vue'
export default {
components: {
Status
},
props: {
value: {
type: Boolean
}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
@color: #325050;
.processing {
&-title {
height: 32px;
line-height: 32px;
background-color: @color;
text-align: center;
}
&-list {
&-item {
margin-top: 20px;
display: flex;
gap: 20px;
height: 26px;
line-height: 26px;
.description {
flex: 1;
background-color: @color;
text-align: center;
}
}
}
}
</style>

View File

@ -0,0 +1,81 @@
<template>
<custom-modal v-model="visible" title="Save Setting" :width="380" :okHandler="handleOk">
<div class="save-setting">
<div class="save-setting-all">
<a-checkbox v-model="saveAll">
Save All
</a-checkbox>
</div>
<div>
<title-over-boarder title="Format">
<a-radio-group v-model="saveFormat" class="format-radio-group">
<a-radio value="txt">Save as Txt</a-radio>
<a-radio value="excel">Save as Excel</a-radio>
</a-radio-group>
</title-over-boarder>
</div>
</div>
</custom-modal>
</template>
<script>
import { downloadFile } from '../../../../api/manage'
import TitleOverBoarder from '../TitleOverBoarder.vue'
export default {
components: { TitleOverBoarder },
props: {
value: {
type: Boolean
}
},
data() {
return {
saveAll: false,
saveFormat: 'txt'
}
},
methods: {
reset() {
this.saveAll = false
this.saveFormat = 'txt'
},
handleOk() {
console.log('%c [ save ]-22', 'font-size:13px; background:pink; color:#bf2c9f;')
downloadFile('', 'result.' + this.saveFormat, {})
}
},
computed: {
visible: {
set(val) {
this.$emit('input', val)
},
get() {
if (this.value) {
this.reset()
}
return this.value
}
}
}
}
</script>
<style lang="less" scoped>
.save-setting {
display: flex;
align-items: center;
&-all {
width: 65%;
text-align: center;
}
.format-radio-group {
.ant-radio-wrapper:first-child {
margin-bottom: 10px;
}
}
}
</style>

View File

@ -0,0 +1,250 @@
<template>
<custom-modal v-model="visible" title="Zero Time" :width="940" :footer="null">
<div class="zero-time">
<!-- 左侧 -->
<div class="zero-time-left">
<title-over-boarder title="Fission Product Infomation">
<div class="fission-product">
<div class="fission-product-container">
<div class="fission-product-title">
Fission Product 1
</div>
<div class="fission-product-list">
<div class="fission-product-list-item" v-for="(item, index) in fissionProductList1" :key="index">
{{ item.title }}
</div>
</div>
</div>
<div class="fission-product-container">
<div class="fission-product-title">
Fission Product 2
</div>
<div class="fission-product-list">
<div class="fission-product-list-item" v-for="(item, index) in fissionProductList2" :key="index">
{{ item.title }}
</div>
</div>
</div>
</div>
</title-over-boarder>
<!-- Result of Zero Time -->
<title-over-boarder class="mt-20" title="Result of Zero Time">
<div class="result-of-zero-time">2015-05-30 17:30:60</div>
</title-over-boarder>
</div>
<!-- 左侧结束 -->
<!-- 右侧 -->
<div class="zero-time-right">
<!-- Active of Fission Product -->
<title-over-boarder title="Active of Fission Product">
<div class="active-of-fission-product">
<div class="item">
<div class="title">
Fission Product 1
</div>
<div>
<a-input></a-input>
</div>
</div>
<div class="operator">
-----Bq-----
</div>
<div class="item">
<div class="title">
Fission Product 2
</div>
<div>
<a-input></a-input>
</div>
</div>
</div>
</title-over-boarder>
<div class="zero-time-right-center mt-20">
<!-- Fission Target -->
<title-over-boarder class="fission-target" title="Fission Target">
<a-radio-group>
<a-radio>U-235</a-radio>
<a-radio>U-238</a-radio>
<a-radio>PU-239</a-radio>
</a-radio-group>
</title-over-boarder>
<title-over-boarder class="fission-energy" title="Energy of Fission Neutron">
<a-radio-group>
<a-radio>T&gt;Thermal_spectrum</a-radio>
<a-radio>F&gt;Fission_spectrum</a-radio>
<a-radio>H-&gt;Fast_Neutron</a-radio>
</a-radio-group>
</title-over-boarder>
</div>
<title-over-boarder class="mt-20" title="Reference Time">
<a-form-model layout="inline">
<a-form-model-item label="Date">
<custom-date-picker />
</a-form-model-item>
<a-form-model-item label="Time">
<a-time-picker></a-time-picker>
</a-form-model-item>
</a-form-model>
</title-over-boarder>
<div class="zero-time-right-buttons mt-20">
<a-button type="primary">Analysis</a-button>
<a-button type="primary">Save</a-button>
<a-button type="primary">Exit</a-button>
</div>
</div>
<!-- 右侧结束 -->
</div>
</custom-modal>
</template>
<script>
import TitleOverBoarder from '../TitleOverBoarder.vue'
export default {
components: { TitleOverBoarder },
props: {
value: {
type: Boolean
}
},
data() {
return {
fissionProductList1: [
{
id: 1,
title: 'Ba140'
},
{
id: 2,
title: 'Ce141'
}
],
fissionProductList2: [
{
id: 1,
title: 'Ba140'
}
]
}
},
computed: {
visible: {
set(val) {
this.$emit('input', val)
},
get() {
return this.value
}
}
}
}
</script>
<style lang="less" scoped>
.zero-time {
display: flex;
gap: 30px;
&-left {
width: 40%;
.fission-product {
display: flex;
gap: 15px;
&-container {
flex: 1;
}
&-title {
height: 32px;
line-height: 32px;
font-size: 16px;
background-color: #497e9d;
text-align: center;
}
&-list {
margin-top: 5px;
height: 255px;
overflow: auto;
padding: 0 10px;
background-color: #275466;
&-item {
height: 32px;
line-height: 32px;
}
}
}
.result-of-zero-time {
height: 32px;
line-height: 32px;
text-align: center;
background-color: #00ff7f;
font-size: 18px;
}
}
//
&-right {
flex: 1;
.active-of-fission-product {
display: flex;
align-items: end;
padding: 0 60px;
.item {
flex: 1;
.title {
font-size: 16px;
margin-bottom: 10px;
}
}
.operator {
margin: 5px 15px;
}
}
&-center {
display: flex;
gap: 20px;
.fission-target {
width: 40%;
}
.fission-energy {
flex: 1;
}
.ant-radio-wrapper {
display: block;
&:not(:first-child) {
margin-top: 20px;
}
}
}
&-buttons {
display: flex;
justify-content: space-between;
.ant-btn {
padding: 0 45px;
}
}
}
}
.mt-20 {
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<a-menu mode="vertical" :style="{ width }" class="multi-level-menu">
<template v-for="(item, index) in children">
<a-menu-item :key="index" v-bind="item.attrs" @click="handleMenuClick(item)">
{{ item.title }}
<div v-if="item.children" :key="index">
<a-menu class="multi-level-menu-sub-menu">
<a-menu-item v-for="child in item.children" :key="child.key" @click="handleSubMenuClick(item, child)">
{{ child.title }}
</a-menu-item>
</a-menu>
</div>
</a-menu-item>
</template>
</a-menu>
</template>
<script>
export default {
props: {
children: {
type: Array,
default: () => []
},
width: {
type: String,
default: 'auto'
}
},
methods: {
handleMenuClick(item) {
if (!item.children) {
this.$emit('menuClick', item)
}
},
handleSubMenuClick(item, child) {
this.$emit('submenuClick', { item, child })
}
}
}
</script>
<style lang="less">
.multi-level-menu {
.ant-menu-item {
overflow: visible;
.multi-level-menu-sub-menu {
position: absolute;
top: 0;
right: 0;
transform: translateX(100%);
display: none;
background: #03353f;
}
&-active {
.multi-level-menu-sub-menu {
display: block;
}
}
}
}
</style>

View File

@ -0,0 +1,39 @@
<template>
<label class="file-select">
<input type="file" @change="handleFileChange" accept=".phd, .PHD" />
<div class="file-name">
<slot />
</div>
</label>
</template>
<script>
export default {
methods: {
handleFileChange(e) {
const file = e.target.files[0]
if (file) {
this.$emit('change', file)
}
e.target.value = ''
}
}
}
</script>
<style lang="less" scoped>
.file-select {
display: block;
height: 42px;
line-height: 42px;
input {
display: none;
}
.file-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
</style>

View File

@ -0,0 +1,360 @@
<template>
<a-modal v-model="visible" title="Peak Infomation" :width="1231" :footer="null" class="peak-infomation">
<div v-if="compareVisible" class="comparison-list">
<div class="comparison-list-item" v-for="(item, index) in compareList" :key="index">
<div class="comparison-list-item-title">{{ item.title }}</div>
<custom-table :list="item.list" :scroll="{ y: 230 }" :columns="columns"></custom-table>
</div>
</div>
<custom-table v-else :columns="columns" :list="list"></custom-table>
<!-- 底部按钮 -->
<div class="peak-infomation-footer">
<a-space :size="20">
<a-button :type="compareVisible ? 'grey' : 'primary'" @click="handleComparision">
<img src="@/assets/images/spectrum/comparation.png" />
{{ compareVisible ? 'Cancel comparison' : 'Comparison' }}
</a-button>
<a-button type="primary" @click="handleExportToExcel">
<img src="@/assets/images/spectrum/download.png" />
Export to Excel
</a-button>
</a-space>
</div>
</a-modal>
</template>
<script>
const columns = [
{
title: 'Index',
dataIndex: 'index',
align: 'center',
customRender: (_, __, index) => {
return index + 1
}
},
{
title: 'Energy(keV)',
dataIndex: 'energy'
},
{
title: 'Centroid',
dataIndex: 'centroid'
},
{
title: 'Multiplet',
dataIndex: 'multiplet'
},
{
title: 'Fwhm(keV)',
dataIndex: 'fwhm'
},
{
title: 'NetArea',
dataIndex: 'netArea'
},
{
title: 'AreaErr(%)',
dataIndex: 'areaErr'
},
{
title: 'Significant',
dataIndex: 'significant'
},
{
title: 'Sensitivity',
dataIndex: 'sensitivity'
},
{
title: 'Indentify',
dataIndex: 'indentify'
}
]
export default {
props: {
value: {
type: Boolean
}
},
data() {
this.columns = columns
return {
list: [
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
}
],
compareList: [
{
title: 'ARMD',
list: [
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
},
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
}
]
},
{
title: 'IDC',
list: [
{
id: 1,
energy: 'energy',
centroid: 'centroid',
multiplet: 'multiplet',
fwhm: 'fwhm',
netArea: 'netArea',
areaErr: 'areaErr',
significant: 'significant',
sensitivity: 'sensitivity',
indentify: 'indentify'
}
]
}
],
compareVisible: true
}
},
methods: {
//
handleComparision() {
this.compareVisible = !this.compareVisible
},
// Excel
handleExportToExcel() {}
},
computed: {
visible: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>
<style lang="less" scoped>
.peak-infomation {
::v-deep {
.ant-modal-body {
padding: 20px 16px 16px;
}
}
&-footer {
margin-top: 10px;
text-align: right;
.ant-btn {
display: flex;
align-items: center;
img {
margin-right: 10px;
}
}
}
}
.comparison-list {
&-item {
&-title {
color: #0cebc9;
}
&:last-child {
margin-top: 12px;
}
}
}
</style>

View File

@ -0,0 +1,213 @@
<template>
<div class="result-display-content">
<a-table :data-source="source1" rowKey="id" :columns="columns" :pagination="false">
<template slot="flag">
<a-checkbox></a-checkbox>
</template>
<template slot="concentration" slot-scope="text">
<div class="concentration color-box">
{{ text }}
</div>
</template>
<template slot="uncertainty" slot-scope="text">
<div class="uncertainty color-box">
{{ text }}
</div>
</template>
<template slot="mdc" slot-scope="text">
<div class="mdc color-box">
{{ text }}
</div>
</template>
<template slot="operator">
<div class="search"></div>
</template>
</a-table>
<a-table :data-source="source2" rowKey="id" :columns="columns" :pagination="false">
<template slot="flag">
<a-checkbox></a-checkbox>
</template>
<template slot="concentration" slot-scope="text">
<div class="concentration color-box error">
{{ text }}
</div>
</template>
<template slot="uncertainty" slot-scope="text">
<div class="uncertainty color-box">
{{ text }}
</div>
</template>
<template slot="mdc" slot-scope="text">
<div class="mdc color-box">
{{ text }}
</div>
</template>
<template slot="operator">
<div class="search"></div>
</template>
</a-table>
</div>
</template>
<script>
const columns = [
{
title: 'Flag',
align: 'center',
scopedSlots: {
customRender: 'flag'
},
width: 40
},
{
title: 'Isotope',
dataIndex: 'isotope',
ellipsis: true,
width: 76
},
{
title: 'Concentration',
dataIndex: 'concentration',
scopedSlots: {
customRender: 'concentration'
},
width: 128
},
{
title: 'Uncertainty',
dataIndex: 'uncertainty',
scopedSlots: {
customRender: 'uncertainty'
},
width: 118
},
{
title: 'MDC[mBq/m3]',
dataIndex: 'mdc',
scopedSlots: {
customRender: 'mdc'
},
width: 133
},
{
title: '',
scopedSlots: {
customRender: 'operator'
},
width: 34
}
]
export default {
props: {
data: {
type: Array,
default: []
}
},
data() {
this.columns = columns
return {
source1: [],
source2: []
}
},
watch: {
data: {
handler(val) {
this.source1 = val.slice(0, 2)
this.source2 = val.slice(2, 4)
},
immediate: true
}
}
}
</script>
<style lang="less" scoped>
.result-display-content {
display: flex;
.ant-table-wrapper {
flex: 1;
&:first-child {
margin-right: 20px;
}
::v-deep {
.ant-table {
border: none;
}
.ant-table-thead > tr th {
color: #00e9fe;
font-family: MicrosoftYaHei;
font-size: 16px;
background-color: transparent !important;
&:first-child {
padding-left: 0 !important;
}
&:last-child {
padding-right: 0 !important;
}
}
.ant-table-tbody {
tr {
background-color: transparent;
td {
&:first-child {
padding-left: 0 !important;
}
&:last-child {
padding-right: 0 !important;
}
}
&:hover {
td {
background-color: transparent !important;
}
}
}
}
}
}
.color-box {
height: 36px;
line-height: 36px;
text-align: center;
color: #fff;
}
.concentration {
background-color: #ad8815;
&.error {
background-color: #c11414;
}
}
.uncertainty {
background-color: rgba(57, 184, 222, 0.4);
}
.mdc {
background-color: rgba(57, 184, 222, 0.4);
}
.search {
width: 24px;
height: 24px;
cursor: pointer;
background: url(~@/assets/images/spectrum/search.png) center no-repeat;
&:hover {
background: url(~@/assets/images/spectrum/search-hover.png) center no-repeat;
}
}
}
</style>

View File

@ -0,0 +1,83 @@
<template>
<a-menu class="spectra-list-in-menu">
<a-menu-item v-for="item in list" :key="item.sampleId" @click="handleClick(item)">
<span class="checkbox">
<a-icon v-if="item.checked" type="check" style="color: #0de30d" />
</span>
<span class="name">{{ getFileName(item.inputFileName) }}</span>
<a-icon type="delete" @click.stop="handleRemove(item)" />
</a-menu-item>
</a-menu>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
}
},
methods: {
handleClick(spectraItem) {
this.list.forEach(item => (item.checked = false))
spectraItem && (spectraItem.checked = true)
this.$emit('change', spectraItem)
this.$forceUpdate()
},
handleRemove(spectraItem) {
const index = this.list.findIndex(item => item == spectraItem)
this.list.splice(index, 1)
//
if (spectraItem.checked) {
if (index == 0) {
//
this.handleClick(this.list[0])
} else {
//
this.handleClick(this.list[index - 1])
}
}
this.$forceUpdate()
},
/**
* 获取文件名
* @param {String} inputFileName
*/
getFileName(inputFileName) {
if (inputFileName) {
const arr = inputFileName.split('/')
return arr[arr.length - 1]
}
}
},
watch: {
list(newVal) {
if (newVal.length) {
this.handleClick(newVal[0])
}
}
}
}
</script>
<style lang="less" scoped>
.spectra-list-in-menu {
.checkbox {
width: 14px;
height: 14px;
display: inline-block;
}
.name {
display: inline-block;
width: 300px;
margin: 0 5px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
}
}
</style>

View File

@ -0,0 +1,319 @@
<template>
<div class="spectrum-line-chart">
<div class="summary-text">
<span>Channel: {{ summary.channel }}</span>
<span>Count: {{ summary.count }}</span>
<span class="error">Energy: {{ summary.energy }}</span>
</div>
<div class="chart-container">
<div class="left-title">{{ title + ' Count' }}</div>
<custom-chart
class="spectrum-line-chart-main"
ref="chartRef"
:option="option"
style="height: 100%"
@zr:mousemove="handleMouseMove"
@zr:mousedown="handleMouseDown"
@zr:mouseup="handleMouseUp"
@brushEnd="handleBrushEnd"
></custom-chart>
</div>
<div class="bottom-title">
{{ title + ' Channel' }}
</div>
</div>
</template>
<script>
import CustomChart from '@/components/CustomChart/index.vue'
import { cloneDeep } from 'lodash'
import { getXAxisAndYAxisByPosition } from '@/utils/chartHelper.js'
const initialOption = {
grid: {
top: 10,
right: 15,
bottom: 20
},
xAxis: {
min: 0,
max: 256,
interval: 64,
axisLine: {
lineStyle: {
color: 'rgb(119, 181, 213, 0.5)'
}
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(119, 181, 213, .2)'
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#ade6ee'
},
name: '',
nameLocation: 'center',
nameTextStyle: {
fontSize: 14,
color: '#5b9cba'
},
nameGap: 25
},
yAxis: {
min: 0,
max: 0,
interval: 0,
axisLine: {
show: true,
lineStyle: {
color: 'rgb(119, 181, 213, 0.5)'
}
},
splitLine: {
lineStyle: {
color: 'rgba(119, 181, 213, .2)'
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#ade6ee'
}
},
series: {
type: 'line',
itemStyle: {
color: ''
},
symbol: 'none',
data: [],
markLine: {
symbol: 'none',
animation: false,
label: {
show: false
},
lineStyle: {
type: 'solid',
color: 'yellow'
},
silent: true,
data: []
}
},
brush: {}
}
export default {
components: {
CustomChart
},
props: {
color: {
type: String,
default: 'red'
},
title: {
type: String,
default: 'Gamma'
},
data: {
type: Array,
default: () => []
}
},
data() {
const option = cloneDeep(initialOption)
option.series.itemStyle.color = this.color
option.xAxis.name = this.title + ' Channel'
return {
option,
summary: {
channel: 0,
count: 0,
energy: 0
}
}
},
mounted() {
this.option.brush = { toolbox: [] }
},
methods: {
resize() {
this.$refs.chartRef && this.$refs.chartRef.resize()
},
// 线
setLinePosition(xAxis) {
setTimeout(() => {
if (xAxis) {
this.option.series.markLine.data = [{ xAxis }]
this.summary.channel = xAxis
const find = this.data.find(item => item.x == xAxis)
if (find) {
this.summary.count = find.y
}
} else {
this.option.series.markLine.data = []
this.summary.channel = 0
this.summary.count = 0
this.summary.energy = 0
}
}, 0)
},
//
setRange(min, max) {
this.option.xAxis.min = min
this.option.xAxis.max = max
},
//
handleMouseMove(param) {
const { offsetX, offsetY } = param
const point = getXAxisAndYAxisByPosition(this.$refs.chartRef.getChartInstance(), offsetX, offsetY)
this.setLinePosition(point ? point[0].toFixed() : null)
},
//
handleMouseDown() {
const chart = this.$refs.chartRef.getChartInstance()
chart.dispatchAction({
type: 'takeGlobalCursor',
//
key: 'brush',
brushOption: {
// brush brushType false
brushType: 'lineX'
}
})
},
handleMouseUp() {
setTimeout(() => {
const chart = this.$refs.chartRef.getChartInstance()
//
chart.dispatchAction({
type: 'brush',
areas: []
})
//
chart.dispatchAction({
type: 'takeGlobalCursor'
})
}, 0)
},
//
handleBrushEnd(param) {
const chart = this.$refs.chartRef.getChartInstance()
const areas = param.areas[0]
if (areas) {
const range = areas.range
const [minX, maxX] = range
const point1 = chart.convertFromPixel({ seriesIndex: 0 }, [minX, 0])
const point2 = chart.convertFromPixel({ seriesIndex: 0 }, [maxX, 0])
const [x1, x2] = [parseInt(point1[0].toFixed()), parseInt(point2[0].toFixed())] //
this.option.xAxis.min = x1
this.option.xAxis.max = x2
this.emitRangeChange([x1, x2])
}
//
chart.dispatchAction({
type: 'brush',
areas: []
})
//
chart.dispatchAction({
type: 'takeGlobalCursor'
})
},
emitRangeChange(range) {
this.$emit('rangeChange', range)
}
},
watch: {
data: {
handler(newVal) {
this.option.series.data = newVal.map(({ x, y }) => [x, y])
const max = Math.max(...newVal.map(item => item.y))
this.option.yAxis.interval = Math.ceil(max / 4)
this.option.yAxis.max = this.option.yAxis.interval * 4
},
immediate: true
}
}
}
</script>
<style lang="less" scoped>
.spectrum-line-chart {
height: 100%;
.summary-text {
line-height: 10px;
text-align: right;
font-size: 14px;
user-select: none;
.error {
color: #ff5656;
}
span {
color: #ade6ee;
&:not(:last-child) {
margin-right: 27px;
}
}
}
.chart-container {
display: flex;
margin-top: 7px;
margin-bottom: 8px;
height: calc(100% - 35px);
.left-title {
writing-mode: vertical-rl;
color: #5b9cba;
font-size: 14px;
transform: rotate(180deg);
text-align: center;
user-select: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.spectrum-line-chart-main {
flex: 1;
}
}
.bottom-title {
line-height: 10px;
font-size: 14px;
color: #5b9cba;
text-align: center;
user-select: none;
}
}
</style>

View File

@ -0,0 +1,48 @@
<template>
<div class="btn-with-switch-icon">
<i @click="handleClick('left')">
<img src="@/assets/images/spectrum/left-arrow.png" />
</i>
<span>
<slot></slot>
</span>
<i @click="handleClick('right')">
<img src="@/assets/images/spectrum/right-arrow.png" />
</i>
</div>
</template>
<script>
export default {
methods: {
handleClick(direction) {
this.$emit('change', direction)
}
}
}
</script>
<style lang="less" scoped>
.btn-with-switch-icon {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #0a544e;
padding: 0 4px;
height: 100%;
letter-spacing: 1px;
color: #ade6ee;
i {
cursor: pointer;
width: 16px;
text-align: center;
}
span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>

View File

@ -0,0 +1,140 @@
<template>
<div class="detailed-infomation">
<a-form :labelCol="{ style: { width: 120 } }">
<a-row v-for="(row, index) in items" :key="index">
<a-col v-for="(item, i) in row" :key="i" :span="item.span || 4">
<a-form-item :label="item.label">
{{ data[item.name] }}
</a-form-item>
</a-col>
</a-row>
</a-form>
</div>
</template>
<script>
const items = [
[
{
label: 'Sample Id',
name: 'sampleId'
},
{
label: 'Data Type',
name: 'dataType'
},
{
label: 'Collection Start',
name: 'collectionStart',
span: 6
},
{
label: 'Acquisition Start',
name: 'acquisitionStart',
span: 6
},
{
label: 'Auto.Cat',
name: 'autoCat'
}
],
[
{
label: 'Station Code',
name: 'stationCode'
},
{
label: 'Spectral Qualifier',
name: 'spectralQualifier'
},
{
label: 'Sampling Time',
name: 'samplingTime',
span: 6
},
{
label: 'Acq.Real',
name: 'acqReal',
span: 6
},
{
label: 'Category',
name: 'category'
}
],
[
{
label: 'Detector Code',
name: 'detectorCode'
},
{
label: 'SRID',
name: 'srid'
},
{
label: 'Quantity',
name: 'quantity',
span: 6
},
{
label: 'Acq.Live',
name: 'acqLive',
span: 6
}
],
[
{
label: 'System Type',
name: 'systemType'
},
{
label: 'Sample Status',
name: 'sampleStatus'
},
{
label: 'Flow Rate',
name: 'flowRate',
span: 6
},
{
label: 'Decay Time',
name: 'decayTime',
span: 6
}
]
]
export default {
props: {
data: {
type: Object,
default: () => ({
sampleId: 1,
dataType: 'SAMPLEPHD'
})
}
},
created() {
this.items = items
}
}
</script>
<style lang="less" scoped>
.detailed-infomation {
width: 1200px;
.ant-form-item {
margin-bottom: 0;
::v-deep {
.ant-form-item-label > label {
color: #ade6ee;
}
.ant-form-item-children {
color: #0cecca;
}
}
}
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<div class="graph-assistance">
<div class="graph-assistance-item" v-for="conf in config" :key="conf.title">
<span>{{ conf.label }}</span>
<a-switch v-model="conf.checked" @change="handleChange(conf)"></a-switch>
</div>
</div>
</template>
<script>
const config = [
{
label: 'Log10',
checked: true
},
{
label: 'Cursor',
checked: false
},
{
label: 'Lc',
checked: false
},
{
label: 'Baseline',
checked: false
},
{
label: 'Channel',
checked: false
},
{
label: 'Lines',
checked: false
},
{
label: 'S CAC',
checked: false
}
]
export default {
data() {
return {
config
}
},
methods: {
handleChange(conf) {
console.log('%c [ conf ]-47', 'font-size:13px; background:pink; color:#bf2c9f;', conf)
}
}
}
</script>
<style lang="less" scoped>
.graph-assistance {
display: flex;
width: 790px;
justify-content: space-between;
&-item {
span {
margin-right: 10px;
}
}
}
</style>

View File

@ -0,0 +1,59 @@
<template>
<div class="nuclear-library">
<div class="nuclear-library-item" v-for="item in list" :key="item.id">
{{ item.title }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{
id: '1',
title: 'Ac228'
},
{
id: '2',
title: 'Ac229'
},
{
id: '3',
title: 'Ac230'
},
{
id: '4',
title: 'Eu152'
},
{
id: '5',
title: 'I132'
},
{
id: '6',
title: 'Ir192'
}
]
}
}
}
</script>
<style lang="less" scoped>
.nuclear-library {
width: 230px;
max-height: 200px;
overflow: auto;
&-item {
padding: 4px 14px;
// cursor: pointer;
// &:hover {
// background-color: #055565;
// }
}
}
</style>

View File

@ -0,0 +1,83 @@
<template>
<a-popover :placement="placement" overlayClassName="popover-with-icon" v-model="innerVisible">
<div class="pop-over-with-icon">
<span class="text">
<slot />
</span>
<img src="@/assets/images/global/select-down.png" alt="" />
</div>
<template slot="content">
<slot name="content" />
</template>
</a-popover>
</template>
<script>
export default {
props: {
placement: {
type: String,
default: 'bottom'
},
value: {
type: Boolean
}
},
data() {
return {
innerVisible: false
}
},
watch: {
value: {
handler(val) {
this.innerVisible = val
},
immediate: true
},
innerVisible(val) {
this.$emit('input', val)
}
}
}
</script>
<style lang="less" scoped>
.pop-over-with-icon {
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #0a544e;
height: 100%;
padding: 0 11px;
cursor: pointer;
.text {
font-family: MicrosoftYaHei;
color: #ade6ee;
letter-spacing: 1px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
user-select: none;
}
img {
margin-left: 5px;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
flex-shrink: 0;
}
&.ant-popover-open {
img {
transform: rotate(180deg);
}
}
}
</style>
<style lang="less">
.popover-with-icon {
.ant-popover-inner-content {
padding: 8px;
}
}
</style>

View File

@ -0,0 +1,84 @@
<template>
<div class="qc-flags">
<div class="qc-flags-item" v-for="conf in config" :key="conf.label">
<span :class="'dot' + (data[conf.name] ? ' green' : '')"></span>
{{ conf.label }}
</div>
</div>
</template>
<script>
//
const config = [
{
label: 'Collection Time',
name: 'collectionTime'
},
{
label: 'Acq Time',
name: 'acqTime'
},
{
label: 'Decay Time',
name: 'decayTime'
},
{
label: 'SampVol',
name: 'sampVol'
},
{
label: 'Be7-FWHM',
name: 'be7Fwhm'
},
{
label: 'Ba140-MDC',
name: 'ba140Mdc'
},
{
label: 'Xe133-MDC',
name: 'xe133Mdc'
}
]
export default {
props: {
data: {
type: Object,
default: () => ({})
}
},
created() {
this.config = config
}
}
</script>
<style lang="less" scoped>
.qc-flags {
display: flex;
&-item {
background-color: #46738e;
display: flex;
align-items: center;
width: 150px;
height: 30px;
&:not(:last-child) {
margin-right: 2px;
}
span {
margin-left: 20px;
margin-right: 5px;
width: 14px;
height: 14px;
border-radius: 50%;
background: radial-gradient(circle, #979797 0, #777a7c 100%);
&.green {
background: radial-gradient(circle, #00fe7f 0, #00d56a 100%);
}
}
}
}
</style>

View File

@ -0,0 +1,74 @@
<template>
<div class="spectra">
<div
:class="'spectra-item' + (item.title == innerValue ? ' active' : '')"
v-for="(item, index) in list"
:key="index"
@click="handleClick(item)"
>
{{ item.title }}
</div>
</div>
</template>
<script>
const list = [
{
title: 'Sample Data'
},
{
title: 'GasBg Data'
},
{
title: 'DetBg Data'
},
{
title: 'QC Data'
}
]
export default {
props: {
value: {
type: String,
required: true
}
},
data() {
this.list = list
return {}
},
methods: {
handleClick(item) {
this.innerValue = item.title
}
},
computed: {
innerValue: {
set(val) {
this.$emit('input', val)
},
get() {
return this.value
}
}
}
}
</script>
<style lang="less" scoped>
.spectra {
width: 159px;
max-height: 200px;
overflow: auto;
&-item {
padding: 4px 14px;
cursor: pointer;
&:hover,
&.active {
background-color: #055565;
}
}
}
</style>

View File

@ -0,0 +1,39 @@
<template>
<div class="title-over-border">
<div class="title-over-border-title">{{ title }}</div>
<div class="title-over-border-content">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String
}
}
}
</script>
<style lang="less" scoped>
@color: rgba(12, 235, 201, 0.6);
.title-over-border {
border: 1px solid @color;
position: relative;
&-title {
color: @color;
background-color: #022024;
position: absolute;
top: -11px;
left: 10px;
padding: 0 10px;
}
&-content {
padding: 20px;
}
}
</style>

View File

@ -0,0 +1,325 @@
<template>
<div class="gamma-analysis">
<!-- 二级交互栏 -->
<div class="spectrum-analysis-sub-operators">
<pop-over-with-icon placement="bottomLeft">
Detailed-Information
<detailed-infomation slot="content" />
</pop-over-with-icon>
<pop-over-with-icon placement="bottomLeft">
QC Flags
<qc-flags slot="content" :data="{ collectionTime: '123' }" />
</pop-over-with-icon>
<pop-over-with-icon>
Graph Assistance
<graph-assistance slot="content" />
</pop-over-with-icon>
<pop-over-with-icon>
Nuclide Library
<nuclear-library slot="content" />
</pop-over-with-icon>
<div class="peak-info">
<button-with-switch-icon @change="handlePeakInfoChange">
Peak Information
</button-with-switch-icon>
</div>
</div>
<!-- 二级交互栏结束 -->
<!-- 主体部分 -->
<div class="gamma-analysis-main">
<div class="gamma-analysis-chart">
<custom-chart ref="chartRef" :option="option" style="height: 100%" />
</div>
<div class="gamma-analysis-thumbnail">
<custom-chart :option="thumbnailOption" style="height: 100%" />
</div>
</div>
<!-- 主体部分结束 -->
</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 NuclearLibrary from './components/SubOperators/NuclearLibrary.vue'
import ButtonWithSwitchIcon from './components/SubOperators/ButtonWithSwitchIcon.vue'
//
const initialOption = {
grid: {
top: 40,
left: 60,
right: 0
},
title: {
text: '',
left: 'center',
bottom: 10,
textStyle: {
color: '#8FD4F8',
rich: {
a: {
padding: [0, 20, 0, 0],
fontSize: 16
}
}
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
animation: false,
type: 'cross',
lineStyle: {
type: 'dashed'
}
}
},
xAxis: {
type: 'category',
axisLine: {
lineStyle: {
color: '#ade6ee'
}
},
splitLine: {
show: false
},
axisLabel: {
textStyle: {
color: '#ade6ee'
}
},
data: new Array(3928).fill(0).map((_, index) => index)
},
yAxis: {
name: 'Counts',
nameTextStyle: {
color: '#8FD4F8',
fontSize: 16
},
axisLine: {
show: true,
lineStyle: {
color: '#ade6ee'
}
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(173, 230, 238, .2)'
}
},
axisLabel: {
textStyle: {
color: '#ade6ee'
}
}
},
series: [
{
type: 'line',
data: new Array(3928)
.fill(0)
.map((_, index) => (Math.random() < 0.05 ? parseInt(Math.random() * 16000) : parseInt(Math.random() * 800))),
itemStyle: {
color: '#24FF0B'
},
lineStyle: {
width: 1
},
symbol: 'none',
markLine: {
symbol: 'none',
label: {
show: false
},
lineStyle: {
type: 'solid'
},
data: [
{
xAxis: 100,
lineStyle: {
color: 'red'
}
}
]
}
},
{
type: 'line',
data: new Array(3928)
.fill(0)
.map((_, index) => (Math.random() < 0.05 ? parseInt(Math.random() * 14000) : parseInt(Math.random() * 600))),
itemStyle: {
color: '#D8DE07'
},
lineStyle: {
width: 1
},
symbol: 'none'
}
],
dataZoom: {
type: 'inside',
start: 0,
end: 20,
zoomLock: true
}
}
//
const thumbnailOption = {
grid: {
top: 0,
left: 5,
right: 5,
bottom: 0
},
xAxis: {
type: 'category',
axisLine: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
show: false
},
data: new Array(3928).fill(0).map((_, index) => index)
},
yAxis: {
axisLine: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
show: false
}
},
series: [
{
type: 'line',
data: new Array(3928)
.fill(0)
.map((_, index) => (Math.random() < 0.05 ? parseInt(Math.random() * 16000) : parseInt(Math.random() * 800))),
itemStyle: {
color: '#24FF0B'
},
lineStyle: {
width: 1
},
symbol: 'none'
},
{
type: 'line',
data: new Array(3928)
.fill(0)
.map((_, index) => (Math.random() < 0.05 ? parseInt(Math.random() * 14000) : parseInt(Math.random() * 600))),
itemStyle: {
color: '#D8DE07'
},
lineStyle: {
width: 1
},
symbol: 'none'
}
]
}
export default {
props: {
data: {
type: Object
},
chartType: {
type: String,
default: ''
}
},
components: {
CustomChart,
PopOverWithIcon,
DetailedInfomation,
QcFlags,
GraphAssistance,
NuclearLibrary,
ButtonWithSwitchIcon
},
data() {
return {
option: initialOption,
thumbnailOption
}
},
created() {
this.option.title.text = '{a|Channel:0} {a|Energy:0} {a|Counts:0} {a|Detectability:0}'
console.log('%c [ ]-108', 'font-size:13px; background:pink; color:#bf2c9f;', this.option)
},
methods: {
resize() {
this.$refs.chartRef.resize()
},
// peak info
handlePeakInfoChange(direction) {
this.moveMarkLine(direction)
},
/**
* 向某一个方向移动标记线
* @param { 'left'| 'right' } direction
*/
moveMarkLine(direction) {
if (direction == 'left') {
this.option.series[0].markLine.data[0].xAxis = this.option.series[0].markLine.data[0].xAxis - 10
} else {
this.option.series[0].markLine.data[0].xAxis = this.option.series[0].markLine.data[0].xAxis + 10
}
this.$emit('markLineChange', {})
}
},
watch: {
data: {
handler() {},
deep: true
}
}
}
</script>
<style lang="less" scoped>
.gamma-analysis {
height: 100%;
&-main {
height: calc(100% - 51px);
display: flex;
overflow: auto hidden;
position: relative;
}
&-chart {
width: 100%;
height: 100%;
}
&-thumbnail {
position: absolute;
top: 50px;
right: 10px;
width: 500px;
height: 150px;
background-color: #153e44;
}
}
</style>

View File

@ -1,3 +1,754 @@
<template>
<div>能谱分析页面</div>
</template>
<div class="spectrum-analysis">
<!-- 顶部操作栏 -->
<div class="spectrum-analysis-operators">
<a-dropdown
class="spectrum-analysis-operators-item"
overlayClassName="spectrum-analysis-operators-dropdown-overlay"
:overlay-style="operation.style"
v-for="operation in operations"
:key="operation.title"
>
<a-button type="primary">{{ operation.title }}</a-button>
<div slot="overlay">
<template v-for="(child, index) in operation.children">
<component :is="child.type" :key="index" v-bind="child.attrs" v-on="child.on">
<component :is="item.type" v-for="item in child.children" :key="item.title" @click="item.handler">
{{ item.title }}
</component>
</component>
</template>
</div>
</a-dropdown>
</div>
<!-- 顶部操作栏结束 -->
<!-- 频谱分析部分 -->
<div class="spectrum-analysis-main">
<gamma-analysis v-if="analysisType == ANALYZE_TYPE.GAMMA" ref="gammaAnalysisRef" />
<beta-gamma-analysis
v-if="analysisType == ANALYZE_TYPE.BETA_GAMMA"
ref="betaGammaAnalysisRef"
:data="analysisData"
/>
<resize-observer @notify="handleResize" />
</div>
<!-- 频谱分析部分结束 -->
<!-- 从数据库加载开始 -->
<load-from-db-modal v-model="loadFromDbModalVisible" @loadSample="handleLoadSampleFromDB" />
<!-- 从数据库加载结束 -->
<!-- 从文件加载开始 -->
<load-from-file-modal v-model="loadFromFileModalVisible" />
<!-- 从文件加载结束 -->
<!-- Peak Infomation 弹窗开始 -->
<peak-infomation v-model="peakInfomationModalVisible" />
<!-- Peak Infomation 弹窗结束 -->
<!-- Nuclide Activity and MDC 弹窗开始 -->
<nuclide-activity-and-mdc-modal v-model="nuclideActivityAndMDCModalVisible" />
<!-- Nuclide Activity and MDC 弹窗结束 -->
<!-- Save Setting 弹窗开始 -->
<save-setting-modal v-model="saveSettingModalVisible" />
<!-- Save Setting 弹窗结束 -->
<!-- 分析-设置弹窗开始 -->
<analyze-setting-modal v-model="analyzeConfigureModalVisible" />
<!-- 分析-设置弹窗结束 -->
<!-- 分析工具弹窗开始 -->
<analyze-interactive-tool-modal v-model="analyzeInteractiveToolModalVisible" />
<!-- 分析工具弹窗结束 -->
<!-- Korsum 弹窗开始 -->
<korsum-modal v-model="korsumModalShow" />
<!-- Korsum 弹窗结束 -->
<!-- ReProcessing 弹窗开始 -->
<re-processing-modal v-model="reprocessingModalVisible" />
<!-- ReProcessing 弹窗结束 -->
<!-- Zero Time 弹窗开始 -->
<zero-time-modal v-model="zeroTimeModalVisible" />
<!-- Zero Time 弹窗结束 -->
<!-- Efficiency Calibration 弹窗开始 -->
<efficiency-calibration-modal v-model="efficiencyCalibrationModalShow" />
<!-- Efficiency Calibration 弹窗结束 -->
</div>
</template>
<script>
import GammaAnalysis from './gamma-analysis.vue'
import BetaGammaAnalysis from './beta-gamma-analysis.vue'
import SpectraListInMenu from './components/SpectraListInMenu.vue'
import LoadFromDbModal from './components/Modals/LoadFromDBModal.vue'
import LoadFromFileModal from './components/Modals/LoadFromFileModal.vue'
import PeakInfomation from './components/PeakInfomation.vue'
import NuclideActivityAndMdcModal from './components/Modals/NuclideActivityAndMDCModal.vue'
import MultiLevelMenu from './components/MultiLevelMenu.vue'
import SaveSettingModal from './components/Modals/SaveSettingModal.vue'
import AnalyzeSettingModal from './components/Modals/AnalyzeSettingModal.vue'
import AnalyzeInteractiveToolModal from './components/Modals/AnalyzeInteractiveToolModal/index.vue'
import { getAction } from '../../api/manage'
import KorsumModal from './components/Modals/KorsumModal.vue'
import ReProcessingModal from './components/Modals/ReProcessingModal/index.vue'
import ZeroTimeModal from './components/Modals/ZeroTimeModal.vue'
import EfficiencyCalibrationModal from './components/Modals/EfficiencyCalibrationModal.vue'
//
const ANALYZE_TYPE = {
GAMMA: 'gammaAnalysis',
BETA_GAMMA: 'betaGammaAnalysis'
}
export default {
components: {
BetaGammaAnalysis,
GammaAnalysis,
SpectraListInMenu,
LoadFromDbModal,
LoadFromFileModal,
PeakInfomation,
NuclideActivityAndMdcModal,
MultiLevelMenu,
SaveSettingModal,
AnalyzeSettingModal,
AnalyzeInteractiveToolModal,
KorsumModal,
ReProcessingModal,
ZeroTimeModal,
EfficiencyCalibrationModal
},
data() {
this.ANALYZE_TYPE = ANALYZE_TYPE
return {
analysisType: null, //
sampleList: [],
loadFromDbModalVisible: false, //
loadFromFileModalVisible: false, //
analysisData: {}, //
peakInfomationModalVisible: false,
nuclideActivityAndMDCModalVisible: false,
saveSettingModalVisible: false, //
analyzeConfigureModalVisible: false, //
reprocessingModalVisible: false, //
analyzeInteractiveToolModalVisible: false, //
zeroTimeModalVisible: false, // Zero Time
korsumModalShow: false, // Korsum
efficiencyCalibrationModalShow: false // Calibration -> efficiency
}
},
created() {
//
this.loadSelectedSample({
dbName: 'auto',
sampleType: 'B',
sampleId: '1523651'
})
},
methods: {
//
handleLoadFromDb() {
this.loadFromDbModalVisible = true
},
// -
handleLoadSampleFromDB(sampleList) {
this.sampleList = sampleList
},
//
async loadSelectedSample({ dbName, sampleType, sampleId }) {
// Bbeta-gamma P Ggamma
if (sampleType == 'B') {
const { success, result, message } = await getAction('/spectrumAnalysis/getDBSpectrumChart', {
dbName,
sampleId: sampleId
})
if (success) {
this.analysisData = result.sample
this.analysisType = ANALYZE_TYPE.BETA_GAMMA
} else {
this.$message.error(message)
}
} else {
// gamma
}
},
//
handleLoadFromFile() {
this.loadFromFileModalVisible = true
},
//
handleCleanAll() {
this.sampleList = []
},
//
handleSaveResultsToFile() {
this.saveSettingModalVisible = true
},
/**
* 保存结果到数据库
* @param { 'all' | 'current' } type
*/
handleSaveResultsToDB(type) {
console.log('%c [ saveResultsToDB ]-157', 'font-size:13px; background:pink; color:#bf2c9f;', type)
},
/**
* 将谱列表中所有谱数据均以IMS2.0格式保存为PHD文件
* 服务端生成文件前端下载
* @param { 'all' | 'current' } type
*/
handleSavePHDToFile(type) {
console.log('%c [ savePHDToFile ]-162', 'font-size:13px; background:pink; color:#bf2c9f;', type)
},
//
handleShowConfigureModal() {
this.analyzeConfigureModalVisible = true
},
handleReprocessAll() {
console.log('%c [ handleReprocessAll ]-216', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleEnergy() {
console.log('%c [ handleEnergy ]-163', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleResolution() {
console.log('%c [ handleResolution ]-167', 'font-size:13px; background:pink; color:#bf2c9f;')
},
// Nuclide Library
handleNuclideLib() {
console.log('%c [ handleNuclideLib ]-178', 'font-size:13px; background:pink; color:#bf2c9f;')
},
handleConfigUserLib() {
console.log('%c [ handleConfigUserLib ]-182', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleViewARR() {
console.log('%c [ handleViewARR ]-186', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleViewRRR() {
console.log('%c [ handleViewRRR ]-192', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleViewSpectrum() {
console.log('%c [ handleViewSpectrum ]-198', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleViewComments() {
console.log('%c [ viewComments ]-162', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleAddComments() {
console.log('%c [ handleAddComments ]-167', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleAutoAnalysisLog() {
console.log('%c [ handleAutoAnalysisLog ]-211', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleGammaViewerLog() {
console.log('%c [ handleGammaViewerLog ]-211', 'font-size:13px; background:pink; color:#bf2c9f;')
},
//
handleHelp() {
console.log('%c [ handleHelp ]-221', 'font-size:13px; background:pink; color:#bf2c9f;')
},
// 线
handleLineColorConfig() {
console.log('%c [ handleLineColorConfig ]-225', 'font-size:13px; background:pink; color:#bf2c9f;')
},
handleResize() {
this.$refs.gammaAnalysisRef && this.$refs.gammaAnalysisRef.resize()
this.$refs.betaGammaAnalysisRef && this.$refs.betaGammaAnalysisRef.resize()
}
},
computed: {
operations() {
return [
{
title: 'SAMPLE',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'Load From DB',
handler: this.handleLoadFromDb
},
{
type: 'a-menu-item',
title: 'Load From File',
handler: this.handleLoadFromFile
},
{
type: 'a-menu-item',
title: 'Clean All',
handler: this.handleCleanAll
}
]
},
{
type: 'a-divider',
attrs: {
style: {
marginTop: '5px',
marginBottom: '5px',
display: this.sampleList.length ? '' : 'none'
}
}
},
{
type: 'SpectraListInMenu',
attrs: {
list: this.sampleList
},
on: {
change: spectra => {
if (spectra) {
this.loadSelectedSample(spectra)
}
}
}
}
]
},
{
title: 'SAVE',
children: [
{
type: 'MultiLevelMenu',
attrs: {
children: [
{
title: 'Save Results to File'
},
{
title: 'Save Results to DB',
children: [
{
title: 'Save Current',
key: 'current'
},
{
title: 'Save All',
key: 'all'
}
]
},
{
title: 'Save PHD to File',
children: [
{
title: 'Save Current',
key: 'current'
},
{
title: 'Save All',
key: 'all'
}
]
}
],
width: '170px'
},
on: {
menuClick: () => {
this.handleSaveResultsToFile()
},
submenuClick: ({ item, child }) => {
if (item.title == 'Save Results to DB') {
this.handleSaveResultsToDB(child.key)
} else if (item.title == 'Save PHD to File') {
this.handleSavePHDToFile(child.key)
}
}
}
}
]
},
{
title: 'ANALYZE',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'Configure',
handler: this.handleShowConfigureModal
},
{
type: 'a-menu-item',
title: 'ReProcessing',
handler: () => {
this.reprocessingModalVisible = true
}
},
{
type: 'a-menu-item',
title: 'Reprocess All',
handler: this.handleReprocessAll
},
{
type: 'a-menu-item',
title: 'Interactive Tool',
handler: () => {
this.analyzeInteractiveToolModalVisible = true
}
},
{
type: 'a-menu-item',
title: 'Zero Time',
handler: () => {
this.zeroTimeModalVisible = true
}
},
{
type: 'a-menu-item',
title: 'Korsum',
handler: () => {
this.korsumModalShow = true
}
}
]
}
]
},
{
title: 'CALIBRATION',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'Energy',
handler: this.handleEnergy
},
{
type: 'a-menu-item',
title: 'Resolution',
handler: this.handleResolution
},
{
type: 'a-menu-item',
title: 'Efficiency',
handler: () => {
this.efficiencyCalibrationModalShow = true
}
}
]
}
]
},
{
title: 'NUCLIDELIBRARY',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'Nuclide Library',
handler: this.handleNuclideLib
},
{
type: 'a-menu-item',
title: 'Config User Library',
handler: this.handleConfigUserLib
}
]
}
]
},
{
title: 'COMMENTS',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'View Comments',
handler: this.handleViewComments
},
{
type: 'a-menu-item',
title: 'Add Comments',
handler: this.handleAddComments
}
]
}
]
},
{
title: 'REPORTS',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'View ARR',
handler: this.handleViewARR
},
{
type: 'a-menu-item',
title: 'View RRR',
handler: this.handleViewRRR
},
{
type: 'a-menu-item',
title: 'View Spectrum',
handler: this.handleViewSpectrum
}
]
}
]
},
{
title: 'LOG',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'Automatic Analysis Log',
handler: this.handleAutoAnalysisLog
},
{
type: 'a-menu-item',
title: 'GammaViewer Log',
handler: this.handleGammaViewerLog
}
]
}
]
},
{
title: 'HELP',
children: [
{
type: 'a-menu',
children: [
{
type: 'a-menu-item',
title: 'Help',
handler: this.handleHelp
},
{
type: 'a-menu-item',
title: 'Line Color Config',
handler: this.handleLineColorConfig
}
]
}
]
}
]
}
}
}
</script>
<style lang="less" scoped>
.spectrum-analysis {
padding-top: 17px;
height: 100%;
display: flex;
flex-direction: column;
//
&-operators {
flex-shrink: 0;
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
overflow: auto;
&-item {
width: 158px;
border: 1px solid rgba(12, 235, 201, 0.6);
border-top-width: 3px;
height: 30px;
background-color: rgba(51, 202, 217, 0.2);
color: #ccede8;
&:not(:last-child) {
margin-right: 15px;
}
::v-deep {
span {
text-shadow: none;
line-height: 26px;
letter-spacing: 2px;
}
}
&:nth-child(4) {
width: 224px;
}
&:nth-child(5) {
width: 268px;
}
&:nth-child(6) {
width: 257px;
}
&:nth-child(7) {
width: 234px;
}
&:nth-child(8) {
width: 125px;
}
}
}
//
::v-deep {
//
.spectrum-analysis-sub-operators {
flex-shrink: 0;
margin-bottom: 19px;
display: flex;
flex-wrap: nowrap;
overflow: auto;
.pop-over-with-icon {
height: 32px;
&:not(:last-child) {
margin-right: 11px;
}
&:nth-child(1) {
width: 256px;
}
&:nth-child(2) {
width: 186px;
}
&:nth-child(3) {
width: 246px;
}
&:nth-child(4) {
width: 246px;
}
}
.peak-info {
width: 306px;
height: 32px;
display: inline-block;
}
}
//
}
//
&-main {
margin-top: 15px;
height: calc(100% - 45px);
overflow: hidden;
}
//
}
</style>
<style lang="less">
.spectrum-analysis-operators-dropdown-overlay {
background-color: #03353f;
.ant-menu {
background: transparent;
padding: 0;
position: relative;
border-right: 0;
&-submenu {
&-active {
background-color: #055565 !important;
}
&-title {
height: 30px !important;
line-height: 30px !important;
color: #fff;
margin: 0;
&:active {
background-color: #055565 !important;
}
.ant-menu-submenu-arrow {
&::before,
&::after {
background: #fff !important;
}
}
}
}
&-item {
color: #fff;
font-family: Arial;
border: 0;
background-color: transparent !important;
padding: 4px 14px;
height: 30px;
line-height: 22px;
margin: 0 !important;
&:hover {
background-color: #055565 !important;
}
&-selected {
font-weight: normal;
}
&-disabled {
color: #476d74 !important;
&:hover {
background-color: transparent !important;
}
}
}
}
}
</style>

View File

@ -152,7 +152,7 @@
:bodyStyle="{ padding: '15px 0 10px' }"
title="Data Recevice status Monitoring"
:width="1230"
:showFooter="false"
:footer="null"
@fullscreen="onModalFullScreen"
:getContainer="getModalContainer"
>

View File

@ -29,7 +29,7 @@
:loading="loading"
@change="handleTableChange"
:selectedRowKeys.sync="selectedRowKeys"
:scroll="{ y: 'calc(100vh - 365px)' }"
:scroll="{ y: 'calc(100vh - 395px)' }"
>
<template slot="index" slot-scope="{ index }">
{{ index + 1 }}

View File

@ -43,7 +43,7 @@
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:scroll="{ y: 'calc(100vh - 400px)' }"
:scroll="{ y: 'calc(100vh - 402px)' }"
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">

View File

@ -21,7 +21,7 @@
:pagination="false"
:dataSource="dataSource"
:loading="loading"
:scroll="{ y: 'calc(100vh - 285px)'}"
:scroll="{ y: 'calc(100vh - 290px)'}"
@expand="expandSubmenu"
:expandedRowKeys="expandedRowKeys"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"

View File

@ -29,7 +29,7 @@
:loading="loading"
@change="handleTableChange"
:selectedRowKeys.sync="selectedRowKeys"
:scroll="{ y: 'calc(100vh - 365px)' }"
:scroll="{ y: 'calc(100vh - 370px)' }"
>
<template slot="index" slot-scope="{ index }">
{{ index + 1 }}

View File

@ -29,7 +29,7 @@
:loading="loading"
@change="handleTableChange"
:selectedRowKeys.sync="selectedRowKeys"
:scroll="{ y: 'calc(100vh - 365px)' }"
:scroll="{ y: 'calc(100vh - 370px)' }"
>
<template slot="index" slot-scope="{ index }">
{{ index + 1 }}