Просмотр исходного кода

feat(platform): 引入 getWindowWidth 工具函数并优化屏幕宽度获取逻辑

- 新增 platform 工具文件,提供异步获取窗口宽度的通用方法
- 优化 ScaleRuler 组件中屏幕宽度的获取方式,使用新工具函数替换原有同步调用
- 在多个页面组件中更新 Canvas 尺寸计算逻辑,确保适配不同屏幕尺寸
- 修复 QR 码生成时尺寸计算不准确的问题,引入 rpx 到 px 的转换工具
- 提升跨平台兼容性,支持多种 UniApp API 获取屏幕信息的回退机制
- 统一处理窗口宽度获取失败的情况,设置默认值 375px 保证正常渲染
mcbaiyun 1 месяц назад
Родитель
Сommit
ad7b9d8aa5

+ 22 - 17
src/components/scale-ruler.vue

@@ -22,6 +22,7 @@
 <script setup lang="ts">
 import { ref, computed, onMounted } from 'vue'
 import { getCurrentInstance } from 'vue'
+import { getWindowWidth } from '@/utils/platform'
 
 interface GridItem { num: number; displayNum: number | string; isLongGrid: boolean; showText: boolean }
 
@@ -65,8 +66,7 @@ const intStep = Math.round(props.step * scaleFactor)
 const totalUnits = computed(() => Math.round((intMax - intMin) / intStep))
 
 
-const extraGridCount = Math.ceil((uni?.getSystemInfoSync?.().windowWidth || 375) / props.gutter / 2) * 2
-
+const extraGridCount = ref(0)
 const gridList = ref<GridItem[]>([])
 const totalWidth = ref(0)
 
@@ -75,8 +75,9 @@ const gridItemStyle = computed(() => ({ width: props.gutter + 'px', height: '24p
 function buildGrid() {
   const count = totalUnits.value
   const arr: GridItem[] = []
-  for (let i = 0; i <= count + extraGridCount * 1; i++) {
-    const numIndex = i - extraGridCount / 2
+  const extra = extraGridCount.value || 0
+  for (let i = 0; i <= count + extra * 1; i++) {
+    const numIndex = i - extra / 2
     const intNum = intMin + numIndex * intStep
     const num = intNum / scaleFactor
     const displayNum = (Number.isInteger(num) ? num : Number(num.toFixed(stepDecimals)))
@@ -89,23 +90,27 @@ function buildGrid() {
   totalWidth.value = arr.length * props.gutter
 }
 
-buildGrid()
-
-const offsetScroll = computed(() => extraGridCount * props.gutter/2)
+const offsetScroll = computed(() => (extraGridCount.value || 0) * props.gutter / 2)
 
-const windowWidth = uni?.getSystemInfoSync?.().windowWidth || 375
-const halfWindow = windowWidth / 2
+const windowWidthRef = ref(375)
+const halfWindow = computed(() => windowWidthRef.value / 2)
 
 
-onMounted(() => {
+onMounted(async () => {
+  // 获取宽度并初始化相关计算
+  const w = await getWindowWidth().catch(() => 375)
+  windowWidthRef.value = w
+  extraGridCount.value = Math.ceil((w || 375) / props.gutter / 2) * 2
+  // 重建 grid
+  buildGrid()
 
   // initialize using integer index space
   const initIndex = Math.round((Math.round((props.initialValue || props.min) * scaleFactor) - intMin) / intStep)
-  scrollLeft.value = offsetScroll.value + initIndex * props.gutter + props.gutter / 2 - halfWindow
+  scrollLeft.value = offsetScroll.value + initIndex * props.gutter + props.gutter / 2 - halfWindow.value
   const initVal = (intMin + initIndex * intStep) / scaleFactor
   currentValue.value = Number(stepDecimals ? initVal.toFixed(stepDecimals) : String(initVal))
 
-  scrollLeft.value = offsetScroll.value + initIndex * props.gutter + props.gutter / 2 - halfWindow
+  scrollLeft.value = offsetScroll.value + initIndex * props.gutter + props.gutter / 2 - halfWindow.value
 
   currentValue.value = Math.round(initIndex * props.step + props.min)
 })
@@ -114,7 +119,7 @@ function onScroll(e: any) {
   const left = e?.detail?.scrollLeft ?? e?.detail?.scrollLeft ?? 0
   actualScrollLeft.value = left
 
-  const numIndex = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
+  const numIndex = Math.round((left + halfWindow.value - offsetScroll.value - props.gutter / 2) / props.gutter)
   let intValue = intMin + numIndex * intStep
   if (intValue < intMin) intValue = intMin
   if (intValue > intMax) intValue = intMax
@@ -127,11 +132,11 @@ function adjustScrollPosition() {
 
   const left = actualScrollLeft.value
 
-  const numIndex = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
+  const numIndex = Math.round((left + halfWindow.value - offsetScroll.value - props.gutter / 2) / props.gutter)
 
-  const targetLeft = offsetScroll.value + numIndex * props.gutter + props.gutter / 2 - halfWindow
+  const targetLeft = offsetScroll.value + numIndex * props.gutter + props.gutter / 2 - halfWindow.value
 
-  const maxScroll = Math.max(0, totalWidth.value - windowWidth)
+  const maxScroll = Math.max(0, totalWidth.value - windowWidthRef.value)
   const clamped = Math.min(Math.max(targetLeft, 0), maxScroll)
   scrollLeft.value = clamped
 }
@@ -141,7 +146,7 @@ function onTouchEnd() {
   adjustScrollPosition()
 
   const left = scrollLeft.value
-  const numIndex = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
+  const numIndex = Math.round((left + halfWindow.value - offsetScroll.value - props.gutter / 2) / props.gutter)
   let intValue = intMin + numIndex * intStep
   if (intValue < intMin) intValue = intMin
   if (intValue > intMax) intValue = intMax

+ 6 - 7
src/pages/patient/health/details/blood-glucose.vue

@@ -95,6 +95,7 @@ import CustomNav from '@/components/custom-nav.vue'
 import ScaleRuler from '@/components/scale-ruler.vue'
 import { createUChart } from '@/composables/useUChart'
 import { getWeekStart, getWeekEnd, formatDisplayDate, formatPickerDate, daysInMonth } from '@/utils/date'
+import { getWindowWidth } from '@/utils/platform'
 
 type RecordItem = { id: string; date: string; value: number; type: string }
 
@@ -118,13 +119,11 @@ const canvasHeight = ref(280)
 
 // 获取Canvas实际尺寸的函数 - 参考微信小程序示例使用固定尺寸
 function getCanvasSize(): Promise<{ width: number; height: number }> {
-  return new Promise((resolve) => {
-    // 使用固定尺寸,参考微信小程序示例
-    const windowWidth = uni.getSystemInfoSync().windowWidth;
-    const width = windowWidth; // 占满屏幕宽度
-    const height = 280 / 750 * windowWidth; // 280rpx转换为px,与CSS高度匹配
-    resolve({ width, height });
-  });
+  return new Promise(async (resolve) => {
+    const width = await getWindowWidth().catch(() => 375)
+    const height = Math.round((280 / 750) * width)
+    resolve({ width, height })
+  })
 }
 
 // 使用共享日期工具 (src/utils/date.ts)

+ 6 - 7
src/pages/patient/health/details/blood-pressure.vue

@@ -97,6 +97,7 @@ import CustomNav from '@/components/custom-nav.vue'
 
 import ScaleRuler from '@/components/scale-ruler.vue'
 import { getWeekStart, getWeekEnd, formatDisplayDate, formatPickerDate, daysInMonth } from '@/utils/date'
+import { getWindowWidth } from '@/utils/platform'
 
 type RecordItem = { id: string; date: string; s: number; d: number }
 
@@ -120,13 +121,11 @@ const canvasHeight = ref(320)
 
 // 获取Canvas实际尺寸的函数 - 参考微信小程序示例使用固定尺寸
 function getCanvasSize(): Promise<{ width: number; height: number }> {
-  return new Promise((resolve) => {
-    // 使用固定尺寸,参考微信小程序示例
-    const windowWidth = uni.getSystemInfoSync().windowWidth;
-    const width = windowWidth; // 占满屏幕宽度
-    const height = 320 / 750 * windowWidth; // 320rpx转换为px,与CSS高度匹配
-    resolve({ width, height });
-  });
+  return new Promise(async (resolve) => {
+    const width = await getWindowWidth().catch(() => 375)
+    const height = Math.round((320 / 750) * width)
+    resolve({ width, height })
+  })
 }
 
 // 使用 formatPickerDate 从 src/utils/date.ts

+ 6 - 7
src/pages/patient/health/details/heart-rate.vue

@@ -87,6 +87,7 @@ import CustomNav from '@/components/custom-nav.vue'
 
 import ScaleRuler from '@/components/scale-ruler.vue'
 import { getWeekStart, getWeekEnd, formatDisplayDate, formatPickerDate, daysInMonth } from '@/utils/date'
+import { getWindowWidth } from '@/utils/platform'
 
 type RecordItem = { id: string; date: string; hr: number }
 
@@ -110,13 +111,11 @@ const canvasHeight = ref(280)
 
 // 获取Canvas实际尺寸的函数 - 参考微信小程序示例使用固定尺寸
 function getCanvasSize(): Promise<{ width: number; height: number }> {
-  return new Promise((resolve) => {
-    // 使用固定尺寸,参考微信小程序示例
-    const windowWidth = uni.getSystemInfoSync().windowWidth;
-    const width = windowWidth; // 占满屏幕宽度
-    const height = 280 / 750 * windowWidth; // 280rpx转换为px,与CSS高度匹配
-    resolve({ width, height });
-  });
+  return new Promise(async (resolve) => {
+    const width = await getWindowWidth().catch(() => 375)
+    const height = Math.round((280 / 750) * width)
+    resolve({ width, height })
+  })
 }
 
 // 使用共享日期工具 (src/utils/date.ts)

+ 6 - 7
src/pages/patient/health/details/physical.vue

@@ -103,6 +103,7 @@ import CustomNav from '@/components/custom-nav.vue'
 
 import ScaleRuler from '@/components/scale-ruler.vue'
 import { getWeekStart, getWeekEnd, formatDisplayDate, formatPickerDate, daysInMonth } from '@/utils/date'
+import { getWindowWidth, rpxToPx } from '@/utils/platform'
 
 type RecordItem = { id: string; date: string; h: number; w: number; bmi: number }
 
@@ -126,13 +127,11 @@ const canvasHeight = ref(320)
 
 // 获取Canvas实际尺寸的函数 - 参考微信小程序示例使用固定尺寸
 function getCanvasSize(): Promise<{ width: number; height: number }> {
-  return new Promise((resolve) => {
-    // 使用固定尺寸,参考微信小程序示例
-    const windowWidth = uni.getSystemInfoSync().windowWidth;
-    const width = windowWidth; // 占满屏幕宽度
-    const height = 320 / 750 * windowWidth; // 320rpx转换为px,与CSS高度匹配
-    resolve({ width, height });
-  });
+  return new Promise(async (resolve) => {
+    const width = await getWindowWidth().catch(() => 375)
+    const height = Math.round((320 / 750) * width)
+    resolve({ width, height })
+  })
 }
 
 // 使用 formatPickerDate 从 src/utils/date.ts

+ 5 - 6
src/pages/public/profile/qr/index.vue

@@ -28,6 +28,7 @@
 
 <script setup lang="ts">
 import { ref, onMounted } from 'vue'
+import { getWindowWidth, rpxToPx } from '@/utils/platform'
 import { onShow } from '@dcloudio/uni-app'
 import CustomNav from '@/components/custom-nav.vue'
 // @ts-ignore
@@ -135,7 +136,7 @@ const refreshAndGenerate = async () => {
   }
 }
 
-const generateQRCode = () => {
+const generateQRCode = async () => {
   console.log('Generating QR code, user data:', user.value)
   if (!user.value.wx_openid || !user.value.role) {
     console.log('Missing wx_openid or role:', { wx_openid: user.value.wx_openid, role: user.value.role })
@@ -148,11 +149,9 @@ const generateQRCode = () => {
   })
   console.log('QR data:', data)
   qrData.value = data
-  // 获取系统信息,计算 rpx 到 px 的转换
-  const systemInfo = uni.getSystemInfoSync()
-  const rpxToPx = systemInfo.windowWidth / 750
-  const qrSizeRpx = 350 // 与 CSS 中的 .qr-canvas 尺寸一致 (rpx)
-  const qrSizePx = Math.floor(qrSizeRpx * rpxToPx) // 转换为像素
+  // 获取屏幕宽度并计算 rpx->px
+  const width = await getWindowWidth().catch(() => 375)
+  const qrSizePx = rpxToPx(350, width)
   // 使用 weapp-qrcode 生成二维码
   drawQrcode({
     width: qrSizePx,

+ 45 - 0
src/utils/platform.ts

@@ -0,0 +1,45 @@
+export async function getWindowWidth(): Promise<number> {
+  let windowWidth: number | undefined
+  try {
+    // 优先使用新的 uni API(可能返回值或 Promise)
+    const u: any = typeof uni !== 'undefined' ? uni : (globalThis as any).wx || {}
+
+    if (typeof u.getWindowInfo === 'function') {
+      const ret = u.getWindowInfo()
+      const info = ret && ret.then ? await ret : ret
+      windowWidth = info?.windowWidth || info?.screenWidth
+    }
+
+    if (!windowWidth && typeof u.getDeviceInfo === 'function') {
+      const ret = u.getDeviceInfo()
+      const info = ret && ret.then ? await ret : ret
+      windowWidth = info?.windowWidth || info?.screenWidth
+    }
+
+    if (!windowWidth && typeof u.getAppBaseInfo === 'function') {
+      const ret = u.getAppBaseInfo()
+      const info = ret && ret.then ? await ret : ret
+      windowWidth = info?.windowWidth || info?.screenWidth
+    }
+  } catch (e) {
+    // 忽略错误,后面回退
+    console.warn('getWindowWidth prefer APIs failed', e)
+  }
+
+  if (!windowWidth) {
+    try {
+      const sys = (uni as any).getSystemInfoSync()
+      windowWidth = sys?.windowWidth
+    } catch (e) {
+      // 最后使用一个安全默认
+      windowWidth = 375
+    }
+  }
+
+  return windowWidth as number
+}
+
+export function rpxToPx(rpx: number, windowWidth?: number) {
+  const w = windowWidth || 375
+  return Math.floor((rpx / 750) * w)
+}