Procházet zdrojové kódy

用户端小程序页面打磨

skyline před 1 dnem
rodič
revize
3cfa2a0744

+ 1 - 0
car-wash-entity/src/main/java/com/kym/entity/queryParams/StationQueryParams.java

@@ -8,6 +8,7 @@ import lombok.Data;
  */
 @Data
 public class StationQueryParams extends PageParams {
+    private String stationId;
     private String stationName;
     private String stationType;
     private String address;

+ 55 - 107
car-wash-mp/src/components/station/index.vue

@@ -2,7 +2,8 @@
   <view class="station_item"
         @click="handleNavStation(item)">
     <view class="station_item-title">
-      <text>{{ item.stationName }}</text>
+      <text class="station_item-idle" v-if="item.idleParkingNum !== undefined && item.idleParkingNum !== null">空闲{{ item.idleParkingNum }}</text>
+      <text class="station_item-name">{{ item.stationName }}</text>
     </view>
 
     <view class="station_item-status">
@@ -10,19 +11,10 @@
     </view>
 
     <view class="station_item-content">
-      <view class="station_item-content-left">
-        <view class="station_item-content-left-label">
-          <view class="station_item-content-left-label-left">
-            <text class="station_item-content-left-label-left_idle">空闲: {{ item.idleParkingNum }}</text>
-          </view>
-        </view>
-        <view class="station_item-content-left-position">
-          <uv-icon name="empty-address" size="18" color="#999999"></uv-icon>
-          <text class="station_address">{{ item.address }}</text>
-        </view>
-      </view>
-      <view class="station_item-content-right">
-        <text @click.stop="handleNavMap(item)">{{ item.distance }}km</text>
+      <view class="station_item-content-address">
+        <uv-icon name="empty-address" size="18" color="#999999"></uv-icon>
+        <text class="station_address">{{ item.address }}</text>
+        <text class="station_distance" v-if="item.distance !== undefined && item.distance !== null" @click.stop="handleNavMap(item)">{{ item.distance }}km</text>
       </view>
     </view>
 
@@ -125,10 +117,32 @@ defineExpose({
   &-title {
     display: flex;
     align-items: center;
+    gap: 12rpx;
+    margin-bottom: 20rpx;
+    padding-right: 120rpx;
+    min-width: 0;
+  }
+
+  &-idle {
+    background: $uni-color-primary;
+    padding: 4rpx 14rpx;
+    color: #fff;
+    font-size: 22rpx;
+    font-weight: 600;
+    border-radius: 20rpx;
+    flex-shrink: 0;
+    line-height: 1.5;
+  }
+
+  &-name {
     font-weight: $uni-font-weight-semibold;
     font-size: $uni-font-size-xl;
     color: $uni-text-color;
-    margin-bottom: 12rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    flex: 1;
+    min-width: 0;
   }
 
   &-status {
@@ -146,104 +160,18 @@ defineExpose({
   }
 
   &-content {
-    display: flex;
-    justify-content: space-between;
-    align-items: flex-start;
     width: 100%;
     margin-bottom: 16rpx;
     box-sizing: border-box;
 
-    &-left {
-      flex: 1;
+    &-address {
       display: flex;
-      flex-direction: column;
-      min-width: 0;
-
-      &-label {
-        display: flex;
-        flex-wrap: wrap;
-        gap: 12rpx;
-        margin-bottom: 12rpx;
-
-        &-left {
-          display: flex;
-          gap: 12rpx;
-
-          &_idle {
-            background: $uni-color-primary;
-            padding: 8rpx 16rpx;
-            color: $uni-text-color-inverse;
-            font-size: $uni-font-size-xs;
-            border-radius: 16rpx;
-            font-weight: $uni-font-weight-medium;
-          }
-
-          &_count {
-            background: $uni-color-highlight;
-            padding: 8rpx 16rpx;
-            color: $uni-color-primary;
-            font-size: $uni-font-size-xs;
-            border-radius: 16rpx;
-            border: 1px solid $uni-color-primary;
-          }
-        }
-
-
-      }
-
-      &-position {
-        display: flex;
-        align-items: center;
-        gap: 8rpx;
-        font-size: $uni-font-size-sm;
-        color: $uni-text-color-secondary;
-        line-height: $uni-line-height-sm;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-
-        .station_address {
-          flex: 1;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-          min-width: 0;
-        }
-      }
-    }
-
-    &-right {
-      display: flex;
-      flex-direction: column;
       align-items: center;
-      gap: 4rpx;
-      padding: 8rpx 12rpx;
-      background: $uni-bg-color-hover;
-      border-radius: 8rpx;
-      transition: all 0.2s ease;
-      flex-shrink: 0;
-
-      text {
-        font-size: $uni-font-size-base;
-        color: $uni-color-primary;
-        font-weight: $uni-font-weight-semibold;
-        cursor: pointer;
-        transition: all 0.2s ease;
-
-        &:hover {
-          color: $uni-color-primary-dark;
-        }
-
-        &:active {
-          transform: scale(0.94);
-          opacity: 0.9;
-        }
-      }
-
-      &:active {
-        transform: scale(0.96);
-        background: $uni-border-color-light;
-      }
+      gap: 8rpx;
+      font-size: $uni-font-size-sm;
+      color: $uni-text-color-secondary;
+      line-height: $uni-line-height-sm;
+      overflow: hidden;
     }
   }
 
@@ -304,4 +232,24 @@ defineExpose({
   }
 }
 
+.station_address {
+  flex: 1;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  min-width: 0;
+}
+
+.station_distance {
+  font-size: $uni-font-size-sm;
+  color: $uni-color-primary;
+  font-weight: $uni-font-weight-semibold;
+  flex-shrink: 0;
+  margin-left: 4rpx;
+
+  &:active {
+    opacity: 0.7;
+  }
+}
+
 </style>

+ 93 - 7
car-wash-mp/src/pages-wash/device/index.vue

@@ -5,7 +5,6 @@
       <!-- 设备信息卡片 -->
       <view class="device-info-card">
         <view class="device-number">
-          <uv-icon name="car" size="24" color="#C6171E"></uv-icon>
           <text class="number-text">洗车机 No.{{ state.device?.shortId }}</text>
           <text v-if="state.device?.hasPa" class="pa-badge">PA</text>
         </view>
@@ -27,25 +26,42 @@
         </view>
       </view>
 
+      <!-- 停车费提示 -->
+      <view class="parking-notice" v-if="state.parkingFee">
+        <view class="parking-notice-left">
+          <text class="parking-icon">P</text>
+          <text class="parking-text">{{ state.parkingFee }}</text>
+        </view>
+      </view>
+
       <!-- 操作按钮卡片 -->
       <view class="control-card">
         <view class="control-wrapper">
           <view
             class="control-button"
-            :class="{ 'control-button--active': state.device?.state !== 'idle' }"
-            @click="debounceStartStopDevice"
+            :class="{
+              'control-button--active': state.device?.state === 'busy',
+              'control-button--disabled': !isDeviceOperable
+            }"
+            @click="isDeviceOperable && debounceStartStopDevice()"
           >
             <view class="button-icon">
               <view v-if="state.device?.state==='idle'" class="icon-play">
                 <uv-icon name="play-circle-fill" size="56" color="#FFFFFF"></uv-icon>
               </view>
-              <view v-else class="icon-stop">
+              <view v-else-if="state.device?.state==='busy'" class="icon-stop">
                 <uv-icon name="pause-circle-fill" size="56" color="#FFFFFF"></uv-icon>
               </view>
+              <view v-else class="icon-disabled">
+                <uv-icon name="error-circle-fill" size="56" color="#FFFFFF"></uv-icon>
+              </view>
             </view>
             <text class="button-text" v-if="state.device?.state==='idle'">启动设备</text>
-            <text class="button-text" v-else>停止设备</text>
-            <text class="button-tip">{{ state.device?.state==='idle' ? '点击开始洗车' : '点击结束洗车' }}</text>
+            <text class="button-text" v-else-if="state.device?.state==='busy'">停止设备</text>
+            <text class="button-text" v-else>设备{{ fmtDictName('WashDevice.state', state.device?.state) }}</text>
+            <text class="button-tip" v-if="state.device?.state==='idle'">点击开始洗车</text>
+            <text class="button-tip" v-else-if="state.device?.state==='busy'">点击结束洗车</text>
+            <text class="button-tip" v-else>当前无法操作</text>
           </view>
         </view>
       </view>
@@ -95,7 +111,7 @@
 
 <script setup lang="ts">
 import {onHide, onLoad, onShow} from "@dcloudio/uni-app";
-import {reactive, ref} from "vue";
+import {computed, reactive, ref} from "vue";
 import {debounce, fmtDictName} from "@/utils/common";
 import {get, post} from "@/utils/https";
 import {checkLogin, fetchToken, tryLogin} from "@/utils/auth";
@@ -119,6 +135,7 @@ const initState = () => ({
     state: '',
     stationId: ''
   },
+  parkingFee: '',
   time: "00:00:00",
   start: new Date(),
   deviceId: null,
@@ -128,6 +145,11 @@ const initState = () => ({
 const state = reactive(initState())
 const timerId = ref<ReturnType<typeof setInterval> | null>(null)
 
+const isDeviceOperable = computed(() => {
+  const s = state.device?.state
+  return s === 'idle' || s === 'busy'
+})
+
 const loadBalance = () => {
   get('/account/balance').then((res: any) => {
     state.balance = res.balance
@@ -235,6 +257,7 @@ const  loadDeviceDetail = (id: any) => {
     }
     res.functionList = res.functions?.split("|") || []
     state.device = res;
+    loadParkingFee(res.stationId);
     getApp<any>().globalData.deviceId = id;
   }).catch(e => {
     console.error(e)
@@ -316,6 +339,16 @@ const countTime = () => {
 }
 
 
+const loadParkingFee = (stationId: string) => {
+  if (!stationId) return
+  post('/wash-station/listStation', { stationId, pageSize: 1 }).then((res: any) => {
+    const list = res?.list || res?.records || []
+    if (list.length > 0) {
+      state.parkingFee = list[0].parkingFee || ''
+    }
+  })
+}
+
 const handleGotoRechage = () => {
   uni.navigateTo({
     url: `/pages-user/wallet/recharge?stationId=${state.device.stationId}`
@@ -458,6 +491,44 @@ const handleGotoRechage = () => {
   }
 }
 
+// 停车费提示
+.parking-notice {
+  margin: 0 30rpx 24rpx;
+  padding: 20rpx 28rpx;
+  background: rgba($uni-color-primary, 0.05);
+  border: 1rpx solid rgba($uni-color-primary, 0.12);
+  border-radius: 16rpx;
+  display: flex;
+  align-items: center;
+
+  &-left {
+    display: flex;
+    align-items: center;
+    gap: 12rpx;
+    flex: 1;
+  }
+
+  .parking-icon {
+    width: 36rpx;
+    height: 36rpx;
+    line-height: 36rpx;
+    text-align: center;
+    font-size: 22rpx;
+    font-weight: $uni-font-weight-bold;
+    color: #fff;
+    background: $uni-color-primary;
+    border-radius: 6rpx;
+    flex-shrink: 0;
+  }
+
+  .parking-text {
+    font-size: 26rpx;
+    color: $uni-text-color-secondary;
+    line-height: 1.5;
+    flex: 1;
+  }
+}
+
 // 控制按钮卡片
 .control-card {
   margin: 0 30rpx 24rpx;
@@ -558,6 +629,21 @@ const handleGotoRechage = () => {
           box-shadow: 0 8rpx 24rpx rgba(232, 69, 69, 0.35);
         }
       }
+
+      &.control-button--disabled {
+        background: linear-gradient(135deg, #b0b0b0 0%, #909399 100%);
+        box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
+        cursor: not-allowed;
+
+        &:active {
+          transform: none;
+          box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
+        }
+
+        &::after {
+          display: none;
+        }
+      }
     }
   }
 }

+ 90 - 95
car-wash-mp/src/pages/user/index.vue

@@ -21,11 +21,7 @@
           <view class="user-avatar-wrapper">
             <image class="user-avatar" src='/static/iconfont/me.svg'></image>
           </view>
-
-          <view class="user-info">
-            <view class="user-phone">{{ user.mobilePhone || '未登录' }}</view>
-            <view class="user-tip">欢迎使用Yeswash洗车</view>
-          </view>
+          <text class="user-phone">{{ user.mobilePhone || '未登录' }}</text>
         </view>
 
         <!-- 分割线 -->
@@ -35,26 +31,28 @@
         <view class="wallet-section" @click="toPage({path: '/pages-user/wallet/index'})">
           <view class="wallet-header">
             <view class="wallet-title">
-              <uv-icon name="bag" size="18" color="#C6171E"></uv-icon>
-              <text>我的钱包</text>
+              <uv-icon name="red-packet" size="22" color="#C6171E"></uv-icon>
+              <text class="wallet-title-text">钱包余额</text>
             </view>
             <uv-icon name="arrow-right" size="14" color="#C0C4CC"></uv-icon>
           </view>
 
-          <view class="wallet-balance">
-            <text class="balance-label">账户余额 (元)</text>
-            <view class="balance-value">
-              <text class="balance-symbol">¥</text>
-              <text class="balance-amount">{{ ((user.balance || 0) / 100).toFixed(2) }}</text>
+          <view class="wallet-body">
+            <view class="wallet-balance">
+              <view class="balance-value">
+                <text class="balance-symbol">¥</text>
+                <text class="balance-amount">{{ ((user.balance || 0) / 100).toFixed(2) }}</text>
+                <text class="balance-unit">元</text>
+              </view>
             </view>
-          </view>
 
-          <view class="wallet-actions">
-            <view class="action-btn action-recharge" @click.stop="toPage({path: '/pages-user/wallet/recharge'})">
-              <text>充值</text>
-            </view>
-            <view class="action-btn action-detail" @click.stop="toPage({path: '/pages-user/wallet/index'})">
-              <text>明细</text>
+            <view class="wallet-actions">
+              <view class="action-btn action-recharge" @click.stop="toPage({path: '/pages-user/wallet/recharge'})">
+                <text>充值</text>
+              </view>
+              <view class="action-btn action-detail" @click.stop="toPage({path: '/pages-user/wallet/index'})">
+                <text>明细</text>
+              </view>
             </view>
           </view>
         </view>
@@ -75,8 +73,9 @@
             @click="toPage(item)"
           >
             <view class="menu-left">
-              <view class="menu-icon-box">
-                <image class="menu-icon" :src="item.icon" mode="aspectFit"></image>
+              <view class="menu-icon-box" :class="'menu-icon-box--' + item.color">
+                <image v-if="item.iconType === 'image'" class="menu-icon" :src="item.icon" mode="aspectFit"></image>
+                <uv-icon v-else :name="item.icon" size="22" :color="item.iconColor || '#C6171E'"></uv-icon>
               </view>
               <text class="menu-text">{{ item.title }}</text>
             </view>
@@ -88,7 +87,7 @@
       <!-- 退出登录按钮 -->
       <view class="logout-wrapper" v-if="isLogin">
         <view class="logout-btn" @click="logoutUser">
-          <uv-icon name="error-circle" color="#DD524D" size="18"></uv-icon>
+          <uv-icon name="backspace" color="#DD524D" size="18"></uv-icon>
           <text>退出登录</text>
         </view>
       </view>
@@ -104,12 +103,10 @@
 
 <script setup lang="ts">
 import {onHide, onLoad, onShow} from "@dcloudio/uni-app";
-import {computed, ref} from "vue";
+import {ref} from "vue";
 import TabBar from "@/components/tab-bar/index.vue";
-import LoginBar from "@/components/login-bar/index.vue";
 import {checkLogin, clearToken, loadUserInfo} from "@/utils/auth"
 import {get} from "@/utils/https";
-import {getServicePhone} from "@/utils/common";
 
 const statusBarHeight = ref(0)
 const user = ref<any>({
@@ -119,49 +116,45 @@ const user = ref<any>({
   balance: 0,
 });
 const isLogin = ref(false)
-const service = ref("15012341234");
 const menu = ref([
   {
     title: "绑定车辆",
     path: "/pages-user/profile/index",
-    icon: '/static/user/profile.png'
+    icon: '/static/iconfont/car.svg',
+    iconType: 'image',
+    color: 'red',
   },
   {
     title: "我的订单",
     path: "/pages-order/list/index",
-    icon: '/static/user/faq.png'
-  },
-  {
-    title: "联系我们",
-    path: "/pages-user/contact/index",
-    icon: '/static/user/contact.png'
+    icon: 'order',
+    iconColor: '#C6171E',
+    color: 'red',
   },
+  // {
+  //   title: "联系我们",
+  //   path: "/pages-user/contact/index",
+  //   icon: '/static/user/contact.png'
+  // },
   {
     title: "洗车指导",
     path: "/pages-user/faq/index",
-    icon: '/static/iconfont/default/guide.svg'
+    icon: 'question-circle',
+    iconColor: '#C6171E',
+    color: 'red',
   },
   {
     title: "故障反馈",
     path: "/pages-user/feedback/index",
-    icon: '/static/user/feedback.png'
+    icon: 'warning',
+    iconColor: '#C6171E',
+    color: 'red',
   },
 ]);
 
 
 const toPage = (item: any) => {
   checkLogin().then(() => {
-    let {title, path} = item;
-    let servicePhone = getServicePhone();
-    if (path.includes('contact')) {
-      uni.makePhoneCall({
-        phoneNumber: servicePhone,
-        fail: (error) => {
-        }
-      });
-      return;
-    }
-
     uni.navigateTo({
       url: item.path,
     });
@@ -174,10 +167,6 @@ const toPage = (item: any) => {
 
 };
 
-const loginListen = () => {
-
-}
-
 const logoutUser = () => {
   uni.showModal({
     title: "温馨提示",
@@ -251,11 +240,6 @@ onShow(() => {
       }
     }
   }
-  let currentPages = getCurrentPages();
-  if (currentPages.length > 1) {
-    let lastPage = currentPages[currentPages.length - 2]
-  }
-
   addListener();
 });
 
@@ -328,38 +312,28 @@ page {
 
   // 用户信息区域
   .user-section {
-    padding: 32rpx;
+    padding: 24rpx 32rpx;
     display: flex;
     align-items: center;
-    gap: 24rpx;
+    gap: 20rpx;
 
     .user-avatar-wrapper {
       flex-shrink: 0;
 
       .user-avatar {
-        width: 88rpx;
-        height: 88rpx;
+        width: 80rpx;
+        height: 80rpx;
         border-radius: 50%;
         background: rgba($uni-color-primary, 0.08);
-        padding: 8rpx;
+        padding: 10rpx;
         box-sizing: border-box;
       }
     }
 
-    .user-info {
-      flex: 1;
-
-      .user-phone {
-        font-size: 32rpx;
-        font-weight: $uni-font-weight-semibold;
-        color: $uni-text-color;
-        margin-bottom: 8rpx;
-      }
-
-      .user-tip {
-        font-size: 24rpx;
-        color: $uni-text-color-hint;
-      }
+    .user-phone {
+      font-size: 30rpx;
+      font-weight: $uni-font-weight-semibold;
+      color: $uni-text-color;
     }
   }
 
@@ -373,13 +347,12 @@ page {
   // 钱包区域
   .wallet-section {
     padding: 28rpx 32rpx 24rpx;
-    text-align: center;
 
     .wallet-header {
       display: flex;
       justify-content: space-between;
       align-items: center;
-      margin-bottom: 24rpx;
+      margin-bottom: 20rpx;
 
       .wallet-title {
         display: flex;
@@ -388,50 +361,57 @@ page {
         font-size: 26rpx;
         font-weight: $uni-font-weight-semibold;
         color: $uni-text-color;
+
+        .wallet-title-text {
+          font-size: 30rpx;
+        }
       }
     }
 
-    .wallet-balance {
-      margin-bottom: 28rpx;
-
-      .balance-label {
-        font-size: 24rpx;
-        color: $uni-text-color-hint;
-        margin-bottom: 12rpx;
-        display: block;
-      }
+    .wallet-body {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
 
+    .wallet-balance {
       .balance-value {
         display: flex;
         align-items: baseline;
-        justify-content: center;
-        gap: 6rpx;
+        gap: 4rpx;
 
         .balance-symbol {
-          font-size: 36rpx;
+          font-size: 28rpx;
           color: $uni-text-color-dark;
           font-weight: $uni-font-weight-semibold;
         }
 
         .balance-amount {
-          font-size: 64rpx;
+          font-size: 44rpx;
           color: $uni-text-color-dark;
           font-weight: $uni-font-weight-bold;
           line-height: 1;
         }
+
+        .balance-unit {
+          font-size: 24rpx;
+          color: $uni-text-color-hint;
+          margin-left: 2rpx;
+        }
       }
     }
 
     .wallet-actions {
       display: flex;
-      justify-content: center;
-      gap: 20rpx;
+      gap: 16rpx;
+      flex-shrink: 0;
 
       .action-btn {
-        padding: 14rpx 48rpx;
+        padding: 12rpx 36rpx;
         border-radius: 40rpx;
-        font-size: 26rpx;
+        font-size: 24rpx;
         font-weight: $uni-font-weight-medium;
+        text-align: center;
 
         &.action-recharge {
           background: $uni-color-primary;
@@ -478,7 +458,7 @@ page {
     display: flex;
     justify-content: space-between;
     align-items: center;
-    padding: 28rpx 32rpx;
+    padding: 24rpx 32rpx;
     border-bottom: 1rpx solid $uni-border-color-light;
 
     &:last-child {
@@ -493,7 +473,6 @@ page {
       .menu-icon-box {
         width: 72rpx;
         height: 72rpx;
-        background: rgba($uni-color-primary, 0.08);
         border-radius: 16rpx;
         display: flex;
         align-items: center;
@@ -503,6 +482,22 @@ page {
           width: 42rpx;
           height: 42rpx;
         }
+
+        &--red {
+          background: rgba($uni-color-primary, 0.08);
+        }
+
+        &--blue {
+          background: rgba(33, 150, 243, 0.08);
+        }
+
+        &--green {
+          background: rgba(76, 175, 80, 0.08);
+        }
+
+        &--orange {
+          background: rgba(255, 152, 0, 0.08);
+        }
       }
 
       .menu-text {

+ 26 - 0
car-wash-mp/src/static/iconfont/car.svg

@@ -0,0 +1,26 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" stroke="#C6171E" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
+  <!-- 车身轮廓 -->
+  <path d="M4 34 L10 34 L16 20 L48 20 L54 34 L60 34"/>
+  <!-- 车顶弧线 -->
+  <path d="M16 20 L24 14 L40 14 L48 20"/>
+  <!-- 车身底部 -->
+  <line x1="4" y1="34" x2="60" y2="34"/>
+  <!-- 车尾 -->
+  <line x1="60" y1="34" x2="60" y2="42"/>
+  <!-- 车身下沿 -->
+  <line x1="4" y1="42" x2="60" y2="42"/>
+  <!-- 车头 -->
+  <line x1="4" y1="34" x2="4" y2="42"/>
+  <!-- 前车窗斜线 -->
+  <line x1="42" y1="16" x2="48" y2="20"/>
+  <!-- 后车窗斜线 -->
+  <line x1="22" y1="16" x2="16" y2="20"/>
+  <!-- 中间窗柱 -->
+  <line x1="32" y1="15" x2="32" y2="20"/>
+  <!-- 前轮 -->
+  <circle cx="46" cy="42" r="5"/>
+  <circle cx="46" cy="42" r="2" fill="#C6171E" stroke="none"/>
+  <!-- 后轮 -->
+  <circle cx="16" cy="42" r="5"/>
+  <circle cx="16" cy="42" r="2" fill="#C6171E" stroke="none"/>
+</svg>

+ 1 - 0
car-wash-service/src/main/java/com/kym/service/impl/WashStationServiceImpl.java

@@ -97,6 +97,7 @@ public class WashStationServiceImpl extends MyBaseServiceImpl<WashStationMapper,
     public PageBean<WashStationVo> listStationForApp(StationQueryParams params) {
         PageHelper.startPage(params.getPageNum(), params.getPageSize());
         var stationList = lambdaQuery()
+                .eq(CommUtil.isNotEmptyAndNull(params.getStationId()), WashStation::getStationId, params.getStationId())
                 .like(CommUtil.isNotEmptyAndNull(params.getStationName()), WashStation::getStationName, params.getStationName())
                 .list();
         // 查询站点下的所有设备,按照站点统计可用设备数量