|
|
|
|
<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>
|