Browse Source

```
feat(charge): 新增充电模块功能

新增充电站相关的API类型定义,包括充电站信息、详情、价格、连接器等
接口。添加充电相关的API接口定义和全局方法。增加充电地图页面配置,
启用首页充电功能入口。实现充电详情页、站点详情页和充电启动页的功能,
包括获取站点信息、价格列表、连接器状态、设备详情等数据展示和交互功
能。
```

zouzexu 1 day ago
parent
commit
0aae44409f

+ 338 - 0
src/api/api.type.d.ts

@@ -1467,5 +1467,343 @@ namespace Api {
     spec?: string
     [property: string]: any
   }
+  // ===============充电模块================
+  interface chargeStationInfoPage {
+    /**
+     * 充电站id
+     */
+    stationId?: number
+    /**
+     * 充电站名称
+     */
+    stationName?: string
+    /**
+     * 提示语
+     */
+    tips?: string
+    /**
+     * 快充
+     */
+    fastCharging?: string
+    /**
+     * 慢充
+     */
+    slowCharging?: string
+    /**
+     * 距离
+     */
+    distance?: number
+    /**
+     * 企业价格
+     */
+    enterprisePrice?: number
+    /**
+     * 平台价格
+     */
+    platformPrice?: number
+    /**
+     * 当前峰值
+     */
+    peakValue?: string
+    /**
+     * 时间段
+     */
+    peakTime?: string
+  }
+
+  interface chargeStationDetail {
+    /**
+     * 详细地址
+     */
+    address?: string
+    /**
+     * 营业时间(如:周一至周日 00:00-24:00)
+     */
+    businessHours?: string
+    /**
+     * 充电终端列表
+     */
+    connectorList?: ConnectorInfoVO[]
+    /**
+     * 当前时段(如:峰10:00-13:00)
+     */
+    currentPeriod?: string
+    /**
+     * 当前价(元/度)
+     */
+    currentPrice?: number
+    /**
+     * 客服热线
+     */
+    customerServiceHotline?: string
+    /**
+     * 距离(km)
+     */
+    distance?: number
+    /**
+     * 企业专享价(元/度)
+     */
+    enterprisePrice?: number
+    /**
+     * 单笔预计省(元)
+     */
+    estimatedSaving?: number
+    /**
+     * 是否企业用户
+     */
+    firmUser?: boolean
+    /**
+     * 空闲终端数
+     */
+    idleCount?: number
+    /**
+     * 发票提供方
+     */
+    invoiceProvider?: string
+    /**
+     * 纬度
+     */
+    latitude?: number
+    /**
+     * 经度
+     */
+    longitude?: number
+    /**
+     * 占用终端数
+     */
+    occupiedCount?: number
+    /**
+     * 离线终端数
+     */
+    offlineCount?: number
+    /**
+     * 原价/划线价(元/度)
+     */
+    originalPrice?: number
+    /**
+     * 站点图片列表(JSON数组)
+     */
+    pictures?: string
+    /**
+     * 服务提供方
+     */
+    serviceProvider?: string
+    /**
+     * 是否显示特惠价标签
+     */
+    showSpecialPriceTag?: boolean
+    /**
+     * 站点ID
+     */
+    stationId?: number
+    /**
+     * 站点名称
+     */
+    stationName?: string
+    /**
+     * 提示语/标签(如:充电减免2小时停车费,超出部分按每小时3元计费)
+     */
+    tips?: string
+  }
+
+  interface chargeStationPrices {
+    /**
+     * 是否有企业价格
+     */
+    hasEnterprisePrice?: boolean
+    /**
+     * 价格列表
+     */
+    priceList?: PriceItemVO[]
+    /**
+     * 站点ID
+     */
+    stationId?: number
+    /**
+     * 站点名称
+     */
+    stationName?: string
+    /**
+     * 提示语/标签(如:充电减免2小时停车费,超出部分按每小时3元计费)
+     */
+    tips?: string
+  }
 
+  interface chargeStationConnectors {
+    /**
+     * 充电终端列表
+     */
+    connectorList?: ConnectorItemVO[]
+    /**
+     * 空闲终端数
+     */
+    idleCount?: number
+    /**
+     * 占用终端数
+     */
+    occupiedCount?: number
+    /**
+     * 离线终端数
+     */
+    offlineCount?: number
+    /**
+     * 站点ID
+     */
+    stationId?: number
+    /**
+     * 站点名称
+     */
+    stationName?: string
+    /**
+     * 提示语/标签(如:充电减免2小时停车费,超出部分按每小时3元计费)
+     */
+    tips?: string
+  }
+
+  interface chargeConnectorDetail {
+    /**
+     * 用户可用余额(元)
+     */
+    availableBalance?: number
+    /**
+     * 充电设备接口编码
+     */
+    connectorCode?: string
+    /**
+     * 充电设备接口ID
+     */
+    connectorId?: number
+    /**
+     * 充电设备接口名称
+     */
+    connectorName?: string
+    /**
+     * 接口类型:1-家用插座 2-交流接口插座 3-交流接口插头 4-直流接口枪头 5-无线充电座 6-其他
+     */
+    connectorType?: number
+    /**
+     * 接口类型名称
+     */
+    connectorTypeName?: string
+    /**
+     * 额定电流(A)
+     */
+    current?: number
+    /**
+     * 当前时段描述
+     */
+    currentPeriodDesc?: string
+    /**
+     * 常规价格(元/度),电价+服务费+常规运营费+增值费用
+     */
+    currentPrice?: number
+    /**
+     * 企业价格(元/度),电价+服务费+企业运营费+增值费用,仅企业用户有值
+     */
+    enterprisePrice?: number
+    /**
+     * 设备编码
+     */
+    equipmentCode?: string
+    /**
+     * 设备ID
+     */
+    equipmentId?: number
+    /**
+     * 设备名称
+     */
+    equipmentName?: string
+    /**
+     * 设备类型:1-直流设备 2-交流设备 3-交直流一体设备 4-无线设备 5-其他
+     */
+    equipmentType?: number
+    /**
+     * 设备类型名称
+     */
+    equipmentTypeName?: string
+    /**
+     * 是否企业用户
+     */
+    isFirmUser?: boolean
+    /**
+     * 最后更新时间
+     */
+    lastUpdateTime?: string
+    /**
+     * 国家标准:1-2011 2-2015
+     */
+    nationalStandard?: number
+    /**
+     * 国家标准名称
+     */
+    nationalStandardName?: string
+    /**
+     * 新用户首单优惠金额(元),仅新用户且有优惠活动时返回
+     */
+    newUserDiscount?: number
+    /**
+     * 提示语/停车费说明
+     */
+    parkingTips?: string
+    /**
+     * 车位号
+     */
+    parkNo?: string
+    /**
+     * 额定功率(kW)
+     */
+    power?: number
+    /**
+     * 充电站地址
+     */
+    stationAddress?: string
+    /**
+     * 充电站ID
+     */
+    stationId?: number
+    /**
+     * 充电站名称
+     */
+    stationName?: string
+    /**
+     * 终端状态:0-离网 1-空闲 2-占用(未充电) 3-占用(充电中) 4-占用(预约锁定) 255-故障
+     */
+    status?: number
+    /**
+     * 终端状态名称
+     */
+    statusName?: string
+    /**
+     * 额定电压下限(V)
+     */
+    voltageLowerLimits?: number
+    /**
+     * 额定电压上限(V)
+     */
+    voltageUpperLimits?: number
+    currentVoltage?: number
+  }
+
+  interface invokeChargeList {
+    /**
+     * 充电桩编号
+     */
+    equipmentId?: number
+    /**
+     * 充电桩id
+     */
+    stationId?: number
+    /**
+     * 充电设备接口编码
+     */
+    connectorId?: number
+    /**
+     * 用户昵称
+     */
+    consigneeName?: string
+    /**
+     * 用户手机号
+     */
+    consigneeMobile?: string
+  }
 }

+ 10 - 1
src/api/apiDefinitions.ts

@@ -68,5 +68,14 @@ export default {
   'common.shoppingCartOrderConfirm':['GET', '/smqjh-oms/app-api/v1/shoppingCart/shoppingCartOrderConfirm/{ids}'],
   'common.addOrder':['POST', '/smqjh-oms/api/v1/order/addOrder'],
   'common.hybridPayment':['POST', '/smqjh-oms/service/pay/hybridPayment'],
-  'smqjh.getCategoryList':['POST', '/smqjh-pms/app-api/v1/categories/getCategoryList'],
+  'smqjh.getCategoryList': ['POST', '/smqjh-pms/app-api/v1/categories/getCategoryList'],
+
+  'charge.getStationInfoPage':['POST','/smqjh-system/applet/v1/homePage/getStationInfoPage'],
+  'charge.getMemberInfo': ['GET', '/smqjh-system/applet/v1/homePage/getMemberInfo'],
+  'charge.detail': ['GET', '/smqjh-system/applet/v1/station/detail'],
+  'charge.prices':['GET','/smqjh-system/applet/v1/station/prices'],
+  'charge.connectors':['GET','/smqjh-system/applet/v1/station/connectors'],
+  'charge.connectorDetail':['GET','/smqjh-system/applet/v1/station/connector/detail'],
+  'charge.invokeCharge':['POST','/smqjh-system/applet/v1/station/addCDOrder'],
+
 };

+ 74 - 4
src/api/globals.d.ts

@@ -195,7 +195,7 @@ declare global {
       refundDetails<
         Config extends Alova2MethodConfig<apiResData<Api.OrderRefundDetails>> & {
           data: {
-             refundNumber: string;
+            refundNumber: string;
           };
         }
       >(
@@ -214,7 +214,7 @@ declare global {
         Config extends Alova2MethodConfig<listData<Api.AppRefundOrderListVo>> & {
           data: {
             pageNum: number;
-            pageSize:number
+            pageSize: number
           };
         }
       >(
@@ -665,11 +665,81 @@ declare global {
         config: Config
       ): Alova2Method<apiResData<Api.smqjhCategoryList[]>, 'smqjh.getCategoryList', Config>;
     }
+    charge: {
+      getStationInfoPage<
+        Config extends Alova2MethodConfig<listData<Api.chargeStationInfoPage>> & {
+          data: {
+            pageNum?: number;
+            pageSize?: number;
+            sortType?: number;
+            longitude?: number;
+            latitude?: number;
+            userId?: number;
+          }
+        }
+      >(
+        config: Config
+      ): Alova2Method<listData<Api.chargeStationInfoPage>, 'charge.getStationInfoPage', Config>;
 
-  }
+      getMemberInfo<
+        Config extends Alova2MethodConfig<apiResData<Api.chargeMemberInfo>> & {}
+      >(
+        config: Config
+      ): Alova2Method<apiResData<Api.chargeMemberInfo>, 'charge.getMemberInfo', Config>;
 
-  var Apis: Apis;
+      detail<
+        Config extends Alova2MethodConfig<apiResData<Api.chargeStationDetail>> & {
+          data: {
+            stationId?: number;
+            longitude?: number | null;
+            latitude?: number | null;
+          }
+        }
+      >(
+        config: Config
+      ): Alova2Method<apiResData<Api.chargeStationDetail>, 'charge.detail', Config>;
+
+      prices<
+        Config extends Alova2MethodConfig<apiResData<Api.chargeStationPrices>> & {
+          data: {
+            stationId?: number;
+          }
+        }
+      >(
+        config: Config
+      ): Alova2Method<apiResData<Api.chargeStationPrices>, 'charge.prices', Config>;
+
+      connectors<
+        Config extends Alova2MethodConfig<apiResData<Api.chargeStationConnectors>> & {
+          data: {
+            stationId?: number;
+          }
+        }
+      >(
+        config: Config
+      ): Alova2Method<apiResData<Api.chargeStationConnectors>, 'charge.connectors', Config>;
+
+      connectorDetail<
+        Config extends Alova2MethodConfig<apiResData<Api.chargeConnectorDetail>> & {
+          data: {
+            connectorCode?: string;
+          }
+        }
+      >(
+        config: Config
+      ): Alova2Method<apiResData<Api.chargeConnectorDetail>, 'charge.detail', Config>;
+
+      invokeCharge<
+        Config extends Alova2MethodConfig<any> & {
+          data: Api.invokeChargeList;
+        }
+      >(
+        config: Config
+      ): Alova2Method<any, 'charge.invokeCharge', Config>;
+    }
+  }
 }
+var Apis: Apis;
 
 
 export interface loginModel {

+ 3 - 1
src/config/index.ts

@@ -6,9 +6,11 @@ const mapEnvVersion = {
   // develop: 'http://192.168.1.101:8080',
   // develop: 'http://192.168.0.157:8080',
   // develop: 'http://192.168.1.253:8080',
+  develop: 'http://192.168.0.19:8080',
+  // develop: 'http://192.168.0.217:8080',
   // develop: 'http://192.168.1.89:8080', // 田
   // develop: 'http://47.109.84.152:8081',
-  develop: 'https://smqjh.api.zswlgz.com',
+  // develop: 'https://smqjh.api.zswlgz.com',
   /**
    * 体验版
    */

+ 10 - 0
src/pages.json

@@ -330,6 +330,16 @@
             "navigationStyle": "custom"
           }
         },
+        {
+          "path": "chargeMap/chargeMap",
+          "type": "page",
+          "name": "charge-map",
+          "islogin": false,
+          "style": {
+            "navigationBarTitleText": "地图模式",
+            "navigationStyle": "custom"
+          }
+        },
         {
           "path": "chargeSiteDetail/chargeSiteDetail",
           "type": "page",

+ 1 - 1
src/pages/index/index.vue

@@ -55,7 +55,7 @@ onReachBottom(() => {
 const navList = computed(() => {
   const list = [
     { icon: `${StaticUrl}/xsb.png`, title: '星闪豹', name: 'xsb-homeTabbar', show: true },
-    { icon: `${StaticUrl}/smqjh-index-cd.png`, title: '充电', name: 'charge-index', show: !isOnlineAudit.value }, // !isOnlineAudit.value
+    { icon: `${StaticUrl}/smqjh-index-cd.png`, title: '充电', name: 'charge-index', show: true }, // !isOnlineAudit.value
     { icon: `${StaticUrl}/smqjh-sp.png`, title: '电影演出', name: '', show: !isOnlineAudit.value },
     { icon: `${StaticUrl}/smqjh-vip.png`, title: '视频权益', name: '', show: !isOnlineAudit.value },
     { icon: `${StaticUrl}/smqjh-diancan.png`, title: '大牌点餐', name: '', show: !isOnlineAudit.value },

+ 61 - 18
src/subPack-charge/chargeDetail/chargeDetail.vue

@@ -12,7 +12,44 @@ definePage({
     navigationStyle: 'custom',
   },
 })
+const stationId = ref()
+onLoad((options: any) => {
+  stationId.value = Number(options.stationId)
+  activeTab.value = options.type
+})
+onMounted(() => {
+  getPricesList()
+  getConnectorsList()
+})
+
+const priceDetail = ref<Api.chargeStationPrices>()
+async function getPricesList() {
+  const res = await Apis.charge.prices({ data: { stationId: stationId.value } })
+  priceDetail.value = res.data
+}
+
+const connectorsDetail = ref<Api.chargeStationConnectors>()
+async function getConnectorsList() {
+  const res = await Apis.charge.connectors({ data: { stationId: stationId.value } })
+  connectorsDetail.value = res.data
+}
 
+/**
+ * 处理站点设备状态
+ *status 状态:0-离线 1-空闲 2-占用
+ */
+function getStatusImageByStatus(deviceStatus: number) {
+  switch (deviceStatus) {
+    case 1: // 空闲
+      return 'kx'
+    case 2: // 占用
+      return 'zy'
+    case 0: // 离线
+      return 'lx'
+    default:
+      return 'unknown'
+  }
+}
 // 切换选项卡的方法
 function switchTab(tab: string) {
   activeTab.value = tab
@@ -37,18 +74,23 @@ function getTabStyle(tab: string) {
       <view class="flex items-center gap-24rpx">
         <view>
           <view class="text-32rpx font-bold">
-            贵阳花果园购物中心充电站
+            {{ priceDetail?.stationName }}
           </view>
           <view class="mt-16rpx text-24rpx text-#AAA">
-            充电减免2小时停车费,超出部分按每小时3元计算
+            {{ priceDetail?.tips || '--' }}
           </view>
         </view>
-        <view>icon</view>
+        <view>
+          <image
+            class="h-132rpx w-140rpx"
+            :src="`${StaticUrl}/site-name-icon.png`"
+          />
+        </view>
       </view>
       <view class="items-centerrounded-16rpx mt-20rpx flex bg-#FFF p-20rpx">
         <view class="w-230rpx text-center">
           <view class="text-32rpx text-#9ED605 font-bold">
-            9
+            {{ connectorsDetail?.idleCount }}
           </view>
           <view class="text-24rpx font-500">
             空闲
@@ -57,7 +99,7 @@ function getTabStyle(tab: string) {
         <view class="h-76rpx w-2rpx bg-#F0F0F0" />
         <view class="w-230rpx text-center">
           <view class="text-32rpx text-#9ED605 font-bold">
-            7
+            {{ connectorsDetail?.occupiedCount }}
           </view>
           <view class="text-24rpx font-500">
             占用
@@ -66,7 +108,7 @@ function getTabStyle(tab: string) {
         <view class="h-76rpx w-2rpx bg-#F0F0F0" />
         <view class="w-230rpx text-center">
           <view class="text-32rpx text-#9ED605 font-bold">
-            6
+            {{ connectorsDetail?.offlineCount }}
           </view>
           <view class="text-24rpx font-500">
             离线
@@ -90,19 +132,20 @@ function getTabStyle(tab: string) {
         </view>
       </view>
       <view v-if="activeTab == 'price'">
-        <view class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx" style="border:2rpx solid #9ED605;">
+        <view v-for="item in priceDetail?.priceList" :key="item.timePeriod" class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx" :style="{ border: item.currentPeriod ? '2rpx solid #9ED605' : '' }">
           <view class="relative flex items-center justify-between">
             <view class="flex items-center gap-20rpx">
               <view
                 class="h-40rpx w-40rpx rounded-8rpx bg-#CCC text-center text-28rpx text-#FFF font-bold line-height-[40rpx]"
               >
-                
+                {{ item.periodFlagName }}
               </view>
               <view class="text-28rpx font-bold">
-                00:00-08:00
+                {{ item.timePeriod }}
               </view>
             </view>
             <view
+              v-if="item.currentPeriod"
               class="absolute h-40rpx w-152rpx rounded-[0_16rpx_0_16rpx] bg-[linear-gradient(99deg,#D2F670_0%,#9ED605_100%)] text-center text-28rpx text-#FFF font-600 -right-24rpx -top-24rpx"
             >
               当前时段
@@ -113,8 +156,8 @@ function getTabStyle(tab: string) {
               <view class="text-24rpx text-#222222">
                 抵扣券电价
               </view>
-              <view class="text-24rpx" style="color: #FF6464;font-weight: 800;">
-                <text>0.8800</text>
+              <view class="text-24rpx" :style="{ color: item.currentPeriod ? '#FF6464' : '', fontWeight: item.currentPeriod ? '800' : '' }">
+                <text>{{ item.totalPrice }}</text>
                 <text class="text-#AAA">
                   元/度
                 </text>
@@ -124,24 +167,24 @@ function getTabStyle(tab: string) {
         </view>
       </view>
       <view v-if="activeTab == 'terminal'">
-        <view class="mt-20rpx flex items-center gap-20rpx rounded-16rpx bg-#FFF p-20rpx">
+        <view v-for="item in connectorsDetail?.connectorList" :key="item.connectorId" class="mt-20rpx flex items-center gap-20rpx rounded-16rpx bg-#FFF p-20rpx">
           <view
             class="h-116rpx w-116rpx text-center line-height-[116rpx]"
-            :style="{ backgroundImage: `url(${StaticUrl}/site-status-kx.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }"
+            :style="{ backgroundImage: `url(${StaticUrl}/site-status-${getStatusImageByStatus(item.status)}.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }"
           >
             <view class="text-24rpx font-bold">
-              空闲
+              {{ item.statusName }}
             </view>
           </view>
           <view>
             <view class="text-bold text-28rpx">
-              101号直流充电桩
+              {{ item.connectorName }}
             </view>
             <view class="mt-4rpx text-24rpx text-#AAA">
-              电类分类:直流设备
+              电类分类:{{ item.equipmentType }}
             </view>
-            <view class="mt-4rpx text-24rpx text-#AAA">
-              终端编号:52155648615
+            <view class="mt-4rpx w-400rpx overflow-hidden truncate whitespace-nowrap text-24rpx text-#AAA">
+              终端编号:{{ item.connectorCode }}
             </view>
           </view>
         </view>

+ 118 - 42
src/subPack-charge/chargeSiteDetail/chargeSiteDetail.vue

@@ -2,9 +2,15 @@
 import router from '@/router'
 import { StaticUrl } from '@/config'
 
-const swiperList = ['https://www.keaitupian.cn/cjpic/frombd/2/253/1659552792/3869332496.jpg']
-
+// const swiperList = ['https://www.keaitupian.cn/cjpic/frombd/2/253/1659552792/3869332496.jpg']
+const { statusBarHeight, MenuButtonHeight } = storeToRefs(useSysStore())
+const { Location } = storeToRefs(useAddressStore())
 const { opcity } = storeToRefs(useSysStore())
+const stationId = ref()
+onLoad((options: any) => {
+  console.log(options)
+  stationId.value = Number(options.stationId)
+})
 definePage({
   name: 'charge-site-detail',
   islogin: true,
@@ -14,24 +20,88 @@ definePage({
   },
 })
 const activeFilter = ref('0')
-const filterOptions = [
-  { key: '0', label: '空闲(10)' },
-  { key: '1', label: '占用(8)' },
-  { key: '2', label: '离线(5)' },
-]
-// 处理筛选项点击的方法
-function handleFilterClick(filterKey: string) {
-  activeFilter.value = filterKey
-  console.log(`选择了: ${filterKey}`)
-}
 onMounted(() => {
+  getStationDetail()
   opcity.value = 0
 })
+/**
+ * 获取电站详情
+ */
+const stationDetail = ref<Api.chargeStationDetail>()
+async function getStationDetail() {
+  useGlobalLoading().loading({})
+  const res = await Apis.charge.detail({ data: { stationId: stationId.value, latitude: Location.value.latitude, longitude: Location.value.longitude } })
+  stationDetail.value = res.data
+  useGlobalLoading().close()
+}
+// 使用计算属性动态计算筛选选项
+const filterOptions = computed(() => {
+  const counts = {
+    0: 0, // 离线
+    1: 0, // 空闲
+    2: 0, // 占用
+  }
+
+  // 遍历充电站连接器列表,统计各状态数量
+  if (stationDetail.value?.connectorList) {
+    stationDetail.value.connectorList.forEach((item) => {
+      // 检查status是否为有效键值
+      if (item.status === 0 || item.status === 1 || item.status === 2) {
+        counts[item.status as keyof typeof counts]++
+      }
+    })
+  }
+
+  return [
+    { key: '0', label: `离线(${counts['0']})` },
+    { key: '1', label: `空闲(${counts['1']})` },
+    { key: '2', label: `占用(${counts['2']})` },
+  ]
+})
+
+// 添加计算属性来过滤设备列表
+const filteredConnectors = computed(() => {
+  if (!stationDetail.value?.connectorList)
+    return []
+  // 根据当前选中的状态过滤设备,并限制为前3个
+  return stationDetail.value.connectorList.filter(
+    item => String(item.status) === activeFilter.value,
+  ).slice(0, 3)
+})
+/**
+ * 处理站点设备状态
+ *status 状态:0-离线 1-空闲 2-占用
+ */
+function getStatusImageByStatus(deviceStatus: number) {
+  switch (deviceStatus) {
+    case 1: // 空闲
+      return 'kx'
+    case 2: // 占用
+      return 'zy'
+    case 0: // 离线
+      return 'lx'
+    default:
+      return 'unknown'
+  }
+}
 
 onPageScroll((e) => {
   const calculatedOpacity = e.scrollTop / 100
   opcity.value = Math.min(1, Math.max(0.1, calculatedOpacity))
 })
+
+// 处理筛选项点击的方法
+function handleFilterClick(filterKey: string) {
+  activeFilter.value = filterKey
+  console.log(`选择了: ${filterKey}`)
+}
+
+function openMap() {
+  uni.openLocation({
+    latitude: Number(stationDetail.value?.latitude),
+    longitude: Number(stationDetail.value?.longitude),
+  })
+}
 </script>
 
 <template>
@@ -40,38 +110,39 @@ onPageScroll((e) => {
       title="站点详情" :custom-style="`background-color: rgba(226, 255, 145, ${opcity})`" :bordered="false"
       :z-index="999" safe-area-inset-top left-arrow fixed @click-left="router.back()"
     />
-    <view class="site-detail-content relative">
-      <view>
+    <view :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }" />
+    <view class="site-detail-content">
+      <!-- <view>
         <wd-swiper :list="swiperList" :height="260" :indicator="{ type: 'fraction' }" value-key="advertImg" />
-      </view>
-      <view class="absolute left-0 right-0 z-10 rounded-[32rpx_32rpx_0_0] bg-#FFF -bottom-100rpx">
+      </view> -->
+      <view class="bg-#FFF p-20rpx">
         <view class="mt-28rpx box-border px24rpx">
           <view class="text-32rpx font-800">
-            贵阳花果园购物中心充电站
+            {{ stationDetail?.stationName }}
           </view>
           <view class="mt-20rpx flex items-center gap-20rpx">
             <view class="h-30rpx w-30rpx rounded-4rpx bg-#5BE7FF text-center text-24rpx text-#fff line-height-[30rpx]">
               P
             </view>
             <view class="text-24rpx text-#AAA">
-              充电减免2小时停车费,超出部分按每小时3元计算
+              {{ stationDetail?.tips || '--' }}
             </view>
           </view>
         </view>
-        <view class="box-border px24rpx">
+        <view class="ml-10rpx">
           <view
-            class="cardBg-set mt-20rpx box-border h-138rpx w-702rpx flex items-center justify-between rounded-16rpx"
+            class="cardBg-set mt-20rpx box-border h-138rpx w-680rpx flex items-center justify-between rounded-16rpx"
             :style="{ backgroundImage: `url(${StaticUrl}/site-detail-navBg.png)` }"
           >
             <view class="ml-24rpx">
               <view class="text-28rpx text-#2B303A font-bold">
-                距离您1.3km
+                距离您{{ stationDetail?.distance || '--' }}km
               </view>
               <view class="mt-8rpx w-408rpx overflow-hidden text-ellipsis whitespace-nowrap text-24rpx text-#AAA">
-                贵州省贵阳市观山湖区贵安新区群航贵州省贵阳市观山湖区贵
+                {{ stationDetail?.address }}
               </view>
             </view>
-            <view class="mr-24rpx">
+            <view class="mr-24rpx" @click="openMap">
               <view>
                 <image class="h-40rpx w-40rpx" :src="`${StaticUrl}/site-detail-nav.png`" />
               </view>
@@ -83,14 +154,13 @@ onPageScroll((e) => {
         </view>
       </view>
     </view>
-    <view class="h-100rpx" />
     <view class="mt20rpx box-border px24rpx">
       <view class="rounded-24rpx bg-#FFF p-24rpx">
         <view class="flex items-center justify-between">
           <view class="text-32rpx font-bold">
             费用信息
           </view>
-          <view class="flex items-center" @click="router.push({ name: 'charge-detail' })">
+          <view class="flex items-center" @click="router.push({ name: 'charge-detail', params: { stationId: String(stationDetail?.stationId), type: 'price' } })">
             <view class="text-24rpx text-#AAA">
               查看全部
             </view>
@@ -110,7 +180,7 @@ onPageScroll((e) => {
             <view>
               <view class="flex items-center">
                 <text class="text-48rpx text-#FF6464 font-800">
-                  1.2026
+                  {{ stationDetail?.currentPrice }}
                 </text>
                 <text class="text-24rpx">
                   元/度
@@ -120,7 +190,7 @@ onPageScroll((e) => {
                 当前时段:
               </view>
               <view class="text-bold mt-16rpx text-28rpx">
-                平13:00-17:00
+                {{ stationDetail?.currentPeriod }}
               </view>
             </view>
             <view>
@@ -134,7 +204,7 @@ onPageScroll((e) => {
           <view class="text-32rpx font-bold">
             充电终端
           </view>
-          <view class="flex items-center">
+          <view class="flex items-center" @click="router.push({ name: 'charge-detail', params: { stationId: String(stationDetail?.stationId), type: 'terminal' } })">
             <view class="text-24rpx text-#AAA">
               查看全部
             </view>
@@ -143,35 +213,41 @@ onPageScroll((e) => {
         </view>
         <view class="mt-28rpx flex items-center gap-20rpx">
           <view
-            v-for="option in filterOptions" :key="option.key"
-            class="select-item h-60rpx w-152rpx text-28rpx line-height-[60rpx]" :class="[{ 'select-item-active': activeFilter === option.key },
-            ]" @click="handleFilterClick(option.key)"
+            v-for="item in filterOptions" :key="item.key"
+            class="select-item h-60rpx w-152rpx text-28rpx line-height-[60rpx]" :class="[{ 'select-item-active': activeFilter === item.key }]" @click="handleFilterClick(item.key)"
           >
-            {{ option.label }}
+            {{ item.label }}
           </view>
         </view>
         <view class="mt-24rpx">
-          <view class="mb-20rpx flex items-center gap-20rpx rounded-16rpx bg-#F6F6F6 p-20rpx" @click="router.push({ name: 'charge-start' })">
+          <view v-for="item in filteredConnectors" :key="item.connectorId" class="mb-20rpx flex items-center gap-20rpx rounded-16rpx bg-#F6F6F6 p-20rpx" @click="router.push({ name: 'charge-start', params: { connectorCode: item.connectorCode } })">
             <view
-              class="h-116rpx w-116rpx text-center line-height-[116rpx]"
-              :style="{ backgroundImage: `url(${StaticUrl}/site-status-kx.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }"
+              class="h-116rpx w-116rpx text-center"
+              :style="{ backgroundImage: `url(${StaticUrl}/site-status-${getStatusImageByStatus(item.status)}.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }"
             >
+              <image
+                class="mt-20rpx h-38rpx w-27.18rpx"
+                :src="`${StaticUrl}/terminal-icon.png`"
+              />
               <view class="text-24rpx font-bold">
-                空闲
+                {{ item?.statusName }}
               </view>
             </view>
             <view>
               <view class="text-bold text-28rpx">
-                101号直流充电桩
+                {{ item.connectorName }}
               </view>
               <view class="mt-4rpx text-24rpx text-#AAA">
-                电类分类:直流设备
+                电类分类:{{ item.equipmentType }}
               </view>
-              <view class="mt-4rpx text-24rpx text-#AAA">
-                终端编号:52155648615
+              <view class="mt-4rpx w-300rpx overflow-hidden truncate whitespace-nowrap text-24rpx text-#AAA">
+                终端编号:{{ item.connectorCode }}
               </view>
             </view>
           </view>
+          <view v-if="filteredConnectors.length < 1" class="h-100rpx w-full text-center text-24rpx text-#AAA line-height-[100rpx]">
+            暂无终端信息
+          </view>
         </view>
       </view>
     </view>
@@ -187,7 +263,7 @@ onPageScroll((e) => {
             </text>
             <text class="text-bold text-40rpx text-#F5531A">
-              1.2099
+              {{ stationDetail?.currentPrice }}
             </text>
             <text class="text-24rpx text-#AAA">
               元/度
@@ -209,7 +285,7 @@ onPageScroll((e) => {
 }
 
 .select-item {
-  background: #FFFFFF;
+  background: #f5f3f3;
   border-radius: 16rpx;
   color: #2B303A;
   text-align: center;

+ 35 - 8
src/subPack-charge/chargeStart/chargeStart.vue

@@ -3,6 +3,7 @@ import router from '@/router'
 import { StaticUrl } from '@/config'
 
 const { statusBarHeight, MenuButtonHeight, opcity } = storeToRefs(useSysStore())
+const { userInfo } = storeToRefs(useUserStore())
 definePage({
   name: 'charge-start',
   islogin: true,
@@ -11,14 +12,40 @@ definePage({
     navigationStyle: 'custom',
   },
 })
+const connectorCode = ref()
+onLoad((options: any) => {
+  connectorCode.value = options.connectorCode
+})
+
 onMounted(() => {
   opcity.value = 0
+  getConnectorDetail()
 })
 
 onPageScroll((e) => {
   const calculatedOpacity = e.scrollTop / 100
   opcity.value = Math.min(1, Math.max(0.1, calculatedOpacity))
 })
+
+const connectorDetailInfo = ref<Api.chargeConnectorDetail>()
+async function getConnectorDetail() {
+  const res = await Apis.charge.connectorDetail({ data: { connectorCode: connectorCode.value } })
+  connectorDetailInfo.value = res.data
+}
+
+const fromData = ref<Api.invokeChargeList>({
+  equipmentId: 0,
+  stationId: 0,
+  connectorId: 0,
+  consigneeName: userInfo.value?.nickName,
+  consigneeMobile: userInfo.value?.mobile,
+})
+async function launchCharge() {
+  fromData.value.equipmentId = connectorDetailInfo.value?.equipmentId
+  fromData.value.stationId = connectorDetailInfo.value?.stationId
+  fromData.value.connectorId = connectorDetailInfo.value?.connectorId
+  await Apis.charge.invokeCharge({ data: fromData.value })
+}
 </script>
 
 <template>
@@ -38,10 +65,10 @@ onPageScroll((e) => {
       <view class="mt-94rpx flex items-center justify-center">
         <view class="w-182rpx text-center">
           <view class="text-28rpx text-#AAA">
-            电流
+            电流A
           </view>
           <view class="mt-24rpx text-32rpx font-800">
-            126.80
+            {{ connectorDetailInfo?.current }}
           </view>
         </view>
         <view class="h-40rpx w-2rpx bg-#DEDEDE" />
@@ -50,7 +77,7 @@ onPageScroll((e) => {
             电压V
           </view>
           <view class="mt-24rpx text-32rpx font-800">
-            126.80
+            {{ connectorDetailInfo?.currentVoltage || '0' }}
           </view>
         </view>
         <view class="h-40rpx w-2rpx bg-#DEDEDE" />
@@ -59,7 +86,7 @@ onPageScroll((e) => {
             功率KW
           </view>
           <view class="mt-24rpx text-32rpx font-800">
-            126.80
+            {{ connectorDetailInfo?.power }}
           </view>
         </view>
       </view>
@@ -70,7 +97,7 @@ onPageScroll((e) => {
           </view>
           <view class="flex items-center">
             <text class="text-30rpx text-#FC5A5A font-bold">
-              0.79
+              {{ connectorDetailInfo?.currentPrice }}
             </text>
             <text class="text-28rpx text-#AAA">
               /度
@@ -82,7 +109,7 @@ onPageScroll((e) => {
             当前时段
           </view>
           <view class="text-28rpx text-#AAA">
-            平:13:00-17:00
+            {{ connectorDetailInfo?.currentPeriodDesc }}
           </view>
         </view>
         <view class="mt-20rpx flex items-center justify-between">
@@ -90,7 +117,7 @@ onPageScroll((e) => {
             停车参考
           </view>
           <view class="text-28rpx text-#AAA">
-            以车场实际计费规则为准
+            {{ connectorDetailInfo?.parkingTips || '--' }}
           </view>
         </view>
         <view class="mt-28rpx text-24rpx text-#AAA">
@@ -98,7 +125,7 @@ onPageScroll((e) => {
         </view>
       </view>
     </view>
-    <view class="fixed bottom-66rpx left-24rpx h-100rpx w-702rpx rounded-16rpx bg-[linear-gradient(90deg,#DBFC81_0%,#9ED605_100%)] text-center text-28rpx font-800 line-height-[100rpx] shadow-[inset_0rpx_6rpx_20rpx_2rpx_#FFFFFF]" @click="router.push({ name: 'chargeing' })">
+    <view class="fixed bottom-66rpx left-24rpx h-100rpx w-702rpx rounded-16rpx bg-[linear-gradient(90deg,#DBFC81_0%,#9ED605_100%)] text-center text-28rpx font-800 line-height-[100rpx] shadow-[inset_0rpx_6rpx_20rpx_2rpx_#FFFFFF]" @click="launchCharge">
       启动终端充电
     </view>
   </view>

+ 92 - 46
src/subPack-charge/index/index.vue

@@ -3,10 +3,12 @@ import chargeSearch from '../components/search.vue'
 import chargeFooter from '../components/charge-tab.vue'
 import router from '@/router'
 import { StaticUrl } from '@/config'
+import { createGlobalLoadingMiddleware } from '@/api/core/middleware'
 
 const { statusBarHeight, MenuButtonHeight, opcity } = storeToRefs(useSysStore())
-const { userInfo } = storeToRefs(useUserStore())
-const swiperList = ['https://www.keaitupian.cn/cjpic/frombd/2/253/1659552792/3869332496.jpg']
+const { token, userInfo } = storeToRefs(useUserStore())
+const { Location } = storeToRefs(useAddressStore())
+// const swiperList = ['https://www.keaitupian.cn/cjpic/frombd/2/253/1659552792/3869332496.jpg']
 definePage({
   name: 'charge-index',
   islogin: false,
@@ -16,29 +18,53 @@ definePage({
     backgroundColorBottom: '#fff',
   },
 })
+const activeFilter = ref<number>(1)
 const filterOptions = [
-  { key: 'nearest', label: '离我最近', widthClass: 'w-152rpx' },
-  { key: 'most-available', label: '空闲最多', widthClass: '' },
-  { key: 'lowest-price', label: '电费最低', widthClass: '' },
+  { key: 1, label: '离我最近', widthClass: 'w-152rpx' },
+  { key: 2, label: '空闲最多', widthClass: '' },
+  { key: 3, label: '电费最低', widthClass: '' },
 ]
-const activeFilter = ref('nearest')
 
+/**
+ * 获取充电站列表
+ */
+const { data: stationList, isLastPage, page, refresh, reload } = usePagination((pageNum, pageSize) =>
+  Apis.charge.getStationInfoPage({ data: { pageNum, pageSize, sortType: activeFilter.value, longitude: Location.value.longitude || 106.620256, latitude: Location.value.latitude || 26.648327, userId: userInfo.value.id } }), {
+  data: resp => resp.data?.list,
+  initialData: [],
+  initialPage: 1,
+  initialPageSize: 10,
+  append: true,
+  immediate: true,
+  middleware: createGlobalLoadingMiddleware(),
+})
+onMounted(() => {
+  getUserAccountInfo()
+  opcity.value = 0
+})
+onShow(() => refresh())
+onPageScroll((e) => {
+  const calculatedOpacity = e.scrollTop / 100
+  opcity.value = Math.min(1, Math.max(0.1, calculatedOpacity))
+})
+onReachBottom(() => {
+  if (!isLastPage.value) {
+    page.value++
+  }
+})
+
+/**
+ * 获取用户账户信息
+ */
+const userAccountInfo = ref()
+async function getUserAccountInfo() {
+  const res = await Apis.charge.getMemberInfo({})
+  userAccountInfo.value = res.data
+}
 // 处理筛选项点击的方法
-function handleFilterClick(filterKey: string) {
+function handleFilterClick(filterKey: number) {
   activeFilter.value = filterKey
-  console.log(`选择了: ${filterKey}`)
-  // 根据不同筛选类型执行相应操作
-  switch (filterKey) {
-    case 'nearest':
-      // 执行距离排序逻辑
-      break
-    case 'most-available':
-      // 执行空闲数量排序逻辑
-      break
-    case 'lowest-price':
-      // 执行价格排序逻辑
-      break
-  }
+  reload()
 }
 </script>
 
@@ -58,7 +84,7 @@ function handleFilterClick(filterKey: string) {
       </template>
     </wd-navbar>
     <view :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }" class="px24rpx">
-      <charge-search />
+      <charge-search map-mode-text-value="地图模式" @map-mode-click="router.push({ name: 'charge-map' })" />
       <view class="userInfo-card">
         <view class="flex items-center gap-20rpx">
           <image
@@ -69,9 +95,12 @@ function handleFilterClick(filterKey: string) {
             <view class="text-32rpx text-#2B303A font-bold">
               {{ userInfo?.nickName || '游客' }}
             </view>
-            <view class="text-24rpx text-#9ED605">
+            <view v-if="!token" class="text-24rpx text-#9ED605" @click="router.replace({ name: 'smqjh-login' })">
               授权登录
             </view>
+            <view v-else class="rounded-8rpx bg-#9ED605 px12rpx py4rpx text-24rpx text-#FFF opacity-70">
+              {{ userInfo.channelName }}
+            </view>
           </view>
         </view>
         <view class="mt-20rpx flex items-center justify-between gap-18rpx">
@@ -80,16 +109,18 @@ function handleFilterClick(filterKey: string) {
               <view>我的积分</view>
               <view>可用充电余额</view>
             </view>
-            <view class="mt-24rpx flex items-center gap-30rpx text-40rpx text-#9ED605 font-bold">
+            <view class="mt-24rpx flex items-center gap-30rpx text-28rpx text-#9ED605 font-500">
               <view class="flex items-center gap-20rpx">
-                <text>896</text>
-                <image class="h-48rpx w-48rpx" :src="`${StaticUrl}/charge-acc.png`" />
+                <text class="w-120rpx overflow-hidden truncate whitespace-nowrap">
+                  {{ userAccountInfo?.availablePoints || '--' }}
+                </text>
+                <image class="h-30rpx w-30rpx" :src="`${StaticUrl}/charge-acc.png`" />
               </view>
-              <view>
-                <text class="text-28rpx">
+              <view class="w-120rpx overflow-hidden truncate whitespace-nowrap">
+                <text class="text-20rpx">
                 </text>
-                89.6
+                {{ userAccountInfo?.balance || '--' }}
               </view>
             </view>
           </view>
@@ -98,7 +129,7 @@ function handleFilterClick(filterKey: string) {
               <view class="text-28rpx font-bold">
                 充电订单
               </view>
-              <view class="mt-24rpx text-40rpx text-#9ED605 font-bold">
+              <view class="mt-24rpx text-28rpx text-#9ED605 font-500">
                 956
               </view>
             </view>
@@ -106,9 +137,9 @@ function handleFilterClick(filterKey: string) {
           </view>
         </view>
       </view>
-      <view class="mt-24rpx">
+      <!-- <view class="mt-24rpx">
         <wd-swiper :list="swiperList" :height="100" :indicator="false" value-key="advertImg" />
-      </view>
+      </view> -->
       <view class="mt-24rpx flex items-center gap-20rpx">
         <view
           v-for="option in filterOptions"
@@ -123,16 +154,16 @@ function handleFilterClick(filterKey: string) {
         </view>
       </view>
       <view>
-        <view class="relative mt-24rpx rounded-16rpx bg-#FFFFFF p-24rpx" @click="router.push({ name: 'charge-site-detail' })">
+        <view v-for="item in stationList" :key="item.stationId" class="relative mt-24rpx rounded-16rpx bg-#FFFFFF p-24rpx" @click="router.push({ name: 'charge-site-detail', params: { stationId: String(item.stationId) } })">
           <image
             class="absolute right-0 top-0 h-52rpx w-186rpx"
             :src="`${StaticUrl}/charge-firm-tag.png`"
           />
           <view class="text-32rpx text-#2B303A font-bold">
-            贵阳花果园购物中心充电站
+            {{ item.stationName }}
           </view>
           <view class="mt-20rpx text-24rpx text-#aaa">
-            充电减免2小时停车费,超出部分按每小时3元计算
+            {{ item.tips || '暂无提示' }}
           </view>
           <view class="mt-24rpx flex items-center rounded-16rpx bg-[linear-gradient(90deg,rgba(170,255,235,0.3)_0%,rgba(175,247,252,0.2)_43.57%,rgba(139,232,252,0)_100%)] p-20rpx">
             <view class="flex items-center gap-16rpx">
@@ -141,10 +172,7 @@ function handleFilterClick(filterKey: string) {
               </view>
               <view class="flex items-center">
                 <text class="text-32rpx font-bold">
-                  12
-                </text>
-                <text class="text-24rpx text-#AAAAAA">
-                  /12
+                  {{ item.fastCharging }}
                 </text>
               </view>
             </view>
@@ -154,10 +182,7 @@ function handleFilterClick(filterKey: string) {
               </view>
               <view class="flex items-center">
                 <text class="text-32rpx font-bold">
-                  12
-                </text>
-                <text class="text-24rpx text-#AAAAAA">
-                  /12
+                  {{ item.slowCharging }}
                 </text>
               </view>
             </view>
@@ -166,15 +191,15 @@ function handleFilterClick(filterKey: string) {
                 <wd-icon name="location" size="16px" color="#FFF" />
               </view>
               <view class="text-24rpx text-#3EB6F8">
-                1.55km
+                {{ item.distance }}km
               </view>
             </view>
           </view>
-          <view class="mt-28rpx flex items-center justify-between">
+          <view v-if="!item.enterprisePrice" class="mt-28rpx flex items-center justify-between">
             <view class="relative flex">
               <view class="absolute left-30rpx z-10 flex items-center -top-26rpx">
                 <text class="text-40rpx text-#FF6464 font-bold">
-                  1.0026
+                  {{ item.platformPrice }}
                 </text>
                 <text class="w-100rpx text-24rpx">
                   元/度
@@ -186,11 +211,32 @@ function handleFilterClick(filterKey: string) {
               />
             </view>
             <view class="text-24rpx text-#2B303A">
-              峰:10:00-13:00
+              {{ item.peakValue }}:{{ item.peakTime }}
+            </view>
+          </view>
+          <view v-else class="mt-20rpx flex items-center justify-between">
+            <view class="flex items-center">
+              <view class="flex items-center -mt-10rpx">
+                <text class="text-40rpx text-#FF6464 font-bold">
+                  {{ item.platformPrice }}
+                </text>
+                <text class="w-100rpx text-24rpx">
+                  元/度
+                </text>
+              </view>
+              <view class="h-52rpx w-212rpx text-center" :style="{ backgroundImage: `url(${StaticUrl}/charge-firm.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }">
+                <text class="ml-70rpx text-28rpx text-#FF6464">
+                  {{ item.enterprisePrice }}
+                </text>
+              </view>
+            </view>
+            <view class="text-24rpx text-#2B303A">
+              {{ item.peakValue }}:{{ item.peakTime }}
             </view>
           </view>
         </view>
       </view>
+      <view class="h-160rpx" />
     </view>
     <chargeFooter />
   </view>

+ 1 - 0
src/uni-pages.d.ts

@@ -31,6 +31,7 @@ type _LocationUrl =
   "/subPack-smqjh/order/index" |
   "/subPack-charge/chargeDetail/chargeDetail" |
   "/subPack-charge/chargeing/chargeing" |
+  "/subPack-charge/chargeMap/chargeMap" |
   "/subPack-charge/chargeSiteDetail/chargeSiteDetail" |
   "/subPack-charge/chargeStart/chargeStart" |
   "/subPack-charge/index/index";