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

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