You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
8.2 KiB
381 lines
8.2 KiB
<template> |
|
<RootView> |
|
<view class="page-container"> |
|
<!-- 顶部标题 --> |
|
<view class="header"> |
|
<text class="page-title">选择闸口</text> |
|
<text v-if="selectedStation" class="selected-info">{{ selectedStation.name }}</text> |
|
</view> |
|
|
|
<!-- 搜索框 --> |
|
<view class="search-container"> |
|
<view class="search-box"> |
|
<i class="i-tabler-search search-icon"></i> |
|
<input |
|
v-model="searchKeyword" |
|
type="text" |
|
placeholder="搜索闸口名称或位置" |
|
class="search-input" |
|
@input="onSearch" |
|
/> |
|
<i v-if="searchKeyword" class="i-tabler-x clear-icon" @click="clearSearch"></i> |
|
</view> |
|
<text class="result-count">{{ filteredStations.length }} 个闸口</text> |
|
</view> |
|
|
|
<!-- 闸口列表 --> |
|
<scroll-view class="station-list" scroll-y enhanced :show-scrollbar="false"> |
|
<view |
|
v-for="station in filteredStations" |
|
:key="station.id" |
|
class="station-item" |
|
:class="{ 'selected': selectedStation?.id === station.id }" |
|
@click="selectStation(station)" |
|
> |
|
<view class="station-indicator"> |
|
<view class="indicator-dot" :class="{ 'active': station.status === 'active' }"></view> |
|
</view> |
|
<view class="station-content"> |
|
<text class="station-name">{{ station.name }}</text> |
|
<text class="station-location">{{ station.location }}</text> |
|
</view> |
|
<view class="station-right"> |
|
<text class="station-status" :class="getStatusClass(station.status)"> |
|
{{ gateStatusMap[station.status] }} |
|
</text> |
|
<i class="i-tabler-check check-icon" v-if="selectedStation?.id === station.id"></i> |
|
</view> |
|
</view> |
|
</scroll-view> |
|
|
|
<!-- 空状态 --> |
|
<view v-if="filteredStations.length === 0" class="empty-state"> |
|
<i class="i-tabler-building-factory-2"></i> |
|
<text class="empty-text">{{ searchKeyword ? '未找到匹配的闸口' : '暂无可用闸口' }}</text> |
|
</view> |
|
|
|
<!-- 底部按钮 --> |
|
<view v-if="selectedStation" class="footer"> |
|
<button class="confirm-btn" @click="confirmSelection"> |
|
确认选择 |
|
</button> |
|
</view> |
|
</view> |
|
</RootView> |
|
</template> |
|
|
|
<script setup lang="ts"> |
|
import { ref, computed, onMounted } from 'vue' |
|
import RootView from '@/@layout/RootView.vue' |
|
import { useGateStore } from '@/stores/gate.store' |
|
import { gateStatusMap } from '@/common/gate-data' |
|
import type { GateStation } from '../../../types/dto/gate.dto' |
|
|
|
const gateStore = useGateStore() |
|
|
|
// 响应式数据 |
|
const searchKeyword = ref('') |
|
const selectedStation = ref<GateStation | null>(null) |
|
|
|
// 计算属性 |
|
const filteredStations = computed(() => { |
|
if (!searchKeyword.value) { |
|
return gateStore.activeStations |
|
} |
|
|
|
const keyword = searchKeyword.value.toLowerCase() |
|
return gateStore.activeStations.filter(station => |
|
station.name.toLowerCase().includes(keyword) || |
|
station.location.toLowerCase().includes(keyword) |
|
) |
|
}) |
|
|
|
// 获取状态样式 |
|
const getStatusClass = (status: string) => { |
|
switch (status) { |
|
case 'active': |
|
return 'status-active' |
|
case 'inactive': |
|
return 'status-inactive' |
|
case 'maintenance': |
|
return 'status-maintenance' |
|
default: |
|
return 'status-default' |
|
} |
|
} |
|
|
|
// 获取状态背景颜色 |
|
const getStatusBgColor = (status: string) => { |
|
switch (status) { |
|
case 'active': |
|
return 'status-bg-active' |
|
case 'inactive': |
|
return 'status-bg-inactive' |
|
case 'maintenance': |
|
return 'status-bg-maintenance' |
|
default: |
|
return 'status-bg-default' |
|
} |
|
} |
|
|
|
// 清空搜索 |
|
const clearSearch = () => { |
|
searchKeyword.value = '' |
|
} |
|
|
|
// 搜索处理 |
|
const onSearch = () => { |
|
// 搜索逻辑已在计算属性中处理 |
|
} |
|
|
|
// 选择闸口 |
|
const selectStation = (station: GateStation) => { |
|
selectedStation.value = station |
|
} |
|
|
|
// 确认选择 |
|
const confirmSelection = () => { |
|
if (selectedStation.value) { |
|
gateStore.setCurrentStation(selectedStation.value) |
|
uni.navigateBack() |
|
} |
|
} |
|
|
|
onMounted(() => { |
|
// 设置默认选择第一个闸口 |
|
if (gateStore.activeStations.length > 0 && !selectedStation.value) { |
|
selectedStation.value = gateStore.activeStations[0] |
|
} |
|
}) |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.page-container { |
|
height: 100vh; |
|
display: flex; |
|
flex-direction: column; |
|
background: #ffffff; |
|
overflow: hidden; |
|
} |
|
|
|
// 顶部标题 |
|
.header { |
|
padding: 60rpx 40rpx 24rpx; |
|
background: #ffffff; |
|
border-bottom: 1rpx solid #f2f2f7; |
|
text-align: center; |
|
|
|
.page-title { |
|
font-size: 56rpx; |
|
font-weight: 600; |
|
color: #000000; |
|
display: block; |
|
margin-bottom: 8rpx; |
|
} |
|
|
|
.selected-info { |
|
font-size: 28rpx; |
|
color: #007aff; |
|
} |
|
} |
|
|
|
// 搜索区域 |
|
.search-container { |
|
padding: 24rpx 40rpx; |
|
background: #ffffff; |
|
border-bottom: 1rpx solid #f2f2f7; |
|
|
|
.search-box { |
|
display: flex; |
|
align-items: center; |
|
background: #f2f2f7; |
|
border-radius: 16rpx; |
|
padding: 0 24rpx; |
|
height: 80rpx; |
|
margin-bottom: 16rpx; |
|
|
|
.search-icon { |
|
font-size: 32rpx; |
|
color: #8e8e93; |
|
margin-right: 16rpx; |
|
} |
|
|
|
.search-input { |
|
flex: 1; |
|
height: 100%; |
|
font-size: 30rpx; |
|
color: #000000; |
|
background: transparent; |
|
|
|
&::placeholder { |
|
color: #8e8e93; |
|
} |
|
} |
|
|
|
.clear-icon { |
|
font-size: 28rpx; |
|
color: #8e8e93; |
|
padding: 8rpx; |
|
margin-left: 16rpx; |
|
} |
|
} |
|
|
|
.result-count { |
|
font-size: 26rpx; |
|
color: #8e8e93; |
|
} |
|
} |
|
|
|
// 闸口列表 |
|
.station-list { |
|
flex: 1; |
|
overflow: hidden; |
|
padding: 0 10rpx 0 40rpx; // 进一步减少右侧padding |
|
} |
|
|
|
.station-item { |
|
display: flex; |
|
align-items: center; |
|
padding: 28rpx 0; |
|
border-bottom: 1rpx solid #f2f2f7; |
|
transition: background-color 0.2s ease; |
|
|
|
&:active { |
|
background-color: #f2f2f7; |
|
} |
|
|
|
&:last-child { |
|
border-bottom: none; |
|
} |
|
|
|
&.selected { |
|
.station-content .station-name { |
|
color: #007aff; |
|
} |
|
} |
|
|
|
.station-indicator { |
|
margin-right: 12rpx; |
|
flex-shrink: 0; |
|
|
|
.indicator-dot { |
|
width: 12rpx; |
|
height: 12rpx; |
|
border-radius: 50%; |
|
background: #c7c7cc; |
|
|
|
&.active { |
|
background: #34c759; |
|
} |
|
} |
|
} |
|
|
|
.station-content { |
|
flex: 1; |
|
min-width: 0; // 防止内容溢出 |
|
|
|
.station-name { |
|
font-size: 32rpx; |
|
color: #000000; |
|
display: block; |
|
margin-bottom: 6rpx; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
white-space: nowrap; |
|
} |
|
|
|
.station-location { |
|
font-size: 26rpx; |
|
color: #8e8e93; |
|
display: block; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
white-space: nowrap; |
|
} |
|
} |
|
|
|
.station-right { |
|
display: flex; |
|
align-items: center; |
|
gap: 6rpx; |
|
flex-shrink: 0; // 防止被压缩 |
|
min-width: 120rpx; // 确保最小宽度能显示"运行中" |
|
|
|
.station-status { |
|
font-size: 22rpx; // 稍微减小字体 |
|
padding: 2rpx 6rpx; // 进一步减少内边距 |
|
border-radius: 6rpx; |
|
white-space: nowrap; |
|
|
|
&.status-active { |
|
background: #f0f9ff; |
|
color: #007aff; |
|
} |
|
|
|
&.status-inactive { |
|
background: #f2f2f7; |
|
color: #8e8e93; |
|
} |
|
|
|
&.status-maintenance { |
|
background: #fff7ed; |
|
color: #ff9500; |
|
} |
|
} |
|
|
|
.check-icon { |
|
font-size: 28rpx; // 稍微减小图标 |
|
color: #34c759; |
|
flex-shrink: 0; |
|
} |
|
} |
|
} |
|
|
|
// 空状态 |
|
.empty-state { |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
justify-content: center; |
|
padding: 120rpx 40rpx; |
|
|
|
i { |
|
font-size: 120rpx; |
|
color: #c7c7cc; |
|
margin-bottom: 32rpx; |
|
} |
|
|
|
.empty-text { |
|
font-size: 30rpx; |
|
color: #8e8e93; |
|
} |
|
} |
|
|
|
// 底部按钮 |
|
.footer { |
|
padding: 24rpx 40rpx 40rpx; |
|
background: #ffffff; |
|
border-top: 1rpx solid #f2f2f7; |
|
|
|
.confirm-btn { |
|
width: 100%; |
|
height: 112rpx; |
|
background: #007aff; |
|
border: none; |
|
border-radius: 28rpx; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
color: #ffffff; |
|
font-size: 34rpx; |
|
font-weight: 600; |
|
transition: all 0.2s ease; |
|
|
|
&:active { |
|
opacity: 0.8; |
|
transform: scale(0.98); |
|
} |
|
} |
|
} |
|
</style> |