-
5public/static/config.js
-
34src/api/ai/ai.js
-
BINsrc/assets/images/serve1-1.png
-
BINsrc/assets/images/serve1-2.png
-
BINsrc/assets/images/serve1-3.png
-
BINsrc/assets/images/serve1.png
-
BINsrc/assets/images/ter1-1.png
-
BINsrc/assets/images/ter1.png
-
BINsrc/assets/images/ter2-1.png
-
BINsrc/assets/images/ter2.png
-
BINsrc/assets/images/ter3-1.png
-
BINsrc/assets/images/ter3.png
-
BINsrc/assets/images/ter4-1.png
-
BINsrc/assets/images/ter4.png
-
BINsrc/assets/images/ter5-1.png
-
BINsrc/assets/images/ter5.png
-
31src/assets/styles/archives-manage.scss
-
1src/assets/styles/index.scss
-
4src/assets/styles/sidebar.scss
-
11src/layout/components/Navbar.vue
-
2src/views/archivesManage/managementLibrary/anjuan/index.vue
-
14src/views/archivesManage/managementLibrary/anjuan/tableList.vue
-
3src/views/archivesManage/managementLibrary/file/index.vue
-
43src/views/archivesManage/managementLibrary/index.vue
-
25src/views/archivesManage/managementLibrary/juannei/index.vue
-
6src/views/archivesManage/managementLibrary/mixins/index.js
-
42src/views/archivesManage/managementLibrary/module/collectHeader.vue
-
4src/views/archivesStatistics/customDefinedStatistics/index.vue
-
6src/views/collectReorganizi/batchConnection/index.vue
-
6src/views/collectReorganizi/collectionLibrary/anjuan/index.vue
-
59src/views/collectReorganizi/collectionLibrary/file/index.vue
-
4src/views/collectReorganizi/collectionLibrary/index.vue
-
178src/views/collectReorganizi/collectionLibrary/juannei/index.vue
-
2src/views/components/category/PreviewForm.vue
-
60src/views/components/categoryTree.vue
-
220src/views/components/echarts/serverGpu.vue
-
237src/views/components/echarts/serverGpuOther.vue
-
219src/views/components/echarts/serverGpuUse.vue
-
8src/views/components/echarts/serverProgress.vue
-
275src/views/components/echarts/serverProgress2.vue
-
314src/views/components/serveTerminal.vue
-
111src/views/home.vue
-
12src/views/login.vue
-
492src/views/system/paramSetting/index.vue
@ -1,7 +1,8 @@ |
|||
window.g = { |
|||
AXIOS_TIMEOUT: 10000, |
|||
// ApiUrl: 'http://27.16.212.58:11100', // 配置服务器地址,
|
|||
ApiUrl: 'http://192.168.99.71:11110', |
|||
ApiUrl: 'http://27.19.50.212:11100', |
|||
// ApiUrl: 'http://27.16.212.58:11100',
|
|||
// ApiUrl: 'http://192.168.99.71:11110',
|
|||
// ApiUrl: 'http://192.168.99.107:11100',
|
|||
AIDeepSeekUrl:'http://192.168.99.86:12123', |
|||
ProcessModelUrl:'http://192.168.99.72:11200', |
|||
|
After Width: 200 | Height: 200 | Size: 3.5 KiB |
|
After Width: 200 | Height: 200 | Size: 3.1 KiB |
|
After Width: 200 | Height: 200 | Size: 4.8 KiB |
|
After Width: 200 | Height: 200 | Size: 3.5 KiB |
|
After Width: 200 | Height: 200 | Size: 4.7 KiB |
|
After Width: 200 | Height: 200 | Size: 4.7 KiB |
|
After Width: 222 | Height: 200 | Size: 3.8 KiB |
|
After Width: 222 | Height: 200 | Size: 3.8 KiB |
|
After Width: 200 | Height: 200 | Size: 1.8 KiB |
|
After Width: 200 | Height: 200 | Size: 1.8 KiB |
|
After Width: 200 | Height: 200 | Size: 4.0 KiB |
|
After Width: 200 | Height: 200 | Size: 4.0 KiB |
|
After Width: 200 | Height: 200 | Size: 2.8 KiB |
|
After Width: 200 | Height: 200 | Size: 2.8 KiB |
@ -0,0 +1,220 @@ |
|||
<template> |
|||
<div id="main" :style="{height:height,width:width}" style="margin-top: -20px;" /> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as echarts from 'echarts' |
|||
import resize from '@/views/dashboard/mixins/resize' |
|||
|
|||
export default { |
|||
name: 'EchartsComponent', |
|||
mixins: [resize], |
|||
props: { |
|||
temperature: { |
|||
type: Number, |
|||
require: true, |
|||
default: function() { |
|||
return 0 |
|||
} |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '50%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '100%' |
|||
} |
|||
}, |
|||
watch: { |
|||
'temperature': { |
|||
handler(val) { |
|||
setTimeout(() => { |
|||
this.initChart() |
|||
}, 100) |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.initChart() |
|||
window.addEventListener('resize', this.__resizeHandler) |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
const chartDom = document.getElementById('main') |
|||
const myChart = echarts.init(chartDom) |
|||
|
|||
const axisLineHandler = (value) => { |
|||
const ratio = Number(value / 100) |
|||
if (ratio <= 0.7) { |
|||
return [ |
|||
[ratio, '#56BC91'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} else if (ratio <= 0.9) { |
|||
return [ |
|||
[ratio, '#FF973E'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} else if (ratio <= 1) { |
|||
return [ |
|||
[ratio, '#fd666d'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} |
|||
} |
|||
|
|||
const itemStyleHandler = (value) => { |
|||
if (value <= 70) { |
|||
return `#56BC91` |
|||
} else if (value <= 90) { |
|||
return `#FF973E` |
|||
} else if (value <= 100) { |
|||
return `#fd666d` |
|||
} |
|||
return '' |
|||
} |
|||
|
|||
// const dataNameHandler = (value) => { |
|||
// if (value <= 60) { |
|||
// return value + '°C' |
|||
// } else if (value <= 80) { |
|||
// return value + '°C' |
|||
// } else if (value <= 100) { |
|||
// return value + '°C' |
|||
// } |
|||
// return '' |
|||
// } |
|||
|
|||
const option = { |
|||
series: [ |
|||
{ |
|||
type: 'gauge', |
|||
center: ['40%', '38%'], |
|||
radius: 60, |
|||
startAngle: 200, |
|||
endAngle: -20, |
|||
min: 0, |
|||
max: 100, |
|||
splitNumber: 10, |
|||
itemStyle: { |
|||
color: itemStyleHandler(this.temperature) |
|||
}, |
|||
progress: { |
|||
show: true, |
|||
width: 20 |
|||
}, |
|||
pointer: { |
|||
show: false |
|||
}, |
|||
axisLine: { |
|||
lineStyle: { |
|||
width: 14, |
|||
color: axisLineHandler(this.temperature) |
|||
} |
|||
}, |
|||
axisTick: { |
|||
show: false, |
|||
distance: -35, |
|||
splitNumber: 5, |
|||
lineStyle: { |
|||
width: 2, |
|||
color: 'auto' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
show: false, |
|||
distance: -42, |
|||
length: 14, |
|||
lineStyle: { |
|||
width: 3, |
|||
color: 'auto' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
show: false, |
|||
distance: -40, |
|||
color: 'inherit', |
|||
fontSize: 14 |
|||
}, |
|||
anchor: { |
|||
show: false |
|||
}, |
|||
title: { |
|||
show: true, |
|||
offsetCenter: [0, '50%'], |
|||
fontSize: 14, |
|||
color: '#000' |
|||
}, |
|||
detail: { |
|||
valueAnimation: true, |
|||
width: '60%', |
|||
lineHeight: 40, |
|||
borderRadius: 8, |
|||
offsetCenter: [0, '0'], |
|||
fontSize: 26, |
|||
fontWeight: 'bolder', |
|||
formatter: '{value} °C', |
|||
color: 'auto' |
|||
}, |
|||
data: [ |
|||
{ |
|||
value: this.temperature, |
|||
// name: dataNameHandler(dataValue) |
|||
name: '温度' |
|||
} |
|||
] |
|||
}, |
|||
// 最外侧 |
|||
{ |
|||
type: 'gauge', |
|||
radius: 66, // 半径 |
|||
center: ['40%', '38%'], // 位置 |
|||
min: 0, |
|||
max: 100, |
|||
startAngle: 200, |
|||
endAngle: -20, |
|||
axisLine: { |
|||
show: false, |
|||
lineStyle: { |
|||
width: 2, |
|||
color: '#999' |
|||
} |
|||
}, |
|||
axisTick: { |
|||
show: true, |
|||
splitNumber: 7, |
|||
length: 2, |
|||
lineStyle: { |
|||
width: 1, |
|||
color: '#999' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
show: false |
|||
}, |
|||
axisLabel: { |
|||
show: false |
|||
}, |
|||
pointer: { |
|||
show: false |
|||
}, |
|||
detail: { |
|||
show: false |
|||
} |
|||
} |
|||
] |
|||
} |
|||
|
|||
if (option) { |
|||
myChart.setOption(option) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
</style> |
|||
@ -0,0 +1,237 @@ |
|||
<template> |
|||
<div id="mainOther" :style="{height:height,width:width}" style="margin-top: -20px;" /> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as echarts from 'echarts' |
|||
import resize from '@/views/dashboard/mixins/resize' |
|||
|
|||
export default { |
|||
name: 'EchartsComponent', |
|||
mixins: [resize], |
|||
props: { |
|||
memoryTotal: { |
|||
type: Number, |
|||
require: true, |
|||
default: function() { |
|||
return 0 |
|||
} |
|||
}, |
|||
memoryFree: { |
|||
type: Number, |
|||
require: true, |
|||
default: function() { |
|||
return 0 |
|||
} |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '50%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '100%' |
|||
} |
|||
}, |
|||
watch: { |
|||
'memoryTotal': { |
|||
handler(val) { |
|||
setTimeout(() => { |
|||
this.initChart() |
|||
}, 100) |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
}, |
|||
'memoryFree': { |
|||
handler(val) { |
|||
setTimeout(() => { |
|||
this.initChart() |
|||
}, 100) |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.initChart() |
|||
// window.addEventListener('resize', this.__resizeHandler) |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
const chartDom = document.getElementById('mainOther') |
|||
const myChart = echarts.init(chartDom) |
|||
|
|||
const dataValue = this.memoryTotal === 0 ? 0 : ((this.memoryTotal - this.memoryFree) / this.memoryTotal * 100).toFixed(0) |
|||
|
|||
const axisLineHandler = (value) => { |
|||
const ratio = Number(value / 100) |
|||
if (ratio <= 0.7) { |
|||
return [ |
|||
[ratio, '#56BC91'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} else if (ratio <= 0.9) { |
|||
return [ |
|||
[ratio, '#FF973E'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} else if (ratio <= 1) { |
|||
return [ |
|||
[ratio, '#fd666d'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} |
|||
} |
|||
|
|||
const itemStyleHandler = (value) => { |
|||
if (value <= 70) { |
|||
return `#56BC91` |
|||
} else if (value <= 90) { |
|||
return `#FF973E` |
|||
} else if (value <= 100) { |
|||
return `#fd666d` |
|||
} |
|||
return '' |
|||
} |
|||
|
|||
// const dataNameHandler = (value) => { |
|||
// if (value <= 60) { |
|||
// return value + '°C' |
|||
// } else if (value <= 80) { |
|||
// return value + '°C' |
|||
// } else if (value <= 100) { |
|||
// return value + '°C' |
|||
// } |
|||
// return '' |
|||
// } |
|||
|
|||
const option = { |
|||
series: [ |
|||
{ |
|||
type: 'gauge', |
|||
center: ['40%', '38%'], |
|||
radius: 60, |
|||
startAngle: 200, |
|||
endAngle: -20, |
|||
min: 0, |
|||
max: 100, |
|||
splitNumber: 10, |
|||
itemStyle: { |
|||
color: itemStyleHandler(dataValue) |
|||
}, |
|||
progress: { |
|||
show: true, |
|||
width: 20 |
|||
}, |
|||
pointer: { |
|||
show: false |
|||
}, |
|||
axisLine: { |
|||
lineStyle: { |
|||
width: 14, |
|||
color: axisLineHandler(dataValue) |
|||
} |
|||
}, |
|||
axisTick: { |
|||
show: false, |
|||
distance: -35, |
|||
splitNumber: 5, |
|||
lineStyle: { |
|||
width: 2, |
|||
color: 'auto' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
show: false, |
|||
distance: -42, |
|||
length: 14, |
|||
lineStyle: { |
|||
width: 3, |
|||
color: 'auto' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
show: false, |
|||
distance: -40, |
|||
color: 'inherit', |
|||
fontSize: 14 |
|||
}, |
|||
anchor: { |
|||
show: false |
|||
}, |
|||
title: { |
|||
show: true, |
|||
offsetCenter: [0, '50%'], |
|||
fontSize: 14, |
|||
color: '#000' |
|||
}, |
|||
detail: { |
|||
valueAnimation: true, |
|||
width: '60%', |
|||
lineHeight: 40, |
|||
borderRadius: 8, |
|||
offsetCenter: [0, '0'], |
|||
fontSize: 26, |
|||
fontWeight: 'bolder', |
|||
formatter: '{value} %', |
|||
color: 'auto' |
|||
}, |
|||
data: [ |
|||
{ |
|||
value: dataValue, |
|||
name: ((this.memoryTotal - this.memoryFree) / 1024).toFixed(2) + 'G' + ' / ' + (this.memoryTotal / 1024).toFixed(0) + 'G' |
|||
} |
|||
] |
|||
}, |
|||
// 最外侧 |
|||
{ |
|||
type: 'gauge', |
|||
radius: 66, // 半径 |
|||
center: ['40%', '38%'], // 位置 |
|||
min: 0, |
|||
max: 100, |
|||
startAngle: 200, |
|||
endAngle: -20, |
|||
axisLine: { |
|||
show: false, |
|||
lineStyle: { |
|||
width: 1, |
|||
color: '#999' |
|||
} |
|||
}, |
|||
axisTick: { |
|||
show: true, |
|||
splitNumber: 8, |
|||
length: 2, |
|||
lineStyle: { |
|||
width: 1, |
|||
color: '#999' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
show: false |
|||
}, |
|||
axisLabel: { |
|||
show: false |
|||
}, |
|||
pointer: { |
|||
show: false |
|||
}, |
|||
detail: { |
|||
show: false |
|||
} |
|||
} |
|||
] |
|||
} |
|||
|
|||
if (option) { |
|||
myChart.setOption(option) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
</style> |
|||
@ -0,0 +1,219 @@ |
|||
<template> |
|||
<div id="mainUse" :style="{height:height,width:width}" /> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as echarts from 'echarts' |
|||
import resize from '@/views/dashboard/mixins/resize' |
|||
|
|||
export default { |
|||
name: 'EchartsComponent', |
|||
mixins: [resize], |
|||
props: { |
|||
utilization: { |
|||
type: Number, |
|||
require: true, |
|||
default: function() { |
|||
return 0 |
|||
} |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '50%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '100%' |
|||
} |
|||
}, |
|||
watch: { |
|||
'utilization': { |
|||
handler(val) { |
|||
setTimeout(() => { |
|||
this.initChart() |
|||
}, 100) |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.initChart() |
|||
// window.addEventListener('resize', this.__resizeHandler) |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
const chartDom = document.getElementById('mainUse') |
|||
const myChart = echarts.init(chartDom) |
|||
|
|||
const axisLineHandler = (value) => { |
|||
const ratio = Number(value / 100) |
|||
if (ratio <= 0.7) { |
|||
return [ |
|||
[ratio, '#56BC91'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} else if (ratio <= 0.9) { |
|||
return [ |
|||
[ratio, '#FF973E'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} else if (ratio <= 1) { |
|||
return [ |
|||
[ratio, '#fd666d'], // 进度色 |
|||
[1, 'rgba(216, 216, 216, 1)'] // 背景色 |
|||
] |
|||
} |
|||
} |
|||
|
|||
const itemStyleHandler = (value) => { |
|||
if (value <= 70) { |
|||
return `#56BC91` |
|||
} else if (value <= 90) { |
|||
return `#FF973E` |
|||
} else if (value <= 100) { |
|||
return `#fd666d` |
|||
} |
|||
return '' |
|||
} |
|||
|
|||
// const dataNameHandler = (value) => { |
|||
// if (value <= 60) { |
|||
// return value + '°C' |
|||
// } else if (value <= 80) { |
|||
// return value + '°C' |
|||
// } else if (value <= 100) { |
|||
// return value + '°C' |
|||
// } |
|||
// return '' |
|||
// } |
|||
|
|||
const option = { |
|||
series: [ |
|||
{ |
|||
type: 'gauge', |
|||
center: ['40%', '38%'], |
|||
radius: 120, |
|||
startAngle: 200, |
|||
endAngle: -20, |
|||
min: 0, |
|||
max: 100, |
|||
splitNumber: 10, |
|||
itemStyle: { |
|||
color: itemStyleHandler(this.utilization) |
|||
}, |
|||
progress: { |
|||
show: true, |
|||
width: 20 |
|||
}, |
|||
pointer: { |
|||
show: false |
|||
}, |
|||
axisLine: { |
|||
lineStyle: { |
|||
width: 26, |
|||
color: axisLineHandler(this.utilization) |
|||
} |
|||
}, |
|||
axisTick: { |
|||
show: false, |
|||
distance: -35, |
|||
splitNumber: 5, |
|||
lineStyle: { |
|||
width: 2, |
|||
color: 'auto' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
show: false, |
|||
distance: -42, |
|||
length: 14, |
|||
lineStyle: { |
|||
width: 3, |
|||
color: 'auto' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
show: false, |
|||
distance: -40, |
|||
color: 'inherit', |
|||
fontSize: 14 |
|||
}, |
|||
anchor: { |
|||
show: false |
|||
}, |
|||
title: { |
|||
show: true, |
|||
offsetCenter: [0, '40%'], |
|||
fontSize: 18, |
|||
color: '#000' |
|||
}, |
|||
detail: { |
|||
valueAnimation: true, |
|||
width: '60%', |
|||
lineHeight: 40, |
|||
borderRadius: 8, |
|||
offsetCenter: [0, '0'], |
|||
fontSize: 40, |
|||
fontWeight: 'bolder', |
|||
formatter: '{value} %', |
|||
color: 'auto' |
|||
}, |
|||
data: [ |
|||
{ |
|||
value: this.utilization, |
|||
name: '占用率' |
|||
} |
|||
] |
|||
}, |
|||
// 最外侧 |
|||
{ |
|||
type: 'gauge', |
|||
radius: 130, // 半径 |
|||
center: ['40%', '38%'], // 位置 |
|||
min: 0, |
|||
max: 100, |
|||
startAngle: 200, |
|||
endAngle: -20, |
|||
axisLine: { |
|||
show: false, |
|||
lineStyle: { |
|||
width: 1, |
|||
color: '#999' |
|||
} |
|||
}, |
|||
axisTick: { |
|||
show: true, |
|||
splitNumber: 8, |
|||
length: 2, |
|||
lineStyle: { |
|||
width: 1, |
|||
color: '#999' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
show: false |
|||
}, |
|||
axisLabel: { |
|||
show: false |
|||
}, |
|||
pointer: { |
|||
show: false |
|||
}, |
|||
detail: { |
|||
show: false |
|||
} |
|||
} |
|||
] |
|||
} |
|||
|
|||
if (option) { |
|||
myChart.setOption(option) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
</style> |
|||
@ -1,275 +0,0 @@ |
|||
<template> |
|||
<div id="main4" :style="{height:height}" /> |
|||
</template> |
|||
|
|||
<script> |
|||
import echarts from 'echarts' |
|||
require('echarts/theme/macarons') |
|||
import resize from '@/views/dashboard/mixins/resize' |
|||
// const gaugeData = [ |
|||
// { |
|||
// value: 20, |
|||
// name: 'Perfect', |
|||
// title: { |
|||
// offsetCenter: ['0%', '-30%'] |
|||
// }, |
|||
// detail: { |
|||
// valueAnimation: true, |
|||
// offsetCenter: ['0%', '-20%'] |
|||
// } |
|||
// }, |
|||
// { |
|||
// value: 40, |
|||
// name: 'Good', |
|||
// title: { |
|||
// offsetCenter: ['0%', '0%'] |
|||
// }, |
|||
// detail: { |
|||
// valueAnimation: true, |
|||
// offsetCenter: ['0%', '10%'] |
|||
// } |
|||
// }, |
|||
// { |
|||
// value: 60, |
|||
// name: 'Commonly', |
|||
// title: { |
|||
// offsetCenter: ['0%', '30%'] |
|||
// }, |
|||
// detail: { |
|||
// valueAnimation: true, |
|||
// offsetCenter: ['0%', '40%'] |
|||
// } |
|||
// } |
|||
// ] |
|||
// var ROOT_PATH = 'https://echarts.apache.org/examples/data/asset/img/custom-gauge-panel.png' |
|||
// var _panelImageURL = ROOT_PATH + '/data/asset/img/custom-gauge-panel.png' |
|||
// var _animationDuration = 1000 |
|||
// var _animationDurationUpdate = 1000 |
|||
// var _animationEasingUpdate = 'quarticInOut' |
|||
// var _valOnRadianMax = 80 |
|||
// var _outerRadius = 80 |
|||
// var _innerRadius = 50 |
|||
// var _pointerInnerRadius = 50 |
|||
// var _insidePanelRadius = 30 |
|||
|
|||
// var _currentDataIndex = 0 |
|||
export default { |
|||
name: 'AcrossEcharts', |
|||
mixins: [resize], |
|||
props: { |
|||
addArcivesData: { |
|||
type: Object, |
|||
require: true, |
|||
default: function() { |
|||
return {} |
|||
} |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '100%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '100%' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
chart: null, |
|||
panelImageURL: 'https://echarts.apache.org/examples/data/asset/img/custom-gauge-panel.png', |
|||
animationDuration: 1000, |
|||
animationDurationUpdate: 1000, |
|||
animationEasingUpdate: 'quarticInOut', |
|||
valOnRadianMax: 200, |
|||
outerRadius: 200, |
|||
innerRadius: 170, |
|||
pointerInnerRadius: 40, |
|||
insidePanelRadius: 140 |
|||
} |
|||
}, |
|||
watch: { |
|||
// 'addArcivesData': { |
|||
// handler(val) { |
|||
// setTimeout(() => { |
|||
// this.drawChart() |
|||
// }, 100) |
|||
// }, |
|||
// immediate: true, |
|||
// deep: true |
|||
// } |
|||
}, |
|||
mounted() { |
|||
this.drawChart() |
|||
window.addEventListener('resize', this.__resizeHandler) |
|||
}, |
|||
methods: { |
|||
renderItem(params, api) { |
|||
var valOnRadian = api.value(1) |
|||
var coords = api.coord([api.value(0), valOnRadian]) |
|||
var polarEndRadian = coords[3] |
|||
var imageStyle = { |
|||
image: this.panelImageURL, |
|||
x: params.coordSys.cx - this.outerRadius, |
|||
y: params.coordSys.cy - this.outerRadius, |
|||
width: this.outerRadius * 2, |
|||
height: this.outerRadius * 2 |
|||
} |
|||
return { |
|||
type: 'group', |
|||
children: [ |
|||
{ |
|||
type: 'image', |
|||
style: imageStyle, |
|||
clipPath: { |
|||
type: 'sector', |
|||
shape: { |
|||
cx: params.coordSys.cx, |
|||
cy: params.coordSys.cy, |
|||
r: this.uterRadius, |
|||
r0: this.innerRadius, |
|||
startAngle: 0, |
|||
endAngle: -polarEndRadian, |
|||
transition: 'endAngle', |
|||
enterFrom: { endAngle: 0 } |
|||
} |
|||
} |
|||
}, |
|||
{ |
|||
type: 'image', |
|||
style: imageStyle, |
|||
clipPath: { |
|||
type: 'polygon', |
|||
shape: { |
|||
points: this.makePionterPoints(params, polarEndRadian) |
|||
}, |
|||
extra: { |
|||
polarEndRadian: polarEndRadian, |
|||
transition: 'polarEndRadian', |
|||
enterFrom: { polarEndRadian: 0 } |
|||
}, |
|||
during: function(apiDuring) { |
|||
apiDuring.setShape( |
|||
'points', |
|||
this.makePionterPoints(params, apiDuring.getExtra('polarEndRadian')) |
|||
) |
|||
} |
|||
} |
|||
}, |
|||
{ |
|||
type: 'circle', |
|||
shape: { |
|||
cx: params.coordSys.cx, |
|||
cy: params.coordSys.cy, |
|||
r: this.insidePanelRadius |
|||
}, |
|||
style: { |
|||
fill: '#fff', |
|||
shadowBlur: 25, |
|||
shadowOffsetX: 0, |
|||
shadowOffsetY: 0, |
|||
shadowColor: 'rgba(76,107,167,0.4)' |
|||
} |
|||
}, |
|||
{ |
|||
type: 'text', |
|||
extra: { |
|||
valOnRadian: valOnRadian, |
|||
transition: 'valOnRadian', |
|||
enterFrom: { valOnRadian: 0 } |
|||
}, |
|||
style: { |
|||
text: this.makeText(valOnRadian), |
|||
fontSize: 30, |
|||
fontWeight: 700, |
|||
x: params.coordSys.cx, |
|||
y: params.coordSys.cy, |
|||
fill: 'rgb(0,50,190)', |
|||
align: 'center', |
|||
verticalAlign: 'middle', |
|||
enterFrom: { opacity: 0 } |
|||
}, |
|||
during: function(apiDuring) { |
|||
apiDuring.setStyle( |
|||
'text', |
|||
this.makeText(apiDuring.getExtra('valOnRadian')) |
|||
) |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
makeText(valOnRadian) { |
|||
// Validate additive animation calc. |
|||
if (valOnRadian < -10) { |
|||
alert('illegal during val: ' + valOnRadian) |
|||
} |
|||
return ((valOnRadian / this.valOnRadianMax) * 100).toFixed(0) + '%' |
|||
}, |
|||
convertToPolarPoint(renderItemParams, radius, radian) { |
|||
return [ |
|||
Math.cos(radian) * radius + renderItemParams.coordSys.cx, |
|||
-Math.sin(radian) * radius + renderItemParams.coordSys.cy |
|||
] |
|||
}, |
|||
makePionterPoints(renderItemParams, polarEndRadian) { |
|||
return [ |
|||
this.convertToPolarPoint(renderItemParams, this.outerRadius, polarEndRadian), |
|||
this.convertToPolarPoint( |
|||
renderItemParams, |
|||
this.outerRadius, |
|||
polarEndRadian + Math.PI * 0.03 |
|||
), |
|||
this.convertToPolarPoint(renderItemParams, this.pointerInnerRadius, polarEndRadian) |
|||
] |
|||
}, |
|||
drawChart() { |
|||
const chartDom = document.getElementById('main4') |
|||
this.chart = echarts.init(chartDom) |
|||
let option = null |
|||
option = { |
|||
animationEasing: this.animationEasingUpdate, |
|||
animationDuration: this.animationDuration, |
|||
animationDurationUpdate: this.animationDurationUpdate, |
|||
animationEasingUpdate: this.animationEasingUpdate, |
|||
dataset: { |
|||
source: [[1, 156]] |
|||
}, |
|||
tooltip: {}, |
|||
angleAxis: { |
|||
type: 'value', |
|||
startAngle: 0, |
|||
show: false, |
|||
min: 0, |
|||
max: this.valOnRadianMax |
|||
}, |
|||
radiusAxis: { |
|||
type: 'value', |
|||
show: false |
|||
}, |
|||
polar: {}, |
|||
series: [ |
|||
{ |
|||
type: 'custom', |
|||
coordinateSystem: 'polar', |
|||
renderItem: this.renderItem |
|||
} |
|||
] |
|||
} |
|||
var _this = this |
|||
setInterval(function() { |
|||
var nextSource = [[1, Math.round(Math.random() * this.valOnRadianMax)]] |
|||
_this.chart.setOption({ |
|||
dataset: { |
|||
source: nextSource |
|||
} |
|||
}) |
|||
}, 3000) |
|||
option && this.chart.setOption(option) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
</style> |
|||
@ -0,0 +1,314 @@ |
|||
<template> |
|||
<div class="service-all"> |
|||
<div v-if="serviceTop" class="service-top-text" :class="!serviceTop ? 'false-active' : 'true-active'">AI处理终端 |
|||
<div class="service-left" /> |
|||
<div class="service-right" /> |
|||
</div> |
|||
<ul v-if="serviceTop" class="service-list"> |
|||
<li v-for="(item, index) in serviceItems" :key="index"> |
|||
<p :class="index <= currentIndex && item.status === 'running'? 'true-active' : 'false-active' "> |
|||
{{ item.serviceName }} |
|||
</p> |
|||
</li> |
|||
</ul> |
|||
<div v-if="servicesDisplayed && isAllServicesRunning" class="service-bottom-text" :class="{ 'fade-in': servicesDisplayed && isAllServicesRunning }" style="color: rgb(18, 196, 122);">所有服务均正常运行,请放心使用</div> |
|||
<div v-else-if="servicesDisplayed && !isAllServicesRunning" class="service-bottom-text" :class="{ 'fade-in': servicesDisplayed &&!isAllServicesRunning }" style="color: #ED4A41;">请尽快联系系统维护人员进行恢复</div> |
|||
<div v-if="!serviceTop" class="tip-service" :class="{ 'fade-in': !serviceTop }"> |
|||
<i class="iconfont icon-lianjieduankai" /> |
|||
<div class="tip-service-content"> |
|||
<p>AI处理终端连接超时,请检查配置是否正确或终端是否运行成功!</p> |
|||
<p>请尽快联系系统维护人员进行恢复</p> |
|||
</div> |
|||
</div> |
|||
</div></template> |
|||
|
|||
<script> |
|||
import crudAiTask, { FetchAITerminalStatusQuery } from '@/api/ai/ai' |
|||
import { mapGetters } from 'vuex' |
|||
export default { |
|||
name: 'ServeTerminal', |
|||
components: { }, |
|||
props: { |
|||
}, |
|||
data() { |
|||
return { |
|||
service: { |
|||
'service_FileParsing_v1': { 'last_heartbeat': 1736496962.2368362, 'status': '' }, |
|||
'service_fileParsing': { 'last_heartbeat': 1736496961.953832, 'status': '' }, |
|||
'service_imgOCR': { 'last_heartbeat': 1736496961.6238313, 'status': '' }, |
|||
'service_aiResult': { 'last_heartbeat': 1736496960.8598323, 'status': '' } |
|||
}, |
|||
serviceItems: [], |
|||
currentIndex: -1, |
|||
timer: null, |
|||
servicesDisplayed: false, |
|||
serviceTop: false |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'baseApi' |
|||
]), |
|||
isAllServicesRunning() { |
|||
return Object.values(this.service).every(service => service.status === 'running') |
|||
} |
|||
}, |
|||
mounted() { |
|||
}, |
|||
methods: { |
|||
initData() { |
|||
crudAiTask.FetchInitSetting().then(res => { |
|||
if (res) { |
|||
this.handleService(res.ip) |
|||
} |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
handleService(ip) { |
|||
this.servicesDisplayed = false |
|||
FetchAITerminalStatusQuery({ 'ip': ip }).then(res => { |
|||
// { |
|||
// "service_FileParsing_v1":{"last_heartbeat":1736496962.2368362,"status":"running"}, |
|||
// "service_fileParsing":{"last_heartbeat":1736496961.953832,"status":"running"} |
|||
// "service_imgOCR":{"last_heartbeat":1736496961.6238313,"status":"running"}, |
|||
// "service_aiResult":{"last_heartbeat":1736496960.8598323,"status":"running"}, |
|||
// } |
|||
if (res) { |
|||
this.serviceTop = true |
|||
this.service = JSON.parse(res) |
|||
this.serviceItems = [] |
|||
const keysOrder = ['service_FileParsing_v1', 'service_fileParsing', 'service_imgOCR', 'service_aiResult'] |
|||
keysOrder.forEach(key => { |
|||
let serviceName = '' |
|||
switch (key) { |
|||
case 'service_FileParsing_v1': |
|||
serviceName = '文件解析V1' |
|||
break |
|||
case 'service_fileParsing': |
|||
serviceName = '文件解析' |
|||
break |
|||
case 'service_imgOCR': |
|||
serviceName = '文字识别' |
|||
break |
|||
case 'service_aiResult': |
|||
serviceName = '数据同步' |
|||
break |
|||
} |
|||
this.serviceItems.push({ |
|||
serviceName: serviceName, |
|||
status: this.service[key].status |
|||
}) |
|||
}) |
|||
this.showServicesSequentially() |
|||
} else { |
|||
this.serviceTop = false |
|||
} |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
showServicesSequentially() { |
|||
let index = 0 |
|||
const interval = 300 |
|||
this.timer = setInterval(() => { |
|||
this.currentIndex = index |
|||
index++ |
|||
if (index >= this.serviceItems.length) { |
|||
clearInterval(this.timer) |
|||
setTimeout(() => { |
|||
this.servicesDisplayed = true |
|||
}, 500) |
|||
} |
|||
}, interval) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tip-service{ |
|||
display: flex; |
|||
justify-content: center; |
|||
color: #0C0E1E; |
|||
font-size: 16px; |
|||
line-height: 40px; |
|||
padding: 40px 0; |
|||
.iconfont{ |
|||
font-size: 30px; |
|||
margin-right: 10px; |
|||
color: #ED4A41; |
|||
} |
|||
p{ |
|||
&:first-child{ |
|||
color: #ED4A41; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.service-all{ |
|||
position: relative; |
|||
height: 230px; |
|||
color: #0C0E1E; |
|||
} |
|||
.service-top-text{ |
|||
position: relative; |
|||
font-size: 12px; |
|||
margin: 0 77px; |
|||
height: 72px; |
|||
text-align: center; |
|||
background: url('~@/assets/images/serve1.png') no-repeat center center; |
|||
background-size: 40px auto; |
|||
&.false-active{ |
|||
background: url('~@/assets/images/serve1-1.png') no-repeat center center; |
|||
background-size: 40px auto; |
|||
} |
|||
&.true-active{ |
|||
&::after{ |
|||
content: ""; |
|||
position: absolute; |
|||
right: 0; |
|||
bottom: -10px; |
|||
width: 67%; |
|||
height: 1px; |
|||
background-color: #9098a4; |
|||
margin-left: -1px; |
|||
} |
|||
} |
|||
} |
|||
.service-left{ |
|||
position: relative; |
|||
position: absolute; |
|||
left: -1px; |
|||
top: 40px; |
|||
width: 45%; |
|||
height: 82%; |
|||
border-top: 1px solid #9098a4; |
|||
border-left: 1px solid #9098a4; |
|||
} |
|||
.service-right{ |
|||
position: relative; |
|||
position: absolute; |
|||
right: 33%; |
|||
top: 40px; |
|||
width: 13%; |
|||
height: 74%; |
|||
border-top: 1px solid #9098a4; |
|||
border-right: 1px solid #9098a4; |
|||
} |
|||
.service-list{ |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 30px 40px 10px 40px; |
|||
li{ |
|||
position: relative; |
|||
&::before{ |
|||
content: ""; |
|||
position: absolute; |
|||
left: 50%; |
|||
top: -20px; |
|||
width: 1px; |
|||
height: 10px; |
|||
background-color: #9098a4; |
|||
margin-left: -1px; |
|||
} |
|||
p{ |
|||
width: 74px; |
|||
height: 70px; |
|||
font-size: 12px; |
|||
text-align: center; |
|||
} |
|||
&:nth-child(1){ |
|||
&::before{ |
|||
background-color: transparent; |
|||
} |
|||
p{ |
|||
&.false-active{ |
|||
background: url('~@/assets/images/ter1-1.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
&.true-active{ |
|||
background: url('~@/assets/images/ter1.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
} |
|||
} |
|||
&:nth-child(2){ |
|||
p{ |
|||
&.false-active{ |
|||
background: url('~@/assets/images/ter1-1.png') no-repeat center center; |
|||
background-size: 32px auto; |
|||
} |
|||
&.true-active{ |
|||
background: url('~@/assets/images/ter1.png') no-repeat center center; |
|||
background-size: 32px auto; |
|||
} |
|||
} |
|||
} |
|||
&:nth-child(3){ |
|||
&::before{ |
|||
background-color: transparent; |
|||
} |
|||
p{ |
|||
&.false-active{ |
|||
background: url('~@/assets/images/ter3-1.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
&.true-active{ |
|||
background: url('~@/assets/images/ter3.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
} |
|||
} |
|||
&:nth-child(4){ |
|||
p{ |
|||
&.false-active{ |
|||
background: url('~@/assets/images/ter4-1.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
&.true-active{ |
|||
background: url('~@/assets/images/ter4.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
} |
|||
} |
|||
&:nth-child(5){ |
|||
p{ |
|||
&.false-active{ |
|||
background: url('~@/assets/images/ter5-1.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
&.true-active{ |
|||
background: url('~@/assets/images/ter5.png') no-repeat center center; |
|||
background-size: 36px auto; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.service-bottom-text{ |
|||
font-size: 12px; |
|||
text-align: center; |
|||
} |
|||
.fade-enter-active, |
|||
.fade-leave-active { |
|||
transition: all 0.5s ease; |
|||
} |
|||
.fade-enter, |
|||
.fade-leave-to { |
|||
opacity: 0; |
|||
transform: translateY(20px); |
|||
} |
|||
.fade-in { |
|||
animation: fadeIn 0.5s ease; |
|||
} |
|||
@keyframes fadeIn { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(20px); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,492 @@ |
|||
<template> |
|||
<div class="app-container row-container"> |
|||
<div class="container-wrap" style="height: calc(100vh - 200px);"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-bottom-line" /> |
|||
<el-form ref="form" :rules="rules" :model="form" size="small" label-width="120px"> |
|||
<el-row style="display: flex; justify-content: flex-start;"> |
|||
<el-form-item label="AI处理终端IP" prop="ip"> |
|||
<el-input v-model="form.ip" placeholder="请输入IP地址,如:192.168.1.1" style="width: 300px;" /> |
|||
</el-form-item> |
|||
<div v-if="form.ip" style="margin-left: 20px; margin-top: 6px; cursor: pointer;" @click="handleService"><i class="iconfont icon-bendiguajie" /></div> |
|||
<p style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置成功后,方可执行视觉盘点任务</p> |
|||
<div style="margin-left: 20px;"> |
|||
<el-button :loading="resetLoading" @click="toVerify('reset')">重启服务</el-button> |
|||
<!-- <el-button>关闭</el-button> --> |
|||
</div> |
|||
</el-row> |
|||
<!-- <el-row style="display: flex; justify-content: flex-start;"> |
|||
<el-form-item label="层位占用上限" prop="maxNum"> |
|||
<el-input v-model="form.maxNum" type="number" placeholder="请输入" style="width: 300px;" /> |
|||
</el-form-item> |
|||
<p style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置成功后,方可在倒架建议中给出正确的数据(通常情况下,上限为 50 册)</p> |
|||
</el-row> --> |
|||
</el-form> |
|||
<div> |
|||
<el-button style="margin-left: 30px;" :loading="crud.status.cu === 2" type="primary" @click="toVerify('add')">保存</el-button> |
|||
<span style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置需要超级管理员权限授权!</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<el-dialog class="tip-dialog tip-middle-dialog" title="操作提示" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="verifyDialogVisible" :before-close="handleClose"> |
|||
<div class="setting-dialog"> |
|||
<div class="tip-content"> |
|||
<p class="tipMsg">这里为技术人员维护系统时使用,普通用户无需设置</p> |
|||
<p class="delt-tip"><span>注意:强行修改会导致系统数据异常或丢失!如因用户强行修改,本系统不负责因此导致的相关后果!</span></p> |
|||
</div> |
|||
<el-form ref="verfiyForm" :model="verfiyForm" style="margin-top:30px;" @submit.native.prevent> |
|||
<el-form-item label="维护验证码" label-width="110px"> |
|||
<el-input v-model="verfiyForm.verifyCode" show-password style="width: 480px;" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button @click="handleClose">取消 </el-button> |
|||
<el-button type="primary" @click.native="handleConfirm">确定</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<el-dialog class="tip-dialog tip-middle-dialog" title="AI处理终端连接测试" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="serviceDialogVisible" :before-close="handleClose"> |
|||
<div class="setting-dialog tip-service"> |
|||
<i class="iconfont icon-lianjieduankai" /> |
|||
<div class="tip-service-content"> |
|||
<p>终端连接超时,请检查配置是否正确或终端是否运行成功!</p> |
|||
<p>请尽快联系系统维护人员进行恢复</p> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<el-dialog class="tip-dialog tip-middle-dialog" title="AI处理终端连接测试" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="serviceContentDialogVisible" :before-close="handleClose"> |
|||
<div class="setting-dialog service-all"> |
|||
<div class="service-top-text"><i class="iconfont icon-zhongduanjiankong" />终端连接正常</div> |
|||
<!-- <ul> |
|||
<li v-for="(item, index) in serviceItems" :key="index" :style="{animationDelay: index * 300 + 'ms'}"> |
|||
<p :class="item.status === 'running'? 'true-active' : 'false-active' ">{{ item.serviceName }}</p> |
|||
<i v-if="item.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
</ul> --> |
|||
<ul> |
|||
<li v-for="(item, index) in serviceItems" :key="index"> |
|||
<p :class="index <= currentIndex && item.status === 'running'? 'true-active' : 'false-active' ">{{ item.serviceName }}</p> |
|||
<i v-if="index <= currentIndex && item.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else-if="index <= currentIndex" class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
</ul> |
|||
<!-- <ul> |
|||
<li> |
|||
<p :class="service.service_imgCamera.status === 'running' ? 'true-active' : 'false-active' ">图像采集</p> |
|||
<i v-if="service.service_imgCamera.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
<li> |
|||
<p :class="service.service_imgProcess.status === 'running' ? 'true-active' : 'false-active' ">图像处理</p> |
|||
<i v-if="service.service_imgProcess.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
<li> |
|||
<p :class="service.service_imgYolo.status === 'running' ? 'true-active' : 'false-active' ">图像识别</p> |
|||
<i v-if="service.service_imgYolo.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
<li> |
|||
<p :class="service.service_imgOcr.status === 'running' ? 'true-active' : 'false-active' ">文字识别</p> |
|||
<i v-if="service.service_imgOcr.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
<li> |
|||
<p :class="service.service_imgResult.status === 'running' ? 'true-active' : 'false-active' ">同步服务</p> |
|||
<i v-if="service.service_imgResult.status === 'running'" class="iconfont icon-shi" /> |
|||
<i v-else class="iconfont icon-cuowu1" /> |
|||
</li> |
|||
</ul> --> |
|||
<div v-if="servicesDisplayed && isAllServicesRunning" class="service-bottom-text" :class="{ 'fade-in': servicesDisplayed && isAllServicesRunning }" style="color: rgb(18, 196, 122);">所有服务均正常运行,请放心使用</div> |
|||
<div v-else-if="servicesDisplayed && !isAllServicesRunning" class="service-bottom-text" :class="{ 'fade-in': servicesDisplayed &&!isAllServicesRunning }" style="color: #ED4A41;">请尽快联系系统维护人员进行恢复</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import crudAiTask, { FetchAITerminalStatusQuery, FetchStartStopBookAIService } from '@/api/ai/ai' |
|||
import { encrypt } from '@/utils/rsaEncrypt' |
|||
import { verifyMaintenance } from '@/api/system/field' |
|||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|||
import { mapGetters } from 'vuex' |
|||
|
|||
const defaultForm = { ip: '', maxNum: null } |
|||
|
|||
export default { |
|||
name: 'ParamSetting', |
|||
components: { }, |
|||
cruds() { |
|||
return CRUD({ |
|||
title: '参数设置', |
|||
url: 'api/ai/initSetting', |
|||
crudMethod: { ...crudAiTask }, |
|||
sort: [], |
|||
query: { |
|||
size: null, |
|||
page: null |
|||
}, |
|||
optShow: { |
|||
add: true, |
|||
edit: false, |
|||
del: false, |
|||
download: false, |
|||
group: false, |
|||
reset: false |
|||
}, |
|||
queryOnPresenterCreated: false |
|||
}) |
|||
}, |
|||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|||
data() { |
|||
return { |
|||
permission: { |
|||
add: ['admin', 'paramSetting:add'], |
|||
edit: ['admin', 'paramSetting:edit'], |
|||
del: ['admin', 'paramSetting:del'] |
|||
}, |
|||
verifyDialogVisible: false, |
|||
verfiyForm: { |
|||
verifyCode: '' |
|||
}, |
|||
verifyStatus: '', |
|||
showVerifyDialog: true, |
|||
resetLoading: false, |
|||
rules: { |
|||
ip: [ |
|||
{ required: true, message: 'AI处理终端IP不可为空', trigger: 'blur' } |
|||
], |
|||
maxNum: [ |
|||
{ required: true, message: '层位占用上限不可为空', trigger: 'blur' } |
|||
] |
|||
}, |
|||
serviceDialogVisible: false, |
|||
serviceContentDialogVisible: false, |
|||
service: { |
|||
'service_FileParsing_v1': { 'last_heartbeat': 1736496962.2368362, 'status': '' }, |
|||
'service_fileParsing': { 'last_heartbeat': 1736496961.953832, 'status': '' }, |
|||
'service_imgOCR': { 'last_heartbeat': 1736496961.6238313, 'status': '' }, |
|||
'service_aiResult': { 'last_heartbeat': 1736496960.8598323, 'status': '' } |
|||
}, |
|||
serviceItems: [], |
|||
currentIndex: -1, |
|||
timer: null, |
|||
servicesDisplayed: false, |
|||
|
|||
formValidate: { |
|||
mainImage: '' |
|||
}, |
|||
ruleValidate: { |
|||
mainImage: [ |
|||
{ required: true, message: '请上传照片', trigger: 'blur' } |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'baseApi' |
|||
]), |
|||
isAllServicesRunning() { |
|||
return Object.values(this.service).every(service => service.status === 'running') |
|||
} |
|||
}, |
|||
created() { |
|||
this.initData() |
|||
}, |
|||
beforeDestroy() { |
|||
if (this.timer) { |
|||
clearInterval(this.timer) |
|||
} |
|||
}, |
|||
methods: { |
|||
initData() { |
|||
crudAiTask.FetchInitSetting().then(res => { |
|||
this.crud.form.ip = res.ip |
|||
this.maxNum = res.maxNum |
|||
this.crud.form.maxNum = res.maxNum |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
handleService() { |
|||
this.servicesDisplayed = false |
|||
FetchAITerminalStatusQuery({ 'ip': this.crud.form.ip }).then(res => { |
|||
// { |
|||
// "service_FileParsing_v1":{"last_heartbeat":1736496962.2368362,"status":"running"}, |
|||
// "service_fileParsing":{"last_heartbeat":1736496961.953832,"status":"running"} |
|||
// "service_imgOCR":{"last_heartbeat":1736496961.6238313,"status":"running"}, |
|||
// "service_aiResult":{"last_heartbeat":1736496960.8598323,"status":"running"}, |
|||
// } |
|||
if (res) { |
|||
this.serviceContentDialogVisible = true |
|||
this.service = JSON.parse(res) |
|||
this.serviceItems = [] |
|||
const keysOrder = ['service_FileParsing_v1', 'service_fileParsing', 'service_imgOCR', 'service_aiResult'] |
|||
keysOrder.forEach(key => { |
|||
let serviceName = '' |
|||
switch (key) { |
|||
case 'service_FileParsing_v1': |
|||
serviceName = '文件解析V1' |
|||
break |
|||
case 'service_fileParsing': |
|||
serviceName = '文件解析' |
|||
break |
|||
case 'service_imgOCR': |
|||
serviceName = '文字识别' |
|||
break |
|||
case 'service_aiResult': |
|||
serviceName = '数据同步' |
|||
break |
|||
} |
|||
this.serviceItems.push({ |
|||
serviceName: serviceName, |
|||
status: this.service[key].status |
|||
}) |
|||
}) |
|||
this.showServicesSequentially() |
|||
} else { |
|||
this.serviceDialogVisible = true |
|||
} |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
showServicesSequentially() { |
|||
// let delay = 0 |
|||
// this.serviceItems.forEach((item, index) => { |
|||
// setTimeout(() => { |
|||
// this.$set(this.serviceItems, index, { |
|||
// ...item, |
|||
// opacity: 1 |
|||
// }) |
|||
// }, delay) |
|||
// delay += 300 |
|||
// }) |
|||
let index = 0 |
|||
const interval = 300 |
|||
this.timer = setInterval(() => { |
|||
this.currentIndex = index |
|||
index++ |
|||
if (index >= this.serviceItems.length) { |
|||
clearInterval(this.timer) |
|||
setTimeout(() => { |
|||
this.servicesDisplayed = true |
|||
}, 500) |
|||
} |
|||
}, interval) |
|||
}, |
|||
[CRUD.HOOK.beforeToCU](crud, form, btn) { |
|||
if (this.showVerifyDialog) { |
|||
// 打开输入验证码对话框 |
|||
this.verifyDialogVisible = true |
|||
return false |
|||
} |
|||
}, |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
|
|||
}, |
|||
// 提交前的验证 |
|||
[CRUD.HOOK.afterValidateCU](crud) { |
|||
console.log(crud.form) |
|||
return false |
|||
}, |
|||
toVerify(btn) { |
|||
this.verifyStatus = btn |
|||
if (btn === 'reset') { |
|||
this.verifyDialogVisible = true |
|||
} else { |
|||
if (this.form.ip) { |
|||
if (this.showVerifyDialog) { |
|||
this.verifyDialogVisible = true |
|||
return false |
|||
} |
|||
} else { |
|||
this.$refs.form.validateField(['ip'], err => { |
|||
console.log('err', err) |
|||
if (err) { |
|||
return |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
handleConfirm() { |
|||
verifyMaintenance(encrypt(this.verfiyForm.verifyCode)).then((res) => { |
|||
if (res) { |
|||
this.verifyDialogVisible = false |
|||
this.verfiyForm.verifyCode = '' |
|||
this.showVerifyDialog = false |
|||
if (this.verifyStatus === 'add') { |
|||
crudAiTask.FetchEditSetting(this.crud.form).then(res => { |
|||
this.$message({ message: '修改成功', type: 'success', offset: 8 }) |
|||
this.initData() |
|||
}).catch(() => { |
|||
}) |
|||
} else { |
|||
this.resetLoading = true |
|||
// 重启服务 |
|||
this.handleConnectAIService() |
|||
} |
|||
} else { |
|||
this.$message({ message: '验证码错误!', type: 'error', offset: 8 }) |
|||
} |
|||
}) |
|||
}, |
|||
async handleConnectAIService() { |
|||
try { |
|||
// // 第一次先关闭 |
|||
// const firstRes = await FetchStartStopBookAIService({ runType: 0 }) |
|||
// console.log('先关闭', firstRes) |
|||
// this.$message({ message: '关闭服务成功', type: 'success', offset: 8 }) |
|||
// 第二次重新开启 |
|||
// 1开启(先关后开) 2关闭 (彻底关闭) |
|||
const secondRes = await FetchStartStopBookAIService({ runType: 1 }) |
|||
console.log('后开启', secondRes) |
|||
this.$message({ message: '重启服务成功', type: 'success', offset: 8 }) |
|||
this.resetLoading = false |
|||
} catch (error) { |
|||
this.$message({ message: '请求失败', type: 'error', offset: 8 }) |
|||
this.resetLoading = false |
|||
} |
|||
}, |
|||
handleClose() { |
|||
if (this.$refs.verfiyForm) { |
|||
this.verfiyForm.verifyCode = '' |
|||
this.$refs.verfiyForm.resetFields() |
|||
this.verifyDialogVisible = false |
|||
} |
|||
|
|||
this.serviceContentDialogVisible = false |
|||
this.serviceDialogVisible = false |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
::v-deep div.el-dialog__footer { |
|||
text-align: center; |
|||
} |
|||
.tip-service{ |
|||
display: flex; |
|||
justify-content: center; |
|||
color: #0C0E1E; |
|||
font-size: 16px; |
|||
line-height: 40px; |
|||
padding: 40px !important; |
|||
.iconfont{ |
|||
font-size: 30px; |
|||
margin-right: 10px; |
|||
color: #ED4A41; |
|||
} |
|||
p{ |
|||
&:first-child{ |
|||
color: #ED4A41; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.service-all{ |
|||
text-align: center; |
|||
padding: 30px 0 30px 0 !important; |
|||
color: #0C0E1E; |
|||
ul{ |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding: 60px 0 40px 0; |
|||
li{ |
|||
position: relative; |
|||
&::before{ |
|||
content: ""; |
|||
position: absolute; |
|||
left: 50%; |
|||
top: -30px; |
|||
width: 1px; |
|||
height: 20px; |
|||
background-color: #9098a4; |
|||
margin-left: -1px; |
|||
} |
|||
p{ |
|||
padding: 5px; |
|||
border: 1px solid #9098a4; |
|||
margin-bottom: 10px; |
|||
border-radius: 4px; |
|||
&.false-active{ |
|||
border-color: #ED4A41; |
|||
color: #ED4A41; |
|||
} |
|||
&.true-active{ |
|||
border-color: rgb(18, 196, 122); |
|||
color: rgb(18, 196, 122); |
|||
} |
|||
} |
|||
.iconfont::before{ |
|||
margin-right: 0 !important; |
|||
} |
|||
.icon-cuowu1{ |
|||
color: #ED4A41; |
|||
} |
|||
.icon-shi{ |
|||
color: rgb(18, 196, 122); |
|||
} |
|||
} |
|||
} |
|||
.service-top-text{ |
|||
position: relative; |
|||
font-size: 18px; |
|||
margin: 0 33px 0 43px; |
|||
color: rgb(18, 196, 122); |
|||
i.iconfont{ |
|||
font-size: 18px; |
|||
margin-right: 6px; |
|||
} |
|||
&::before{ |
|||
content: ""; |
|||
position: absolute; |
|||
left: 50%; |
|||
bottom: -30px; |
|||
width: 1px; |
|||
height: 20px; |
|||
background-color:#9098a4; |
|||
margin-left: -1px; |
|||
} |
|||
&::after{ |
|||
content: ""; |
|||
position: absolute; |
|||
left: 0; |
|||
bottom: -30px; |
|||
width: 100%; |
|||
height: 1px; |
|||
background-color: #9098a4; |
|||
margin-left: -1px; |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.fade-enter-active, |
|||
.fade-leave-active { |
|||
transition: all 0.5s ease; |
|||
} |
|||
.fade-enter, |
|||
.fade-leave-to { |
|||
opacity: 0; |
|||
transform: translateY(20px); |
|||
} |
|||
.fade-in { |
|||
animation: fadeIn 0.5s ease; |
|||
} |
|||
@keyframes fadeIn { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(20px); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
</style> |
|||