| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- <script setup lang="ts">
- import { computed, ref } from 'vue'
- import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
- import AppHeader from '@/components/AppHeader.vue'
- import SearchBar from '@/components/SearchBar.vue'
- import SegmentTabs from '@/components/SegmentTabs.vue'
- import { getMobileEquipmentPage, type Equipment } from '@/services/equipment'
- import { navigateTo } from '@/utils/navigation'
- const keyword = ref('')
- const activeStatus = ref(0)
- const alarmOnly = ref(false)
- const devices = ref<Equipment[]>([])
- const total = ref(0)
- const pageNum = ref(1)
- const loading = ref(false)
- const loaded = ref(false)
- const hasMore = computed(() => devices.value.length < total.value)
- const statusTabs = [{ label: '全部', value: '' }, { label: '在线', value: '1' }, { label: '离线', value: '0' }]
- onLoad(() => loadDevices(true))
- onPullDownRefresh(async () => {
- await loadDevices(true)
- uni.stopPullDownRefresh()
- })
- onReachBottom(() => loadDevices())
- async function loadDevices(reset = false) {
- if (loading.value || (!reset && !hasMore.value)) return
- if (reset) {
- pageNum.value = 1
- devices.value = []
- total.value = 0
- }
- loading.value = true
- try {
- const result = await getMobileEquipmentPage({
- pageNum: pageNum.value,
- pageSize: 10,
- keyword: keyword.value.trim() || undefined,
- onlineStatus: statusTabs[activeStatus.value].value === '' ? undefined : Number(statusTabs[activeStatus.value].value),
- alarmStatus: alarmOnly.value ? 1 : undefined,
- })
- devices.value = reset ? result.records : devices.value.concat(result.records)
- total.value = Number(result.total) || 0
- pageNum.value += 1
- } catch (error) {
- uni.showToast({ title: error instanceof Error ? error.message : '设备列表获取失败', icon: 'none' })
- } finally {
- loading.value = false
- loaded.value = true
- }
- }
- function selectStatus(value: number) {
- if (activeStatus.value === value) return
- activeStatus.value = value
- loadDevices(true)
- }
- function search() { loadDevices(true) }
- function toggleAlarm() { alarmOnly.value = !alarmOnly.value; loadDevices(true) }
- function openDetail(item: Equipment) {
- navigateTo(`/pages/office/device-detail?id=${encodeURIComponent(item.equipmentId)}`)
- }
- function onlineLabel(status?: number) { return Number(status) === 1 ? '在线' : '离线' }
- function districtLabel(district?: number) { return ['城南', '城北', '太常'][Number(district)] || '—' }
- </script>
- <template>
- <view class="page">
- <AppHeader title="设备信息查询" />
- <SegmentTabs :model-value="activeStatus" :items="statusTabs.map(item => item.label)" @update:model-value="selectStatus" />
- <SearchBar v-model="keyword" attached placeholder="请输入设备编码、名称" @search="search">
- <template #prefix>
- <view class="alarm-prefix" @tap="toggleAlarm">
- <view class="checkbox" :class="{ checked: alarmOnly }">{{ alarmOnly ? '✓' : '' }}</view>
- <text>报警</text>
- </view>
- </template>
- </SearchBar>
- <view class="result-count">共 {{ total }} 条设备</view>
- <view class="page-content device-list">
- <view v-for="item in devices" :key="item.equipmentId" class="device-card card" @tap="openDetail(item)">
- <view class="device-head">
- <text class="device-name">{{ item.equipmentName || '未命名设备' }}</text>
- <text class="online" :class="Number(item.onlineStatus) === 1 ? 'online-on' : 'online-off'"><i></i>{{ onlineLabel(item.onlineStatus) }}</text>
- <text v-if="Number(item.alarmStatus) === 1" class="alarm-tag">报警</text>
- </view>
- <text class="device-meta">编码:{{ item.equipmentCode || '—' }}</text>
- <text class="device-meta">类型:{{ item.equipmentTypeName || '—' }}</text>
- <text class="device-meta">片区:{{ districtLabel(item.district) }}</text>
- <view class="device-foot"><text class="location">{{ item.equipmentLocation || '未填写安装位置' }}</text><text class="detail-link">详情 ›</text></view>
- </view>
- <view v-if="loaded && !devices.length" class="empty">暂无匹配设备</view>
- <view v-else-if="loading" class="load-tip">正在加载...</view>
- <view v-else-if="devices.length && !hasMore" class="load-tip">已加载全部</view>
- </view>
- </view>
- </template>
- <style scoped lang="scss">
- .alarm-prefix{display:flex;flex-shrink:0;align-items:center;gap:8rpx;padding-left:24rpx;color:#25364b;font-size:23rpx}.checkbox{display:flex;align-items:center;justify-content:center;width:30rpx;height:30rpx;border:2rpx solid #aab6c3;border-radius:5rpx;color:#fff;font-size:22rpx}.checkbox.checked{border-color:#3b5bdb;background:#3b5bdb}.result-count{padding:14rpx 26rpx 0;color:#8a9aa5;background:#fff;font-size:22rpx}.device-list{padding-top:18rpx}.device-card{padding:23rpx 24rpx;margin-bottom:16rpx}.device-head{display:flex;align-items:center;gap:12rpx;margin-bottom:12rpx}.device-name{flex:1;min-width:0;overflow:hidden;color:#0b1119;font-size:28rpx;font-weight:700;text-overflow:ellipsis;white-space:nowrap}.online{display:flex;flex-shrink:0;align-items:center;gap:7rpx;font-size:21rpx;font-weight:600}.online i{width:12rpx;height:12rpx;border-radius:50%}.online-on{color:#1a9e6b}.online-on i{background:#1a9e6b}.online-off{color:#e02020}.online-off i{background:#e02020}.alarm-tag{flex-shrink:0;padding:4rpx 13rpx;color:#e02020;border-radius:99rpx;background:#fdecec;font-size:20rpx;font-weight:600}.device-meta{display:block;margin-top:7rpx;color:#5a6b73;font-size:23rpx;line-height:1.5}.device-foot{display:flex;align-items:center;justify-content:space-between;gap:12rpx;margin-top:14rpx;padding-top:13rpx;border-top:1rpx dashed #e8eef3}.location{flex:1;min-width:0;overflow:hidden;color:#3b5bdb;font-size:22rpx;text-overflow:ellipsis;white-space:nowrap}.detail-link{flex-shrink:0;color:#3b5bdb;font-size:23rpx;font-weight:600}.empty,.load-tip{padding:56rpx 0;color:#98a4b2;text-align:center;font-size:23rpx}
- </style>
|