Преглед изворни кода

feat(app): 新增优惠券相关接口及兑换功能组件

- 新增优惠券分页查询、详情查询、兑换明细和积分兑换接口定义
- 添加优惠券信息相关类型声明及返回数据结构
- 优化401未授权错误处理,清除用户信息并提示重新登录
- 新增积分兑换弹窗组件integralPopup,实现优惠券积分兑换展示与确认功能
- 新增状态提示组件StatusTip,支持自定义显示图片与大小
- 热更新开发环境API基础地址
- 修正加油确认页输入类型为digit,优化油号选择UI布局
- 新增支付成功页面paySuccess,显示支付结果及订单信息,支持查看订单与申请发票
- 优化加油站详情页,展示可用抵扣券列表及积分兑换操作
- 添加跳转过渡页transition用于支付后流程控制
- 修复首页优惠券支持状态显示逻辑错误,调整tab头z-index值
- 调整manifest配置格式,修复格式错误导致配置无效问题
zhangtao пре 6 дана
родитељ
комит
990c780e27

+ 3 - 1
.env.development

@@ -4,7 +4,9 @@
 # API 基础 URL - 开发环境
 # VITE_API_BASE_URL=http://192.168.0.19:8080
 # VITE_API_BASE_URL=http://192.168.0.11:8080
-VITE_API_BASE_URL=http://192.168.1.166:8080
+# VITE_API_BASE_URL=http://192.168.1.166:8080
+# VITE_API_BASE_URL=https://smqjh.api.zswlgz.com
+VITE_API_BASE_URL=https://7a8e0952.r28.cpolar.top
 
 # 静态资源基础 URL - 测试环境
 VITE_STATIC_BASE_URL=https://zswl-smqjh.oss-cn-chengdu.aliyuncs.com/static/static

+ 1 - 0
manifest.config.ts

@@ -81,6 +81,7 @@ export default defineManifestConfig({
   'h5': {
     darkmode: true,
     themeLocation: 'theme.json',
+
   },
   'uniStatistics': {
     enable: false,

+ 5 - 0
src/api/apiDefinitions.ts

@@ -22,6 +22,11 @@ export default {
   'app.get_smqjh_system_app_api_coupon_findbyid': ['GET', '/smqjh-system/app-api/coupon/findById'],
   'app.get_smqjh_system_app_api_coupon_exchangeinfo': ['GET', '/smqjh-system/app-api/coupon/exchangeInfo'],
   'app.get_smqjh_system_app_api_coupon_exchangepoints': ['GET', '/smqjh-system/app-api/coupon/exchangePoints'],
+  'app.get_app_api_coupon_page': ['GET', '/app-api/coupon/page'],
+  'app.get_app_api_coupon_findbyid': ['GET', '/app-api/coupon/findById'],
+  'app.get_app_api_coupon_exchangeinfo': ['GET', '/app-api/coupon/exchangeInfo'],
+  'app.get_app_api_coupon_exchangepoints': ['GET', '/app-api/coupon/exchangePoints'],
+  'app.get_smqjh_system_app_api_coupon_findlist': ['GET', '/smqjh-system/app-api/coupon/findList'],
   'general.post_smqjh_auth_oauth2_token': ['POST', '/smqjh-auth/oauth2/token'],
   'general.post_smqjh_auth_api_v1_auth_sms_code': ['POST', '/smqjh-auth/api/v1/auth/sms_code'],
   'general.get_api_v1_auth_captcha': ['GET', '/api/v1/auth/captcha'],

+ 5 - 2
src/api/core/handlers.ts

@@ -34,6 +34,7 @@ export async function handleAlovaResponse(
   // 处理401/403错误(如果不是在handleAlovaResponse中处理的)
   if ((statusCode === 401 || statusCode === 403)) {
     // 如果是未授权错误,清除用户信息并跳转到登录页
+    useUserStore().$reset()
     globalToast.error({ msg: '登录已过期,请重新登录!', duration: 500 })
     const timer = setTimeout(() => {
       clearTimeout(timer)
@@ -42,11 +43,13 @@ export async function handleAlovaResponse(
 
     throw new ApiError('登录已过期,请重新登录!', statusCode, data)
   }
+  console.log(data, 'sdds')
 
   // Handle HTTP error status codes
   if (statusCode >= 400) {
-    globalToast.error(`Request failed with status: ${statusCode}`)
-    throw new ApiError(`Request failed with status: ${statusCode}`, statusCode, data)
+    const message = data as ApiResponse
+    globalToast.error(message.msg as string)
+    throw new ApiError(message.msg as string, statusCode)
   }
 
   // The data is already parsed by UniApp adapter

+ 407 - 66
src/api/globals.d.ts

@@ -591,6 +591,83 @@ export interface NotifyOrderInfoRequest {
    */
   refundTime?: string;
 }
+export interface CouponInfoAppVo {
+  /**
+   * id
+   */
+  id?: string;
+  /**
+   * 活动id
+   */
+  activityId?: string;
+  /**
+   * 活动名称
+   */
+  activityName?: string;
+  /**
+   * 优惠类型 1.满减、2.立减
+   */
+  promotionType?: number;
+  /**
+   * 门槛(单位(分)) 满减时的需要达到什么金额
+   */
+  amountMoney?: number;
+  /**
+   * 面额(单位(分)) 优惠的金额
+   */
+  discountMoney?: number;
+  /**
+   * 库存
+   */
+  inventoryTotal?: number;
+  /**
+   * 实际库存
+   */
+  inventoryActual?: number;
+  /**
+   * 含税采购价(元)
+   */
+  purchasePrice?: number;
+  /**
+   * 优惠券开始时间
+   */
+  couponStartTime?: string;
+  /**
+   * 优惠券结束时间
+   */
+  couponEndTime?: string;
+  /**
+   * 有效期,领取后多少天内有效(单位天)
+   */
+  expirationDate?: number;
+  /**
+   * 创建时间
+   */
+  createTime?: string;
+  /**
+   * 更新时间
+   */
+  updateTime?: string;
+  /**
+   * 标识是否有领取数
+   */
+  receiveSign?: boolean;
+  /**
+   * 过期时间
+   */
+  expirationTime?: string;
+}
+export interface ResultListCouponInfoAppVo {
+  /**
+   * 返回状态码
+   */
+  code?: string;
+  /**
+   * 返回数据对象
+   */
+  data?: CouponInfoAppVo[];
+  msg?: string;
+}
 export interface CaptchaResult {
   /**
    * 验证码唯一标识(用于从Redis获取验证码Code)
@@ -830,72 +907,6 @@ export interface ResultAppCouponDetailsVO {
   data?: AppCouponDetailsVO;
   msg?: string;
 }
-export interface CouponInfoAppVo {
-  /**
-   * id
-   */
-  id?: string;
-  /**
-   * 活动id
-   */
-  activityId?: string;
-  /**
-   * 活动名称
-   */
-  activityName?: string;
-  /**
-   * 优惠类型 1.满减、2.立减
-   */
-  promotionType?: number;
-  /**
-   * 门槛(单位(分)) 满减时的需要达到什么金额
-   */
-  amountMoney?: number;
-  /**
-   * 面额(单位(分)) 优惠的金额
-   */
-  discountMoney?: number;
-  /**
-   * 库存
-   */
-  inventoryTotal?: number;
-  /**
-   * 实际库存
-   */
-  inventoryActual?: number;
-  /**
-   * 含税采购价(元)
-   */
-  purchasePrice?: number;
-  /**
-   * 优惠券开始时间
-   */
-  couponStartTime?: string;
-  /**
-   * 优惠券结束时间
-   */
-  couponEndTime?: string;
-  /**
-   * 有效期,领取后多少天内有效(单位天)
-   */
-  expirationDate?: number;
-  /**
-   * 创建时间
-   */
-  createTime?: string;
-  /**
-   * 更新时间
-   */
-  updateTime?: string;
-  /**
-   * 标识是否有领取数
-   */
-  receiveSign?: boolean;
-  /**
-   * 过期时间
-   */
-  expirationTime?: string;
-}
 export interface DataCouponInfoAppVo {
   list?: CouponInfoAppVo[];
   total?: number;
@@ -2329,6 +2340,336 @@ declare global {
       >(
         config: Config
       ): Alova2Method<ResultCouponExchangePointsVo, 'app.get_smqjh_system_app_api_coupon_exchangepoints', Config>;
+      /**
+       * ---
+       *
+       * [GET] 优惠券活动列表查询
+       *
+       * **path:** /app-api/coupon/page
+       *
+       * ---
+       *
+       * **Query Parameters**
+       * ```ts
+       * type QueryParameters = {
+       *   // 页码
+       *   pageNum?: number
+       *   // 每页记录数
+       *   pageSize?: number
+       * }
+       * ```
+       *
+       * ---
+       *
+       * **Response**
+       * ```ts
+       * type Response = {
+       *   // 返回状态码
+       *   code?: string
+       *   data?: {
+       *     // [items] start
+       *     // [items] end
+       *     list?: Array<{
+       *       // id
+       *       id?: string
+       *       // 活动id
+       *       activityId?: string
+       *       // 活动名称
+       *       activityName?: string
+       *       // 优惠类型 1.满减、2.立减
+       *       promotionType?: number
+       *       // 门槛(单位(分)) 满减时的需要达到什么金额
+       *       amountMoney?: number
+       *       // 面额(单位(分)) 优惠的金额
+       *       discountMoney?: number
+       *       // 库存
+       *       inventoryTotal?: number
+       *       // 实际库存
+       *       inventoryActual?: number
+       *       // 含税采购价(元)
+       *       purchasePrice?: number
+       *       // 优惠券开始时间
+       *       couponStartTime?: string
+       *       // 优惠券结束时间
+       *       couponEndTime?: string
+       *       // 有效期,领取后多少天内有效(单位天)
+       *       expirationDate?: number
+       *       // 创建时间
+       *       createTime?: string
+       *       // 更新时间
+       *       updateTime?: string
+       *       // 标识是否有领取数
+       *       receiveSign?: boolean
+       *       // 过期时间
+       *       expirationTime?: string
+       *     }>
+       *     total?: number
+       *   }
+       *   // 返回处理消息
+       *   msg?: string
+       * }
+       * ```
+       */
+      get_app_api_coupon_page<
+        Config extends Alova2MethodConfig<PageResultCouponInfoAppVo> & {
+          params: {
+            /**
+             * 页码
+             */
+            pageNum?: number;
+            /**
+             * 每页记录数
+             */
+            pageSize?: number;
+          };
+        }
+      >(
+        config: Config
+      ): Alova2Method<PageResultCouponInfoAppVo, 'app.get_app_api_coupon_page', Config>;
+      /**
+       * ---
+       *
+       * [GET] 查询优惠券详情信息
+       *
+       * **path:** /app-api/coupon/findById
+       *
+       * ---
+       *
+       * **Query Parameters**
+       * ```ts
+       * type QueryParameters = {
+       *   couponId: string
+       * }
+       * ```
+       *
+       * ---
+       *
+       * **Response**
+       * ```ts
+       * type Response = {
+       *   // 返回状态码
+       *   code?: string
+       *   data?: {
+       *     // id
+       *     id?: string
+       *     // 活动id
+       *     activityId?: string
+       *     // 活动名称
+       *     activityName?: string
+       *     // 优惠类型 1.满减、2.立减
+       *     promotionType?: number
+       *     // 门槛(单位(分)) 满减时的需要达到什么金额
+       *     amountMoney?: number
+       *     // 面额(单位(分)) 优惠的金额
+       *     discountMoney?: number
+       *     // 库存
+       *     inventoryTotal?: number
+       *     // 实际库存
+       *     inventoryActual?: number
+       *     // 含税采购价(元)
+       *     purchasePrice?: number
+       *     // 优惠券开始时间
+       *     couponStartTime?: string
+       *     // 优惠券结束时间
+       *     couponEndTime?: string
+       *     // 有效期,领取后多少天内有效(单位天)
+       *     expirationDate?: number
+       *     // 创建时间
+       *     createTime?: string
+       *     // 更新时间
+       *     updateTime?: string
+       *     // 标识是否有领取数
+       *     receiveSign?: boolean
+       *     // 过期时间
+       *     expirationTime?: string
+       *   }
+       *   msg?: string
+       * }
+       * ```
+       */
+      get_app_api_coupon_findbyid<
+        Config extends Alova2MethodConfig<ResultCouponInfoAppVo> & {
+          params: {
+            couponId: string;
+          };
+        }
+      >(
+        config: Config
+      ): Alova2Method<ResultCouponInfoAppVo, 'app.get_app_api_coupon_findbyid', Config>;
+      /**
+       * ---
+       *
+       * [GET] 兑换明细
+       *
+       * **path:** /app-api/coupon/exchangeInfo
+       *
+       * ---
+       *
+       * **Query Parameters**
+       * ```ts
+       * type QueryParameters = {
+       *   couponId: string
+       * }
+       * ```
+       *
+       * ---
+       *
+       * **Response**
+       * ```ts
+       * type Response = {
+       *   // 返回状态码
+       *   code?: string
+       *   data?: {
+       *     // id
+       *     id?: string
+       *     // 活动id
+       *     activityId?: string
+       *     // 活动名称
+       *     activityName?: string
+       *     // 优惠类型 1.满减、2.立减
+       *     promotionType?: number
+       *     // 门槛(单位(分)) 满减时的需要达到什么金额
+       *     amountMoney?: number
+       *     // 面额(单位(分)) 优惠的金额
+       *     discountMoney?: number
+       *     // 积分金额
+       *     pointsMoney?: number
+       *     // 总库存
+       *     inventoryTotal?: number
+       *     // 实际库存
+       *     inventoryActual?: number
+       *     // 优惠券开始时间
+       *     couponStartTime?: string
+       *     // 优惠券结束时间
+       *     couponEndTime?: string
+       *     // 有效期,领取后多少天内有效(单位天)
+       *     expirationDate?: number
+       *   }
+       *   msg?: string
+       * }
+       * ```
+       */
+      get_app_api_coupon_exchangeinfo<
+        Config extends Alova2MethodConfig<ResultCouponExchangeVo> & {
+          params: {
+            couponId: string;
+          };
+        }
+      >(
+        config: Config
+      ): Alova2Method<ResultCouponExchangeVo, 'app.get_app_api_coupon_exchangeinfo', Config>;
+      /**
+       * ---
+       *
+       * [GET] 使用积分进行兑换
+       *
+       * **path:** /app-api/coupon/exchangePoints
+       *
+       * ---
+       *
+       * **Query Parameters**
+       * ```ts
+       * type QueryParameters = {
+       *   couponId: string
+       * }
+       * ```
+       *
+       * ---
+       *
+       * **Response**
+       * ```ts
+       * type Response = {
+       *   // 返回状态码
+       *   code?: string
+       *   data?: {
+       *     // 抵扣券id
+       *     id?: string
+       *     // 活动id
+       *     activityId?: string
+       *     // 活动名称
+       *     activityName?: string
+       *     // 门槛(单位(分)) 满减时的需要达到什么金额
+       *     amountMoney?: number
+       *     // 面额(单位(分)) 优惠的金额
+       *     discountMoney?: number
+       *     // 第三方的津贴/券id
+       *     allowanceId?: string
+       *     // 批次id
+       *     batchId?: string
+       *     // 有效期,领取后多少天内有效(单位天)
+       *     expirationDate?: number
+       *   }
+       *   msg?: string
+       * }
+       * ```
+       */
+      get_app_api_coupon_exchangepoints<
+        Config extends Alova2MethodConfig<ResultCouponExchangePointsVo> & {
+          params: {
+            couponId: string;
+          };
+        }
+      >(
+        config: Config
+      ): Alova2Method<ResultCouponExchangePointsVo, 'app.get_app_api_coupon_exchangepoints', Config>;
+      /**
+       * ---
+       *
+       * [GET] 优惠券活动列表查询
+       *
+       * **path:** /smqjh-system/app-api/coupon/findList
+       *
+       * ---
+       *
+       * **Response**
+       * ```ts
+       * type Response = {
+       *   // 返回状态码
+       *   code?: string
+       *   // 返回数据对象
+       *   // [items] start
+       *   // [items] end
+       *   data?: Array<{
+       *     // id
+       *     id?: string
+       *     // 活动id
+       *     activityId?: string
+       *     // 活动名称
+       *     activityName?: string
+       *     // 优惠类型 1.满减、2.立减
+       *     promotionType?: number
+       *     // 门槛(单位(分)) 满减时的需要达到什么金额
+       *     amountMoney?: number
+       *     // 面额(单位(分)) 优惠的金额
+       *     discountMoney?: number
+       *     // 库存
+       *     inventoryTotal?: number
+       *     // 实际库存
+       *     inventoryActual?: number
+       *     // 含税采购价(元)
+       *     purchasePrice?: number
+       *     // 优惠券开始时间
+       *     couponStartTime?: string
+       *     // 优惠券结束时间
+       *     couponEndTime?: string
+       *     // 有效期,领取后多少天内有效(单位天)
+       *     expirationDate?: number
+       *     // 创建时间
+       *     createTime?: string
+       *     // 更新时间
+       *     updateTime?: string
+       *     // 标识是否有领取数
+       *     receiveSign?: boolean
+       *     // 过期时间
+       *     expirationTime?: string
+       *   }>
+       *   msg?: string
+       * }
+       * ```
+       */
+      get_smqjh_system_app_api_coupon_findlist<Config extends Alova2MethodConfig<ResultListCouponInfoAppVo>>(
+        config?: Config
+      ): Alova2Method<ResultListCouponInfoAppVo, 'app.get_smqjh_system_app_api_coupon_findlist', Config>;
     };
     general: {
       /**

+ 3 - 3
src/components.d.ts

@@ -14,16 +14,16 @@ declare module 'vue' {
     GlobalToast: typeof import('./components/GlobalToast.vue')['default']
     IntegralPopup: typeof import('./components/integralPopup.vue')['default']
     PrivacyPopup: typeof import('./components/PrivacyPopup.vue')['default']
+    StatusTip: typeof import('./components/StatusTip.vue')['default']
     WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
     WdConfigProvider: typeof import('wot-design-uni/components/wd-config-provider/wd-config-provider.vue')['default']
+    WdCountDown: typeof import('wot-design-uni/components/wd-count-down/wd-count-down.vue')['default']
     WdGap: typeof import('wot-design-uni/components/wd-gap/wd-gap.vue')['default']
     WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default']
     WdMessageBox: typeof import('wot-design-uni/components/wd-message-box/wd-message-box.vue')['default']
     WdNotify: typeof import('wot-design-uni/components/wd-notify/wd-notify.vue')['default']
     WdPopup: typeof import('wot-design-uni/components/wd-popup/wd-popup.vue')['default']
-    WdRadio: typeof import('wot-design-uni/components/wd-radio/wd-radio.vue')['default']
-    WdRadioGroup: typeof import('wot-design-uni/components/wd-radio-group/wd-radio-group.vue')['default']
-    WdSticky: typeof import('wot-design-uni/components/wd-sticky/wd-sticky.vue')['default']
+    WdStatusTip: typeof import('wot-design-uni/components/wd-status-tip/wd-status-tip.vue')['default']
     WdSwiper: typeof import('wot-design-uni/components/wd-swiper/wd-swiper.vue')['default']
     WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
     WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']

+ 26 - 0
src/components/StatusTip.vue

@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import { statusTipProps } from 'wot-design-uni/components/wd-status-tip/types'
+
+const props = defineProps({ ...statusTipProps, image: { type: String, default: '' }, imageSize: { type: String, default: '248rpx' } })
+
+const StaticUrl = import.meta.env.VITE_STATIC_BASE_URL
+
+const imgs = computed(() => {
+  if (props.image)
+    return `${StaticUrl}/${props.image}`
+  return `${StaticUrl}/status-tip.png`
+})
+</script>
+
+<template>
+  <wd-status-tip v-bind="props">
+    <template #image>
+      <image
+        :style="{ width: imageSize, height: imageSize }"
+        :src="imgs"
+      />
+    </template>
+  </wd-status-tip>
+</template>
+
+<style lang="scss" scoped></style>

+ 27 - 9
src/components/integralPopup.vue

@@ -1,35 +1,49 @@
 <script setup lang="ts">
+import type { CouponExchangeVo } from '@/api/globals'
+
+const props = defineProps<{ couponId: string }>()
 const show = defineModel({ default: false })
+const couponInfo = ref<CouponExchangeVo>()
+
+async function getCouponInfo() {
+  const res = await Apis.app.get_smqjh_system_app_api_coupon_exchangeinfo({ params: { couponId: props.couponId } })
+  couponInfo.value = res.data
+}
+watch(show, () => {
+  if (show.value) {
+    getCouponInfo()
+  }
+})
 </script>
 
 <template>
   <Zpopup v-model="show" bg="#fff">
-    <view class="px24rpx py28rpx">
+    <view v-if="couponInfo" class="px24rpx py28rpx">
       <view class="text-center text-32rpx font-semibold">
         积分兑换
       </view>
       <view class="mt20rpx flex items-center">
         <view class="jf-box mr16rpx flex-shrink-0 rounded-16rpx p20rpx">
           <view class="text-center text-48rpx text-#FF4D3A font-semibold">
-            ¥ 50
+            ¥ {{ couponInfo.discountMoney }}
           </view>
           <view class="my8rpx text-center">
-            满20元可用
+            {{ couponInfo.promotionType === 1 ? `满${couponInfo.amountMoney}减${couponInfo.discountMoney}` : `立减${couponInfo.discountMoney}` }}
           </view>
         </view>
         <view class="ml20rpx">
           <view class="text-32rpx font-semibold">
-            兑换需50积分
+            兑换需{{ couponInfo.pointsMoney }}积分
           </view>
           <view class="text-#aaa">
             <view class="mt10rpx">
-              已兑换:232/1000
+              已兑换:{{ couponInfo.inventoryActual }}/{{ couponInfo.inventoryTotal }}
             </view>
             <view class="mt10rpx">
-              兑换期截至:2026-07-06 23:59:59
+              兑换期截至: {{ couponInfo.couponEndTime }}
             </view>
             <view class="mt10rpx">
-              使用有效期:兑换后15天有效
+              使用有效期:兑换后{{ couponInfo.expirationDate }}天有效
             </view>
           </view>
         </view>
@@ -67,12 +81,16 @@ const show = defineModel({ default: false })
         <wd-button type="info" @click="show = false">
           取消
         </wd-button>
-        <wd-button>确认兑换</wd-button>
+        <wd-button @click="useUserStore().handleExchange(couponInfo)">
+          确认兑换
+        </wd-button>
       </view>
     </FixedLayout>
   </Zpopup>
 </template>
 
 <style scoped>
-
+.jf-box{
+  background: linear-gradient( 180deg, #FFC2BC 0%, rgba(255,238,238,0.16) 57.27%, #FFEFEF 100%);
+}
 </style>

+ 19 - 1
src/pages.json

@@ -73,6 +73,15 @@
       },
       "layout": "tabbar"
     },
+    {
+      "path": "pages/paySuccess/index",
+      "name": "paySuccess",
+      "islogin": true,
+      "style": {
+        "navigationBarTitleText": "支付",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/refuelDetaile/index",
       "name": "refuelDetaile",
@@ -82,12 +91,21 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/transition/index",
+      "name": "transition",
+      "islogin": false,
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/voucher/index",
       "name": "voucher",
       "layout": "tabbar",
       "style": {
-        "navigationBarTitleText": "抵扣卷",
+        "navigationBarTitleText": "抵扣",
         "navigationStyle": "custom"
       }
     }

+ 12 - 14
src/pages/confirmOrder/index.vue

@@ -59,9 +59,9 @@ function handlePay() {
   console.log('handlePay')
 }
 async function handleBlur() {
-  if (Number(refuelMoney.value) < 10) {
-    return useGlobalToast().show('最小金额为10元')
-  }
+  // if (Number(refuelMoney.value) < 10) {
+  //   return useGlobalToast().show('最小金额为10元')
+  // }
   if (!storeDetail.value)
     return
   const nams = storeDetail.value?.itemInfoList?.find(item => item.itemId === refuelNumber.value)?.itemName
@@ -98,7 +98,7 @@ async function goPay() {
     } })
     uni.hideLoading()
     // #ifdef H5
-    window.location.href = res.data as string
+    window.location.href = `${res.data}&redirectUrl=https://smqjh.admin.zswlgz.com/h5/#/pages/transition/index`
     // #endif
   }
   catch {
@@ -163,7 +163,7 @@ async function goPay() {
           加油金额
         </view>
         <view class="mt20rpx bg-#F9F9F9 px24rpx py20rpx">
-          <input v-model="refuelMoney" type="number" class="w-full" placeholder="请输入加油金额,优惠价格计算" @blur="handleBlur">
+          <input v-model="refuelMoney" type="digit" class="w-full" placeholder="请输入加油金额,优惠价格计算" @blur="handleBlur">
         </view>
         <view class="mt20rpx text-#ff4d3a">
           最小金额10元
@@ -190,7 +190,7 @@ async function goPay() {
         <view class="mt16rpx">
           抵扣金额:-¥100
         </view>
-        <template v-if="ThreePrice">
+        <template v-if="ThreePrice && refuelMoney">
           <view class="mb20rpx mt24rpx text-32rpx font-semibold">
             价格明细
           </view>
@@ -235,12 +235,10 @@ async function goPay() {
           油号
         </view>
         <wd-radio-group v-model="refuelNumber" shape="button">
-          <view class="grid grid-cols-5 gap-20rpx">
-            <view v-for="item in storeDetail?.itemInfoList" :key="item.itemId">
-              <wd-radio :value="String(item.itemId)">
-                {{ item.itemName }}
-              </wd-radio>
-            </view>
+          <view class="flex flex-wrap items-center gap-20rpx">
+            <wd-radio v-for="item in storeDetail?.itemInfoList" :key="item.itemId" :value="String(item.itemId)">
+              {{ item.itemName }}
+            </wd-radio>
           </view>
         </wd-radio-group>
         <view v-if="refuelGunList" class="mb20rpx mt20rpx text-32rpx font-semibold">
@@ -323,8 +321,8 @@ async function goPay() {
       </template>
     </Zpopup>
     <FixedLayout>
-      <view :class="[ThreePrice && 'justify-between flex items-center']">
-        <view v-if="ThreePrice" class="text-32rpx text-#FF4A39 font-semibold">
+      <view :class="[ThreePrice && refuelMoney && 'justify-between flex items-center']">
+        <view v-if="ThreePrice && refuelMoney" class="text-32rpx text-#FF4A39 font-semibold">
           <text class="text-24rpx">
           </text><text>{{ ThreePrice?.realPrice ? ThreePrice?.realPrice / 100 : 0 }}</text>

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

@@ -55,7 +55,7 @@ watch(() => currentTab.value, () => {
     </view> -->
     <view class="box-border px24rpx py20px">
       <!-- <wd-sticky :offset-top="-44"> -->
-      <view class="sticky top-0 z999 box-border w-full flex items-center bg-#f9f9f9 pb20rpx pt20rpx">
+      <view class="sticky top-0 z9 box-border w-full flex items-center bg-#f9f9f9 pb20rpx pt20rpx">
         <view v-for="item in tabList" :key="item.value" class="mr28rpx rounded-24rpx px16rpx py8rpx text-24rpx" :class="[currentTab === item.value ? 'bg-[var(--them-color)] text-white ' : 'bg-white']" @click="currentTab = item.value">
           {{ item.label }}
         </view>
@@ -74,7 +74,7 @@ watch(() => currentTab.value, () => {
           {{ item.address }}
         </view>
         <view class="mt20rpx flex items-center justify-between">
-          <view v-if="!item.allowanceClientScheme" class="flex items-center rounded-8rpx bg-#E6E6E6 px12rpx py8rpx">
+          <view v-if="item.allowanceClientScheme" class="flex items-center rounded-8rpx bg-#E6E6E6 px12rpx py8rpx">
             <view class="text-22rpx text-#AAAAAA">
               不支持优惠券
             </view>

+ 160 - 0
src/pages/paySuccess/index.vue

@@ -0,0 +1,160 @@
+<script setup lang="ts">
+import type { PayResultInfoVO } from '@/api/globals'
+
+definePage({
+  name: 'paySuccess',
+  islogin: true,
+  style: {
+    navigationBarTitleText: '支付',
+    navigationStyle: 'custom',
+  },
+})
+
+const outerOrderId = ref('')
+const orderInfo = ref<PayResultInfoVO>()
+const payTime = ref('')
+
+const { send } = useRequest(
+  (orderId: string) => Apis.general.get_smqjh_oms_api_v1_oil_order_payresultinfo({ params: { orderId } }),
+  { immediate: false },
+).onSuccess((res) => {
+  orderInfo.value = res.data.data
+})
+
+onLoad((options: any) => {
+  outerOrderId.value = options.outerOrderId || ''
+  // 记录支付时间
+  const now = new Date()
+  payTime.value = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
+
+  if (outerOrderId.value) {
+    send(outerOrderId.value)
+  }
+})
+
+// 申请开票(占位)
+function handleInvoice() {
+  useGlobalToast().show('功能开发中')
+}
+
+// 查看订单
+function handleViewOrder() {
+  uni.switchTab({ url: '/pages/order/index' })
+}
+
+// 返回首页
+function handleBackHome() {
+  uni.switchTab({ url: '/pages/index/index' })
+}
+</script>
+
+<template>
+  <view class="min-h-100vh bg-#f5f5f5">
+    <!-- 成功状态 -->
+    <view class="flex items-center justify-center py32rpx">
+      <view class="mr12rpx h40rpx w40rpx flex items-center justify-center rounded-full bg-#9ED605">
+        <wd-icon name="check" size="24rpx" color="#fff" />
+      </view>
+      <view class="text-32rpx text-#9ED605 font-semibold">
+        支付成功
+      </view>
+    </view>
+
+    <!-- 订单金额卡片 -->
+    <view class="mx24rpx rounded-16rpx bg-white px28rpx py32rpx">
+      <view class="flex items-center justify-between">
+        <view class="text-28rpx text-#333">
+          订单金额
+        </view>
+        <view class="text-32rpx text-#ff4d3a font-semibold">
+          ¥{{ orderInfo?.totalMoney ? (orderInfo.totalMoney / 100).toFixed(2) : '0.00' }}
+        </view>
+      </view>
+      <view class="mt20rpx flex items-center justify-between">
+        <view class="text-28rpx text-#333">
+          支付时间
+        </view>
+        <view class="text-28rpx text-#666">
+          {{ payTime }}
+        </view>
+      </view>
+    </view>
+
+    <!-- 订单信息卡片 -->
+    <view class="mx24rpx mt20rpx rounded-16rpx bg-white px28rpx py32rpx">
+      <view class="mb24rpx text-30rpx font-semibold">
+        订单信息
+      </view>
+      <view class="flex items-center justify-between py16rpx">
+        <view class="text-28rpx text-#999">
+          平台订单号
+        </view>
+        <view class="text-28rpx text-#333">
+          {{ orderInfo?.orderNumber || '-' }}
+        </view>
+      </view>
+      <view class="flex items-center justify-between py16rpx">
+        <view class="text-28rpx text-#999">
+          小桔订单号
+        </view>
+        <view class="text-28rpx text-#333">
+          {{ orderInfo?.thirdOrderId || outerOrderId || '-' }}
+        </view>
+      </view>
+      <view class="flex items-center justify-between py16rpx">
+        <view class="text-28rpx text-#999">
+          油站
+        </view>
+        <view class="text-28rpx text-#333">
+          {{ orderInfo?.storeName || '-' }}
+        </view>
+      </view>
+      <view class="flex items-center justify-between py16rpx">
+        <view class="text-28rpx text-#999">
+          油号
+        </view>
+        <view class="text-28rpx text-#333">
+          {{ orderInfo?.itemName || '-' }}
+        </view>
+      </view>
+      <view class="flex items-center justify-between py16rpx">
+        <view class="text-28rpx text-#999">
+          油枪
+        </view>
+        <view class="text-28rpx text-#333">
+          {{ orderInfo?.gunNo ? `${orderInfo.gunNo}号枪` : '-' }}
+        </view>
+      </view>
+      <view class="flex items-center justify-between py16rpx">
+        <view class="text-28rpx text-#999">
+          加油量
+        </view>
+        <view class="text-28rpx text-#333">
+          {{ orderInfo?.quantity ? `${orderInfo.quantity}L` : '-' }}
+        </view>
+      </view>
+    </view>
+
+    <!-- 底部按钮 -->
+    <view class="mt48rpx flex items-center justify-center gap-24rpx px48rpx">
+      <wd-button plain size="medium" custom-class="action-btn" @click="handleInvoice">
+        申请开票
+      </wd-button>
+      <wd-button plain size="medium" custom-class="action-btn" @click="handleViewOrder">
+        查看订单
+      </wd-button>
+      <wd-button plain size="medium" custom-class="action-btn" @click="handleBackHome">
+        返回首页
+      </wd-button>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+:deep(.action-btn) {
+  border-color: #333 !important;
+  color: #333 !important;
+  border-radius: 32rpx !important;
+  min-width: 160rpx !important;
+}
+</style>

+ 36 - 15
src/pages/refuelDetaile/index.vue

@@ -1,11 +1,13 @@
 <script setup lang="ts">
-import type { GasStationDetailVO } from '@/api/globals'
+import type { CouponInfoAppVo, GasStationDetailVO } from '@/api/globals'
 import router from '@/router'
 
 definePage({ name: 'refuelDetaile', islogin: false, style: { navigationBarTitleText: '加油站详情', navigationStyle: 'custom' } })
 const StaticUrl = import.meta.env.VITE_STATIC_BASE_URL
 const showModel = ref(false)
 const storeDetail = ref<GasStationDetailVO>()
+const dklist = ref<CouponInfoAppVo[]>([])
+const clickItem = ref<CouponInfoAppVo>()
 onLoad(async (options: any) => {
   await getData(options.id)
 })
@@ -13,6 +15,8 @@ onLoad(async (options: any) => {
 async function getData(storeId: string) {
   const res = await Apis.general.post_smqjh_pms_app_api_v1_product_oil_querystoredetail({ data: { storeId, lat: useUserStore().lat, lon: useUserStore().lng } })
   storeDetail.value = res.data
+  const { data } = await Apis.app.get_smqjh_system_app_api_coupon_findlist()
+  dklist.value = data || []
 }
 function handleShowMap() {
   console.log('show map')
@@ -24,6 +28,15 @@ function handleShowMap() {
     },
   })
 }
+function handleExchange(item: CouponInfoAppVo) {
+  console.log('exchange', item)
+  if (item.receiveSign)
+    return
+  if ((Number(item.inventoryTotal) - Number(item.inventoryActual)) === 0)
+    return
+  clickItem.value = item
+  showModel.value = true
+}
 </script>
 
 <template>
@@ -62,25 +75,33 @@ function handleShowMap() {
           </view>
         </view>
       </view>
-      <view class="mt20rpx rounded-16rpx bg-white px24rpx py28rpx">
+      <view v-if="dklist" class="mt20rpx rounded-16rpx bg-white px24rpx py28rpx">
         <view class="flex items-center">
-          <wd-icon name="check-circle-filled" size="22px" color="#52C41A" />
-          <view class="ml20rpx text-28rpx font-semibold">
-            本站可用抵扣券
-          </view>
+          <template v-if="!storeDetail.allowanceClientScheme">
+            <wd-icon name="check-circle-filled" size="22px" color="#52C41A" />
+            <view class="ml20rpx text-28rpx font-semibold">
+              本站可用抵扣券
+            </view>
+          </template>
+          <template v-else>
+            <wd-icon name="close-circle-filled" size="22px" color="#FF4D3A" />
+            <view class="ml20rpx text-28rpx font-semibold">
+              本站暂无抵扣券
+            </view>
+          </template>
         </view>
-        <view class="mt24rpx flex overflow-x-scroll">
-          <view v-for="item in 10" :key="item" class="jf-box mr16rpx flex-shrink-0 rounded-16rpx p20rpx">
-            <view class="text-center text-36rpx text-#FF4D3A font-semibold">
+        <view v-if="!storeDetail.allowanceClientScheme" class="mt24rpx flex overflow-x-scroll">
+          <view v-for="item in dklist" :key="item.id" :class="[(Number(item.inventoryTotal) - Number(item.inventoryActual)) === 0 || item.receiveSign ? 'bg-#F0F0F0' : 'jf-box']" class="mr16rpx flex-shrink-0 rounded-16rpx p20rpx">
+            <view class="text-center text-36rpx font-semibold" :class="[(Number(item.inventoryTotal) - Number(item.inventoryActual)) === 0 || item.receiveSign ? 'text-#aaa' : 'text-#FF4D3A']">
               <text class="text-20rpx">
-              </text> 50
+              </text> {{ item.discountMoney }}
             </view>
-            <view class="my8rpx text-center">
-              无门槛使用
+            <view class="my8rpx text-center" :class="[(Number(item.inventoryTotal) - Number(item.inventoryActual)) === 0 || item.receiveSign ? 'text-#aaa' : '']">
+              {{ item.amountMoney && item.amountMoney > 0 ? `满${item.amountMoney}减${item.discountMoney}` : `无门槛使用` }}
             </view>
-            <view class="rounded-26rpx bg-#FF4A39 px24rpx py6rpx text-center text-white" @click="showModel = true">
-              积分兑换
+            <view class="rounded-26rpx px24rpx py6rpx text-center" :class="[(Number(item.inventoryTotal) - Number(item.inventoryActual)) === 0 || item.receiveSign ? 'bg-#E6E6E6 text-#aaa' : 'bg-#FF4A39 text-white']" @click="handleExchange(item)">
+              {{ !item.receiveSign ? (Number(item.inventoryTotal) - Number(item.inventoryActual)) === 0 ? '已兑完' : '积分兑换' : '已兑换' }}
             </view>
           </view>
         </view>
@@ -113,7 +134,7 @@ function handleShowMap() {
         立即加油
       </wd-button>
     </FixedLayout>
-    <IntegralPopup v-model="showModel" />
+    <IntegralPopup v-model="showModel" :coupon-id="String(clickItem?.id)" />
   </template>
 </template>
 

+ 49 - 0
src/pages/transition/index.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import router from '@/router'
+
+definePage({
+  name: 'transition',
+  islogin: false,
+  style: {
+    navigationBarTitleText: '',
+    navigationStyle: 'custom',
+  },
+})
+
+const loading = ref(true)
+
+onLoad((options: any) => {
+  console.log(options, 'transition=========================================')
+
+  const payStatus = options.payStatus
+  const outerOrderId = options.outerOrderId || ''
+
+  // 延迟跳转,显示 loading 效果
+  setTimeout(() => {
+    loading.value = false
+
+    if (payStatus === '1') {
+      // 支付成功,跳转支付成功页
+      router.replace({
+        name: 'paySuccess',
+        params: { outerOrderId },
+      })
+    }
+    else {
+      // 支付失败或其他情况,跳转订单列表
+      uni.switchTab({ url: '/pages/order/index' })
+    }
+  }, 2000)
+})
+</script>
+
+<template>
+  <view class="min-h-100vh flex flex-col items-center justify-center bg-#f5f5f5">
+    <wd-loading v-if="loading" size="64rpx" />
+    <view v-if="loading" class="mt24rpx text-28rpx text-#999">
+      正在处理中...
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped></style>

+ 192 - 2
src/pages/voucher/index.vue

@@ -1,14 +1,204 @@
 <script setup lang="ts">
+import type { AppMemberCouponVO } from '@/api/globals'
+
 definePage({
   name: 'voucher',
   layout: 'tabbar',
+  islogin: true,
   style: {
-    navigationBarTitleText: '抵扣',
+    navigationBarTitleText: '抵扣',
     navigationStyle: 'custom',
   },
 })
+
+const StaticUrl = import.meta.env.VITE_STATIC_BASE_URL
+
+// Tab 列表
+const tabList = ref([
+  { label: '可用', value: 0, count: 0 },
+  { label: '已使用', value: 1, count: 0 },
+  { label: '已过期', value: 2, count: 0 },
+])
+const currentTab = ref(0)
+
+// 分页请求
+const { data, send, isLastPage, page } = usePagination(
+  (pageNum, pageSize) => Apis.app.get_smqjh_system_app_api_membercoupon_page({
+    params: { pageNum, pageSize, useStatus: currentTab.value },
+  }),
+  {
+    initialPage: 1,
+    initialPageSize: 10,
+    immediate: false,
+    data: res => res.data?.list,
+    append: true,
+  },
+)
+
+// 切换 Tab
+function handleTabChange(value: number) {
+  currentTab.value = value
+  data.value = []
+  page.value = 1
+  send()
+}
+
+// 去使用
+function handleUse(_item: AppMemberCouponVO) {
+  // TODO: 跳转到使用页面
+  uni.switchTab({ url: '/pages/index/index' })
+}
+
+// 取消订单(占位)
+function handleCancelOrder(_item: AppMemberCouponVO) {
+  useGlobalToast().show('功能开发中')
+}
+
+// 付款(占位)
+function handlePay(_item: AppMemberCouponVO) {
+  useGlobalToast().show('功能开发中')
+}
+
+// 计算倒计时剩余毫秒数
+function getCountdownTime(orderCreateTime?: string): number {
+  if (!orderCreateTime)
+    return 0
+  const createTime = new Date(orderCreateTime).getTime()
+  const expireTime = createTime + 15 * 60 * 1000 // 假设15分钟支付有效期
+  const remaining = expireTime - Date.now()
+  return remaining > 0 ? remaining : 0
+}
+
+onShow(() => {
+  data.value = []
+  page.value = 1
+  send()
+})
+
+onReachBottom(() => {
+  if (!isLastPage.value) {
+    page.value++
+  }
+})
+
+watch(() => currentTab.value, () => {
+  data.value = []
+  page.value = 1
+  send()
+})
 </script>
 
 <template>
-  <view> 12</view>
+  <view class="min-h-100vh bg-#f5f5f5">
+    <!-- Tab 切换 -->
+    <view class="sticky top-0 z-10 flex items-center bg-white px24rpx">
+      <view
+        v-for="item in tabList"
+        :key="item.value"
+        class="mr48rpx py24rpx text-28rpx"
+        :class="[currentTab === item.value ? 'text-[var(--them-color)] font-semibold border-b-4rpx border-[var(--them-color)]' : 'text-#666']"
+        @click="handleTabChange(item.value)"
+      >
+        {{ item.label }}
+      </view>
+    </view>
+
+    <!-- 券列表 -->
+    <view class="px24rpx pt20rpx">
+      <view
+        v-for="item in data"
+        :key="item.id"
+        class="mb20rpx rounded-16rpx bg-white px24rpx py28rpx"
+      >
+        <!-- 券信息头部 -->
+        <view class="flex items-center justify-between">
+          <view class="flex items-center">
+            <image
+              :src="`${StaticUrl}/smqjh-reful-juan.png`"
+              class="mr12rpx h32rpx w32rpx"
+            />
+            <view class="text-30rpx font-semibold">
+              抵扣{{ item.discountMoney }}元(满{{ item.amountMoney }}元可用)
+            </view>
+          </view>
+          <!-- 待支付倒计时 -->
+          <view v-if="item.lockStatus === 1 && currentTab === 0" class="text-24rpx text-#1890ff">
+            待支付(<wd-count-down :time="getCountdownTime(item.orderCreateTime)" format="还剩mm:ss" />)
+          </view>
+        </view>
+
+        <!-- 券详情 -->
+        <view class="mt16rpx text-26rpx text-#999">
+          适用:全部合作油站
+        </view>
+        <view class="mt12rpx text-26rpx text-#999">
+          有效期至:{{ item.expirationTime }}
+        </view>
+        <view class="mt12rpx text-26rpx text-#999">
+          可抵扣:<text class="text-#ff4d3a">
+            ¥{{ item.discountMoney }}
+          </text>
+        </view>
+        <view class="mt12rpx text-26rpx text-#999">
+          状态:{{ item.useStatus === 0 ? '可用' : item.useStatus === 1 ? '已使用' : '已过期' }}
+        </view>
+
+        <!-- 操作按钮区域 -->
+        <view v-if="currentTab === 0" class="mt20rpx">
+          <!-- 未被锁定 - 显示去使用 -->
+          <view v-if="item.lockStatus !== 1" class="flex justify-end">
+            <wd-button size="small" plain custom-class="use-btn" @click="handleUse(item)">
+              去使用
+            </wd-button>
+          </view>
+
+          <!-- 被锁定 - 显示订单信息和操作 -->
+          <view v-else>
+            <view class="flex items-center text-26rpx text-#1890ff">
+              <wd-icon name="info-circle" size="28rpx" color="#1890ff" class="mr8rpx" />
+              当前订单未支付,券被占用
+            </view>
+            <view class="mt16rpx flex items-center justify-between">
+              <view class="text-26rpx text-#999">
+                订单号:{{ item.lockOrderId }}
+              </view>
+              <view class="flex items-center gap-16rpx">
+                <wd-button size="small" plain custom-class="cancel-btn" @click="handleCancelOrder(item)">
+                  取消订单
+                </wd-button>
+                <wd-button size="small" plain custom-class="pay-btn" @click="handlePay(item)">
+                  付款
+                </wd-button>
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 空状态 -->
+      <view v-if="data && data.length === 0" class="flex flex-col items-center pt100rpx">
+        <StatusTip tip="暂无抵扣券" />
+      </view>
+    </view>
+  </view>
 </template>
+
+<style lang="scss" scoped>
+:deep(.use-btn) {
+  border-color: #333 !important;
+  color: #333 !important;
+  border-radius: 32rpx !important;
+}
+
+:deep(.cancel-btn) {
+  border-color: #999 !important;
+  color: #999 !important;
+  border-radius: 32rpx !important;
+}
+
+:deep(.pay-btn) {
+  border-color: #333 !important;
+  color: #333 !important;
+  border-radius: 32rpx !important;
+}
+</style>

+ 69 - 27
src/store/user.ts

@@ -31,33 +31,73 @@ export const useUserStore = defineStore('user', {
     getLocationH5() {
       return new Promise((resolve, reject) => {
         uni.showLoading({ mask: true, title: '获取位置中...' })
-        uni.getLocation({
-          type: 'wgs84',
-          isHighAccuracy: true,
-          altitude: true,
-          success: (res) => {
-            uni.hideLoading()
-            console.log('H5位置获取成功', res)
-            this.lat = Number(res.latitude.toFixed(6))
-            this.lng = Number(res.longitude.toFixed(6))
-            resolve(true)
-          },
-          fail: (err) => {
-            uni.hideLoading()
-            reject(new Error('获取位置失败'))
-            console.log('H5获取位置失败', err)
-            const errMsg = err.errMsg || ''
-            if (errMsg.includes('auth deny') || errMsg.includes('authorize')) {
-              useGlobalToast().show('请授权位置权限')
-            }
-            else if (errMsg.includes('timeout')) {
-              useGlobalToast().show('获取位置超时,请重试')
-            }
-            else {
-              useGlobalToast().show(`获取定位失败:${errMsg}`)
-            }
-          },
-        })
+        if (navigator.geolocation) {
+          // 调用定位接口(enableHighAccuracy:是否高精度定位)
+          navigator.geolocation.getCurrentPosition(
+            // 定位成功回调(返回经纬度)
+            (position) => {
+              this.lat = Number(position.coords.latitude.toFixed(6))
+              this.lng = Number(position.coords.longitude.toFixed(6))
+              resolve(true)
+              uni.hideLoading()
+            },
+            // 定位失败回调(处理用户拒绝、设备无GPS等情况)
+            (error) => {
+              reject(error.code)
+              uni.hideLoading()
+              switch (error.code) {
+                case error.PERMISSION_DENIED:
+                  console.log('用户拒绝了定位权限')
+                  // 提示用户开启定位:引导打开手机系统定位 + 微信定位权限
+                  useGlobalToast().show('请允许定位权限以获取当前位置')
+                  break
+                case error.POSITION_UNAVAILABLE:
+                  console.log('定位信息不可用')
+                  useGlobalToast().show('无法获取定位,请检查设备GPS是否开启')
+                  break
+                case error.TIMEOUT:
+                  console.log('定位请求超时')
+
+                  useGlobalToast().show('定位超时,请重试')
+                  break
+              }
+            },
+            // 可选配置项
+            {
+              enableHighAccuracy: true, // 开启高精度(GPS定位,耗时稍长),关闭则用网络定位(更快但精度低)
+              timeout: 10000, // 超时时间(10秒)
+              maximumAge: 300000, // 缓存时间(5分钟内重复定位可复用之前结果)
+            },
+          )
+        }
+        else {
+          uni.getLocation({
+            type: 'wgs84',
+            geocode: true,
+            success: (res) => {
+              uni.hideLoading()
+              console.log('H5位置获取成功', res)
+              this.lat = Number(res.latitude.toFixed(6))
+              this.lng = Number(res.longitude.toFixed(6))
+              resolve(true)
+            },
+            fail: (err) => {
+              uni.hideLoading()
+              reject(new Error('获取位置失败'))
+              console.log('H5获取位置失败', err)
+              const errMsg = err.errMsg || ''
+              if (errMsg.includes('auth deny') || errMsg.includes('authorize')) {
+                useGlobalToast().show('请授权位置权限')
+              }
+              else if (errMsg.includes('timeout')) {
+                useGlobalToast().show('获取位置超时,请重试')
+              }
+              else {
+                useGlobalToast().show(`获取定位失败:${errMsg}`)
+              }
+            },
+          })
+        }
       })
     },
 
@@ -155,6 +195,8 @@ export const useUserStore = defineStore('user', {
         })
       }
       catch (error: any) {
+        console.log(error)
+
         uni.hideLoading()
         // 兑换失败,跳转失败页
         router.push({

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

@@ -10,7 +10,9 @@ interface NavigateToOptions {
        "/pages/exchangeFail/index" |
        "/pages/exchangeSuccess/index" |
        "/pages/login/index" |
-       "/pages/refuelDetaile/index";
+       "/pages/paySuccess/index" |
+       "/pages/refuelDetaile/index" |
+       "/pages/transition/index";
 }
 
 interface RedirectToOptions extends NavigateToOptions {}