1
This commit is contained in:
parent
6b5c739b5d
commit
e801454bd6
@ -1,15 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="curve-chart">
|
<div class="curve-box">
|
||||||
<div class="chart-title">{{title}}</div>
|
<div class="curve-chart">
|
||||||
<div ref="chartRef" style="width: 100%; height: 400px"></div>
|
<div class="chart-title">{{titleA}}</div>
|
||||||
|
<div ref="chartRefA" style="width: 500px; height: 400px"></div>
|
||||||
|
</div>
|
||||||
|
<div class="curve-chart">
|
||||||
|
<div class="chart-title">{{titleB}}</div>
|
||||||
|
<div ref="chartRefB" style="width: 500px; height: 400px"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
import {ref, onMounted, onUnmounted, watch} from 'vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
titleA: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
titleB: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
@ -17,17 +27,44 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '#ff4444'
|
default: '#ff4444'
|
||||||
},
|
},
|
||||||
|
curveData1: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
channelA_data:[],
|
||||||
|
channelB_data:[],
|
||||||
|
intensityA:'',
|
||||||
|
intensityB:'',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
curveData2: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
channelA_data:[],
|
||||||
|
channelB_data:[],
|
||||||
|
intensityA:'',
|
||||||
|
intensityB:'',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
edgesA: {
|
||||||
|
type:Array,
|
||||||
|
default:[]
|
||||||
|
},
|
||||||
|
edgesB: {
|
||||||
|
type:Array,
|
||||||
|
default:[]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
const chartRef = ref(null)
|
const chartRefA = ref(null)
|
||||||
|
const chartRefB = ref(null)
|
||||||
let chart = null
|
let chart = null
|
||||||
|
|
||||||
const initChart = () => {
|
const initChartA = () => {
|
||||||
if (chart) {
|
if (chart) {
|
||||||
chart.dispose()
|
chart.dispose()
|
||||||
}
|
}
|
||||||
|
console.log(props.curveData1.channelA_data,'props.curveData1.channelA_data')
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
chart = echarts.init(chartRef.value)
|
chart = echarts.init(chartRefA.value)
|
||||||
const option = {
|
const option = {
|
||||||
grid: {
|
grid: {
|
||||||
left: '12%', // 增加左边距
|
left: '12%', // 增加左边距
|
||||||
@ -39,8 +76,7 @@ const initChart = () => {
|
|||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 120,
|
interval: 'auto',
|
||||||
interval: 15,
|
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
@ -58,13 +94,89 @@ const initChart = () => {
|
|||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 48000,
|
splitLine: {
|
||||||
interval: 6000,
|
lineStyle: {
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
margin: 16,
|
||||||
|
formatter: '{value}'
|
||||||
|
},
|
||||||
|
nameTextStyle: {
|
||||||
|
padding: [0, 0, 0, 40]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// yAxis: {
|
||||||
|
// type: 'value',
|
||||||
|
// boundaryGap: [0, '100%']
|
||||||
|
// },
|
||||||
|
// visualMap: {
|
||||||
|
// type: 'piecewise',
|
||||||
|
// show: false,
|
||||||
|
// dimension: 0,
|
||||||
|
// seriesIndex: 0,
|
||||||
|
// pieces: [
|
||||||
|
// {
|
||||||
|
// gt: 1,
|
||||||
|
// lt: 3,
|
||||||
|
// color: 'rgba(0, 0, 180, 0.4)'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// gt: 5,
|
||||||
|
// lt: 7,
|
||||||
|
// color: 'rgba(0, 0, 180, 0.4)'
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
data: props.curveData1.channelA_data,
|
||||||
|
symbol: 'none',
|
||||||
|
smooth: true, // 添加平滑度
|
||||||
|
smoothMonotone: 'x', // 保持单调性
|
||||||
|
lineStyle: {
|
||||||
|
color: props.color,
|
||||||
|
width: 2
|
||||||
|
},
|
||||||
|
areaStyle: {},
|
||||||
|
animation: false,
|
||||||
|
// markLine: {
|
||||||
|
// symbol: ['none', 'none'],
|
||||||
|
// label: { show: false },
|
||||||
|
// data: [{ xAxis: 1 }, { xAxis: 3 }, { xAxis: 5 }, { xAxis: 7 }]
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
chart.setOption(option)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const initChartB = () => {
|
||||||
|
if (chart) {
|
||||||
|
chart.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
chart = echarts.init(chartRefB.value)
|
||||||
|
const option = {
|
||||||
|
grid: {
|
||||||
|
left: '12%', // 增加左边距
|
||||||
|
right: '5%',
|
||||||
|
top: '8%', // 增加顶部边距
|
||||||
|
bottom: '12%', // 增加底部边距
|
||||||
|
containLabel: true // 确保标签显示完整
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
interval: 'auto',
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
margin: 16, // 增加标签与轴线距离
|
margin: 12, // 增加标签与轴线距离
|
||||||
formatter: '{value}'
|
formatter: '{value}'
|
||||||
},
|
},
|
||||||
splitLine: {
|
splitLine: {
|
||||||
@ -74,24 +186,65 @@ const initChart = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
series: [{
|
yAxis: {
|
||||||
type: 'line',
|
type: 'value',
|
||||||
data: generateData(),
|
min: 0,
|
||||||
symbol: 'none',
|
// max:1050,
|
||||||
smooth: 0.2, // 添加平滑度
|
splitLine: {
|
||||||
smoothMonotone: 'x', // 保持单调性
|
lineStyle: {
|
||||||
lineStyle: {
|
type: 'dashed'
|
||||||
color: props.color,
|
}
|
||||||
width: 2
|
|
||||||
},
|
},
|
||||||
animation: false
|
axisLabel: {
|
||||||
}]
|
margin: 16,
|
||||||
}
|
formatter: '{value}'
|
||||||
|
},
|
||||||
|
nameTextStyle: {
|
||||||
|
padding: [0, 0, 0, 40]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// visualMap: {
|
||||||
|
// type: 'piecewise',
|
||||||
|
// show: false,
|
||||||
|
// dimension: 0,
|
||||||
|
// seriesIndex: 0,
|
||||||
|
// pieces: [
|
||||||
|
// {
|
||||||
|
// gt: 1,
|
||||||
|
// lt: 3,
|
||||||
|
// color: 'rgba(0, 0, 180, 0.4)'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// gt: 5,
|
||||||
|
// lt: 7,
|
||||||
|
// color: 'rgba(0, 0, 180, 0.4)'
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
data: props.curveData2.channelA_data,
|
||||||
|
symbol: 'none',
|
||||||
|
smooth: true, // 添加平滑度
|
||||||
|
smoothMonotone: 'x', // 保持单调性
|
||||||
|
lineStyle: {
|
||||||
|
color: props.color,
|
||||||
|
width: 2
|
||||||
|
},
|
||||||
|
areaStyle: {},
|
||||||
|
animation: false,
|
||||||
|
// markLine: {
|
||||||
|
// symbol: ['none', 'none'],
|
||||||
|
// label: { show: false },
|
||||||
|
// data: [{ xAxis: 1 }, { xAxis: 3 }, { xAxis: 5 }, { xAxis: 7 }]
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
chart.setOption(option)
|
chart.setOption(option)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加 resize 方法
|
// 添加 resize 方法
|
||||||
const resize = () => {
|
const resize = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -104,32 +257,13 @@ defineExpose({
|
|||||||
resize
|
resize
|
||||||
})
|
})
|
||||||
|
|
||||||
const generateData = () => {
|
watch(() => props.curveData1,(newValue) => {
|
||||||
const data = []
|
console.log(newValue,'====3')
|
||||||
for (let i = 0; i <= 120; i += 0.5) { // 增加采样点密度
|
})
|
||||||
let value
|
|
||||||
if (i <= 45) {
|
|
||||||
value = 40000
|
|
||||||
} else if (i > 45 && i <= 60) {
|
|
||||||
// 使用非线性插值
|
|
||||||
const progress = (i - 45) / 15
|
|
||||||
value = 40000 - (34000 * Math.pow(progress, 1.2))
|
|
||||||
} else if (i > 60 && i <= 75) {
|
|
||||||
value = 6000
|
|
||||||
} else if (i > 75 && i <= 90) {
|
|
||||||
// 使用非线性插值
|
|
||||||
const progress = (i - 75) / 15
|
|
||||||
value = 6000 + (34000 * Math.pow(progress, 0.8))
|
|
||||||
} else {
|
|
||||||
value = 40000
|
|
||||||
}
|
|
||||||
data.push([i, value])
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initChart()
|
console.log(props.titleA,props.titleB,'===')
|
||||||
|
initChartA()
|
||||||
|
initChartB()
|
||||||
window.addEventListener('resize', () => chart?.resize())
|
window.addEventListener('resize', () => chart?.resize())
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -140,6 +274,9 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.curve-box {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
.curve-chart {
|
.curve-chart {
|
||||||
width:100%;
|
width:100%;
|
||||||
height:100%;
|
height:100%;
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="chartRef" style="width: 400px; height: 400px;"></div>
|
<div class="curve-chart">
|
||||||
|
<div class="chart-title">{{title}}</div>
|
||||||
|
<div ref="chartRef" style="width: 500px; height: 400px;"></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}
|
||||||
|
})
|
||||||
const chartRef = ref(null)
|
const chartRef = ref(null)
|
||||||
let myChart = null
|
let myChart = null
|
||||||
|
|
||||||
@ -145,4 +153,20 @@ onUnmounted(() => {
|
|||||||
window.removeEventListener('resize', () => myChart?.resize())
|
window.removeEventListener('resize', () => myChart?.resize())
|
||||||
myChart?.dispose()
|
myChart?.dispose()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.curve-chart {
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
padding: 20px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.chart-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -233,25 +233,48 @@
|
|||||||
</el-button-group>
|
</el-button-group>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
<div v-if="showRed">
|
<div v-if="showRed" style="display: flex">
|
||||||
<CurveChart ref="bowlCurveRef" :title="chartTitle.left" :color="colorRed"/>
|
<CurveChart
|
||||||
<CurveChart ref="bowlCurveRef" :title="chartTitle.right" :color="colorRed"/>
|
ref="bowlCurveRef"
|
||||||
|
:curve-data1="imageViewScanner1"
|
||||||
|
:curve-data2="imageViewScanner2"
|
||||||
|
:titleA="chartTitle.leftA"
|
||||||
|
:titleB="chartTitle.rightA"
|
||||||
|
:color="colorRed"
|
||||||
|
:edgesA="edgesA"
|
||||||
|
:edgesB="edgesB"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showGreen">
|
<div v-if="showGreen" style="display: flex">
|
||||||
<CurveChart ref="bowlCurveRef" :title="chartTitle.left" :color="colorGreen"/>
|
<CurveChart
|
||||||
<CurveChart ref="bowlCurveRef" :title="chartTitle.right" :color="colorGreen"/>
|
ref="bowlCurveRef"
|
||||||
|
:curve-data1="imageViewScanner1"
|
||||||
|
:curve-data2="imageViewScanner2"
|
||||||
|
:titleA="chartTitle.leftA"
|
||||||
|
:titleB="chartTitle.rightA"
|
||||||
|
:color="colorGreen"
|
||||||
|
:edgesA="edgesA"
|
||||||
|
:edgesB="edgesB"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showRedGreen">
|
<div v-if="showRedGreen" style="display: flex">
|
||||||
<DualChannelChart
|
<div style="display: flex">
|
||||||
title="扫描臂1"
|
<DualChannelChart
|
||||||
ref="dualChart1Ref"
|
title="扫描臂1"
|
||||||
:chart-data="arm1ChartData"
|
ref="dualChart1Ref"
|
||||||
/>
|
:title="chartTitle.left"
|
||||||
<DualChannelChart
|
:chart-data="arm1ChartData"
|
||||||
title="扫描臂2"
|
/>
|
||||||
ref="dualChart2Ref"
|
</div>
|
||||||
:chart-data="arm2ChartData"
|
<div style="display: flex">
|
||||||
/>
|
<DualChannelChart
|
||||||
|
title="扫描臂2"
|
||||||
|
ref="dualChart2Ref"
|
||||||
|
:title="chartTitle.right"
|
||||||
|
:chart-data="arm2ChartData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@ -349,13 +372,33 @@ const historyDialogRef = ref(null)
|
|||||||
const currentTime = ref('2021-02-11 13:23:39')
|
const currentTime = ref('2021-02-11 13:23:39')
|
||||||
const chartTitle = ref({
|
const chartTitle = ref({
|
||||||
left: '扫描臂1 曲线',
|
left: '扫描臂1 曲线',
|
||||||
right: '扫描臂2 曲线'
|
right: '扫描臂2 曲线',
|
||||||
|
leftA:'扫描臂1-A',
|
||||||
|
rightA: '扫描臂2-A',
|
||||||
|
leftB:'扫描臂1-B',
|
||||||
|
rightB: '扫描臂2-B',
|
||||||
|
|
||||||
})
|
})
|
||||||
const modeTypeMap = {
|
const modeTypeMap = {
|
||||||
'fast':'快速模式',
|
'fast':'快速模式',
|
||||||
'normal':'正常速度',
|
'normal':'正常速度',
|
||||||
'slow':'慢速模式'
|
'slow':'慢速模式'
|
||||||
};
|
};
|
||||||
|
// 图像预览数据
|
||||||
|
const imageViewScanner1 = reactive({
|
||||||
|
channelA_data:[],
|
||||||
|
channelB_data:[],
|
||||||
|
intensityA:'',
|
||||||
|
intensityB:'',
|
||||||
|
})
|
||||||
|
const imageViewScanner2 = reactive({
|
||||||
|
channelA_data:[],
|
||||||
|
channelB_data:[],
|
||||||
|
intensityA:'',
|
||||||
|
intensityB:'',
|
||||||
|
})
|
||||||
|
const edgesA = ref([])
|
||||||
|
const edgesB = ref([])
|
||||||
//产品信息
|
//产品信息
|
||||||
let productInfo = ref(null)
|
let productInfo = ref(null)
|
||||||
const warningList = ref([])
|
const warningList = ref([])
|
||||||
@ -524,6 +567,7 @@ const handleClick = (tab, event) => {
|
|||||||
realtimeChartRef.value?.resize()
|
realtimeChartRef.value?.resize()
|
||||||
}
|
}
|
||||||
if(tab.props.label === '图像预览') {
|
if(tab.props.label === '图像预览') {
|
||||||
|
await collectData();
|
||||||
bowlCurveRef.value?.resize()
|
bowlCurveRef.value?.resize()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -535,10 +579,7 @@ const handlePrevious = (index, index1, currentIndex) => {
|
|||||||
const handleNext = (index, index1, currentIndex) => {
|
const handleNext = (index, index1, currentIndex) => {
|
||||||
useEquipment.setSelectIndex(index, index1, currentIndex, 'next')
|
useEquipment.setSelectIndex(index, index1, currentIndex, 'next')
|
||||||
}
|
}
|
||||||
// 图像预览
|
|
||||||
const handleDataUpdate = (data) => {
|
|
||||||
console.log('数据更新:', data)
|
|
||||||
}
|
|
||||||
// 快速模式
|
// 快速模式
|
||||||
const handleModeChange = () => {
|
const handleModeChange = () => {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
@ -676,7 +717,7 @@ const initSubscribe = async () => {
|
|||||||
}})
|
}})
|
||||||
// 设备状态
|
// 设备状态
|
||||||
subscribe(`v1/cpycal/${deviceInfo.value?.deviceCode}/status`, (message) => {
|
subscribe(`v1/cpycal/${deviceInfo.value?.deviceCode}/status`, (message) => {
|
||||||
// console.log('设备状态消息:', message)
|
console.log('设备状态消息:', message)
|
||||||
if(message && message.running) {
|
if(message && message.running) {
|
||||||
deviceShowStatus.value = proxy.$t('common.online')
|
deviceShowStatus.value = proxy.$t('common.online')
|
||||||
} else {
|
} else {
|
||||||
@ -687,6 +728,8 @@ const initSubscribe = async () => {
|
|||||||
// 计算数据
|
// 计算数据
|
||||||
subscribe(`v1/cpy/${deviceInfo.value?.deviceCode}/calculation`, (message) => {
|
subscribe(`v1/cpy/${deviceInfo.value?.deviceCode}/calculation`, (message) => {
|
||||||
console.log('计算数据:', message)
|
console.log('计算数据:', message)
|
||||||
|
edgesA.value = message.EdgesA;
|
||||||
|
edgesB.value = message.EdgesB;
|
||||||
chartDataList.value.forEach(item => {
|
chartDataList.value.forEach(item => {
|
||||||
item.list.forEach(listItem => {
|
item.list.forEach(listItem => {
|
||||||
if (listItem.calculationValue) {
|
if (listItem.calculationValue) {
|
||||||
@ -715,6 +758,27 @@ const initSubscribe = async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 采集数据
|
||||||
|
const collectData = async() => {
|
||||||
|
// 采集数据
|
||||||
|
await subscribe(`v1/cpy/${deviceInfo.value?.deviceCode}/collect`, (message) => {
|
||||||
|
console.log('采集数据:', message)
|
||||||
|
if(message.method === 'scanner1') {
|
||||||
|
imageViewScanner1.intensityA = message.intensityA;
|
||||||
|
imageViewScanner1.intensityB = message.intensityB;
|
||||||
|
imageViewScanner1.channelA_data = base64Decode(message.channelA_data,true);
|
||||||
|
imageViewScanner1.channelB_data = base64Decode(message.channelB_data,true);
|
||||||
|
}
|
||||||
|
if(message.method === 'scanner2') {
|
||||||
|
imageViewScanner2.intensityA = message.intensityA;
|
||||||
|
imageViewScanner2.intensityB = message.intensityB;
|
||||||
|
imageViewScanner2.channelA_data = base64Decode(message.channelA_data,true);
|
||||||
|
imageViewScanner2.channelB_data = base64Decode(message.channelB_data,true);
|
||||||
|
}
|
||||||
|
console.log(imageViewScanner1,'imageViewScanner1')
|
||||||
|
console.log(imageViewScanner2,'imageViewScanner2')
|
||||||
|
})
|
||||||
|
}
|
||||||
// 设备温度
|
// 设备温度
|
||||||
const sendDeviceTemperature = async () => {
|
const sendDeviceTemperature = async () => {
|
||||||
try {
|
try {
|
||||||
@ -799,6 +863,7 @@ onMounted(async() => {
|
|||||||
deviceId.value= route.query.id;
|
deviceId.value= route.query.id;
|
||||||
await getDeviceDetail()
|
await getDeviceDetail()
|
||||||
}
|
}
|
||||||
|
await collectData()
|
||||||
await sendDeviceTemperature()
|
await sendDeviceTemperature()
|
||||||
await sendDeviceTrend()
|
await sendDeviceTrend()
|
||||||
generateData()
|
generateData()
|
||||||
|
Loading…
Reference in New Issue
Block a user