feat 无项目数据--

This commit is contained in:
Ironsp
2026-09-16 17:42:13 +08:00
parent 4ea627c0c0
commit a84f7c4906
14 changed files with 309 additions and 182 deletions

View File

@@ -184,6 +184,7 @@ declare global {
const useCssVar: typeof import('@vueuse/core')['useCssVar'] const useCssVar: typeof import('@vueuse/core')['useCssVar']
const useCssVars: typeof import('vue')['useCssVars'] const useCssVars: typeof import('vue')['useCssVars']
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement'] const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
const useCurrentProject: typeof import('./composables/useCurrentProject')['useCurrentProject']
const useCycleList: typeof import('@vueuse/core')['useCycleList'] const useCycleList: typeof import('@vueuse/core')['useCycleList']
const useDark: typeof import('@vueuse/core')['useDark'] const useDark: typeof import('@vueuse/core')['useDark']
const useDateFormat: typeof import('@vueuse/core')['useDateFormat'] const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
@@ -531,6 +532,7 @@ declare module 'vue' {
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']> readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']> readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']> readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']>
readonly useCurrentProject: UnwrapRef<typeof import('./composables/useCurrentProject')['useCurrentProject']>
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']> readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']>
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']> readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']>
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']> readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']>

View File

@@ -1,3 +1,9 @@
<script setup lang="ts">
import { useCurrentProject } from '@/composables/useCurrentProject'
const { hasCurrentProject, currentProject } = useCurrentProject()
</script>
<template> <template>
<view class="card"> <view class="card">
<view class="card-header"> <view class="card-header">
@@ -10,10 +16,10 @@
<view class="icon-placeholder" /> <view class="icon-placeholder" />
<view class="info"> <view class="info">
<text class="segment"> <text class="segment">
K12+300 — K125+800 {{ hasCurrentProject ? (currentProject?.stake_range || '--') : '暂无施工段' }}
</text> </text>
<text class="requirement"> <text class="requirement">
压实遍数要求:≥6遍 压实遍数要求:{{ hasCurrentProject ? '≥6遍' : '--' }}
</text> </text>
</view> </view>
</view> </view>

View File

@@ -1,12 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import storage from '@/utils/storage' import { useCurrentProject } from '@/composables/useCurrentProject'
const project = ref(storage.get('current_project')) const { currentProject } = useCurrentProject()
// 页面显示时刷新数据(从设置页返回时)
onShow(() => {
project.value = storage.get('current_project')
})
function onIconClick(name: string) { function onIconClick(name: string) {
if (name === '通知') { if (name === '通知') {
@@ -36,10 +31,10 @@ function onIconClick(name: string) {
<image class="nav-logo" src="/static/logo.png" mode="aspectFit" @tap="onIconClick('logo')" /> <image class="nav-logo" src="/static/logo.png" mode="aspectFit" @tap="onIconClick('logo')" />
<view class="nav-info"> <view class="nav-info">
<text class="nav-title"> <text class="nav-title">
{{ project?.project_name || '--' }} {{ currentProject?.project_name || '--' }}
</text> </text>
<text class="nav-subtitle"> <text class="nav-subtitle">
{{ project?.stake_range || '--' }} {{ currentProject?.stake_range || '--' }}
</text> </text>
</view> </view>
</view> </view>

View File

@@ -1,24 +1,44 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted } from 'vue' import { computed, onMounted } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
import { useDbStore } from '@/store/modules/db' import { useDbStore } from '@/store/modules/db'
const db = useDbStore() const db = useDbStore()
const { hasCurrentProject } = useCurrentProject()
const now = new Date() const now = new Date()
const dateStr = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日` const dateStr = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`
const totalCompactionArea = computed(() => const totalCompactionArea = computed(() => {
(db.work_record || []).reduce((sum, item) => sum + (item.compaction_area ?? 0), 0), if (!hasCurrentProject.value)
) return null
return (db.work_record || []).reduce((sum, item) => sum + (item.compaction_area ?? 0), 0)
})
const totalDuration = computed(() => const totalDuration = computed(() => {
(db.work_record || []).reduce((sum, item) => sum + (item.duration ?? 0), 0), if (!hasCurrentProject.value)
) return null
return (db.work_record || []).reduce((sum, item) => sum + (item.duration ?? 0), 0)
})
function formatNumber(value: number) { const onlineCount = computed(() => {
if (!hasCurrentProject.value)
return null
return 1
})
function formatNumber(value: number | null) {
if (value == null)
return '--'
return Number.isInteger(value) ? String(value) : value.toFixed(1) return Number.isInteger(value) ? String(value) : value.toFixed(1)
} }
function formatCount(value: number | null) {
if (value == null)
return '--'
return `${value}台`
}
onMounted(async () => { onMounted(async () => {
if (!db.work_record?.length) if (!db.work_record?.length)
await db.loadAll() await db.loadAll()
@@ -41,7 +61,7 @@ onMounted(async () => {
实时作业状态(台) 实时作业状态(台)
</text> </text>
<text class="stat-value"> <text class="stat-value">
1台 {{ formatCount(onlineCount) }}
</text> </text>
</view> </view>
<view class="stat-item"> <view class="stat-item">

View File

@@ -1,31 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { onShow } from '@dcloudio/uni-app' import { computed, onMounted } from 'vue'
import { computed, onMounted, ref } from 'vue' import { useCurrentProject } from '@/composables/useCurrentProject'
import { calcUncompactedArea } from '@/service/project' import { calcUncompactedArea } from '@/service/project'
import { useDbStore } from '@/store/modules/db' import { useDbStore } from '@/store/modules/db'
import storage from '@/utils/storage'
const db = useDbStore() const db = useDbStore()
const currentProjectId = ref<number | null>(storage.get('current_project')?.id ?? null) const { currentProject: storedProject, hasCurrentProject } = useCurrentProject()
const currentProject = computed(() => { const currentProject = computed(() => {
const list = db.project || [] if (!hasCurrentProject.value)
if (!list.length)
return null return null
const stored = currentProjectId.value != null const list = db.project || []
? list.find(item => item.id === currentProjectId.value) const storedId = storedProject.value?.id
: null if (storedId == null)
if (stored) return null
return stored
return list.find(item => item.status === 2) || list[0] return list.find(item => item.id === storedId) || null
}) })
const progressPercent = computed(() => { const progressPercent = computed(() => {
const project = currentProject.value const project = currentProject.value
if (!project) if (!project)
return 0 return null
if (project.progress) if (project.progress)
return clampPercent(project.progress) return clampPercent(project.progress)
@@ -35,16 +32,28 @@ const progressPercent = computed(() => {
return clampPercent(((project.total_compaction_area ?? 0) / total) * 100) return clampPercent(((project.total_compaction_area ?? 0) / total) * 100)
}) })
const qualifiedRate = computed(() => currentProject.value?.qualified_rate ?? 0) const qualifiedRate = computed(() => {
if (!currentProject.value)
return null
return currentProject.value.qualified_rate ?? 0
})
const totalArea = computed(() => currentProject.value?.total_area ?? 0) const totalArea = computed(() => {
if (!currentProject.value)
return null
return currentProject.value.total_area ?? 0
})
const compactedArea = computed(() => currentProject.value?.total_compaction_area ?? 0) const compactedArea = computed(() => {
if (!currentProject.value)
return null
return currentProject.value.total_compaction_area ?? 0
})
const uncompactedArea = computed(() => { const uncompactedArea = computed(() => {
const project = currentProject.value const project = currentProject.value
if (!project) if (!project)
return 0 return null
if (project.uncompacted_area != null) if (project.uncompacted_area != null)
return Math.max(0, project.uncompacted_area) return Math.max(0, project.uncompacted_area)
return calcUncompactedArea(project.total_area, project.total_compaction_area) return calcUncompactedArea(project.total_area, project.total_compaction_area)
@@ -54,24 +63,30 @@ function clampPercent(value: number) {
return Math.min(100, Math.max(0, Number(value.toFixed(1)))) return Math.min(100, Math.max(0, Number(value.toFixed(1))))
} }
function formatArea(value: number) { function formatArea(value: number | null) {
if (value == null)
return '--'
const text = Number.isInteger(value) ? String(value) : String(value) const text = Number.isInteger(value) ? String(value) : String(value)
return `${text}m²` return `${text}m²`
} }
function formatRate(value: number) { function formatRate(value: number | null) {
if (value == null)
return '--'
const text = Number.isInteger(value) ? String(value) : value.toFixed(2) const text = Number.isInteger(value) ? String(value) : value.toFixed(2)
return `${text}%` return `${text}%`
} }
function formatPercent(value: number | null) {
if (value == null)
return '--'
return `${value}%`
}
onMounted(async () => { onMounted(async () => {
if (!db.project?.length) if (!db.project?.length)
await db.loadAll() await db.loadAll()
}) })
onShow(() => {
currentProjectId.value = storage.get('current_project')?.id ?? null
})
</script> </script>
<template> <template>
@@ -81,22 +96,19 @@ onShow(() => {
项目作业进度 项目作业进度
</text> </text>
<text class="card-sub"> <text class="card-sub">
{{ currentProject?.stake_range || currentProject?.project_name || '暂无项目' }} {{ currentProject?.stake_range || currentProject?.project_name || '暂无施工段' }}
</text> </text>
</view> </view>
<view class="card-body"> <view class="card-body">
<view v-if="!currentProject" class="empty-tip"> <view class="progress-content">
暂无项目数据
</view>
<view v-else class="progress-content">
<view class="progress-circle"> <view class="progress-circle">
<wd-circle :model-value="progressPercent" :size="120"> <wd-circle :model-value="progressPercent ?? 0" :size="120">
<view class="progress-circle-text"> <view class="progress-circle-text">
<text class="progress-percent"> <text class="progress-percent">
{{ progressPercent }}% {{ hasCurrentProject ? `${progressPercent}%` : '0%' }}
</text> </text>
<text class="progress-label"> <text class="progress-label">
已完成 {{ hasCurrentProject ? '已完成' : '未开始' }}
</text> </text>
</view> </view>
</wd-circle> </wd-circle>
@@ -111,7 +123,7 @@ onShow(() => {
{{ formatRate(qualifiedRate) }} {{ formatRate(qualifiedRate) }}
</text> </text>
</view> </view>
<wd-progress :percentage="clampPercent(qualifiedRate)" hide-text /> <wd-progress :percentage="clampPercent(qualifiedRate ?? 0)" hide-text />
</view> </view>
<view class="progress-item"> <view class="progress-item">
<view class="progress-row"> <view class="progress-row">
@@ -119,10 +131,10 @@ onShow(() => {
完成进度 完成进度
</text> </text>
<text class="progress-value"> <text class="progress-value">
{{ progressPercent }}% {{ formatPercent(progressPercent) }}
</text> </text>
</view> </view>
<wd-progress :percentage="progressPercent" hide-text /> <wd-progress :percentage="progressPercent ?? 0" hide-text />
</view> </view>
<view class="progress-item progress-item-inline"> <view class="progress-item progress-item-inline">
<text class="progress-name"> <text class="progress-name">
@@ -187,13 +199,6 @@ onShow(() => {
padding: 12px 16px; padding: 12px 16px;
} }
.empty-tip {
font-size: 14px;
color: #999999;
text-align: center;
padding: 16px 0;
}
.progress-content { .progress-content {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -1,12 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Project } from '@/service/project' import type { Project } from '@/service/project'
import { onMounted } from 'vue' import { computed, onMounted } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
import { useDbStore } from '@/store/modules/db' import { useDbStore } from '@/store/modules/db'
const db = useDbStore() const db = useDbStore()
const { hasCurrentProject } = useCurrentProject()
/** 首页只展示最近几条 */ /** 首页只展示最近几条 */
const list = computed(() => (db.project || []).slice(0, 2)) const list = computed(() => {
if (!hasCurrentProject.value)
return []
return (db.project || []).slice(0, 2)
})
onMounted(async () => { onMounted(async () => {
if (!db.project?.length) if (!db.project?.length)
@@ -39,7 +45,10 @@ function goToDetail(item: Project) {
</wd-button> </wd-button>
</view> </view>
<view class="card-body"> <view class="card-body">
<view v-if="!list.length" class="empty-tip"> <view v-if="!hasCurrentProject" class="empty-tip">
--
</view>
<view v-else-if="!list.length" class="empty-tip">
暂无项目 暂无项目
</view> </view>
<home-list <home-list
@@ -79,7 +88,7 @@ function goToDetail(item: Project) {
} }
.empty-tip { .empty-tip {
font-size: 14px; font-size: 18px;
color: #999999; color: #999999;
text-align: center; text-align: center;
padding: 16px 0; padding: 16px 0;

View File

@@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCurrentProject } from '@/composables/useCurrentProject'
const { hasCurrentProject } = useCurrentProject()
function goToWork() { function goToWork() {
uni.switchTab({ uni.switchTab({
url: '/pages/work/index', url: '/pages/work/index',
@@ -14,59 +18,64 @@ function goToWork() {
</text> </text>
</view> </view>
<view class="card-body"> <view class="card-body">
<view class="status-info"> <view v-if="!hasCurrentProject" class="empty-tip">
<view class="avatar" /> --
<view class="info">
<text class="name">
徐工XS65H #01
</text>
<text class="sub">
设备ID:G1XG2584-B01
</text>
</view>
<view class="status-tag">
作业中
</view>
</view> </view>
<view class="status-params"> <template v-else>
<view class="param"> <view class="status-info">
<text class="param-label"> <view class="avatar" />
振动频率 <view class="info">
</text> <text class="name">
<text class="param-value"> 徐工XS65H #01
8939HZ </text>
</text> <text class="sub">
设备ID:G1XG2584-B01
</text>
</view>
<view class="status-tag">
作业中
</view>
</view> </view>
<view class="param"> <view class="status-params">
<text class="param-label"> <view class="param">
振幅 <text class="param-label">
</text> 振动频率
<text class="param-value"> </text>
8939mm <text class="param-value">
</text> 8939HZ
</text>
</view>
<view class="param">
<text class="param-label">
振幅
</text>
<text class="param-value">
8939mm
</text>
</view>
<view class="param">
<text class="param-label">
行驶速度
</text>
<text class="param-value">
3km/h
</text>
</view>
<view class="param">
<text class="param-label">
钢轮温度
</text>
<text class="param-value">
8939°C
</text>
</view>
</view> </view>
<view class="param"> <view class="card-footer">
<text class="param-label"> <wd-button size="large" round @tap="goToWork">
行驶速度 进入作业监控
</text> </wd-button>
<text class="param-value">
3km/h
</text>
</view> </view>
<view class="param"> </template>
<text class="param-label">
钢轮温度
</text>
<text class="param-value">
8939°C
</text>
</view>
</view>
<view class="card-footer">
<wd-button size="large" round @tap="goToWork">
进入作业监控
</wd-button>
</view>
</view> </view>
</view> </view>
</template> </template>
@@ -97,6 +106,13 @@ function goToWork() {
padding: 12px 16px; padding: 12px 16px;
} }
.empty-tip {
font-size: 18px;
color: #999999;
text-align: center;
padding: 24px 0;
}
.status-info { .status-info {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -1,12 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import type { WarningRecord } from '@/service/warningRecord' import type { WarningRecord } from '@/service/warningRecord'
import { onMounted } from 'vue' import { computed, onMounted } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
import { useDbStore } from '@/store/modules/db' import { useDbStore } from '@/store/modules/db'
const db = useDbStore() const db = useDbStore()
const { hasCurrentProject, currentProject } = useCurrentProject()
/** 首页只展示最近几条 */ /** 首页只展示当前项目最近几条 */
const list = computed(() => (db.warning_record || []).slice(0, 3)) const list = computed(() => {
if (!hasCurrentProject.value)
return []
const projectId = currentProject.value?.id
return (db.warning_record || [])
.filter(item => projectId == null || item.project_id === projectId)
.slice(0, 3)
})
onMounted(async () => { onMounted(async () => {
if (!db.warning_record?.length) if (!db.warning_record?.length)
@@ -39,7 +48,10 @@ function goToDetail(item: WarningRecord) {
</wd-button> </wd-button>
</view> </view>
<view class="card-body"> <view class="card-body">
<view v-if="!list.length" class="empty-tip"> <view v-if="!hasCurrentProject" class="empty-tip">
--
</view>
<view v-else-if="!list.length" class="empty-tip">
暂无异常警告 暂无异常警告
</view> </view>
<home-warning_list <home-warning_list
@@ -79,7 +91,7 @@ function goToDetail(item: WarningRecord) {
} }
.empty-tip { .empty-tip {
font-size: 14px; font-size: 18px;
color: #999999; color: #999999;
text-align: center; text-align: center;
padding: 16px 0; padding: 16px 0;

View File

@@ -1,23 +1,40 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
const { hasCurrentProject } = useCurrentProject()
// 压实度 (假数据,后续替换) // 压实度 (假数据,后续替换)
const compactionValue = 25 const compactionValue = computed(() => (hasCurrentProject.value ? 25 : 0))
const compactionText = computed(() => (hasCurrentProject.value ? `${compactionValue.value}%` : '--'))
// 车速 (假数据,范围 0-12,中间值 6) // 车速 (假数据,范围 0-12,中间值 6)
const speedValue = 4.2 const speedValue = computed(() => (hasCurrentProject.value ? 4.2 : 0))
const speedText = computed(() => (hasCurrentProject.value ? `${speedValue.value}KM/H` : '--'))
const speedMax = 12 const speedMax = 12
// 指针旋转角度:0km/h → 225°(左下),12km/h → -45°(右下),中间90°(正上) // 指针旋转角度:0km/h → 225°(左下),12km/h → -45°(右下),中间90°(正上)
const needleRotation = computed(() => 225 - (speedValue / speedMax) * 270) const needleRotation = computed(() => 225 - (speedValue.value / speedMax) * 270)
// 今日作业概览数据 (假数据) const frequencyText = computed(() => (hasCurrentProject.value ? '8939HZ' : '--'))
const overviewData = [
{ label: '作业时长', value: '8h' }, // 今日作业概览数据
{ label: '压实面积', value: '28.5m²' }, const overviewData = computed(() => {
{ label: '碾压遍数', value: '10遍' }, if (!hasCurrentProject.value) {
{ label: '异常次数', value: '0' }, return [
] { label: '作业时长', value: '--' },
{ label: '压实面积', value: '--' },
{ label: '碾压遍数', value: '--' },
{ label: '异常次数', value: '--' },
]
}
return [
{ label: '作业时长', value: '8h' },
{ label: '压实面积', value: '28.5m²' },
{ label: '碾压遍数', value: '10遍' },
{ label: '异常次数', value: '0' },
]
})
</script> </script>
<template> <template>
@@ -43,7 +60,7 @@ const overviewData = [
</view> </view>
<!-- 圆环进度(使用 wotui 的 wd-circle 组件) --> <!-- 圆环进度(使用 wotui 的 wd-circle 组件) -->
<view class="ring-wrap"> <view class="ring-wrap">
<wd-circle v-model="compactionValue" :text="`${compactionValue}%`" /> <wd-circle :model-value="compactionValue" :text="compactionText" />
</view> </view>
</view> </view>
@@ -58,7 +75,7 @@ const overviewData = [
</text> </text>
</view> </view>
<text class="gauge-value"> <text class="gauge-value">
{{ speedValue }}KM/H {{ speedText }}
</text> </text>
</view> </view>
</view> </view>
@@ -71,7 +88,7 @@ const overviewData = [
振动频率 振动频率
</text> </text>
<text class="freq-value"> <text class="freq-value">
8939HZ {{ frequencyText }}
</text> </text>
</view> </view>
@@ -80,7 +97,7 @@ const overviewData = [
振动频率 振动频率
</text> </text>
<text class="freq-value"> <text class="freq-value">
8939HZ {{ frequencyText }}
</text> </text>
</view> </view>

View File

@@ -1,15 +1,29 @@
<script setup lang="ts"> <script setup lang="ts">
// 设备状态 + 作业控制组件 import { computed } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
const deviceInfo = { const { hasCurrentProject } = useCurrentProject()
编号: '徐工XS65H #01',
status: '作业中',
connected: '已连接',
workStatus: '正常运行',
signalStatus: '信号良好',
}
const workStatus = '作业进行中' const deviceInfo = computed(() => {
if (!hasCurrentProject.value) {
return {
编号: '--',
status: '--',
connected: '--',
workStatus: '--',
signalStatus: '--',
}
}
return {
编号: '徐工XS65H #01',
status: '作业中',
connected: '已连接',
workStatus: '正常运行',
signalStatus: '信号良好',
}
})
const workStatus = computed(() => (hasCurrentProject.value ? '作业进行中' : '--'))
</script> </script>
<template> <template>
@@ -35,13 +49,13 @@ const workStatus = '作业进行中'
<!-- 左列:作业状态 --> <!-- 左列:作业状态 -->
<view class="status-col"> <view class="status-col">
<view class="tag"> <view class="tag">
<view class="dot dot--green" /> <view class="dot" :class="hasCurrentProject ? 'dot--green' : 'dot--gray'" />
<text>{{ deviceInfo.status }}</text> <text>{{ deviceInfo.status }}</text>
</view> </view>
<text class="info-label"> <text class="info-label">
压实作业 压实作业
</text> </text>
<text class="info-value info-value--green"> <text class="info-value" :class="{ 'info-value--green': hasCurrentProject }">
{{ deviceInfo.workStatus }} {{ deviceInfo.workStatus }}
</text> </text>
</view> </view>
@@ -49,13 +63,13 @@ const workStatus = '作业进行中'
<!-- 右列:连接状态 --> <!-- 右列:连接状态 -->
<view class="status-col"> <view class="status-col">
<view class="tag"> <view class="tag">
<view class="dot dot--green" /> <view class="dot" :class="hasCurrentProject ? 'dot--green' : 'dot--gray'" />
<text>{{ deviceInfo.connected }}</text> <text>{{ deviceInfo.connected }}</text>
</view> </view>
<text class="info-label"> <text class="info-label">
设备连接 设备连接
</text> </text>
<text class="info-value info-value--green"> <text class="info-value" :class="{ 'info-value--green': hasCurrentProject }">
{{ deviceInfo.signalStatus }} {{ deviceInfo.signalStatus }}
</text> </text>
</view> </view>
@@ -85,14 +99,14 @@ const workStatus = '作业进行中'
<!-- 第二行:当前状态(对齐左侧 label 行) --> <!-- 第二行:当前状态(对齐左侧 label 行) -->
<view class="control-row"> <view class="control-row">
<view class="tag"> <view class="tag">
<view class="dot dot--green" /> <view class="dot" :class="hasCurrentProject ? 'dot--green' : 'dot--gray'" />
<text>当前:{{ workStatus }}</text> <text>当前:{{ workStatus }}</text>
</view> </view>
</view> </view>
<!-- 第三行:暂停按钮(对齐左侧 value 行) --> <!-- 第三行:暂停按钮(对齐左侧 value 行) -->
<view class="control-row"> <view class="control-row">
<wd-button type="warning" class="pause-btn" round> <wd-button type="warning" class="pause-btn" round :disabled="!hasCurrentProject">
暂停作业 暂停作业
</wd-button> </wd-button>
</view> </view>
@@ -188,6 +202,10 @@ const workStatus = '作业进行中'
background: #22c55e; background: #22c55e;
} }
.dot--gray {
background: #ccc;
}
.info-label { .info-label {
font-size: 14px; font-size: 14px;
color: #333333; color: #333333;

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
// RTK 轨迹画布 - 占位组件,后续实现轨迹动画 import { useCurrentProject } from '@/composables/useCurrentProject'
const { hasCurrentProject } = useCurrentProject()
function goToRtk() { function goToRtk() {
uni.navigateTo({ uni.navigateTo({
@@ -12,9 +14,9 @@ function goToRtk() {
<view class="rtk-canvas" @click="goToRtk"> <view class="rtk-canvas" @click="goToRtk">
<view class="canvas-placeholder"> <view class="canvas-placeholder">
<text class="placeholder-text"> <text class="placeholder-text">
轨迹动画区域 {{ hasCurrentProject ? '轨迹动画区域' : '--' }}
</text> </text>
<text class="placeholder-hint"> <text v-if="hasCurrentProject" class="placeholder-hint">
(Canvas 绘制行驶轨迹 + 压实热力图) (Canvas 绘制行驶轨迹 + 压实热力图)
</text> </text>
</view> </view>

View File

@@ -1,5 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
// RTK 轨迹底部信息组件(图例 + 位置信息) import { computed } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
const { hasCurrentProject } = useCurrentProject()
const headingText = computed(() => (hasCurrentProject.value ? '航向:NE45°' : '航向:--'))
const locationText = computed(() => (hasCurrentProject.value ? '114.39°E, 39.9087°N' : '--'))
</script> </script>
<template> <template>
@@ -26,10 +32,10 @@
</view> </view>
<view class="location-info"> <view class="location-info">
<text class="location-text"> <text class="location-text">
航向:NE45° {{ headingText }}
</text> </text>
<text class="location-text"> <text class="location-text">
114.39°E, 39.9087°N {{ locationText }}
</text> </text>
</view> </view>
</view> </view>

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
// RTK 轨迹实时监测 - 状态头部组件 import { computed } from 'vue'
import { useCurrentProject } from '@/composables/useCurrentProject'
interface Props { interface Props {
deviceName?: string deviceName?: string
@@ -9,7 +10,7 @@ interface Props {
rtkFixed?: boolean rtkFixed?: boolean
} }
withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
deviceName: '徐工XS65H #01', deviceName: '徐工XS65H #01',
speed: 4.2, speed: 4.2,
frequency: 28.5, frequency: 28.5,
@@ -17,6 +18,13 @@ withDefaults(defineProps<Props>(), {
rtkFixed: true, rtkFixed: true,
}) })
const { hasCurrentProject } = useCurrentProject()
const displayDeviceName = computed(() => (hasCurrentProject.value ? props.deviceName : '--'))
const displaySpeed = computed(() => (hasCurrentProject.value ? `${props.speed} km/h` : '--'))
const displayStatusText = computed(() => (hasCurrentProject.value ? '实时监测中' : '--'))
const displayRtkText = computed(() => (hasCurrentProject.value ? 'RTK固定' : '--'))
function goToHeatmap() { function goToHeatmap() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/heatmap/index', url: '/pages/heatmap/index',
@@ -38,12 +46,12 @@ function goToHeatmap() {
<!-- 设备状态 --> <!-- 设备状态 -->
<view class="device-status"> <view class="device-status">
<view class="status-dot" /> <view class="status-dot" :class="{ 'status-dot--active': hasCurrentProject }" />
<text class="device-name"> <text class="device-name">
{{ deviceName }} {{ displayDeviceName }}
</text> </text>
<text class="status-text"> <text class="status-text">
实时监测中 {{ displayStatusText }}
</text> </text>
</view> </view>
@@ -54,29 +62,13 @@ function goToHeatmap() {
车速 车速
</text> </text>
<text class="data-value"> <text class="data-value">
{{ speed }} km/h {{ displaySpeed }}
</text> </text>
</view> </view>
<!-- <view class="data-item">
<text class="data-label">
振动频率
</text>
<text class="data-value">
{{ frequency }} HZ
</text>
</view> -->
<!-- <view class="data-item">
<text class="data-label">
振幅
</text>
<text class="data-value">
{{ amplitude }} mm
</text>
</view> -->
<view class="rtk-status"> <view class="rtk-status">
<view class="rtk-dot" :class="{ 'rtk-dot--active': rtkFixed }" /> <view class="rtk-dot" :class="{ 'rtk-dot--active': hasCurrentProject && rtkFixed }" />
<text class="rtk-text"> <text class="rtk-text">
RTK固定 {{ displayRtkText }}
</text> </text>
</view> </view>
</view> </view>
@@ -101,11 +93,6 @@ function goToHeatmap() {
color: #333; color: #333;
} }
/* .subtitle {
font-size: 20px;
color: #333;
} */
.device-status { .device-status {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -117,6 +104,10 @@ function goToHeatmap() {
width: 8px; width: 8px;
height: 8px; height: 8px;
border-radius: 50%; border-radius: 50%;
background: #ccc;
}
.status-dot--active {
background: #22c55e; background: #22c55e;
} }

View File

@@ -0,0 +1,28 @@
import { onShow } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
import storage from '@/utils/storage'
const PROJECT_KEY = 'current_project'
/**
* 读取本地当前项目;无项目时首页/压实作业数据统一展示为 `--`
*/
export function useCurrentProject() {
const currentProject = ref(storage.get(PROJECT_KEY))
const hasCurrentProject = computed(() => currentProject.value?.id != null)
function refreshCurrentProject() {
currentProject.value = storage.get(PROJECT_KEY)
}
onShow(() => {
refreshCurrentProject()
})
return {
currentProject,
hasCurrentProject,
refreshCurrentProject,
}
}