Эх сурвалжийг харах

feat: 首页看板增加洗车人数和今日退款,修复公众号客服浮标点击无反应

- admin-h5 首页新增洗车人数、今日退款卡片,后端 DashboardVo 补充对应字段
- car-wash-mp 客服浮标改为按在线时间条件渲染 open-type=contact 按钮,移除无法调起小程序客服的 wx.openCustomerServiceConversation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 2 өдөр өмнө
parent
commit
4b2f2317bc

+ 17 - 1
admin-h5/src/pages/index/index.vue

@@ -72,16 +72,28 @@
         </view>
       </picker>
 
-      <!-- 主指标:订单 + 消费 -->
+      <!-- 主指标:订单 + 洗车人数 -->
       <view class="metrics-primary">
         <view class="metric-card-lg">
           <text class="metric-lg-value">{{ todayOrders }}</text>
           <text class="metric-lg-label">今日订单</text>
         </view>
+        <view class="metric-card-lg">
+          <text class="metric-lg-value">{{ todayWashUsers }}</text>
+          <text class="metric-lg-label">洗车人数</text>
+        </view>
+      </view>
+
+      <!-- 主指标:消费总额 + 今日退款 -->
+      <view class="metrics-primary">
         <view class="metric-card-lg">
           <text class="metric-lg-value">¥{{ formatAmount(todayConsumption) }}</text>
           <text class="metric-lg-label">消费总额</text>
         </view>
+        <view class="metric-card-lg">
+          <text class="metric-lg-value">¥{{ formatAmount(todayRefund) }}</text>
+          <text class="metric-lg-label">今日退款</text>
+        </view>
       </view>
 
       <!-- 次指标:均价 + 时长 -->
@@ -180,7 +192,9 @@ const selectedStationIndex = ref(0)
 
 const todayRevenue = ref(0)
 const todayOrders = ref(0)
+const todayWashUsers = ref(0)
 const todayConsumption = ref(0)
+const todayRefund = ref(0)
 const avgOrderPrice = ref(0)
 const avgDuration = ref(0)
 const todayMembers = ref(0)
@@ -257,7 +271,9 @@ const loadData = async (stationId) => {
       const data = dashboardRes.data
       todayRevenue.value = data.todayIncome || 0
       todayOrders.value = data.todayWashOrders || 0
+      todayWashUsers.value = data.todayWashUsers || 0
       todayConsumption.value = data.todayConsumptionAmount || 0
+      todayRefund.value = data.todayRefundAmount || 0
       avgOrderPrice.value = data.avgOrderPrice || 0
       avgDuration.value = Math.round((data.avgOrderDuration || 0) / 60 * 10) / 10
       todayMembers.value = data.todayRegisteredMembers || 0

+ 10 - 0
car-wash-entity/src/main/java/com/kym/entity/vo/DashboardVo.java

@@ -57,6 +57,16 @@ public class DashboardVo {
      */
     private Integer todayWashOrders;
 
+    /**
+     * 当日洗车人数(去重用户数)
+     */
+    private Integer todayWashUsers;
+
+    /**
+     * 当日退款金额
+     */
+    private Integer todayRefundAmount;
+
     /**
      * 当月洗车订单数量
      */

+ 32 - 16
car-wash-mp/src/components/custom-service/index.vue

@@ -12,7 +12,17 @@
       <view class="cs-button">
         <uv-icon name="kefu-ermai" color="#FFFFFF" size="24"></uv-icon>
       </view>
-      <view class="contact-btn" @click.stop="handleContactClick" />
+      <!-- 工作时间:原生 button 直接调起小程序客服 -->
+      <button
+        v-if="inService"
+        class="contact-btn"
+        open-type="contact"
+        send-message-title="YesWash洗车客服"
+        session-from=""
+        @click.stop
+      />
+      <!-- 非工作时间:先弹确认提示 -->
+      <view v-else class="contact-btn" @click.stop="confirmVisible = true" />
     </movable-view>
 
     <!-- 非工作时间确认弹窗 -->
@@ -38,7 +48,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref, onMounted, onUnmounted } from 'vue'
 
 const POS_KEY = 'kefuPos'
 const confirmVisible = ref(false)
@@ -50,6 +60,18 @@ const isInServiceHours = (): boolean => {
   return current >= 9 * 60 + 30 && current <= 21 * 60 + 30
 }
 
+/* 响应式在线状态,定时刷新以跨越 9:30/21:30 边界 */
+const inService = ref(isInServiceHours())
+let serviceTimer: ReturnType<typeof setInterval> | null = null
+onMounted(() => {
+  serviceTimer = setInterval(() => {
+    inService.value = isInServiceHours()
+  }, 30000)
+})
+onUnmounted(() => {
+  if (serviceTimer) clearInterval(serviceTimer)
+})
+
 /* 实时拖拽位置(非响应式,避免与原生拖拽冲突) */
 let dragX = 600
 let dragY = 800
@@ -89,20 +111,6 @@ function onTouchEnd() {
   snapPos.value = { x: snapX, y: snapY }
   uni.setStorageSync(POS_KEY, { x: snapX, y: snapY })
 }
-
-const handleContactClick = () => {
-  if (isInServiceHours()) {
-    // #ifdef MP-WEIXIN
-    wx.openCustomerServiceConversation({
-      sessionFrom: '',
-      showMessageCard: true,
-      sendMessageTitle: 'YesWash洗车客服'
-    })
-    // #endif
-    return
-  }
-  confirmVisible.value = true
-}
 </script>
 
 <style scoped lang="scss">
@@ -152,6 +160,14 @@ const handleContactClick = () => {
   z-index: 2;
   padding: 0;
   margin: 0;
+  background: none;
+  border: none;
+  border-radius: 0;
+  line-height: normal;
+
+  &::after {
+    border: none;
+  }
 }
 
 .confirm-overlay {

+ 9 - 0
car-wash-service/src/main/java/com/kym/service/impl/StatServiceImpl.java

@@ -147,6 +147,13 @@ public class StatServiceImpl implements StatService {
                 .list().stream().filter(r -> r.getAmount() != null).mapToInt(SplitRecord::getAmount).sum();
         var todayIncome = todayRechargeAndCrossIncome - todayRefund - todayCrossExpend;
 
+        // 今日洗车人数(去重用户)
+        var todayWashUsers = (int) todayOrders.stream()
+                .map(WashOrder::getUserId)
+                .filter(java.util.Objects::nonNull)
+                .distinct()
+                .count();
+
         // 站点今日注册人数
         var todayRegistrations = userService.countDailyRegister(LocalDate.now(), stationId);
 
@@ -211,6 +218,8 @@ public class StatServiceImpl implements StatService {
         dashboardVo.setTodayIncome(todayIncome);
         dashboardVo.setTodayConsumptionAmount(todayConsumptionAmount);
         dashboardVo.setTodayWashOrders(todayOrders.size());
+        dashboardVo.setTodayWashUsers(todayWashUsers);
+        dashboardVo.setTodayRefundAmount(todayRefund);
         dashboardVo.setTodayRegisteredMembers(CommUtil.isEmptyOrNull(todayRegistrations) ? 0 : todayRegistrations.getOrDefault(stationId, 0));
 
         dashboardVo.setMonthIncome(monthIncome);