Преглед на файлове

基础架构+散户加气3.1

chenlei преди 1 година
родител
ревизия
84dc47bdb8
променени са 61 файла, в които са добавени 8415 реда и са изтрити 584 реда
  1. 5 1
      README.md
  2. 1 1
      env/.env
  3. 2 1
      env/.env.development
  4. 31 0
      env/.env.production
  5. 4 0
      env/.env.test
  6. 27 0
      keys/private.wxf69daeba7aec5be4.key
  7. 1 2
      manifest.config.ts
  8. 26 11
      package.json
  9. 6855 343
      pnpm-lock.yaml
  10. 0 1
      scripts/common.js
  11. 2 0
      scripts/test.js
  12. 46 0
      scripts/upload.js
  13. 3 3
      src/App.vue
  14. 31 0
      src/components/business/phone/index.vue
  15. 11 5
      src/components/business/station/index.vue
  16. 42 2
      src/components/container/index.vue
  17. 134 0
      src/components/drawer/index.vue
  18. 52 17
      src/components/flowLine/index.vue
  19. 4 0
      src/components/flowLine1/index.vue
  20. 22 13
      src/components/numer/index.vue
  21. 29 13
      src/components/sticky/index.vue
  22. 2 0
      src/env.d.ts
  23. 1 1
      src/main.ts
  24. 14 20
      src/pages.json
  25. 6 7
      src/pages/account/index.vue
  26. 96 0
      src/pages/cards/index.vue
  27. 111 49
      src/pages/index/index.vue
  28. 4 1
      src/pages/login/index.vue
  29. 4 0
      src/pages/order/createOrder.vue
  30. 2 2
      src/pages/order/index.vue
  31. 17 8
      src/pages/order/orderDetail.vue
  32. 30 13
      src/pages/order/prePay.vue
  33. 6 8
      src/pages/org/index.vue
  34. 2 0
      src/pages/personCenter/index.vue
  35. 1 0
      src/pages/personCenter/password.vue
  36. 3 0
      src/pages/personCenter/userIdCard.vue
  37. 141 0
      src/pages/station/detail.vue
  38. 2 2
      src/pages/truckInfo/detail.vue
  39. 6 1
      src/pages/truckInfo/index.vue
  40. 1 1
      src/pagesSubExample/webview/index.vue
  41. BIN
      src/static/images/defstation.png
  42. BIN
      src/static/images/no-data.png
  43. 6 0
      src/style/_variables.scss
  44. 47 5
      src/style/index.scss
  45. 2 0
      src/types/api.d.ts
  46. 1 1
      src/types/components.ts
  47. 313 0
      src/types/global.d.ts
  48. 5 2
      src/types/page.d.ts
  49. 38 1
      src/types/schemas/custom.d.ts
  50. 5 5
      src/utils/aop/index.ts
  51. 21 3
      src/utils/config/pages.ts
  52. 33 14
      src/utils/container/index.ts
  53. 10 0
      src/utils/func/index.ts
  54. 69 3
      src/utils/func/native.ts
  55. 2 2
      src/utils/store/common.ts
  56. 37 10
      src/utils/store/curPage.ts
  57. 8 1
      src/utils/store/webapi.ts
  58. 3 1
      tsconfig.json
  59. 27 1
      uno.config.ts
  60. 7 6
      vite.config.ts
  61. 4 3
      vitePlugin.ts

+ 5 - 1
README.md

@@ -32,7 +32,9 @@
 ## 🔗 发布
 
 - web平台: `pnpm build:h5`,打包后的文件在 `dist/build/h5`,可以放到web服务器,如nginx运行。如果最终不是放在根目录,可以在 `manifest.config.ts` 文件的 `h5.router.base` 属性进行修改。
-- weixin平台:`pnpm build:mp-weixin`, 打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。
+- weixin平台:开发环境:`pnpm build:d:mp`、
+  测试环境:`pnpm build:t:mp`、 生产环境:`pnpm build:mp`。
+  均可自动上传到对应的小程序后台, 打包后的文件在 `dist/build/mp-weixin`,可用微信开发者工具导入查看效果。
 - APP平台:`pnpm build:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/build/app` 文件夹,选择发行 - APP云打包。
 
 ## 📦 TODO
@@ -59,3 +61,5 @@
 - 20.公共请求框架,根据swagger导入接口信息支持增量导入。
 - 21.页面方法公共初始化,对页面方法进行集中拦截、公共管控,已支持自动为对象内所有方法增加防重提功能(同步方法、异步方法执行中再次触发不执行) 。
 - 22.微信小程序环境支持websocket-stomp协议,收银员扫描驾驶员二维码创建订单后,驾驶员端自动跳转待支付页面。
+- 23.构建项目时自动化上传体验版至小程序后台。√
+- 24.构建项目时可区分开发、测试、生成环境,编写对应的命令。√

+ 1 - 1
env/.env

@@ -9,7 +9,7 @@ VITE_APP_PUBLIC_BASE=/auyen-mobile/
 
 VITE_SERVER_BASEURL = 'https://dapi.auyen.com'
 VITE_RESOURCE_BASEURL = 'https://dwx.auyen.com'
-
+VITE_WEBSOCKET_BASEURL = 'wss://dwx.auyen.com'
 # h5是否需要配置代理
 VITE_APP_PROXY=true
 VITE_APP_PROXY_PREFIX = '/api'

+ 2 - 1
env/.env.development

@@ -8,4 +8,5 @@ VITE_DELETE_CONSOLE = false
 VITE_SHOW_SOURCEMAP = true
 
 VITE_SERVER_BASEURL = 'https://dapi.auyen.com'
-# VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
+VITE_RESOURCE_BASEURL = 'https://dwx.auyen.com'
+VITE_WEBSOCKET_BASEURL = 'wss://dwx.auyen.com'

+ 31 - 0
env/.env.production

@@ -5,4 +5,35 @@ VITE_DELETE_CONSOLE = true
 # 是否开启sourcemap
 VITE_SHOW_SOURCEMAP = false
 
+## 微信小程序appid
+# 开发环境
+# VITE_WX_APPID = 'wxf69daeba7aec5be4'
+# 测试环境
+# VITE_WX_APPID = 'wx0f5cb3758131bea7'
+# 生产环境
+VITE_WX_APPID = 'wx72ba78af2cf68cf0'
+
+## 服务域名
+# 开发环境
+# VITE_SERVER_BASEURL = 'https://dapi.auyen.com'
+# 测试环境
+# VITE_SERVER_BASEURL = 'https://tapi.auyen.com'
+# 生产环境
 VITE_SERVER_BASEURL = 'https://api.auyen.com'
+
+## 静态资源地址
+# 开发环境
+# VITE_RESOURCE_BASEURL = 'https://dwx.auyen.com'
+# 测试环境
+# VITE_RESOURCE_BASEURL = 'https://twx.auyen.com'
+# 生产环境
+VITE_RESOURCE_BASEURL = 'https://wx.auyen.com'
+
+## websocket
+# 开发环境
+# VITE_WEBSOCKET_BASEURL = 'wss://dwx.auyen.com'
+# 测试环境
+# VITE_WEBSOCKET_BASEURL = 'wss://twx.auyen.com'
+# 生产环境
+VITE_WEBSOCKET_BASEURL = 'wss://wx.auyen.com'
+

+ 4 - 0
env/.env.test

@@ -1,6 +1,10 @@
 # 变量必须以 VITE_ 为前缀才能暴露给外部读取
 NODE_ENV = 'test'
+VITE_WX_APPID = 'wx0f5cb3758131bea7'
+
 # 是否去除console 和 debugger
 VITE_DELETE_CONSOLE = false
 
 VITE_SERVER_BASEURL = 'https://tapi.auyen.com'
+VITE_RESOURCE_BASEURL = 'https://twx.auyen.com'
+VITE_WEBSOCKET_BASEURL = 'wss://twx.auyen.com'

+ 27 - 0
keys/private.wxf69daeba7aec5be4.key

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAmQxOAb9pbdnh0Ohu87YMHqEXd0DsL+Ily6xZNwtLGTDPXyJf
+fxT0b8NzIAsapPAa0+Id2ifi5W7wTQB406Y713BgvGuMpuK6atmdJ6BUs0BaZPkw
+jrDg9VptjQHQsbmt3GC5DSu/s4ZyxbcZAA1YPK6u7MLyLk8tZw41rccdyOkMhqWe
+bHSfoapXpT8hFIv2bsChnZyqhcIUlu7Qsbik6qrtJhGQ91B88S270YLs+09WQDkl
+Gy2iVY6gg6EPBEzLeCcSuOjIgt6sRTlRvYaKiReaL7CmCWGu6UUiNchgFEq9GVXK
+Ck0GSmwmRy5p5B3pezfnPBfdf1DzLVeHbM2MQQIDAQABAoIBAEWKU79zi6IASBy2
+IAPYifU42QK0mxy+stGyg+8A0KSnivH9GksR6GcH9b1vjjG3b1kq+slvKid5mvJB
+7qSsebBQPYQfkg8aIf3+1ut0bEfuS6RpnWiYcf7JkdFqK7s1VQw3Xp3fbQFTa77u
+jQt7BMa90Hl/sq7cBxM2X6mQObZZihKF8R4E8GZsEW471zbjzWYvJYfWPeqzbfyW
+s2QgHcamWo1IfYHPh5+EvnUF0K/dlHXJ4hvKl27VO1ZngLWyGT1Ek0DjhtxWyTNe
+FFxPHG1QsT1f1s+t1zzchrFdwzSeGu7aUxbFRvZQGoJbxvGWxpxMwjVjcrDiSJkm
+k6tA74ECgYEAySwZ63TrBgahF7i/J8xAMVoq/SBo6lkEhwrKnPm8bOMJfFs14I7e
+YX0FwSfOlLN/v+Q7gZvyyacbs5yzdGW0csz9DpMQY14/HUvX7k6N88UARsQ0hIyO
+imC6V5I0Kn1luOBbBerLelRi3ivUpngQbXd/EXl4yPcjh8zhamlX4ZkCgYEAwsKN
+LkyT+0XAF0ZcirgmmBntWeBTsvY0/jgKRheEzt2FirCGfIxw22FXx0W4N0nEyWnY
+mpflqESzYkVQwGspRAYwszzprVdmYCL6iW281XOHL0KxEbmVGWci7VHr0xURwkaW
+GKf0JXjE/2PNo5oDrqQuUQoMPlyiU0I1C2iN+OkCgYBWRi2PhwLMAMfRbo+8N6JI
+CA1rpRyZdDe22m/uRkQCxpNo240NkvfYA1AWeEXmC9z7pJvIh+LljF8a9lcX0g5D
+NZpJR9S9aMvUepRORS4nnxLxRm/ncIgo3DbOG4t3tXOMh9tBfGJrQglskouOIOua
+pqa+DcQ5G5QHR1xc0HS58QKBgCZi3Bq1AzGyRLMRrim1M/4klhBx021hc35rozK/
+bfCr3qdANbGUqKXEoN1o028qPfwIvaVyrNQmfkivKsRSGrcKlUyug8wjfs0R99lg
+ZKiZdZqOBYJd1pJELrEhxV48N9zXtruzVr6P+BvyGtTVBUbFm09jsJgV//RzBytx
+dxIJAoGBAJU1PuVT/846n+ewj2vFMLwoa1eczcylXVDghKwSLxaCk3is7Fy7SiO8
+wDbx+25PX4/8yITq6oTR/6iqlVYDJdfvfJtjO9SjVJt8S05Bl5JdGiKNs/OHG/xv
+GfIOwUjy9t1ieFk5hi+NkgIS+t1Jh5DgeHscIAzs59UVqNsp5CFS
+-----END RSA PRIVATE KEY-----

+ 1 - 2
manifest.config.ts

@@ -4,7 +4,7 @@ import path from 'node:path'
 import { loadEnv } from 'vite'
 
 // 获取环境变量的范例
-const env = loadEnv(process.env.NODE_ENV!, path.resolve(process.cwd(), 'env'))
+const env = loadEnv(process.env.VITE_MODE, path.resolve(process.cwd(), 'env'))
 const {
   VITE_APP_TITLE,
   VITE_UNI_APPID,
@@ -12,7 +12,6 @@ const {
   VITE_APP_PUBLIC_BASE,
   VITE_FALLBACK_LOCALE,
 } = env
-
 export default defineManifestConfig({
   name: VITE_APP_TITLE,
   appid: VITE_UNI_APPID,

+ 26 - 11
package.json

@@ -43,7 +43,10 @@
     "build": "uni build",
     "build:h5:ssr": "uni build --ssr",
     "build:mp-alipay": "uni build -p mp-alipay",
-    "build:mp": "uni build -p mp-weixin",
+    "build:d:mp": "uni build -p mp-weixin --mode=development",
+    "build:dp:mp": "uni build -p mp-weixin --mode=development && node ./scripts/upload.js development",
+    "build:tp:mp": "uni build -p mp-weixin --mode=test && node ./scripts/upload.js test",
+    "build:mp": "uni build -p mp-weixin && node ./scripts/upload.js",
     "build:mp-baidu": "uni build -p mp-baidu",
     "build:mp-jd": "uni build -p mp-jd",
     "build:mp-kuaishou": "uni build -p mp-kuaishou",
@@ -73,11 +76,21 @@
     "bin-wrapper": "npm:bin-wrapper-china"
   },
   "dependencies": {
-    "@dcloudio/uni-app": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/uni-app-plus": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/uni-components": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/uni-h5": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/uni-mp-weixin": "3.0.0-alpha-4020220240624001",
+    "@dcloudio/uni-app": "3.0.0-4020920240930001",
+    "@dcloudio/uni-app-harmony": "3.0.0-4020920240930001",
+    "@dcloudio/uni-app-plus": "3.0.0-4020920240930001",
+    "@dcloudio/uni-components": "3.0.0-4020920240930001",
+    "@dcloudio/uni-h5": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-alipay": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-baidu": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-jd": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-kuaishou": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-lark": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-qq": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-toutiao": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-weixin": "3.0.0-4020920240930001",
+    "@dcloudio/uni-mp-xhs": "3.0.0-4020920240930001",
+    "@dcloudio/uni-quickapp-webview": "3.0.0-4020920240930001",
     "@dcloudio/uni-ui": "^1.5.5",
     "czg": "^1.9.3",
     "dayjs": "1.11.10",
@@ -88,17 +101,17 @@
     "stompjs": "^2.3.3",
     "vant": "3.6.12",
     "vue": "3.4.21",
+    "vue-i18n": "^9.1.9",
     "z-paging": "^2.7.10"
   },
   "devDependencies": {
-    "vconsole": "^3.15.1",
     "@commitlint/cli": "^18.6.1",
     "@commitlint/config-conventional": "^18.6.3",
     "@dcloudio/types": "^3.4.8",
-    "@dcloudio/uni-automator": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/uni-cli-shared": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/uni-stacktracey": "3.0.0-alpha-4020220240624001",
-    "@dcloudio/vite-plugin-uni": "3.0.0-alpha-4020220240624001",
+    "@dcloudio/uni-automator": "3.0.0-4020920240930001",
+    "@dcloudio/uni-cli-shared": "3.0.0-4020920240930001",
+    "@dcloudio/uni-stacktracey": "3.0.0-4020920240930001",
+    "@dcloudio/vite-plugin-uni": "3.0.0-4020920240930001",
     "@esbuild/darwin-arm64": "0.20.2",
     "@esbuild/darwin-x64": "0.20.2",
     "@iconify-json/carbon": "^1.1.35",
@@ -126,6 +139,7 @@
     "eslint-plugin-vue": "^9.26.0",
     "husky": "^8.0.3",
     "lint-staged": "^15.2.7",
+    "miniprogram-ci": "^2.0.10",
     "postcss": "^8.4.38",
     "postcss-html": "^1.7.0",
     "postcss-scss": "^4.0.9",
@@ -143,6 +157,7 @@
     "unocss": "^0.58.9",
     "unocss-applet": "^0.7.8",
     "unplugin-auto-import": "^0.17.6",
+    "vconsole": "^3.15.1",
     "vite": "5.2.8",
     "vite-plugin-restart": "^0.4.0",
     "vue-tsc": "^1.8.27"

Файловите разлики са ограничени, защото са твърде много
+ 6855 - 343
pnpm-lock.yaml


+ 0 - 1
scripts/common.js

@@ -83,7 +83,6 @@ const files = {
     } catch {}
   },
 }
-
 module.exports = {
   cl,
   request,

+ 2 - 0
scripts/test.js

@@ -0,0 +1,2 @@
+const os = require('os')
+console.log(os.hostname())

+ 46 - 0
scripts/upload.js

@@ -0,0 +1,46 @@
+/* eslint-disable import/extensions */
+/* eslint-disable @typescript-eslint/no-var-requires */
+const path = require('node:path')
+const { loadEnv } = require('vite')
+const dayjs = require('dayjs')
+const common = require('./common.js')
+const args = process.argv.slice(2) // 去掉第一个和第二个参数(node路径和脚本路径)
+
+const env = loadEnv(args[0], path.resolve(process.cwd(), 'env'))
+// console.log(env)
+const os = require('os')
+const { cl } = common
+
+// 获取当前工作目录的父路径
+const projectDir = path.join(__dirname, '../')
+const ci = require('miniprogram-ci')
+
+const project = new ci.Project({
+  appid: env.VITE_WX_APPID,
+  type: 'miniProgram',
+  projectPath: `${projectDir}/dist/build/mp-weixin`,
+  privateKeyPath: `${projectDir}/keys/private.${env.VITE_WX_APPID}.key`,
+  // ignores: ['node_modules/**/*'],
+})
+cl.logw('上传中...')
+ci.upload({
+  project,
+  version: '2.1.0',
+  desc: `${os.hostname()}于 ${dayjs().format('YYYY-MM-DD HH:mm:ss')} 自动提交上传`,
+  setting: {
+    es6: true,
+    es7: true,
+    minify: true,
+    // autoPrefixWXSS: true,
+    minifyWXML: true,
+    minifyWXSS: true,
+    minifyJS: true,
+    codeProtect: true,
+  },
+  threads: 8,
+  onProgressUpdate: console.log,
+}).then((uploadResult) => {
+  console.log(uploadResult)
+  cl.logs('上传成功!')
+  process.exit(0)
+})

+ 3 - 3
src/App.vue

@@ -2,9 +2,9 @@
 onLaunch(() => {
   //   uni.hideHomeButton()
 })
-// onShow(() => {
-//   console.log('App Show')
-// })
+onShow((options) => {
+  ay.staticData.args.options = options
+})
 // onHide(() => {
 //   console.log('App Hide')
 // })

+ 31 - 0
src/components/business/phone/index.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="gray-color" :class="{ 'text-center': props.center }">
+    {{ props.desc }}
+    <span :class="{ 'p-color': props.phone }" @click="methods.phone">
+      <uni-icons type="phone-filled" color="" class="mr-spacd4" size="none"></uni-icons>
+      <span>{{ func.convert.nullView(props.phone) }}</span>
+    </span>
+  </div>
+</template>
+<script lang="ts" setup>
+defineOptions({
+  name: '',
+})
+
+const props = withDefaults(defineProps<{ desc: string; phone: string; center: boolean }>(), {
+  desc: '',
+  center: true,
+  phone: store.common.data.phone,
+})
+const data = {}
+const methods = {
+  phone() {
+    if (props.phone) {
+      uni.makePhoneCall({
+        phoneNumber: props.phone,
+      })
+    }
+  },
+}
+</script>
+<style lang="scss" scoped></style>

+ 11 - 5
src/components/business/station/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="center justify-between chunk station">
+  <div class="center justify-between chunk station" @click="methods.goDetail('1')">
     <div>
       <image class="mr-spac sta-img" :src="props.stationInfo.url" mode="scaleToFill" />
     </div>
@@ -24,13 +24,14 @@
     </div>
     <div>
       <!-- <div class="s-fz distance">{{ props.stationInfo.distance }} km</div> -->
-      <div class="p-color s-fz detail" v-if="props.type === '2'">
+      <div class="p-color s-fz detail" v-if="props.type === '2'" @click="methods.goDetail('2')">
         详情
         <uni-icons type="right" color="" size="12" />
       </div>
       <div
-        class="center p-color s-fz location"
-        @click="methods.openLocation"
+        class="center s-fz location p-color"
+        :class="{ 'gray-color': !props.stationInfo.longitude }"
+        @click.stop="methods.openLocation"
         v-if="props.type === '1'"
       >
         导航
@@ -53,8 +54,13 @@ const props = withDefaults(defineProps<PropTypes>(), {
 })
 const data = {}
 const methods = {
+  goDetail(type) {
+    if (type === props.type) {
+      ay.goPage(config.pages.station_detail, { params: props.stationInfo })
+    }
+  },
   openLocation() {
-    uni.openLocation({
+    func.native.openLocation({
       latitude: Number(props.stationInfo.latitude),
       longitude: Number(props.stationInfo.longitude),
       name: props.stationInfo.nickName,

+ 42 - 2
src/components/container/index.vue

@@ -1,6 +1,25 @@
 <template>
   <!-- 小程序环境 会把$attrs 解析到最外层标签(虚拟标签,导致无效),只能使用自定义参数 -->
-  <div class="container" :style="props.cusStyle">
+  <div class="container" :style="cusStyle">
+    <ay-sticky
+      top="0px"
+      v-if="store.curPage.pageData?.pageConfig?.style?.navigationStyle === 'custom'"
+    >
+      <div class="page-custom" :style="{ height: props.topHeight }">
+        <div class="center justify-start page-title">
+          <uni-icons
+            class="mr-spacd4"
+            v-if="props.showBackIcon"
+            type="left"
+            color=""
+            size="24"
+            @click="ay.navigateBack()"
+          />
+          <div class="font-bold bs-fz">{{ title }}</div>
+        </div>
+      </div>
+    </ay-sticky>
+
     <!-- 小程序内只能用v-if移除组件,如果用v-show条件false时,整个页面不显示。。 -->
     <ay-pull v-if="store.curPage.pageConfig?.isPager">
       <slot />
@@ -12,7 +31,28 @@
 defineOptions({
   name: 'container',
 })
-const props = defineProps<{ cusStyle?: AnyObject }>()
+const props = withDefaults(
+  defineProps<{
+    cusStyle?: AnyObject
+    title?: string
+    topHeight: string
+    showBackIcon?: boolean
+  }>(),
+  {
+    topHeight: `${config.common.SystemInfo.safeArea.top + 44}px`,
+  },
+)
+const title = computed(() => props.title || store.curPage.pageConfig.title)
+const cusStyle = computed(() => {
+  let rv = props.cusStyle
+  if (title.value) {
+    rv = {
+      'padding-top': 0,
+      ...rv,
+    }
+  }
+  return rv
+})
 </script>
 <style lang="scss" scoped>
 .container {

+ 134 - 0
src/components/drawer/index.vue

@@ -0,0 +1,134 @@
+<template>
+  <view
+    v-if="data.visibleSync"
+    :class="{ 'uni-drawer--visible': data.showDrawer }"
+    class="uni-drawer"
+    :style="{ top: props.top }"
+    @touchmove.stop.prevent="methods.clear"
+  >
+    <view
+      class="uni-drawer__mask"
+      :class="{ 'uni-drawer__mask--visible': data.showDrawer && props.mask }"
+      @tap="methods.close('mask')"
+    />
+    <view
+      class="uni-drawer__content"
+      :class="{
+        'uni-drawer--right': data.rightMode,
+        'uni-drawer--left': !data.rightMode,
+        'uni-drawer__content--visible': data.showDrawer,
+      }"
+      :style="{ width: props.width + 'px' }"
+    >
+      <slot />
+    </view>
+  </view>
+</template>
+
+<script lang="ts" setup>
+const emits = defineEmits(['change'])
+const props = withDefaults(
+  defineProps<{ mode: string; mask: boolean; maskClick: boolean; width: number; top: string }>(),
+  {
+    mode: '',
+    mask: true,
+    maskClick: true,
+    width: 320,
+    top: '',
+  },
+)
+const data = reactive({
+  visibleSync: false,
+  showDrawer: false,
+  rightMode: false,
+  watchTimer: null,
+})
+onMounted(() => {
+  data.rightMode = props.mode === 'right'
+})
+
+const methods = {
+  clear() {},
+  close(type) {
+    // fixed by mehaotian 抽屉尚未完全关闭或遮罩禁止点击时不触发以下逻辑
+    if ((type === 'mask' && !props.maskClick) || !data.visibleSync) return
+    methods._change('showDrawer', 'visibleSync', false)
+  },
+  open() {
+    // fixed by mehaotian 处理重复点击打开的事件
+    if (data.visibleSync) return
+    methods._change('visibleSync', 'showDrawer', true)
+  },
+  _change(param1, param2, status) {
+    data[param1] = status
+    if (data.watchTimer) {
+      clearTimeout(data.watchTimer)
+    }
+    data.watchTimer = setTimeout(
+      () => {
+        data[param2] = status
+        emits('change', status)
+      },
+      50,
+      //   status ? 50 : 300,
+    )
+  },
+}
+defineExpose(methods)
+</script>
+
+<style lang="scss" scoped>
+$uni-mask: rgba(
+  $color: #000000,
+  $alpha: 0.4,
+);
+// 抽屉宽度
+$drawer-width: 220px;
+
+.uni-drawer {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 999;
+  overflow: hidden;
+}
+
+.uni-drawer__content {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  width: $drawer-width;
+  background-color: $uni-bg-color;
+  transition: transform 0.3s ease;
+}
+
+.uni-drawer--left {
+  left: 0;
+}
+
+.uni-drawer--right {
+  right: 0;
+}
+
+.uni-drawer__content--visible {
+  transform: translateX(0px);
+}
+
+.uni-drawer__mask {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  background-color: $uni-mask;
+
+  opacity: 0;
+  transition: opacity 0.3s;
+}
+
+.uni-drawer__mask--visible {
+  opacity: 1;
+}
+</style>

+ 52 - 17
src/components/flowLine/index.vue

@@ -1,11 +1,11 @@
 <template>
   <div class="flow-line">
-    <template v-if="props.loading">
-      <span class="line"></span>
-      <span class="line"></span>
-      <span class="line"></span>
-      <span class="line"></span>
-    </template>
+    <div v-show="data.loading">
+      <span class="line" :style="{ height: props.lineWidth + 'rpx' }"></span>
+      <span class="line" :style="{ width: props.lineWidth + 'rpx' }"></span>
+      <span class="line" :style="{ height: props.lineWidth + 'rpx' }"></span>
+      <span class="line" :style="{ width: props.lineWidth + 'rpx' }"></span>
+    </div>
     <slot />
   </div>
 </template>
@@ -13,13 +13,48 @@
 defineOptions({
   name: 'flow-line',
 })
-const props = defineProps<{ loading: boolean }>()
-const data = {}
+
+const props = withDefaults(
+  defineProps<{ loading: boolean; minLoadTime: number; lineWidth: number }>(),
+  {
+    minLoadTime: 1e3,
+    lineWidth: 2,
+  },
+)
+const data = reactive({
+  loadingTime: 0 as number,
+  loading: false,
+})
+watch(
+  () => props.loading,
+  (nv) => {
+    if (nv) {
+      data.loadingTime = Date.now()
+      data.loading = true
+    } else {
+      const time = Date.now() - data.loadingTime
+      if (time < props.minLoadTime) {
+        func.awaiter(props.minLoadTime - time).then(() => {
+          data.loading = false
+        })
+      } else {
+        data.loading = false
+      }
+    }
+  },
+  {
+    immediate: true,
+  },
+)
+
 const methods = {}
 </script>
 <style lang="scss" scoped>
+$speed: 1s;
+$lineWidth: 2rpx;
 .flow-line {
   position: relative;
+  height: 100%;
   overflow: hidden;
   border-radius: $p-spacd2;
 }
@@ -40,7 +75,7 @@ const methods = {}
 // }
 .line {
   position: absolute;
-  z-index: 1;
+  // z-index: 1;
 }
 
 // $map:(1:(top:0,left:0))
@@ -48,9 +83,9 @@ const methods = {}
   top: 0;
   left: 0;
   width: 100%;
-  height: 4px;
+  height: $lineWidth;
   background: linear-gradient(90deg, transparent, $p-color);
-  animation: move1 0.8s linear infinite;
+  animation: move1 $speed linear infinite;
 }
 @keyframes move1 {
   0% {
@@ -64,10 +99,10 @@ const methods = {}
 .line:nth-child(2) {
   top: -100%;
   right: 0;
-  width: 4px;
+  width: $lineWidth;
   height: 100%;
   background: linear-gradient(180deg, transparent, $p-color);
-  animation: move2 0.8s linear infinite;
+  animation: move2 $speed linear infinite;
   animation-delay: 0.2s;
 }
 @keyframes move2 {
@@ -84,9 +119,9 @@ const methods = {}
   right: -100%;
   bottom: 0;
   width: 100%;
-  height: 4px;
+  height: $lineWidth;
   background: linear-gradient(270deg, transparent, $p-color);
-  animation: move3 0.8s linear infinite;
+  animation: move3 $speed linear infinite;
   animation-delay: 0.4s;
 }
 @keyframes move3 {
@@ -101,10 +136,10 @@ const methods = {}
 .line:nth-child(4) {
   bottom: -100%;
   left: 0;
-  width: 4px;
+  width: $lineWidth;
   height: 100%;
   background: linear-gradient(360deg, transparent, $p-color);
-  animation: move4 0.8s linear infinite;
+  animation: move4 $speed linear infinite;
   animation-delay: 0.6s;
 }
 @keyframes move4 {

+ 4 - 0
src/components/flowLine1/index.vue

@@ -0,0 +1,4 @@
+<template>
+  <div />
+</template>
+<script setup></script>

+ 22 - 13
src/components/numer/index.vue

@@ -1,24 +1,32 @@
 <template>
-  <span>
+  <div>
     <template v-if="props.isSimple">
-      <span v-if="props.pre">{{ props.pre }}</span>
-      <span class="font-bold">{{ props.value }}</span>
-      <span class="unit" v-if="numer.unit">{{ numer.unit }}</span>
+      <div v-if="props.pre">{{ props.pre }}</div>
+      <div v-if="func.isnull(props.value)">
+        {{ props.value }}
+      </div>
+      <div class="font-bold mr-spacd4" v-else>{{ props.value }}</div>
+      <div v-if="numer.unit">{{ numer.unit }}</div>
     </template>
     <template v-else>
-      <span v-if="props.pre">{{ props.pre }}</span>
-      <span class="font-bold b-fz" v-if="numer.integer">{{ numer.integer }}</span>
-      <span class="font-bold" v-if="numer.decimal">{{ numer.decimal }}</span>
-      <span class="unit" v-if="numer.unit">{{ numer.unit }}</span>
+      <div v-if="props.pre">{{ props.pre }}</div>
+      <div v-if="func.isnull(props.value)">
+        {{ props.value }}
+      </div>
+      <div class="mr-spacd4" v-else>
+        <div class="font-bold b-fz" v-if="numer.integer">{{ numer.integer }}</div>
+        <div class="font-bold" v-if="numer.decimal">{{ numer.decimal }}</div>
+      </div>
+      <div v-if="numer.unit">{{ numer.unit }}</div>
     </template>
-  </span>
+  </div>
 </template>
 <script lang="ts" setup>
 type Numer = { integer?: string; decimal?: string; unit: string }
 const props = withDefaults(
-  defineProps<{ isSimple?: boolean; value?: number; pre?: string; unit?: string }>(),
+  defineProps<{ isSimple?: boolean; value?: number | string; pre?: string; unit?: string }>(),
   {
-    value: 0,
+    value: '',
     unit: '',
   },
 )
@@ -33,7 +41,8 @@ const numer = computed(() => {
 </script>
 
 <style lang="scss" scoped>
-.unit {
-  margin-left: $p-spacd4;
+div,
+view {
+  display: inline-block;
 }
 </style>

+ 29 - 13
src/components/sticky/index.vue

@@ -1,39 +1,55 @@
 <template>
-  <div class="sticky" :class="{ stickyed: data.stickyed }">
+  <div class="sticky" :class="{ stickyed: data.stickyed }" :style="{ top: props.top }">
     <slot />
   </div>
 </template>
 <script lang="ts" setup>
 type stickyResult = UniApp.ObserveResult & { stickyed?: boolean }
 const props = withDefaults(
-  defineProps<{ relativeTo: string; targetSelector: string; targetComponent?: any }>(),
-  {},
+  defineProps<{
+    top?: string
+    relativeTo?: string
+    targetSelector?: string
+    targetComponent?: any
+  }>(),
+  {
+    top: '',
+  },
 )
 const emit = defineEmits<{ (e: 'stickChange', sr: stickyResult): void }>()
 const data = reactive({
   stickyed: false,
 })
 onMounted(() => {
-  const iob = uni.createIntersectionObserver(
-    props.targetComponent || getCurrentInstance().parent.parent,
-  )
+  // #ifdef MP
 
-  iob.relativeTo(props.relativeTo).observe(props.targetSelector, (res) => {
-    const sr: stickyResult = res
-    sr.stickyed = res.intersectionRatio > 0
-    data.stickyed = sr.stickyed
-    emit('stickChange', sr)
-  })
+  if (props.relativeTo && props.targetSelector) {
+    const iob = uni.createIntersectionObserver(
+      props.targetComponent || getCurrentInstance().parent.parent,
+    )
+
+    iob.relativeTo(props.relativeTo).observe(props.targetSelector, (res) => {
+      const sr: stickyResult = res
+      console.log(res.intersectionRatio)
+      sr.stickyed = res.intersectionRatio > 0
+      data.stickyed = sr.stickyed
+      emit('stickChange', sr)
+    })
+  }
+  // #endif
 })
 </script>
 
 <style lang="scss" scoped>
 .sticky {
+  // 防止顶部镂空
   top: -1rpx;
   z-index: 1;
+  // 防止部分真机误判相交状态
+  margin-bottom: 1px;
+  background-color: $bg-color;
 }
 .stickyed {
-  background-color: $bg-color;
   border-bottom: 1rpx solid $border-color;
   @extend %box-shadow;
   &::before,

+ 2 - 0
src/env.d.ts

@@ -21,6 +21,8 @@ interface ImportMetaEnv {
   readonly VITE_APP_PROXY_PREFIX: string // 一般是/api
   /** 资源地址域名 */
   readonly VITE_RESOURCE_BASEURL: string
+  /** websocket域名 */
+  readonly VITE_WEBSOCKET_BASEURL: string
   /** 是否清除console */
   readonly VITE_DELETE_CONSOLE: string
   // 更多环境变量...

+ 1 - 1
src/main.ts

@@ -6,7 +6,7 @@ import '@/style/index.scss'
 import { initStore } from './utils/store'
 // #ifdef H5
 import { List } from 'vant'
-import 'vant/lib/index.css'
+// import 'vant/lib/index.css'
 // import Vconsole from 'vconsole'
 // if (import.meta.env.DEV) {
 //   const vc = new Vconsole()

+ 14 - 20
src/pages.json

@@ -22,7 +22,8 @@
       "path": "pages/index/index",
       "type": "home",
       "style": {
-        "enablePullDownRefresh": true
+        "enablePullDownRefresh": false,
+        "navigationStyle": "custom"
       }
     },
     {
@@ -30,6 +31,10 @@
       "type": "page"
     },
     {
+      "path": "pages/cards/index",
+      "type": "page"
+    },
+    {
       "path": "pages/list/index",
       "type": "page"
     },
@@ -53,7 +58,10 @@
     },
     {
       "path": "pages/order/orderDetail",
-      "type": "page"
+      "type": "page",
+      "style": {
+        "navigationStyle": "custom"
+      }
     },
     {
       "path": "pages/order/prePay",
@@ -80,6 +88,10 @@
       "type": "page"
     },
     {
+      "path": "pages/station/detail",
+      "type": "page"
+    },
+    {
       "path": "pages/truckInfo/detail",
       "type": "page"
     },
@@ -116,24 +128,6 @@
           "path": "webview/index",
           "type": "page"
         }
-      ],
-      "cusPages": [
-        {
-          "path": "pagesSubExample/index",
-          "type": "page"
-        },
-        {
-          "path": "pagesSubExample/list/index",
-          "type": "page"
-        },
-        {
-          "path": "pagesSubExample/login/index",
-          "type": "page"
-        },
-        {
-          "path": "pagesSubExample/webview/index",
-          "type": "page"
-        }
       ]
     }
   ]

+ 6 - 7
src/pages/account/index.vue

@@ -6,15 +6,14 @@
     <div class="chunk relative s-fz">
       <div class="yebz absolute" v-if="data.accountInfo.flag === 0">[余额不足]</div>
       <div class="flex items-baseline mb-spacd2">
-        <ay-numer :value="data.accountInfo.totalBalance" :unit="data.accountInfo.unit" />
+        <ay-numer :value="data.accountInfo.showBalance" :unit="data.accountInfo.unit" />
         <span v-if="data.accountInfo.showDet">
-          (直销{{ data.accountInfo.carrierDirectBalance }} | 经销{{
-            data.accountInfo.carrierBalance
-          }})
+          (直销 {{ data.accountInfo.carrierDirectBalance }} | 经销
+          {{ data.accountInfo.carrierBalance }})
         </span>
       </div>
       <div class="mb-spacd4">所属物流:{{ func.convert.nullView(data.accountInfo.orgName) }}</div>
-      <div>车牌号{{ func.convert.nullView(data.accountInfo.carNumber) }}</div>
+      <div>车牌号{{ func.convert.nullView(data.accountInfo.carNumber) }}</div>
     </div>
   </ay-container>
 </template>
@@ -26,7 +25,7 @@ const userTitle = computed(() => {
   return `${ui.user_name}[${ui.mobileDes}]`
 })
 const data = reactive({
-  accountInfo: { showBalance: {} } as IAccountInfo,
+  accountInfo: {} as IAccountInfo,
 })
 
 ay.entrance((args) => {
@@ -42,6 +41,6 @@ ay.entrance((args) => {
 .yebz {
   top: $p-spac;
   right: $p-spac;
-  color: #b8741a;
+  color: $yellow-color;
 }
 </style>

+ 96 - 0
src/pages/cards/index.vue

@@ -0,0 +1,96 @@
+<template>
+  <ay-container>
+    <div class="flex justify-around mb-spac">
+      <div
+        class="card-top-item"
+        v-for="(t, i) in data.tabs"
+        :key="i"
+        :class="{ active: t.active }"
+        @click="methods.tabClick(t)"
+      >
+        {{ t.label }}
+      </div>
+    </div>
+    <ay-skeletons :rowList="data.rowList" :loading="data.loading">
+      <div class="chunk card" v-if="data.tabs[0].active">
+        <div class="font-bold p-color">购车加气优惠卡</div>
+        <div class="s-fz">[{{ func.convert.nullView(data.truckInfo.carNumber) }}]</div>
+        <div class="mt-spac">
+          可用优惠余额
+          <ay-numer :value="data.truckCard.balance" unit="元" />
+        </div>
+      </div>
+    </ay-skeletons>
+    <div class="text-center mt-spac" v-if="data.tabs[1].active">
+      <img class="no-data" src="@img/no-data.png" />
+      <div>暂无可用,敬请期待~</div>
+    </div>
+  </ay-container>
+</template>
+
+<script lang="ts" setup>
+const data = reactive({
+  loading: true,
+  rowList: [
+    {
+      align: 'left',
+      verticalAlign: 'top',
+      colItems: [
+        {
+          style: {
+            height: '200rpx',
+            width: '100%',
+          },
+        },
+      ],
+    },
+  ],
+  tabs: [
+    { label: '优惠卡', active: true },
+    { label: '优惠券', active: false },
+  ],
+  truckInfo: {} as 司机车辆管理信息,
+  truckCard: {} as 车辆购车加气优惠卡信息VO类,
+})
+const methods = {
+  tabClick(t) {
+    data.tabs.forEach((f) => (f.active = false))
+    t.active = true
+  },
+}
+
+ay.entrance(async (args) => {
+  await webapi.strategy
+    .get_truck_info()
+    .then((res) => {
+      data.truckInfo = res
+    })
+    .catch(() => {})
+  await webapi.account
+    .get_truck_card<{
+      orgId: string
+      truckId: string
+    }>({ orgId: store.user.userInfo.orgId, truckId: data.truckInfo.truckId })
+    .then((truckCard) => {
+      data.truckCard = truckCard
+    })
+    .catch(() => {})
+  data.loading = false
+})
+</script>
+
+<style lang="scss" scoped>
+.card {
+  border-color: $p-color;
+}
+.card-top-item {
+  &.active {
+    color: $p-color;
+    border-bottom: 4rpx solid $p-color;
+  }
+}
+.no-data {
+  width: 740rpx;
+  height: 350rpx;
+}
+</style>

+ 111 - 49
src/pages/index/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <ay-container v-show="store.user.isLogined">
+  <ay-container v-show="store.user.isLogined" :title="data.title">
     <div class="chunk">
       <div class="center justify-between top">
         <div class="center" @click="methods.goPerson">
@@ -18,7 +18,11 @@
         ></uni-icons>
       </div>
       <div class="center">
-        <ay-flowLine class="mt-spac mb-spac" :loading="store.webapi.strategy.get_user_qrcode.ing">
+        <ay-flowLine
+          class="mt-spac mb-spac"
+          :lineWidth="4"
+          :loading="store.webapi.strategy.get_user_qrcode.ing"
+        >
           <div class="qrcode">
             <image
               src="@img/qr@3x.png"
@@ -50,23 +54,33 @@
       </div>
     </div>
     <div class="flex">
-      <div class="chunk flex-1 s-fz mr-spac money-bg" @click="methods.goAccount">
-        <div class="mb-spacd4">可用余额</div>
-        <ay-numer :value="data.accountInfo.totalBalance" :unit="data.accountInfo.unit" />
-      </div>
-
-      <div class="chunk flex-1 center justify-start s-fz cars" @click="methods.truckManage">
-        <div class="p-color" v-if="data.truckInfo.length === 0">添加车辆</div>
-        <div v-else>
-          <div class="mb-spacd4">车辆管理</div>
+      <ay-flowLine class="flex-1 mr-spac" :loading="store.webapi.strategy.get_driver_balance.ing">
+        <div class="chunk m0 h-100% s-fz money-bg" @click="methods.goAccount">
+          <div class="mb-spacd4">
+            可用余额
+            <div class="inline yellow-color ss-fz ml-spacd4" v-if="data.accountInfo.flag === 0">
+              [余额不足]
+            </div>
+          </div>
+          <ay-numer :value="data.accountInfo.showBalance" :unit="data.accountInfo.unit" />
+        </div>
+      </ay-flowLine>
+      <ay-flowLine class="flex-1" :loading="store.webapi.strategy.get_truck_info.ing">
+        <div class="chunk m0 h-100% s-fz cars" @click="methods.truckManage">
           <div>
-            <span class="font-bold b-fz">{{ data.truckInfo.length }}</span>
-            辆
+            <div class="mb-spacd4" v-show="showcm">车辆管理</div>
+            <div v-show="store.webapi.strategy.get_truck_info.firstSuccess">
+              <div class="p-color mt-spac" v-if="data.truckInfo.length === 0">添加车辆</div>
+              <div v-else>
+                <span class="font-bold b-fz">{{ data.truckInfo.length }}</span>
+                辆
+              </div>
+            </div>
           </div>
         </div>
-      </div>
+      </ay-flowLine>
     </div>
-    <div class="center justify-around mt-spac">
+    <div class="center justify-around mt-spacm2">
       <div
         class="text-center menu"
         v-for="(m, i) in data.menus"
@@ -78,13 +92,14 @@
       </div>
     </div>
     <div class="chuck list-app">
-      <ay-sticky relativeTo="#stations" targetSelector="#stationTop">
+      <ay-sticky :top="topHeightPX" relativeTo="#stations" targetSelector="#stationTop">
         <div
           class="center justify-between sticky"
           id="stationTop"
           :class="{ stickyed: data.station.stickyed }"
+          @click="methods.hiddenDoora"
         >
-          <div class="title">附近加气站</div>
+          <div class="title" @click.stop="methods.hiddenDoorb">附近加气站</div>
           <div v-if="data.userLocation" @click="methods.drawerOpen">
             {{ data.station.curCity }}
             <uni-icons type="down" size="12" />
@@ -92,6 +107,9 @@
         </div>
       </ay-sticky>
       <div v-show="data.userLocation" id="stations">
+        <ay-flowLine :minLoadTime="400" :loading="store.webapi.strategy.list_mini.ing">
+          <div style="height: 2rpx"></div>
+        </ay-flowLine>
         <ayb-station
           v-for="(la, i) in data.station.listApp"
           :key="i"
@@ -100,8 +118,8 @@
       </div>
       <div
         class="center p-color"
-        v-show="!data.userLocation"
-        @click="methods.getListApp({ first: true })"
+        v-show="!data.firstUnload && !data.userLocation"
+        @click="methods.getListApp({ activation: true })"
       >
         查看附近加气站
       </div>
@@ -128,11 +146,12 @@
       </uni-popup-dialog>
     </uni-popup>
 
-    <uni-drawer
+    <ay-drawer
       ref="drawer"
       mode="right"
       :maskClick="true"
       :width="320"
+      :top="topHeightPX"
       @change="methods.drawerChange"
     >
       <uni-indexed-list
@@ -142,7 +161,7 @@
         ref="indexedList"
         v-if="data.station.indexedListShow"
       />
-    </uni-drawer>
+    </ay-drawer>
     <ayb-carNumber ref="carNumber" />
   </ay-container>
 </template>
@@ -173,13 +192,15 @@ const staticData = {
   /** 页面滚动距离 */
   scrollTop: 0,
 }
-const data = reactive({
+
+const data = ay.initData({
+  /** 未load */
   firstUnload: true,
   /** 存在未支付完成订单 */
   hasnopayfordriver: true,
   invite: {} as 预添加司机详情,
   truckInfo: [] as PersonDriver对象[],
-  accountInfo: { showBalance: { balance: '', suffix: '' } } as IAccountInfo,
+  accountInfo: {} as IAccountInfo,
   /** 用户已授权定位 */
   userLocation: false,
   /** 二维码相关 */
@@ -222,9 +243,36 @@ const data = reactive({
     listApp: [],
     indexedListShow: false,
   },
+  hiddenDoor: [],
+})
+const topHeight = computed(() => config.common.SystemInfo.safeArea.top + 44)
+const topHeightPX = computed(() => `${topHeight.value}px`)
+const showcm = computed(() => {
+  return (
+    !store.webapi.strategy.get_truck_info.firstSuccess ||
+    (store.webapi.strategy.get_truck_info.firstSuccess && data.truckInfo.length)
+  )
 })
 const methods = ay.initMethods(
   {
+    hiddenDoorb() {
+      data.hiddenDoor[data.hiddenDoor.length - 1]++
+    },
+    hiddenDoora() {
+      if (
+        data.hiddenDoor[0] === 3 &&
+        data.hiddenDoor[1] === 1 &&
+        data.hiddenDoor[2] === 2 &&
+        data.hiddenDoor[3] === 4
+      ) {
+        data.hiddenDoor = []
+        uni.setClipboardData({
+          data: JSON.stringify({ userInfo: store.user.userInfo }),
+        })
+      } else {
+        data.hiddenDoor.push(0)
+      }
+    },
     phone(num) {
       uni.makePhoneCall({
         phoneNumber: num,
@@ -232,7 +280,7 @@ const methods = ay.initMethods(
     },
 
     getTruckInfo() {
-      webapi.strategy.get_truck_info().then((res) => {
+      webapi.strategy.get_truck_info({}).then((res) => {
         data.truckInfo = aop.request.AR.truckInfo(res)
       })
     },
@@ -241,6 +289,9 @@ const methods = ay.initMethods(
         ay.goPage(config.pages.truckInfo_index)
       } else {
         carNumber.value.open().then((cn) => {
+          if (store.webapi.strategy.bind_person_truck.ing) {
+            return
+          }
           webapi.strategy
             .bind_person_truck<{ userId: string }>({
               userId: store.user.userInfo.user_id,
@@ -269,7 +320,9 @@ const methods = ay.initMethods(
         2() {
           ay.goPage(config.pages.org_index)
         },
-        3() {},
+        3() {
+          ay.goPage(config.pages.cards_index)
+        },
       }
       maps[menu.id]()
     },
@@ -287,7 +340,7 @@ const methods = ay.initMethods(
         // 小程序环境-每次呈现组件后重新设置winOffsetY
         // #ifdef MP
         if (indexedList.value) {
-          indexedList.value.$data.winOffsetY = staticData.scrollTop
+          indexedList.value.$data.winOffsetY = staticData.scrollTop + topHeight.value
         }
         // #endif
         if (!staticData.indexedListWatcher) {
@@ -296,7 +349,7 @@ const methods = ay.initMethods(
             (nv) => {
               // 小程序环境仅首次呈现监听到, h5环境每次呈现都会监听到
               if (indexedList.value) {
-                indexedList.value.$data.winOffsetY = staticData.scrollTop
+                indexedList.value.$data.winOffsetY = staticData.scrollTop + topHeight.value
               }
             },
             {
@@ -322,7 +375,7 @@ const methods = ay.initMethods(
     initWS() {
       stompSocket
         .init(
-          'wss://dwx.auyen.com/websocket/sockjs',
+          ay.getWebsocketUrl('websocket/sockjs'),
           // 传参
           {
             access_token: store.user.userInfo.token,
@@ -417,6 +470,7 @@ const methods = ay.initMethods(
       const ret: { gasstationId?: string; cashierId?: string } = await func.native.scan()
       if (!(ret.gasstationId && ret.cashierId)) {
         func.native.showToast('二维码无效')
+        return
       }
 
       const user = await webapi.user.find_6({ userId: ret.cashierId })
@@ -444,8 +498,7 @@ const methods = ay.initMethods(
           } else if (gasJudge === 2) {
             func.native.showModal({
               title: '错误提示',
-              content:
-                '该加气站未及时补充平台气源,已无法通过大象平台为您提供优质气源,给您带来的不便深感其歉意,如有疑问可以与加气站沟通,亦可拨打大象加气平台客服电话:"400-0165388"',
+              content: `该加气站未及时补充平台气源,已无法通过大象平台为您提供优质气源,给您带来的不便深感其歉意,如有疑问可以与加气站沟通,亦可拨打大象加气平台客服电话:"${store.common.data.phone}"`,
             })
           }
         }
@@ -496,9 +549,15 @@ const methods = ay.initMethods(
         })
       })
     },
-    async getListApp({ cras = config.common.defAyContainerRefreshArgs, first = false } = {}) {
-      // 非首次 && 未授权
-      if (!first && !data.userLocation) {
+    async getListApp({
+      cras = config.common.defAyContainerRefreshArgs,
+      activation = false,
+      checkScope = false,
+    } = {}) {
+      if (checkScope) {
+      }
+      // 非激活 && 未授权
+      if (!activation && !data.userLocation) {
         // 取消加载中效果
         ay.containerLoaded({
           reqState: enums.ReqState.cancel,
@@ -508,7 +567,8 @@ const methods = ay.initMethods(
       let location = staticData.location
       // 上拉不重新获取位置
       if (!cras.isAdd) {
-        location = await func.native.getLocation()
+        location = await func.native.getLocation(false)
+        if (!location) return
         staticData.location = location
       }
       data.userLocation = true
@@ -523,7 +583,7 @@ const methods = ay.initMethods(
               latitude: location.latitude.toString(),
             },
           },
-          { showLoading: first }, // || !cras.isAdd },
+          { showLoading: activation }, // || !cras.isAdd },
         )
         .then((res) => {
           if (cras.isAdd) {
@@ -538,7 +598,7 @@ const methods = ay.initMethods(
       if (data.hasnopayfordriver || store.webapi.strategy.get_user_qrcode.ing) {
         return
       }
-      return webapi.strategy.get_user_qrcode({}, { minRTime: 1000 }).then(async (res) => {
+      return webapi.strategy.get_user_qrcode({}, { minRTime: 1e3 }).then(async (res) => {
         data.qrcode.img = res
         data.qrcode.expire = false
       })
@@ -552,13 +612,18 @@ ay.entrance(
   async (args) => {
     // staticData.entranceArgs = args
     const init = async () => {
-      webapi.strategy.get_driver_balance().then((res) => {
+      webapi.strategy.get_driver_balance({}).then((res) => {
         data.accountInfo = {
           ...res,
           ...aop.request.AR.getAccountInfo(res),
         }
       })
 
+      data.hasnopayfordriver = await methods.checkNopayfordriver()
+      methods.getTruckInfo()
+    }
+    if (args.loadType === enums.LoadType.onLoad) {
+      // data.title = store.curPage?.pageConfig?.title
       // #ifdef MP
       // 用户是否授权了获取地理位置
       await uni
@@ -569,16 +634,12 @@ ay.entrance(
           }
         })
         .catch()
+
       // #endif
-      methods.getListApp({ cras: args.cras })
-      methods.getTruckInfo()
-      const nopayfordriver = await methods.checkNopayfordriver()
-      data.hasnopayfordriver = nopayfordriver
-    }
-    if (args.loadType === enums.LoadType.onLoad) {
       methods.initWS()
       methods.getCityList()
       data.station.curCity = uni.getStorageSync(staticData.cctkn) || staticData.defCity
+      methods.getListApp({ cras: args.cras, checkScope: true })
       await init()
       // 无未支付订单
       if (!data.hasnopayfordriver) {
@@ -592,12 +653,10 @@ ay.entrance(
     }
 
     if (args.loadType === enums.LoadType.refresh) {
-      if (args.cras.isAdd) {
-        methods.getListApp({ cras: args.cras })
-      } else {
-        // 下拉更新
-        init()
-      }
+      methods.getListApp({ cras: args.cras })
+      // if (!args.cras.isAdd) {
+      //   init()
+      // }
     }
     if (args.loadType === enums.LoadType.onShow) {
       init()
@@ -614,6 +673,9 @@ onPageScroll((res) => {
 </script>
 
 <style lang="scss" scoped>
+.center-item {
+  min-height: 136rpx;
+}
 .top {
   padding-bottom: $p-spac;
   border-bottom: 1px dashed;

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

@@ -1,6 +1,6 @@
 <template>
   <ay-container :cusStyle="{ 'padding-top': config.common.SystemInfo.safeArea.top + 'px' }">
-    <div class="absolute center font-bold $bs-fz title">登录</div>
+    <div class="absolute center font-bold $bs-fz page-title">登录</div>
     <div class="flex-col center justify-between login-con">
       <div class="center info">
         <image class="logo" src="/static/logo.png" mode="scaleToFill" />
@@ -94,6 +94,9 @@ ay.entrance(({ exts }) => {
     // ay.navigateBack()
   }
 })
+onUnload(() => {
+  store.webapi.user.token.set()
+})
 </script>
 <style lang="scss" scoped>
 .title {

+ 4 - 0
src/pages/order/createOrder.vue

@@ -17,6 +17,7 @@
         v-model="data.gasQty"
         type="digit"
         placeholder="请输入"
+        focus
         @input="methods.input"
         @confirm="methods.confirm"
       />
@@ -85,6 +86,9 @@ ay.entrance(async (args) => {
     latitude: location.latitude.toString(),
   })
 })
+onUnload(() => {
+  store.webapi.pay.add.set()
+})
 </script>
 
 <style lang="scss" scoped>

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

@@ -123,7 +123,7 @@ const staticData = {
   ],
 }
 const drawer = ref()
-const data = reactive({
+const data = ay.initData({
   /** 确定选中条件数量 */
   checkCount: 0,
   filters: [
@@ -139,7 +139,7 @@ const data = reactive({
     },
     {
       label: '交易模式',
-      value: 'tradeType',
+      value: 'tradeTypes',
       items: func.convert.getCheckItem(config.common.tradeType),
     },
   ] as any[],

+ 17 - 8
src/pages/order/orderDetail.vue

@@ -1,9 +1,15 @@
 <template>
-  <ay-container>
+  <ay-container :title="data.title" :showBackIcon="true">
     <ay-skeletons :rowList="data.rowList" :loading="store.webapi.strategy.get_order_detail.ing">
       <div class="chunk2 p-color font-bold">
         <div>
-          <div>
+          <div
+            @click="
+              ay.goPage(config.pages.station_detail, {
+                params: { gasstationId: data.orderDetail.gasstationId },
+              })
+            "
+          >
             {{ data.orderDetail.nickName }}
             <uni-icons type="right" color="" size="12" />
           </div>
@@ -44,12 +50,14 @@
         <ay-fieldGroups :fieldGroups="curFieldGroups" :targetData="data.orderDetail" />
       </div>
     </ay-skeletons>
+    <ayb-phone desc="对此单有疑问?请联系"></ayb-phone>
   </ay-container>
 </template>
 
 <script lang="ts" setup>
 const staticData = {}
 const data = reactive({
+  title: '',
   rowList: [
     {
       align: 'left',
@@ -115,7 +123,7 @@ const data = reactive({
         {
           show(data) {
             //  已支付||已退款 才显示
-            return [2, 6].includes(data.settleStatus)
+            return [2, 5, 6].includes(data.settleStatus)
           },
           title: '支付时间',
           key: 'updateDate',
@@ -148,7 +156,7 @@ const data = reactive({
         {
           show(data) {
             //  已支付||已退款 才显示
-            return [2, 6].includes(data.settleStatus)
+            return [2, 5, 6].includes(data.settleStatus)
           },
           title: '支付方式',
           key: 'payType',
@@ -317,7 +325,7 @@ const data = reactive({
         {
           show(data) {
             //  已支付||已退款 才显示
-            return [2, 6].includes(data.settleStatus)
+            return [2, 5, 6].includes(data.settleStatus)
           },
           title: '支付时间',
           key: 'updateDate',
@@ -359,9 +367,10 @@ ay.entrance((args) => {
   webapi.strategy
     .get_order_detail({ orderId: store.curPage.pageConfig.params.orderId, orderType: 1 })
     .then((res) => {
-      uni.setNavigationBarTitle({
-        title: '加气订单 · ' + config.common.settleStatus[res.settleStatus],
-      })
+      data.title = '加气订单 · ' + config.common.settleStatus[res.settleStatus]
+      // store.curPage.pageConfig.title = '加气订单 · ' + config.common.settleStatus[res.settleStatus]
+      // uni.setNavigationBarTitle({ title: store.curPage.pageConfig.title })
+
       data.orderDetail = res
     })
 })

+ 30 - 13
src/pages/order/prePay.vue

@@ -18,7 +18,7 @@
           @click="methods.choose(0)"
         ></span>
         <div>
-          <span class="font-bold" @click="methods.choose(0)">个人支付</span>
+          <div class="font-bold inline" @click="methods.choose(0)">个人支付</div>
           <div class="ml-spacd2 mt-spacd2">
             结算金额 ¥ {{ personPay?.amount }} 元 (结算价 ¥ {{ personPay?.actualPrice }} 元/公斤)
           </div>
@@ -31,7 +31,7 @@
           @click="methods.choose(1)"
         ></span>
         <div class="flex-1">
-          <span class="font-bold" @click="methods.choose(1)">所属物流支付</span>
+          <div class="font-bold inline" @click="methods.choose(1)">所属物流支付</div>
           <div class="childs-fc-mbd2 ml-spacd2 mt-spacd2">
             <div @click="methods.switchRebateDetail">
               结算金额 ¥ {{ carrierPay.amount }} 元 (结算价 ¥
@@ -48,8 +48,7 @@
               />
             </span>
             <span
-              v-if="carrierPay.rebateNum"
-              v-show="data.showRebateDetail"
+              v-if="carrierPay.rebateNum && data.showRebateDetail"
               class="chunk childs-fcjb-mbd2 rebate-detail money-bg"
             >
               <div v-for="(rd, i) in carrierPay.rebateDetail" :key="i">
@@ -59,8 +58,8 @@
             </span>
             <div class="pt-spacd2 top-line">{{ carrierPay.carrierOrgName }}</div>
             <div>[{{ carrierPay.carNumber }}]</div>
-            <div class="justify-start">
-              <div>可用余额¥{{ carrierPay.balance }}元</div>
+            <div class="justify-start" v-if="carrierPay.balanceEnable">
+              <div>可用余额 {{ carrierPay.balanceStr }}元</div>
               <ay-refresh
                 :loading="store.webapi.strategy.paysel.ing"
                 @refresh="methods.paysel"
@@ -72,7 +71,7 @@
       <div class="chunk2">
         <div>
           <span>创建订单</span>
-          <div>{{ data.orderDetail.createDate }}</div>
+          <div>{{ func.getDate(data.orderDetail.createDate).format() }}</div>
         </div>
         <div>
           <span>订单编号</span>
@@ -80,13 +79,17 @@
         </div>
         <div>
           <span>驾驶员</span>
-          <div>{{ data.orderDetail.driverName }}</div>
+          <div>
+            {{ data.orderDetail.driverName }}({{
+              func.convert.mobileDes(data.orderDetail.driverMobile)
+            }})
+          </div>
         </div>
       </div>
       <div class="btns">
         <button
           type="primary"
-          :disabled="!canPay"
+          :disabled="noCanPay"
           :loading="store.webapi.pay.order_pay.ing"
           @click="methods.pay()"
         >
@@ -94,6 +97,7 @@
         </button>
       </div>
     </ay-skeletons>
+    <ayb-phone desc="对此单有疑问?请联系"></ayb-phone>
   </ay-container>
 </template>
 
@@ -106,7 +110,11 @@ const data = reactive({
   orderDetail: {} as 订单详情,
   stationInfo: {} as GasstationVO对象,
   paysel: {} as 待支付订单_可选支付方式获取实体类,
+  /** 展示优惠详情 */
   showRebateDetail: false,
+  /** 原生支付状态 */
+  nativePayState: enums.ReqState.unasked,
+
   rowList: [
     {
       align: 'left',
@@ -160,7 +168,15 @@ const data = reactive({
   ],
 })
 
-const canPay = computed(() => curPay.value?.buttonEnable && !store.webapi.pay.order_pay.ios)
+const noCanPay = computed(
+  () =>
+    // 按钮不可点击
+    !curPay.value?.buttonEnable ||
+    // 订单支付接口请求中
+    store.webapi.pay.order_pay.ing ||
+    // 订单支付接口请求成功 && 原生未支付失败
+    (store.webapi.pay.order_pay.success && data.nativePayState !== enums.ReqState.fail),
+)
 const pageParams = computed(() => store.curPage.pageConfig.params)
 const personPay = computed(() => data.paysel?.personPay)
 const carrierPay = computed(() => data.paysel?.carrierPay)
@@ -215,12 +231,15 @@ const methods = {
     }
     webapi.pay.order_pay(params).then((res) => {
       if ([1, 2, 3].includes(curPay.value.payType)) {
+        data.nativePayState = enums.ReqState.ing
         uni.requestPayment({
           ...JSON.parse(res.payInfo),
           success() {
+            data.nativePayState = enums.ReqState.success
             methods.paySuccess()
           },
           fail() {
+            data.nativePayState = enums.ReqState.fail
             func.native.showToast({
               icon: 'error',
               title: '支付失败',
@@ -282,9 +301,7 @@ ay.entrance(async (args) => {
 })
 
 onUnload(() => {
-  store.webapi.strategy.get_order_detail.set()
-  store.webapi.strategy.paysel.set()
-  store.webapi.strategy.find_for_mini.set()
+  store.webapi.pay.order_pay.set()
 })
 </script>
 

+ 6 - 8
src/pages/org/index.vue

@@ -26,8 +26,9 @@
           <image src="@img/icons/org_icon.png" class="mr-spac org-icon" />
           <div>{{ data.orgInfo.orgName }}</div>
         </div>
+        <!-- <ayb-phone class="b-fz" :phone="data.orgInfo.bindPhone"></ayb-phone> -->
         <div @click="methods.phone(data.orgInfo.bindPhone)" class="mt-spac p-color">
-          <uni-icons type="phone" color="" class="mr-spac" size="36"></uni-icons>
+          <uni-icons type="phone-filled" color="" class="mr-spacd2" size="36"></uni-icons>
           <div class="b-fz">{{ data.orgInfo.bindPhone }}</div>
         </div>
       </div>
@@ -35,13 +36,10 @@
         <template v-if="data.orgDetail.driverApply?.auditStatus === 1">
           若想更快审核通过,可以联系企业联系人
         </template>
-        <div v-if="data.orgDetail.driverApply?.auditStatus === 3" class="text-center">
-          如对处理有异议,请联系物流公司处理或拨打平台客服电话:
-          <span class="p-color" @click="methods.phone(store.common.data.phone)">
-            <uni-icons type="phone" color="" class="mr-spacd4" size="none"></uni-icons>
-            <span>{{ store.common.data.phone }}</span>
-          </span>
-        </div>
+        <ayb-phone
+          desc="如对处理有异议,请联系物流公司处理或拨打平台客服电话:"
+          v-if="data.orgDetail.driverApply?.auditStatus === 3"
+        ></ayb-phone>
       </div>
       <div class="btns">
         <button

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

@@ -55,6 +55,8 @@
         </uni-list-item>
       </uni-list>
     </div>
+    <ayb-phone desc="客服电话"></ayb-phone>
+
     <div class="btns">
       <button type="warn" @click="methods.logout">退出</button>
     </div>

+ 1 - 0
src/pages/personCenter/password.vue

@@ -125,6 +125,7 @@ const methods = {
     })
   },
 }
+ay.entrance()
 </script>
 
 <style lang="scss" scoped></style>

+ 3 - 0
src/pages/personCenter/userIdCard.vue

@@ -227,6 +227,9 @@ const methods = {
   },
 }
 ay.entrance(() => {})
+onUnload(() => {
+  store.webapi.user.idcard_auth.set()
+})
 </script>
 
 <style lang="scss" scoped>

+ 141 - 0
src/pages/station/detail.vue

@@ -0,0 +1,141 @@
+<template>
+  <ay-container :cusStyle="{ padding: 0 }">
+    <swiper
+      class="swiper nmb-spac"
+      circular
+      :indicator-dots="pics.length > 1"
+      :autoplay="true"
+      :interval="3000"
+    >
+      <swiper-item v-for="(p, i) in pics" :key="i">
+        <image mode="aspectFill" :src="p.picPath" />
+      </swiper-item>
+    </swiper>
+    <div class="infos">
+      <div class="font-bold b-fz mb-spac">
+        {{ func.convert.nullView(data.detail.gasstationName) }}
+      </div>
+      <div class="center justify-between mb-spac">
+        <div class="flex-1">
+          <div class="center justify-start mb-spacd2">
+            <uni-icons type="location-filled" size="16" class="mr-spacd4" />
+            {{ func.convert.nullView(stationInfo.distance) }}km |
+            {{ func.convert.nullView(data.detail.address) }}
+          </div>
+          <ayb-phone :phone="data.detail.mobile" :center="false"></ayb-phone>
+        </div>
+        <div
+          class="text-center p-color"
+          :class="{ 'gray-color': !stationInfo.longitude }"
+          @click="methods.openLocation"
+        >
+          <uni-icons type="paperplane-filled" color="" size="24" />
+          <div>导航</div>
+        </div>
+      </div>
+      <div class="chunk childs-fcjb-mbd2">
+        <div>
+          <div class="font-bold bs-fz">今日平台价</div>
+          <div class="gray-color">价格仅供参考,以当天实际为准</div>
+        </div>
+        <div class="mt-spac">
+          <div class="lng bs-fz">LNG</div>
+          <div>
+            <span class="font-bold mr-spacd2 price-color bs-fz">
+              {{ stationInfo.actualPrice }}
+            </span>
+            <span class="s-fz price">元/公斤</span>
+          </div>
+        </div>
+      </div>
+      <div class="chunk">
+        <div class="font-bold bs-fz mb-spacd2">简介</div>
+        <div class="">{{ func.convert.nullView(data.detail.introduce) }}</div>
+      </div>
+      <div class="chunk childs-fcjb-mbd2">
+        <div>
+          <span>加注机数量</span>
+          <div>{{ func.convert.nullView(data.detail.fillingMachineNum) }}</div>
+        </div>
+        <div>
+          <span>收银员数量</span>
+          <div>{{ func.convert.nullView(data.detail.cashierNum) }}</div>
+        </div>
+      </div>
+    </div>
+  </ay-container>
+</template>
+
+<script lang="ts" setup>
+import defstation from '@img/defstation.png'
+const data = reactive({
+  detail: {} as DerIStationDetail,
+  stationInfo: null as GasstationVO对象,
+})
+
+const methods = {
+  openLocation() {
+    func.native.openLocation({
+      latitude: Number(stationInfo.value.latitude),
+      longitude: Number(stationInfo.value.longitude),
+      name: stationInfo.value.nickName,
+      address: stationInfo.value.address,
+    })
+  },
+}
+const params = computed(() => {
+  return store.curPage.pageConfig.params as GasstationVO对象
+})
+const stationInfo = computed(() => {
+  return data.stationInfo || params.value
+})
+const pics = computed(() => {
+  let rv = []
+  if (data.detail.orgPics?.length > 0) {
+    rv = data.detail.orgPics.map((m) => {
+      return {
+        picPath: ay.getResourceUrl(m.picPath),
+      }
+    })
+  } else {
+    rv.push({ picPath: defstation })
+  }
+  return rv
+})
+
+ay.entrance(async (args) => {
+  webapi.user.find_3({ gasstationId: params.value.gasstationId }).then((res) => {
+    data.detail = res
+  })
+  if (!Object.hasOwn(params.value, 'distance')) {
+    const location = await func.native.getLocation()
+    data.stationInfo = await webapi.strategy.find_for_mini({
+      gasstationId: params.value.gasstationId,
+      longitude: location.longitude.toString(),
+      latitude: location.latitude.toString(),
+    })
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+.swiper {
+  height: 488rpx;
+}
+::v-deep .wx-swiper-dots-horizontal,
+::v-deep .uni-swiper-dots-horizontal {
+  margin-bottom: $p-spac;
+}
+.infos {
+  position: relative;
+  padding: $p-spac;
+  background-color: $bg-color;
+  border-radius: $p-spac;
+}
+.lng {
+  padding: $p-spacd4 $p-spacd2;
+  color: $p-recolor;
+  background-color: #00c48c;
+  border-radius: $p-spacd4;
+}
+</style>

+ 2 - 2
src/pages/truckInfo/detail.vue

@@ -134,8 +134,8 @@ const data = reactive({
 const methods = {}
 
 ay.entrance((args) => {
-  webapi.strategy.find_by_id({ id: '800136756804452353' }).then((res) => {
-    // webapi.strategy.find_by_id({ id: store.curPage.pageConfig.params.truckId }).then((res) => {
+  // webapi.strategy.find_by_id({ id: '800136756804452353' }).then((res) => {
+  webapi.strategy.find_by_id({ id: store.curPage.pageConfig.params.truckId }).then((res) => {
     data.truckInfo = res
   })
 })

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

@@ -1,5 +1,6 @@
 <template>
   <ay-container>
+    <span class="font-bold">{{ userTitle }}</span>
     <div class="s-fz">
       <div class="section">所属物流车</div>
       <div class="chunk center justify-between">
@@ -11,7 +12,7 @@
       </div>
       <div class="center justify-between">
         <div class="section">承运协作车</div>
-        <div class="p-color" @click="methods.save">添加车</div>
+        <div class="p-color" @click="methods.save">添加车</div>
       </div>
       <div>
         <div
@@ -45,6 +46,10 @@ const carNumber = ref()
 const data = reactive({
   truckInfo: {} as 司机车辆管理信息,
 })
+const userTitle = computed(() => {
+  const ui = store.user.userInfo
+  return `${ui.user_name}[${ui.mobileDes}]`
+})
 const methods = {
   getTruckInfo() {
     webapi.strategy.get_truck_info().then((res) => {

+ 1 - 1
src/pagesSubExample/webview/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <web-view src="https://dwx.auyen.com/#/login" @message="methods.bindmessage" />
+  <web-view :src="ay.getResourceUrl('#/login')" @message="methods.bindmessage" />
 </template>
 
 <script lang="ts" setup>

BIN
src/static/images/defstation.png


BIN
src/static/images/no-data.png


+ 6 - 0
src/style/_variables.scss

@@ -19,6 +19,8 @@ $p-spac: 24rpx;
 $p-spacd2: calc($p-spac / 2);
 $p-spacd3: calc($p-spac / 3);
 $p-spacd4: calc($p-spac / 4);
+// 主间距*2
+$p-spacm2: calc($p-spac * 2);
 // 价格颜色
 $p-price-color: #ec808d; //#f46d00;
 $gray-color: #868b9a;
@@ -26,7 +28,11 @@ $gray-color: #868b9a;
 $border-color: #ccc;
 // 绿色
 $green-color: #00ad65;
+// 黄色-警告
+$yellow-color: #b8741a;
 $bg-color: #fff;
+
+// 修改uni-ui 样式
 $uni-primary: $p-color;
 $uni-spacing-sm: 10rpx;
 $uni-spacing-base: 10rpx;

+ 47 - 5
src/style/index.scss

@@ -53,10 +53,14 @@
 
 %chunk-base {
   position: relative;
+  box-sizing: border-box;
   padding: $p-spac;
   margin-bottom: $p-spac;
   overflow: hidden;
 
+  &.m0 {
+    margin: 0;
+  }
 }
 
 .chunk {
@@ -83,7 +87,7 @@
   >div,
   >view {
     @apply flex;
-    align-items: center;
+    align-items: baseline;
     justify-content: start;
 
     >div:first-child,
@@ -145,6 +149,10 @@
   @extend .childs-fcjb-mbd2;
   padding-top: 0;
   border-bottom: solid $border-color 1rpx;
+}
+
+.chunk,
+.chunk2 {
 
   >div,
   >view {
@@ -176,11 +184,16 @@ $spac-map: (
 // 循环 $p-spac除以 $j
 @for $j from 1 to 5 {
   $suffix: if($j ==1, '', 'd' + $j);
+  $suffixm: if($j ==1, '', 'm' + $j);
 
   .m-spac#{$suffix} {
     margin:calc($p-spac / #{$j});
   }
 
+  .nm-spac#{$suffix} {
+    margin:calc($p-spac / -#{$j});
+  }
+
   .p-spac#{$suffix} {
     padding:calc($p-spac / #{$j});
   }
@@ -197,6 +210,10 @@ $spac-map: (
       margin-#{map-get($t,1)}: calc($p-spac / #{$j});
     }
 
+    .m#{map-get($t,0)}-spac#{ $suffixm} {
+      margin-#{map-get($t,1)}: calc($p-spac * #{$j});
+    }
+
     .nm#{map-get($t,0)}-spac#{ $suffix} {
       margin-#{map-get($t,1)}: calc($p-spac / -#{$j});
     }
@@ -207,6 +224,7 @@ $spac-map: (
   }
 }
 
+
 .tag-rb {
   position: absolute;
   right: 0;
@@ -283,6 +301,8 @@ image {
   vertical-align: middle;
 }
 
+
+
 // 单行省略,优先使用 unocss: text-ellipsis
 .ellipsis {
   overflow: hidden;
@@ -308,18 +328,19 @@ image {
   -webkit-box-orient: vertical;
 }
 
-// 大字体大小
+// 大字体
 .b-fz {
   font-size: $b-fz;
 }
 
+.bs-fz {
+  font-size: $bs-fz;
+}
+
 .p-fz {
   font-size: $p-fz;
 }
 
-.bs-fz {
-  font-size: $bs-fz;
-}
 
 // 次要字体大小
 .s-fz {
@@ -354,6 +375,10 @@ image {
   color: $green-color;
 }
 
+.yellow-color {
+  color: $yellow-color;
+}
+
 .bline {
   border: solid $border-color 1rpx;
 }
@@ -387,6 +412,23 @@ image {
   }
 }
 
+.page-custom {
+  padding: 0 $p-spac;
+  margin: 0 calc($p-spac / -1);
+  margin-bottom: $p-spac;
+  background-color: #f8f8f8;
+  @apply flex;
+  @apply items-end;
+}
+
+.page-title {
+  // position: absolute;
+  // top: 50px;
+  // right: 0;
+  // left: 0;
+  width: 100%;
+  height: 44px;
+}
 
 // #region 穿透到组件内样式,以pass-com 开头
 .pass-com-rotater {

+ 2 - 0
src/types/api.d.ts

@@ -1,4 +1,6 @@
 // 获取函数的返回类型
+type GetArgType<T> = T extends (arg: infer AT) => any ? AT : never
+// 获取函数的返回类型
 type GetReturnType<T> = T extends (...args: any[]) => infer RT ? RT : never
 
 type IFCommon = {

+ 1 - 1
src/types/components.ts

@@ -54,7 +54,7 @@ interface AyContainerEntryArgs {
   /**
    * 页面参数
    */
-  options?: AnyObject
+  options?: Parameters<Parameters<typeof onShow>[0]>[0]
   /**
    * 分页组件加载数据事件参数
    */

+ 313 - 0
src/types/global.d.ts

@@ -40,3 +40,316 @@ type IFieldGroup<T> = {
     view: (args: T & string) => string
   }[]
 }
+
+interface CopyGlobalStyle {
+  /**
+   * 导航栏背景颜色(同状态栏背景色),支持 HEX 颜色
+   *
+   * @desc APP 与 H5 为 #F8F8F8,小程序平台请参考相应小程序文档
+   *
+   * @format color
+   */
+  navigationBarBackgroundColor?: HEXColor | ThemeVar
+  /**
+   * 导航栏标题颜色及状态栏前景颜色,仅支持 "black" / "white"
+   *
+   * @default "black"
+   *
+   * @desc 支付宝小程序不支持,请使用 my.setNavigationBar
+   */
+  navigationBarTextStyle?: 'black' | 'white' | ThemeVar
+  /**
+   * 导航栏标题文字内容
+   */
+  navigationBarTitleText?: string
+  /**
+   * 导航栏阴影
+   */
+  navigationBarShadow?: {
+    /**
+     * 阴影颜色
+     */
+    colorType?: 'grey' | 'blue' | 'green' | 'orange' | 'red' | 'yellow'
+  }
+  /**
+   * 导航栏样式,仅支持 "default" / "custom"
+   *
+   * "custom" 即取消默认的原生导航栏,详看 [使用注意](https://uniapp.dcloud.net.cn/collocation/pages#customnav)
+   *
+   * @default "default"
+   *
+   * @desc 微信小程序 7.0+、百度小程序、H5、App(2.0.3+)
+   */
+  navigationStyle?: 'default' | 'custom'
+  /**
+   * 下拉显示出来的窗口的背景色,支持 HEX 颜色
+   *
+   * @default "#ffffff"
+   *
+   * @desc 微信小程序
+   *
+   * @format color
+   */
+  backgroundColor?: HEXColor | ThemeVar
+  /**
+   * 下拉 loading 的样式,仅支持 "dark" / "light"
+   *
+   * @default "dark"
+   *
+   * @desc 微信小程序
+   */
+  backgroundTextStyle?: 'dark' | 'light' | ThemeVar
+  /**
+   * 是否开启下拉刷新,详见 [页面生命周期](https://uniapp.dcloud.net.cn/tutorial/page.html#lifecycle)
+   *
+   * @default false
+   */
+  enablePullDownRefresh?: boolean
+  /**
+   * 页面上拉触底事件触发时距页面底部距离,单位为 px,详见 [页面生命周期](https://uniapp.dcloud.net.cn/tutorial/page.html#lifecycle)
+   *
+   * @default 50
+   */
+  onReachBottomDistance?: number
+  /**
+   * 顶部窗口的背景色(bounce回弹区域)
+   *
+   * @default "#ffffff"
+   *
+   * @desc iOS
+   *
+   * @format color
+   */
+  backgroundColorTop?: HEXColor | ThemeVar
+  /**
+   * 底部窗口的背景色(bounce回弹区域)
+   *
+   * @default "#ffffff"
+   *
+   * @desc iOS
+   *
+   * @format color
+   */
+  backgroundColorBottom?: HEXColor | ThemeVar
+  /**
+   * 导航栏图片地址(替换当前文字标题)
+   *
+   * 支付宝小程序内必须使用 https 图片链接地址
+   *
+   * @desc 支付宝小程序、H5、APP
+   */
+  titleImage?: string
+  /**
+   * 导航栏整体(前景、背景)透明设置,仅支持 "always" / "auto" / "none
+   *
+   * "always" 一直透明
+   *
+   * "auto" 滑动自适应
+   *
+   * "none" 不透明
+   *
+   * @default "none"
+   *
+   * @desc 支付宝小程序、H5、APP
+   */
+  transparentTitle?: 'always' | 'auto' | 'none'
+  /**
+   * 导航栏点击穿透
+   *
+   * @default "NO"
+   *
+   * @desc 支付宝小程序、H5
+   */
+  titlePenetrate?: 'YES' | 'NO'
+  /**
+   * 横屏配置,屏幕旋转设置,仅支持 "auto" / "portrait" / "landscape",详见 [响应显示区域变化](https://developers.weixin.qq.com/miniprogram/dev/framework/view/resizable.html)
+   *
+   * "auto" 自动
+   *
+   * "portrait" 竖屏
+   *
+   * "landscape" 横屏
+   *
+   * @default "portrait"
+   *
+   * @desc App 2.4.7+、微信小程序、QQ小程序
+   */
+  pageOrientation?: string
+  /**
+   * 窗口显示的动画效果,详见 [窗口动画](https://uniapp.dcloud.net.cn/api/router#animation)
+   *
+   * @default "pop-in"
+   *
+   * @desc App
+   */
+  animationType?: AnimationType
+  /**
+   * 窗口显示动画的持续时间,单位为 ms
+   *
+   * @default 300
+   *
+   * @desc App
+   */
+  animationDuration?: number
+  /**
+   * 设置编译到 App 平台的特定样式,配置项参考 [app-plus](https://uniapp.dcloud.net.cn/collocation/pages#app-plus)
+   *
+   * 相应的类型是 AppPlus
+   *
+   * @desc App
+   */
+  'app-plus'?: AppPlus
+  /**
+   * 设置编译到 H5 平台的特定样式,配置项参考 [H5](https://uniapp.dcloud.net.cn/collocation/pages#h5)
+   *
+   * 相应的类型是 H5
+   *
+   * @desc H5
+   */
+  h5?: H5
+  /**
+   * 设置编译到 mp-alipay 平台的特定样式,配置项参考 [MP-ALIPAY](https://uniapp.dcloud.net.cn/collocation/pages#mp-alipay) 和 <https://opendocs.alipay.com/mini/framework/app-json#window>
+   *
+   * 相应的类型是 MpAlipay
+   *
+   * @desc 支付宝小程序
+   */
+  'mp-alipay'?: MpAlipay
+  /**
+   * 设置编译到 mp-weixin 平台的特定样式,配置项参考 [MP-WEIXIN](https://uniapp.dcloud.net.cn/collocation/pages#mp-weixin) 和 <https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#window>
+   *
+   * 相应的类型是 MpWeixin
+   *
+   * @desc 微信小程序
+   */
+  'mp-weixin'?: MpWeixin
+  /**
+   * 设置编译到 mp-baidu 平台的特定样式,配置项参考 [MP-BAIDU](https://uniapp.dcloud.net.cn/collocation/pages.html#mp-baidu) 和 <https://smartprogram.baidu.com/docs/develop/framework/process/#window>
+   *
+   * 相应的类型是 MpBaidu
+   *
+   * @desc 百度小程序
+   */
+  'mp-baidu'?: MpBaidu
+  /**
+   * 设置编译到 mp-toutiao 平台的特定样式,配置项参考 <https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/framework/general-configuration#window>
+   *
+   * 相应的类型是 MpToutiao
+   *
+   * @desc 抖音小程序
+   */
+  'mp-toutiao'?: MpToutiao
+  /**
+   * 设置编译到 mp-lark 平台的特定样式
+   *
+   * 相应的类型是 MpLark
+   *
+   * @desc 飞书小程序
+   */
+  'mp-lark'?: MpLark
+  /**
+   * 设置编译到 mp-qq 平台的特定样式
+   *
+   * 相应的类型是 MpQq
+   *
+   * @desc QQ 小程序
+   */
+  'mp-qq'?: MpQq
+  /**
+   * 设置编译到 mp-kuaishou 平台的特定样式
+   *
+   * 相应的类型是 MpKuaishou
+   *
+   * @desc 快手小程序
+   */
+  'mp-kuaishou'?: MpKuaishou
+  /**
+   * 设置编译到 mp-jd 平台的特定样式
+   *
+   * 相应的类型是 MpJd
+   *
+   * @desc 京东小程序
+   */
+  'mp-jd'?: MpJd
+  /**
+   * 引用小程序组件,详见 [小程序组件](https://uniapp.dcloud.net.cn/tutorial/miniprogram-subject.html#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E6%94%AF%E6%8C%81)
+   *
+   * @desc App、微信小程序、支付宝小程序、百度小程序、京东小程序
+   */
+  usingComponents?: Record<string, string>
+  /**
+   * 同层渲染,webrtc(实时音视频)无法正常时尝试配置为 "seperated" 强制关掉同层渲染
+   *
+   * @desc 微信小程序
+   */
+  renderingMode?: string
+  /**
+   * 当存在 leftWindow 时,默认是否显示 leftWindow,详见 [topWindow](https://uniapp.dcloud.net.cn/collocation/pages.html#topwindow)
+   *
+   * @default true
+   *
+   * @desc H5
+   */
+  leftWindow?: boolean
+  /**
+   * 当存在 topWindow 时,默认是否显示 topWindow,详见 [topWindow](https://uniapp.dcloud.net.cn/collocation/pages.html#topwindow)
+   *
+   * @default true
+   *
+   * @desc H5
+   */
+  topWindow?: boolean
+  /**
+   * 当存在 rightWindow 时,默认是否显示 rightWindow,详见 [topWindow](https://uniapp.dcloud.net.cn/collocation/pages.html#topwindow)
+   *
+   * @default true
+   *
+   * @desc H5
+   */
+  rightWindow?: boolean
+  /**
+   * rpx 计算所支持的最大设备宽度,单位为 px
+   *
+   * @default 960
+   *
+   * @desc App(vue2 且不含 nvue)、H5(2.8.12+)
+   */
+  rpxCalcMaxDeviceWidth?: number
+  /**
+   * rpx 计算使用的基准设备宽度,设备实际宽度超出 rpx 计算所支持的最大设备宽度时将按基准宽度计算,单位为 px
+   *
+   * @default 375
+   *
+   * @desc App(vue2 且不含 nvue)、H5(2.8.12+)
+   */
+  rpxCalcBaseDeviceWidth?: number
+  /**
+   * rpx 计算特殊处理的值,始终按实际的设备宽度计算,单位为 rpx
+   *
+   * @default 750
+   *
+   * @desc App(vue2 且不含 nvue)、H5(2.8.12+)
+   */
+  rpxCalcIncludeWidth?: number
+  /**
+   * 是否使用动态 rpx,屏幕大小变化会重新渲染 rpx
+   *
+   * @default false
+   *
+   * @desc App-nvue(vue3 固定值为 true) 3.2.13+
+   */
+  dynamicRpx?: boolean
+  /**
+   * 当浏览器可见区域宽度大于 maxWidth 时两侧留白,当小于等于 maxWidth 时页面铺满,单位为 px
+   *
+   * 不同页面支持配置不同的 maxWidth
+   *
+   * maxWidth = leftWindow(可选)+ page(页面主体)+ rightWindow(可选)
+   *
+   * 使用时,页面内 fixed 元素需要使用 --window-left 和 --window-right 来保证布局位置正确
+   *
+   * @desc H5(2.9.9+)
+   */
+  maxWidth?: number
+  [x: string]: any
+}

+ 5 - 2
src/types/page.d.ts

@@ -7,21 +7,24 @@ interface ayPage {
   /** 页面类型 _禁止修改 */
   readonly _type: keyof typeof enums.PageType
   /** 页面标题 */
-  readonly title: string
+  title: string
   /** 需要身份认证 默认需要 */
   readonly identity?: boolean
   /** 是分页页面 */
   readonly isPager: boolean
   /** 页面配置,对应 小程序.json */
-  style? // @uni-helper/vite-plugin-uni-pages.GlobalStyle
+  readonly style?: CopyGlobalStyle // @uni-helper/vite-plugin-uni-pages.GlobalStyle
   /** 分页数据 */
   readonly pagerInfo?: PagerInfo
   /** 当前页面参数 */
   params?
+  /** 当前页面数据 */
+  data?: AnyObject
   /** 之前页面配置信息 */
   prePage?: ayPage
   /** 当前生命周期内,enums.LoadType.onShow 已触发过 */
   onShowed?: boolean
+  goPageed?: boolean
   // /** 通知页面加载数据 */
   // loadData?: AyEntranceCallBack
   /** 有值时,返回页面时执行AyEntranceCallBack-只执行一次,值为AyEntranceCallBack的参数 */

+ 38 - 1
src/types/schemas/custom.d.ts

@@ -1,3 +1,38 @@
+const stationDetail = {
+  gasstationId: '710272355377020928',
+  introduce: '',
+  fillingMachineNum: 0,
+  cashierNum: 0,
+  creater: null,
+  createrName: null,
+  createDate: null,
+  updater: null,
+  updaterName: null,
+  updateDate: null,
+  truckId: null,
+  gasstationName: '诸城捷通物流有限公司',
+  nickName: '通联测试加气站',
+  address: '山东省潍坊市',
+  listPrice: null,
+  platformPrice: 52.79,
+  actualPrice: 52.79,
+  mobile: '19100000003',
+  province: '',
+  city: null,
+  region: null,
+  longitude: '',
+  latitude: null,
+  url: 'https://twx.auyen.com/image/M00/00/0C/rB86LmHqVrSAec0LAABrWnERfQ0711.jpg',
+  orgPics: [
+    { picPath: 'image/M00/00/0C/rB86LmHqVrSAec0LAABrWnERfQ0711.jpg' },
+    { picPath: 'image/M00/00/0C/rB86LmHqVrSAec0LAABrWnERfQ0711.jpg' },
+  ],
+  gasstationTags: [],
+  presentContent: null,
+  presentContentId: null,
+  gasType: 1001,
+}
+
 const truckInfo = {
   truckId: '800136756804452353',
   tradeType: 1,
@@ -105,10 +140,12 @@ const userinfo = {
 }
 /** 用户信息 -- 推导 /user/user/find 返回值.user */
 type DerIUserInfo = typeof userinfo
+/** 加气站详情 -- 推导 /user/gasstation_card/find 返回值 */
+type DerIStationDetail = typeof stationDetail
 
 type IAccountInfo = {
   /** 显示余额 */
-  showBalance: { balance?: string; suffix?: string }
+  showBalance: string
   /** 单位 */
   unit?: string
   /** 显示详细 */

+ 5 - 5
src/utils/aop/index.ts

@@ -20,10 +20,10 @@ export default {
       },
       getAccountInfo(res: 司机账户余额信息): IAccountInfo {
         const accountInfo: IAccountInfo = {
-          ...res,
-          showBalance: { balance: '', suffix: '' },
-          unit: '暂无余额',
+          showBalance: '',
+          unit: '"暂无余额"',
           showDet: false,
+          ...res,
         }
         accountInfo.orgName = func.convert.nullView(accountInfo.orgName)
         accountInfo.carNumber = func.convert.nullView(accountInfo.carNumber)
@@ -31,10 +31,10 @@ export default {
         if (res.orgId) {
           accountInfo.unit = '元'
           if (res.autoAccount === 1 && res.flag === 1) {
-            accountInfo.showBalance.balance = `> ${res.limitAmount}`
+            accountInfo.showBalance = `> ${res.limitAmount}`
           } else {
             accountInfo.showDet = true
-            // accountInfo.showBalance.balance = res.totalBalance.toString()
+            accountInfo.showBalance = res.totalBalance.toString()
           }
           // if (accountInfo.showBalance.balance.includes('.')) {
           //   const balanceArr = accountInfo.showBalance.balance.split('.')

+ 21 - 3
src/utils/config/pages.ts

@@ -30,7 +30,8 @@ export default {
     identity: true,
     isPager: true,
     style: {
-      enablePullDownRefresh: true
+      enablePullDownRefresh: false,
+      navigationStyle: 'custom'
     }
   } as ayPage,
   webview_login: {
@@ -76,7 +77,10 @@ export default {
     _type: 'page',
     title: '加气订单',
     identity: true,
-    isPager: false
+    isPager: false,
+    style: {
+      navigationStyle: 'custom'
+    }
   } as ayPage,
   order_createOrder: {
     _url: '/pages/order/createOrder',
@@ -88,7 +92,7 @@ export default {
   order_prePay: {
     _url: '/pages/order/prePay',
     _type: 'page',
-    title: '待支付',
+    title: '加气订单 · 待支付',
     identity: true,
     isPager: false
   } as ayPage,
@@ -126,5 +130,19 @@ export default {
     title: '实名认证',
     identity: true,
     isPager: false
+  } as ayPage,
+  station_detail: {
+    _url: '/pages/station/detail',
+    _type: 'page',
+    title: '加气站详情',
+    identity: true,
+    isPager: false
+  } as ayPage,
+  cards_index: {
+    _url: '/pages/cards/index',
+    _type: 'page',
+    title: '优惠卡/券',
+    identity: true,
+    isPager: false
   } as ayPage
 }

+ 33 - 14
src/utils/container/index.ts

@@ -11,10 +11,23 @@ type goPageExt = {
   params?: AnyObject
 }
 const staticData = {
+  args: {} as AyContainerEntryArgs,
   goPageExt: {} as goPageExt,
 }
 type ExtType<T> = Record<keyof T, { showLoading?: boolean }>
 export default {
+  staticData,
+  initData(data) {
+    const rd = reactive(data)
+    const presetCurPage = store.curPage.initPageInfo({ data: rd, preset: true })
+    rd.pageConfig = {
+      title: presetCurPage.title,
+      style: presetCurPage.style,
+    }
+    return rd
+    // data.pageConfig = store.
+    // return reactive(data)
+  },
   /** 初始化对象内的方法,自动为对象内所有方法增加防重提功能(同步方法、异步方法执行中再次触发不执行) */
 
   initMethods<T>(methods: T, ext?: Record<string, { showLoading?: boolean }>): T {
@@ -53,6 +66,10 @@ export default {
   getResourceUrl(url) {
     return import.meta.env.VITE_RESOURCE_BASEURL + '/' + url
   },
+  /** 获取资源完整地址 */
+  getWebsocketUrl(url) {
+    return import.meta.env.VITE_WEBSOCKET_BASEURL + '/' + url
+  },
   goHome() {
     ay.goPage(config.pages.index_index, { goPageType: enums.GoPageType.reLaunch })
   },
@@ -79,7 +96,9 @@ export default {
     /** 有值时,返回页面时执行AyEntranceCallBack-只执行一次 */
     aceas?: AyContainerEntryArgs
   } = {}) {
-    store.curPage.pageConfig.prePage.onceBackReloadArgs = aceas
+    if (store.curPage.pageConfig.prePage && aceas) {
+      store.curPage.pageConfig.prePage.onceBackReloadArgs = aceas
+    }
     await uni.navigateBack(args)
   },
   /** 页面跳转
@@ -93,15 +112,15 @@ export default {
     if (ext?.goPageType) {
       goPageFunc = uni[ext.goPageType]
     }
-    staticData.goPageExt = ext
+    // staticData.goPageExt = ext
 
     // 防止重复跳转
     func.antiShake({
       func: async () => {
-        await goPageFunc({ url: page._url })
-        // if (ext?.params) {
-        //   store.curPage.initPageInfo({ page, params: ext.params })
-        // }
+        goPageFunc({ url: page._url })
+        if (ext?.params) {
+          store.curPage.initPageInfo({ page, params: ext.params, preset: true })
+        }
       },
       immediately: true,
       mark: page._url,
@@ -121,14 +140,13 @@ export default {
     /** 页面实例的唯一标识 */
     const tempid = Math.random().toString()
     const args: AyContainerEntryArgs = {
-      options: {},
       loadType: enums.LoadType.onLoad,
       cras: config.common.defAyContainerRefreshArgs,
     }
+    staticData.args = args
     const init = () => {
-      store.curPage.initPageInfo({ params: staticData.goPageExt?.params })
+      store.curPage.initPageInfo()
       let isLogined = true
-
       const curPage = store.curPage.pageConfig
       if (curPage.identity) {
         if (!store.user.isLogined) {
@@ -142,11 +160,12 @@ export default {
 
       return isLogined
     }
-
+    onHide(() => {})
     onUnload(() => {
       store.curPage.removeCurPagerInfo()
     })
-    onLoad((options) => {
+    onLoad(() => {
+      console.log('onLoad')
       if (!func.antiShake({ func: init, immediately: true, mark: tempid })) {
         return
       }
@@ -171,9 +190,9 @@ export default {
           callBack(args)
         })
       }
-      if (options) {
-        args.options = options
-      }
+      // if (options) {
+      //   args.options = options
+      // }
       callBack(args)
     })
 

+ 10 - 0
src/utils/func/index.ts

@@ -7,6 +7,16 @@ export default {
   native,
   convert,
   validate,
+  isnull(data) {
+    return !data && data !== 0
+  },
+  promise(func) {
+    return new Promise((s, e) => {
+      if (func) {
+        func(s, e)
+      }
+    })
+  },
   getDate(date) {
     const day = dayjs(date)
     return day

+ 69 - 3
src/utils/func/native.ts

@@ -29,12 +29,78 @@ export default {
     }
     return ret
   },
-  /** 获取当前的地理位置、速度, 获取失败不阻塞,返回默认经纬度 */
-  getLocation() {
+  openSetting(authSetting: keyof UniApp.AuthSetting) {
+    return func.promise((s, e) => {
+      uni.authorize({
+        scope: authSetting,
+        success() {
+          s(true)
+        },
+        fail() {
+          func.native.showModal({
+            title: '温馨提示',
+            content: '检测到您没打开获取位置信息功能权限,是否去设置打开?',
+            confirmText: '确认',
+            cancelText: '取消',
+            showCancel: true,
+            success: function (res) {
+              if (res.confirm) {
+                // 确定
+                uni.openSetting({
+                  success: (res) => {
+                    s(true)
+                  },
+                  fail() {
+                    s(false)
+                  },
+                })
+              } else {
+                // 取消
+                s(false)
+              }
+            },
+          })
+        },
+      })
+    })
+  },
+  /** 获取当前的地理位置、速度, 获取失败不阻塞,返回默认经纬度
+   * @params
+   * returnDef: 获取失败 返回默认值
+   */
+  async getLocation(returnDef = true): Promise<
+    | UniApp.GetLocationSuccess
+    | {
+        longitude: string
+        latitude: string
+      }
+  > {
+    if (!returnDef) {
+      const rv = await func.native.openSetting('scope.userLocation')
+      if (!rv) {
+        return undefined
+      }
+    }
     return uni.getLocation().catch(() => {
-      return { longitude: '', latitude: '' }
+      if (returnDef) {
+        return {
+          longitude: '',
+          latitude: '',
+        }
+      } else {
+        return undefined
+      }
     })
   },
+  /** 使用地图查看位置
+   * 有经纬度 才唤起
+   */
+  openLocation(args: UniApp.OpenLocationOptions) {
+    if (args.latitude && args.longitude) {
+      uni.openLocation(args)
+    }
+  },
+
   /** 显示模态弹窗,默认不显示取消按钮 */
   showModal(args: UniApp.ShowModalOptions) {
     const def: UniApp.ShowModalOptions = {

+ 2 - 2
src/utils/store/common.ts

@@ -3,9 +3,9 @@ import { defineStore } from 'pinia'
 export default defineStore('common', () => {
   const data = reactive({
     debug: false,
-    // 加气量上限
+    /** 加气量上限 */
     preferWeight: 800,
-    // 客服电话
+    /** 客服电话 */
     phone: '400-016-5388',
   })
   return {

+ 37 - 10
src/utils/store/curPage.ts

@@ -2,14 +2,20 @@ import { defineStore } from 'pinia'
 const debug = () => import.meta.env.DEV && true
 /** 当前页面地址 */
 const curPage = ref<string>()
+/** 预制页面地址 */
+const presetCurPage = ref<string>()
+
 const pageConfigs = reactive<Record<string, ayPage>>({})
 /** 当前页面配置信息 */
 const pageConfig = computed(() => {
-  return pageConfigs[curPage.value]
+  return pageConfigs[curPage.value] || config.common.defPageConfig
 })
 const pagerInfo = computed(() => {
   return pageConfig.value.pagerInfo
 })
+const pageData = computed(() => {
+  return pageConfig.value.data
+})
 const loadMoreStatus = computed(() => {
   let rv = 'more'
   if (pagerInfo.value.finished) {
@@ -113,32 +119,52 @@ export default defineStore(
        * @param params 当前页面参数
        * @param loadData 通知页面加载数据
        */
-      initPageInfo({ page, params }: { page?: ayPage; params?: AnyObject } = {}) {
+      initPageInfo({
+        page,
+        params,
+        data,
+        preset = false,
+      }: { page?: ayPage; params?: AnyObject; data?: AnyObject; preset?: boolean } = {}) {
         const prePagePath = curPage.value
+        const cps = getCurrentPages()
         if (page) {
-          curPage.value = page._url
+          presetCurPage.value = page._url
         } else {
-          const cps = getCurrentPages()
           if (cps.length === 0) {
             return
           }
+
           const cur = cps[cps.length - 1]
-          curPage.value = '/' + cur.route
+          presetCurPage.value = '/' + cur.route
+          if (!preset) {
+            curPage.value = presetCurPage.value
+          }
         }
-        if (!pageConfigs[curPage.value]) {
-          pageConfigs[curPage.value] = this.getPageInfo(curPage.value)
+        if (!pageConfigs[presetCurPage.value]) {
+          pageConfigs[presetCurPage.value] = this.getPageInfo(presetCurPage.value)
 
           // 页面首次初始化时,记录之前页面信息
-          if (prePagePath) {
+          if (!preset && prePagePath) {
             pageConfig.value.prePage = pageConfigs[prePagePath]
           }
         }
 
         if (params) {
-          pageConfig.value.params = params
+          pageConfigs[presetCurPage.value].params = params
         }
+        if (data) {
+          pageConfigs[presetCurPage.value].data = data
+        }
+        return pageConfigs[presetCurPage.value]
+      },
+      switchPageInfo() {
+        const cps = getCurrentPages()
+        if (cps.length === 0) {
+          return
+        }
+        const cur = cps[cps.length - 1]
+        curPage.value = '/' + cur.route
       },
-
       getPageInfo(route) {
         if (route === '/') {
           route = config.pages.index_index._url
@@ -162,6 +188,7 @@ export default defineStore(
       /** 当前页面配置信息 */
       pageConfig,
       pagerInfo,
+      pageData,
       /** 分页相关方法 */
       pagerMethods,
       /** uni-load-more 状态 */

+ 8 - 1
src/utils/store/webapi.ts

@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
 import webapiImp from '@/utils/config/webapi'
 
 interface webapistate {
+  _state: number
   /** 设置接口请求状态 */
   set(rs?: number): void
   /** 未请求 */
@@ -10,6 +11,8 @@ interface webapistate {
   ing: boolean
   /** 请求成功 */
   success: boolean
+  /** 首次请求成功 */
+  firstSuccess
   /** 请求失败 */
   fail: boolean
   /** 请求结束 */
@@ -28,8 +31,12 @@ for (const [gk, gv] of Object.entries(webapiImp)) {
   for (const [ik, iv] of Object.entries(gv)) {
     webapi[gk][ik] = {
       _state: undefined,
+      firstSuccess: false,
       set(rs) {
         this._state = rs
+        if (!this.firstSuccess && this.success) {
+          this.firstSuccess = true
+        }
       },
       get unasked() {
         return this._state === enums.ReqState.unasked
@@ -50,7 +57,7 @@ for (const [gk, gv] of Object.entries(webapiImp)) {
       get ios() {
         return this.ing || this.success
       },
-    }
+    } as webapistate
   }
 }
 // const getsun = () => {

+ 3 - 1
tsconfig.json

@@ -29,6 +29,8 @@
     "src/**/*.tsx",
     "src/**/*.jsx",
     "src/**/*.vue",
-    "src/**/*.json"
+    "src/**/*.json",
+    "src/components/drawer/index.vue-",
+    "src/components/countdown/index.vue-"
   ]
 }

+ 27 - 1
uno.config.ts

@@ -7,9 +7,12 @@ import {
   presetIcons,
   transformerDirectives,
   transformerVariantGroup,
+  SourceCodeTransformer,
+  cssIdRE,
 } from 'unocss'
 
 import { presetApplet, presetRemRpx, transformerAttributify } from 'unocss-applet'
+// const common = require('./scripts/common.js')
 
 // @see https://unocss.dev/presets/legacy-compat
 // import { presetLegacyCompat } from '@unocss/preset-legacy-compat'
@@ -23,11 +26,33 @@ if (isMp) {
 } else {
   presets.push(
     // 非小程序用官方预设
-    presetUno(),
+    presetUno({
+      transition: '',
+    }),
     // 支持css class属性化
     presetAttributify(),
   )
 }
+// const index = 0
+/** 性能优化,
+ * 去掉unocss全局变量,解决浏览器调试卡顿问题
+ */
+
+function optimization(): SourceCodeTransformer {
+  return {
+    name: 'my-transformer',
+    enforce: 'pre', // enforce before other transformers
+    idFilter(id) {
+      // 样式文件
+      return cssIdRE.test(id)
+    },
+    async transform(code, id, { uno }) {
+      // common.files.write(common.files.getPath(`temp/${index++}.html`), code.toString())
+
+      code.replace(/\/\* layer: preflights \*\/[\s\S]+un-backdrop-sepia: ;\}\n/, '')
+    },
+  }
+}
 export default defineConfig({
   presets: [
     ...presets,
@@ -54,6 +79,7 @@ export default defineConfig({
    */
   shortcuts: [['center', 'flex justify-center items-center']],
   transformers: [
+    optimization(),
     // 启用 @apply 功能
     transformerDirectives(),
     // 启用 () 分组功能

+ 7 - 6
vite.config.ts

@@ -21,6 +21,7 @@ import { slimMPPlugin, generatePageConfig } from './vitePlugin'
 
 // https://vitejs.dev/config/
 export default ({ command, mode }) => {
+  process.env.VITE_MODE = mode
   // console.log(mode === process.env.NODE_ENV) // true
 
   // mode: 区分生产环境还是开发环境
@@ -48,7 +49,11 @@ export default ({ command, mode }) => {
   console.log('环境变量 env -> ', env)
   const config = defineConfig({
     envDir: './env', // 自定义env目录
-
+    define: {
+      __UNI_PLATFORM__: JSON.stringify(UNI_PLATFORM),
+      __VITE_APP_PROXY__: JSON.stringify(VITE_APP_PROXY),
+      // 'process.env.NODE_ENV': mode,
+    },
     plugins: [
       slimMPPlugin(),
       UniPages({
@@ -57,7 +62,7 @@ export default ({ command, mode }) => {
         // routeBlockLang: 'json5', // 虽然设了默认值,但是vue文件还是要加上 lang="json5", 这样才能很好地格式化
         // homePage 通过 vue 文件的 route-block 的type="home"来设定
         // pages 目录为 src/pages,分包目录不能配置在pages目录下
-        subPackages: ['src/pagesSubExample'], // 是个数组,可以配置多个,但是不能为pages里面的目录
+        subPackages: mode === 'development' ? ['src/pagesSubExample'] : [], // 是个数组,可以配置多个,但是不能为pages里面的目录
         // dts: 'src/types/uni-pages.d.ts',
         dts: false,
         // debug: true,
@@ -131,10 +136,6 @@ export default ({ command, mode }) => {
           brotliSize: true,
         }),
     ],
-    define: {
-      __UNI_PLATFORM__: JSON.stringify(UNI_PLATFORM),
-      __VITE_APP_PROXY__: JSON.stringify(VITE_APP_PROXY),
-    },
     css: {
       preprocessorOptions: {
         scss: {

+ 4 - 3
vitePlugin.ts

@@ -178,7 +178,7 @@ const convert = {
   }: {
     ctx?: PageContext
     /** 子包页面 */
-    spmd?: SubPageMetaDatum & { cusPages?: PageMetaDatum[] }
+    spmd?: SubPageMetaDatum
     /** 最终的配置信息-可手动修改,对应utils/config/pages.ts 或 utils/config/subPages.ts */
     pagesContentObj: AnyObject
   }) {
@@ -195,15 +195,16 @@ const convert = {
       // }
       return rv
     }
+    let cusPages = [] as PageMetaDatum[]
     if (spmd?.pages) {
-      spmd.cusPages = spmd.pages.map<PageMetaDatum>((m) => {
+      cusPages = spmd.pages.map<PageMetaDatum>((m) => {
         return {
           ...m,
           path: `${spmd.root}/${m.path}`,
         }
       })
     }
-    const curPages = ctx?.pageMetaData || spmd?.cusPages
+    const curPages = ctx?.pageMetaData || cusPages
     curPages.forEach((f) => {
       let key = f.path.replaceAll('/', '_')
       if (!/^[$A-Z_][0-9A-Z_$]*$/i.test(key)) {