feat 数据流模拟
This commit is contained in:
4
src/auto-imports.d.ts
vendored
4
src/auto-imports.d.ts
vendored
@@ -104,6 +104,7 @@ declare global {
|
|||||||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
||||||
const provide: typeof import('vue')['provide']
|
const provide: typeof import('vue')['provide']
|
||||||
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
||||||
|
const publishRtkPoint: typeof import('./composables/useRtkLive')['publishRtkPoint']
|
||||||
const reactify: typeof import('@vueuse/core')['reactify']
|
const reactify: typeof import('@vueuse/core')['reactify']
|
||||||
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
|
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
|
||||||
const reactive: typeof import('vue')['reactive']
|
const reactive: typeof import('vue')['reactive']
|
||||||
@@ -266,6 +267,7 @@ declare global {
|
|||||||
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
||||||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
||||||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
||||||
|
const useRtkLive: typeof import('./composables/useRtkLive')['useRtkLive']
|
||||||
const useSSRWidth: typeof import('@vueuse/core')['useSSRWidth']
|
const useSSRWidth: typeof import('@vueuse/core')['useSSRWidth']
|
||||||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
||||||
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
||||||
@@ -453,6 +455,7 @@ declare module 'vue' {
|
|||||||
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
|
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
|
||||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||||
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
|
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
|
||||||
|
readonly publishRtkPoint: UnwrapRef<typeof import('./composables/useRtkLive')['publishRtkPoint']>
|
||||||
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
|
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
|
||||||
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
|
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
|
||||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||||
@@ -615,6 +618,7 @@ declare module 'vue' {
|
|||||||
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
|
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
|
||||||
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
|
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
|
||||||
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
|
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
|
||||||
|
readonly useRtkLive: UnwrapRef<typeof import('./composables/useRtkLive')['useRtkLive']>
|
||||||
readonly useSSRWidth: UnwrapRef<typeof import('@vueuse/core')['useSSRWidth']>
|
readonly useSSRWidth: UnwrapRef<typeof import('@vueuse/core')['useSSRWidth']>
|
||||||
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
|
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
|
||||||
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
|
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// RTK 轨迹实时监测 - 状态头部组件
|
import { useRtkLive } from '@/composables/useRtkLive'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
deviceName?: string
|
deviceName?: string
|
||||||
speed?: number
|
|
||||||
frequency?: number
|
|
||||||
amplitude?: number
|
|
||||||
rtkFixed?: boolean
|
rtkFixed?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
withDefaults(defineProps<Props>(), {
|
||||||
deviceName: '徐工XS65H #01',
|
deviceName: '徐工XS65H #01',
|
||||||
speed: 4.2,
|
|
||||||
frequency: 28.5,
|
|
||||||
amplitude: 1.86,
|
|
||||||
rtkFixed: true,
|
rtkFixed: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { speedTextSpaced, frequencyText, amplitudeText } = useRtkLive()
|
||||||
|
|
||||||
function handleToggle() {
|
function handleToggle() {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/work/index',
|
url: '/pages/work/index',
|
||||||
@@ -54,7 +50,7 @@ function handleToggle() {
|
|||||||
车速
|
车速
|
||||||
</text>
|
</text>
|
||||||
<text class="data-value">
|
<text class="data-value">
|
||||||
{{ speed }} km/h
|
{{ speedTextSpaced }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="data-item">
|
<view class="data-item">
|
||||||
@@ -62,7 +58,7 @@ function handleToggle() {
|
|||||||
振动频率
|
振动频率
|
||||||
</text>
|
</text>
|
||||||
<text class="data-value">
|
<text class="data-value">
|
||||||
{{ frequency }} HZ
|
{{ frequencyText }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="data-item">
|
<view class="data-item">
|
||||||
@@ -70,7 +66,7 @@ function handleToggle() {
|
|||||||
振幅
|
振幅
|
||||||
</text>
|
</text>
|
||||||
<text class="data-value">
|
<text class="data-value">
|
||||||
{{ amplitude }} mm
|
{{ amplitudeText }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="rtk-status">
|
<view class="rtk-status">
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type { HeatmapLayerKey } from './heatUtils'
|
|||||||
*/
|
*/
|
||||||
import type { MockRtkPoint } from '@/mock/rtkTrack'
|
import type { MockRtkPoint } from '@/mock/rtkTrack'
|
||||||
import { getCurrentInstance, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { getCurrentInstance, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
|
import { publishRtkPoint } from '@/composables/useRtkLive'
|
||||||
import { createMockRtkStream } from '@/mock/rtkTrack'
|
import { createMockRtkStream } from '@/mock/rtkTrack'
|
||||||
import { colorByScore, layerScore } from './heatUtils'
|
import { colorByScore, layerScore } from './heatUtils'
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ function startStream() {
|
|||||||
|
|
||||||
stream.start((point) => {
|
stream.start((point) => {
|
||||||
appendPoint(point)
|
appendPoint(point)
|
||||||
|
publishRtkPoint(point)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCurrentProject } from '@/composables/useCurrentProject'
|
import { useCurrentProject } from '@/composables/useCurrentProject'
|
||||||
|
import { useRtkLive } from '@/composables/useRtkLive'
|
||||||
|
|
||||||
const { hasCurrentProject } = useCurrentProject()
|
const { hasCurrentProject } = useCurrentProject()
|
||||||
|
const { speedText, tempText } = useRtkLive()
|
||||||
|
|
||||||
function goToWork() {
|
function goToWork() {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
@@ -37,28 +39,12 @@ function goToWork() {
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="status-params">
|
<view class="status-params">
|
||||||
<!-- <view class="param">
|
|
||||||
<text class="param-label">
|
|
||||||
振动频率
|
|
||||||
</text>
|
|
||||||
<text class="param-value">
|
|
||||||
8939HZ
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
<view class="param">
|
|
||||||
<text class="param-label">
|
|
||||||
振幅
|
|
||||||
</text>
|
|
||||||
<text class="param-value">
|
|
||||||
8939mm
|
|
||||||
</text>
|
|
||||||
</view> -->
|
|
||||||
<view class="param">
|
<view class="param">
|
||||||
<text class="param-label">
|
<text class="param-label">
|
||||||
行驶速度
|
行驶速度
|
||||||
</text>
|
</text>
|
||||||
<text class="param-value">
|
<text class="param-value">
|
||||||
3km/h
|
{{ speedText }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="param">
|
<view class="param">
|
||||||
@@ -66,7 +52,7 @@ function goToWork() {
|
|||||||
钢轮温度
|
钢轮温度
|
||||||
</text>
|
</text>
|
||||||
<text class="param-value">
|
<text class="param-value">
|
||||||
8939°C
|
{{ tempText }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,24 +1,39 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useCurrentProject } from '@/composables/useCurrentProject'
|
import { useCurrentProject } from '@/composables/useCurrentProject'
|
||||||
|
import { useRtkLive } from '@/composables/useRtkLive'
|
||||||
|
|
||||||
const { hasCurrentProject } = useCurrentProject()
|
const { hasCurrentProject } = useCurrentProject()
|
||||||
|
const {
|
||||||
|
compactionValue: liveCompaction,
|
||||||
|
speed,
|
||||||
|
compactionText: liveCompactionText,
|
||||||
|
frequencyText: liveFrequencyText,
|
||||||
|
} = useRtkLive()
|
||||||
|
|
||||||
// 压实度 (假数据,后续替换)
|
const compactionValue = computed(() => {
|
||||||
const compactionValue = computed(() => (hasCurrentProject.value ? 25 : 0))
|
if (!hasCurrentProject.value || liveCompaction.value == null)
|
||||||
const compactionText = computed(() => (hasCurrentProject.value ? `${compactionValue.value}%` : '--'))
|
return 0
|
||||||
|
return Math.round(liveCompaction.value)
|
||||||
|
})
|
||||||
|
const compactionText = computed(() => (hasCurrentProject.value ? liveCompactionText.value : '--'))
|
||||||
|
|
||||||
// 车速 (假数据,范围 0-12,中间值 6)
|
const speedValue = computed(() => {
|
||||||
const speedValue = computed(() => (hasCurrentProject.value ? 4.2 : 0))
|
if (!hasCurrentProject.value || speed.value == null)
|
||||||
const speedText = computed(() => (hasCurrentProject.value ? `${speedValue.value}KM/H` : '--'))
|
return 0
|
||||||
|
return speed.value
|
||||||
|
})
|
||||||
|
const speedText = computed(() => {
|
||||||
|
if (!hasCurrentProject.value || speed.value == null)
|
||||||
|
return '--'
|
||||||
|
return `${speed.value}KM/H`
|
||||||
|
})
|
||||||
const speedMax = 12
|
const speedMax = 12
|
||||||
|
|
||||||
// 指针旋转角度:0km/h → 225°(左下),12km/h → -45°(右下),中间90°(正上)
|
|
||||||
const needleRotation = computed(() => 225 - (speedValue.value / speedMax) * 270)
|
const needleRotation = computed(() => 225 - (speedValue.value / speedMax) * 270)
|
||||||
|
|
||||||
const frequencyText = computed(() => (hasCurrentProject.value ? '8939HZ' : '--'))
|
const frequencyText = computed(() => (hasCurrentProject.value ? liveFrequencyText.value : '--'))
|
||||||
|
|
||||||
// 今日作业概览数据
|
|
||||||
const overviewData = computed(() => {
|
const overviewData = computed(() => {
|
||||||
if (!hasCurrentProject.value) {
|
if (!hasCurrentProject.value) {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import type { MockRtkPoint } from '@/mock/rtkTrack'
|
import type { MockRtkPoint } from '@/mock/rtkTrack'
|
||||||
import { getCurrentInstance, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { getCurrentInstance, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { useCurrentProject } from '@/composables/useCurrentProject'
|
import { useCurrentProject } from '@/composables/useCurrentProject'
|
||||||
|
import { publishRtkPoint } from '@/composables/useRtkLive'
|
||||||
import { createMockRtkStream } from '@/mock/rtkTrack'
|
import { createMockRtkStream } from '@/mock/rtkTrack'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
@@ -236,6 +237,7 @@ function startStream() {
|
|||||||
|
|
||||||
stream.start((point, index) => {
|
stream.start((point, index) => {
|
||||||
trail.push(point)
|
trail.push(point)
|
||||||
|
publishRtkPoint(point)
|
||||||
finished = index >= stream.points.length - 1
|
finished = index >= stream.points.length - 1
|
||||||
updateHeightFromTrail()
|
updateHeightFromTrail()
|
||||||
nextTick(() => draw())
|
nextTick(() => draw())
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useCurrentProject } from '@/composables/useCurrentProject'
|
import { useCurrentProject } from '@/composables/useCurrentProject'
|
||||||
|
import { useRtkLive } from '@/composables/useRtkLive'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
deviceName?: string
|
deviceName?: string
|
||||||
speed?: number
|
|
||||||
frequency?: number
|
|
||||||
amplitude?: number
|
|
||||||
rtkFixed?: boolean
|
rtkFixed?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
deviceName: '徐工XS65H #01',
|
deviceName: '徐工XS65H #01',
|
||||||
speed: 4.2,
|
|
||||||
frequency: 28.5,
|
|
||||||
amplitude: 1.86,
|
|
||||||
rtkFixed: true,
|
rtkFixed: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { hasCurrentProject } = useCurrentProject()
|
const { hasCurrentProject } = useCurrentProject()
|
||||||
|
const { speedTextSpaced } = useRtkLive()
|
||||||
|
|
||||||
const displayDeviceName = computed(() => (hasCurrentProject.value ? props.deviceName : '--'))
|
const displayDeviceName = computed(() => (hasCurrentProject.value ? props.deviceName : '--'))
|
||||||
const displaySpeed = computed(() => (hasCurrentProject.value ? `${props.speed} km/h` : '--'))
|
const displaySpeed = computed(() => (hasCurrentProject.value ? speedTextSpaced.value : '--'))
|
||||||
const displayStatusText = computed(() => (hasCurrentProject.value ? '实时监测中' : '--'))
|
const displayStatusText = computed(() => (hasCurrentProject.value ? '实时监测中' : '--'))
|
||||||
const displayRtkText = computed(() => (hasCurrentProject.value ? 'RTK固定' : '--'))
|
const displayRtkText = computed(() => (hasCurrentProject.value ? 'RTK固定' : '--'))
|
||||||
|
|
||||||
|
|||||||
99
src/composables/useRtkLive.ts
Normal file
99
src/composables/useRtkLive.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* RTK 实时遥测:各页面共享最新轨迹点,随假数据/真数据推送刷新
|
||||||
|
*/
|
||||||
|
import type { MockRtkPoint } from '@/mock/rtkTrack'
|
||||||
|
import { computed, onUnmounted, ref } from 'vue'
|
||||||
|
import { createMockRtkStream } from '@/mock/rtkTrack'
|
||||||
|
|
||||||
|
const latestPoint = ref<MockRtkPoint | null>(null)
|
||||||
|
|
||||||
|
let stream: ReturnType<typeof createMockRtkStream> | null = null
|
||||||
|
let subscribers = 0
|
||||||
|
|
||||||
|
function startBackgroundStream() {
|
||||||
|
if (stream)
|
||||||
|
return
|
||||||
|
stream = createMockRtkStream({
|
||||||
|
intervalMs: 80,
|
||||||
|
loop: true,
|
||||||
|
rows: 80,
|
||||||
|
pointsPerRow: 40,
|
||||||
|
})
|
||||||
|
stream.start((point) => {
|
||||||
|
latestPoint.value = point
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopBackgroundStream() {
|
||||||
|
stream?.stop()
|
||||||
|
stream = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 轨迹画布 / 热力图推送最新点(可与后台流并存,以后者为准) */
|
||||||
|
export function publishRtkPoint(point: MockRtkPoint) {
|
||||||
|
latestPoint.value = point
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRtkLive() {
|
||||||
|
subscribers += 1
|
||||||
|
startBackgroundStream()
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
subscribers -= 1
|
||||||
|
if (subscribers <= 0)
|
||||||
|
stopBackgroundStream()
|
||||||
|
})
|
||||||
|
|
||||||
|
const speed = computed(() => latestPoint.value?.speed ?? null)
|
||||||
|
const steelWheelTemp = computed(() => latestPoint.value?.steel_wheel_temp ?? null)
|
||||||
|
const compactionValue = computed(() => latestPoint.value?.compaction_value ?? null)
|
||||||
|
const passCount = computed(() => latestPoint.value?.pass_count ?? null)
|
||||||
|
const qualifiedRate = computed(() => latestPoint.value?.qualified_rate ?? null)
|
||||||
|
const heading = computed(() => latestPoint.value?.heading ?? null)
|
||||||
|
const latitude = computed(() => latestPoint.value?.latitude ?? null)
|
||||||
|
const longitude = computed(() => latestPoint.value?.longitude ?? null)
|
||||||
|
|
||||||
|
/** UI 仍展示的振动频率:由速度衍生的演示值 */
|
||||||
|
const vibrationHz = computed(() => {
|
||||||
|
const s = speed.value
|
||||||
|
if (s == null)
|
||||||
|
return null
|
||||||
|
return Number((26 + s * 0.6).toFixed(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
/** UI 仍展示的振幅:由压实度衍生的演示值 */
|
||||||
|
const amplitudeMm = computed(() => {
|
||||||
|
const c = compactionValue.value
|
||||||
|
if (c == null)
|
||||||
|
return null
|
||||||
|
return Number((1.5 + (c - 85) * 0.04).toFixed(2))
|
||||||
|
})
|
||||||
|
|
||||||
|
const speedText = computed(() => (speed.value == null ? '--' : `${speed.value}km/h`))
|
||||||
|
const speedTextSpaced = computed(() => (speed.value == null ? '--' : `${speed.value} km/h`))
|
||||||
|
const tempText = computed(() => (steelWheelTemp.value == null ? '--' : `${steelWheelTemp.value}°C`))
|
||||||
|
const compactionText = computed(() => (compactionValue.value == null ? '--' : `${Math.round(compactionValue.value)}%`))
|
||||||
|
const frequencyText = computed(() => (vibrationHz.value == null ? '--' : `${vibrationHz.value}HZ`))
|
||||||
|
const amplitudeText = computed(() => (amplitudeMm.value == null ? '--' : `${amplitudeMm.value} mm`))
|
||||||
|
|
||||||
|
return {
|
||||||
|
latestPoint,
|
||||||
|
speed,
|
||||||
|
steelWheelTemp,
|
||||||
|
compactionValue,
|
||||||
|
passCount,
|
||||||
|
qualifiedRate,
|
||||||
|
heading,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
vibrationHz,
|
||||||
|
amplitudeMm,
|
||||||
|
speedText,
|
||||||
|
speedTextSpaced,
|
||||||
|
tempText,
|
||||||
|
compactionText,
|
||||||
|
frequencyText,
|
||||||
|
amplitudeText,
|
||||||
|
publishRtkPoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user