Explorar el Código

feat: 系统更新

ljc hace 2 semanas
padre
commit
e17bf52a1b
Se han modificado 4 ficheros con 1091 adiciones y 1038 borrados
  1. 501 473
      App.vue
  2. 557 539
      hooks/useAppUpdate.ts
  3. 5 2
      pages/login/index.vue
  4. 28 24
      pages/mine/improveImmediately.vue

+ 501 - 473
App.vue

@@ -1,483 +1,511 @@
 <script setup>
-import { ref, onMounted, nextTick, watch, onUnmounted, getCurrentInstance } from 'vue';
-import { useI18n } from "vue-i18n";
-import config from '@/config'
-const { locale } = useI18n();
-const { Host80 } = config
-
-import {
-	onLoad,
-	onShow,
-	onLaunch
-} from '@dcloudio/uni-app'
-import {
-	updateRoute
-} from "@/hooks/useRoute";
-import useGlobalStore from "@/stores/use-global-store";
-import { userToken } from '@/composables/config'
-// import { useAppUpdate } from '@/hooks/useAppUpdate'
-// const { checkUpdate } = useAppUpdate()
-const globalStore = useGlobalStore()
-onLoad((options) => {
-	updateRoute();
-	// checkUpdate()
-})
-onShow((options) => {
-	updateRoute();
-	// checkUpdate()
+  import { ref, onMounted, nextTick, watch, onUnmounted, getCurrentInstance } from 'vue'
+  import { useI18n } from 'vue-i18n'
+  import config from '@/config'
+
+  const { t, locale } = useI18n()
+  const { Host80 } = config
+
+  import {
+    onLoad,
+    onShow,
+    onLaunch,
+  } from '@dcloudio/uni-app'
+  import {
+    updateRoute,
+  } from '@/hooks/useRoute'
+  import useGlobalStore from '@/stores/use-global-store'
+  import { userToken } from '@/composables/config'
+  import { useAppUpdate } from '@/hooks/useAppUpdate'
+
+  const { checkUpdate } = useAppUpdate()
+  const globalStore = useGlobalStore()
+  onLoad((options) => {
+    updateRoute()
+    // checkUpdate()
+  })
+  onShow((options) => {
+    updateRoute()
+    // checkUpdate()
     handleSignupRoute(options)
-})
-
-// App.vue 或你的初始化文件中
-function initTheme() {
-	// #ifdef H5
-	// H5 端:使用 matchMedia 主动获取当前系统主题
-	const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
-	const theme = isDarkMode ? 'dark' : 'light'
-	globalStore.setGlobalTheme(theme)
-
-	// 监听变化(你的 onThemeChange 已经能工作,但可以再加一层保险)
-	const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)')
-	const handleChange = (e) => {
-		const newTheme = e.matches ? 'dark' : 'light'
-		globalStore.setGlobalTheme(newTheme)
-	}
-	// 兼容旧版浏览器
-	if (darkModeQuery.addEventListener) {
-		darkModeQuery.addEventListener('change', handleChange)
-	} else {
-		darkModeQuery.addListener(handleChange)
-	}
-	// 设置 data-bs-theme 属性到 html 标签
-	document.documentElement.setAttribute('data-bs-theme', theme);
-	document.documentElement.setAttribute('data-color-theme', 'blue');
-	// 同时设置到 body 标签
-	document.body.setAttribute('data-bs-theme', theme);
-	document.body.setAttribute('data-color-theme', 'blue');
-	// #endif
-
-	// #ifdef APP-PLUS
-	// App 端:使用原生 API
-	uni.getSystemInfo({
-		success: (res) => {
-			let theme = res.osTheme || 'light'
-			globalStore.setGlobalTheme(theme)
-		}
-	})
-	uni.onThemeChange((res) => {
-		globalStore.setGlobalTheme(res.theme)
-	})
-	// #endif
-}
-
-
-onLaunch((options) => {
-	// updateRoute();
-	// checkUpdate()
-	// 调用初始化
-	// initTheme()
-  // checkWgtUpdate()
-
-
-	// #ifdef H5
-	// 处理 signup 路径
-	document.title = 'CWGMarkets'
-	// 防止后面又被改掉,再加个定时器兜底
-	setInterval(() => {
-		if (!document.title) document.title = 'CWGMarkets'
-	}, 500)
-	// #endif
-
-})
-
-// 解析 URL 参数
-const parseUrlParams = () => {
-	const params = {}
-
-	// #ifdef H5
-	// H5 端:直接从浏览器 URL 解析
-	if (typeof window !== 'undefined' && window.location) {
-		const href = window.location.href
-		// 解析 hash 部分
-		const hashIndex = href.indexOf('#')
-		if (hashIndex !== -1) {
-			const hash = href.substring(hashIndex + 1)
-			// 解析路径
-			const pathMatch = hash.match(/^\/([^/?]+)/)
-			if (pathMatch) {
-				params.path = pathMatch[1]
-			}
-			// 解析路径参数 signup/19628/RHOP4WVa/B0
-			const pathParams = hash.match(/^\/signup\/([^/]+)\/?([^/]+)?\/?([^/]+)?/)
-			if (pathParams) {
-				params.path = 'signup'
-				params.p1 = pathParams[1]
-				params.p2 = pathParams[2]
-				params.p3 = pathParams[3]
-			}
-			// 解析 query 参数
-			const queryIndex = hash.indexOf('?')
-			if (queryIndex !== -1) {
-				const queryStr = hash.substring(queryIndex + 1)
-				const pairs = queryStr.split('&')
-				pairs.forEach(pair => {
-					const [key, value] = pair.split('=')
-					if (key && value) {
-						params[key] = decodeURIComponent(value)
-					}
-				})
-			}
-		}
-	}
-	// #endif
-
-	// #ifndef H5
-	// App 端:从 options 参数获取
-	if (typeof options === 'object' && options !== null) {
-		Object.assign(params, options)
-	}
-	// #endif
-
-	return params
-}
-
-// #ifdef H5
-/** 当前 hash 路径(不含 query) */
-const getHashPath = () => {
-	if (typeof window === 'undefined' || !window.location?.href) return ''
-	const hashIndex = window.location.href.indexOf('#')
-	if (hashIndex === -1) return ''
-	let hash = window.location.href.substring(hashIndex + 1)
-	const queryIndex = hash.indexOf('?')
-	if (queryIndex !== -1) hash = hash.substring(0, queryIndex)
-	if (!hash) return '/'
-	return hash.startsWith('/') ? hash : `/${hash}`
-}
-
-/** hash 是否在 __uniRoutes 白名单内(匹配 path / alias / meta.route) */
-const isInUniRoutes = (hashPath) => {
-	if (typeof __uniRoutes === 'undefined' || !__uniRoutes?.length) return true
-	const normalized = (hashPath || '/').replace(/\/$/, '') || '/'
-	return __uniRoutes.some((route) => {
-		const candidates = [
-			route.path,
-			route.alias,
-			route.meta?.route ? `/${route.meta.route.replace(/^\//, '')}` : '',
-		].filter(Boolean)
-		return candidates.some((p) => {
-			const item = (p || '/').replace(/\/$/, '') || '/'
-			return normalized === item
-		})
-	})
-}
-
-/** 未登录可访问:登录 / 注册 / 修改密码 */
-const AUTH_PUBLIC_PATHS = [
-	'/pages/login/index',
-	'/pages/login/regist',
-	'/pages/login/reset',
-]
-
-const isAuthPublicPath = (hashPath) => {
-	const normalized = (hashPath || '/').replace(/\/$/, '') || '/'
-	return AUTH_PUBLIC_PATHS.includes(normalized)
-}
-// #endif
-
-// 处理 signup 和 signin 路径(仅 H5 端)
-const handleSignupRoute = (options) => {
-	// #ifdef H5
-	// 解析 URL 参数(从浏览器 URL 解析)
-	const query = parseUrlParams()
-	console.log('解析到的参数:', query);
-
-	// 处理 signin 路径(自动登录)
-	if (query.path === 'signin') {
-
-		// 跳转到登录页面 有就携带 token 参数
-		const loginUrl = query?.sysLoginToken ? `/pages/login/index?sysLoginToken=${encodeURIComponent(query.sysLoginToken)}` : '/pages/login/index'
-		console.log('跳转到登录页面:', loginUrl);
-
-		uni.reLaunch({
-			url: loginUrl,
-			success: () => {
-				console.log('跳转成功');
-			},
-			fail: (err) => {
-				console.error('跳转失败:', err);
-			}
-		})
-		return
-	}
-
-	// 判断是否是 signup 路径
-	const isSignup = query.path === 'signup' || query.s || query.signup || query.activeTab === '2'
-
-	if (!isSignup) {
-		const hashPath = getHashPath()
-		// 未登录:仅允许登录 / 注册 / 修改密码
-		if (!userToken.value) {
-			if (!isAuthPublicPath(hashPath)) {
-				uni.reLaunch({ url: '/pages/login/index' })
-			}
-			return
-		}
-		// 已登录:不在 __uniRoutes 内的 hash 路径跳转登录页
-		if (!isInUniRoutes(hashPath)) {
-			uni.reLaunch({ url: '/pages/login/index' })
-		}
-		return
-	}
-
-	// 已在登录页注册 Tab(含代理参数),无需重复 reLaunch
-	const hashPath = getHashPath()
-	if (hashPath === '/pages/login/index' && String(query.activeTab) === '2') {
-		return
-	}
-
-	// 获取参数
-	const id = query.id || query.agentId || query.p1 || ''
-	const subId = query.subId || query.w || query.p2 || ''
-	const code = query.code || query.oc || query.p3 || ''
-
-	// 构建登录页面 URL
-	let loginUrl = '/pages/login/index?activeTab=2'
-	// 携带参数
-	if (id) loginUrl += `&id=${id}`
-	if (subId) loginUrl += `&subId=${subId}`
-	if (code) loginUrl += `&code=${code}`
-
-	console.log('跳转到:', loginUrl);
-
-	// 跳转到注册页面
-	uni.reLaunch({
-		url: loginUrl,
-		success: () => {
-			console.log('跳转成功');
-		},
-		fail: (err) => {
-			console.error('跳转失败:', err);
-		}
-	})
-	// #endif
-}
-
-watch(locale, () => {
-	// const currentPath = route.path;
-	// menu.value.forEach((item, index) => {
-	// 	if (item.children) {
-	// 		const isActive = item.children.some(child => child.path.includes(currentPath));
-	// 		menu.value[index].isOpenMenu = isActive;
-	// 		if (isActive) {
-	// 			nextTick(() => {
-	// 				updateSubmenuHeight(index);
-	// 			});
-	// 		}
-	// 	}
-	// });
-}, { immediate: true })
-
-// 检测版本号更新
-const checkWgtUpdate = async () => {
-	try {
+  })
+
+  // App.vue 或你的初始化文件中
+  function initTheme() {
+    // #ifdef H5
+    // H5 端:使用 matchMedia 主动获取当前系统主题
+    const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
+    const theme = isDarkMode ? 'dark' : 'light'
+    globalStore.setGlobalTheme(theme)
+
+    // 监听变化(你的 onThemeChange 已经能工作,但可以再加一层保险)
+    const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)')
+    const handleChange = (e) => {
+      const newTheme = e.matches ? 'dark' : 'light'
+      globalStore.setGlobalTheme(newTheme)
+    }
+    // 兼容旧版浏览器
+    if (darkModeQuery.addEventListener) {
+      darkModeQuery.addEventListener('change', handleChange)
+    } else {
+      darkModeQuery.addListener(handleChange)
+    }
+    // 设置 data-bs-theme 属性到 html 标签
+    document.documentElement.setAttribute('data-bs-theme', theme)
+    document.documentElement.setAttribute('data-color-theme', 'blue')
+    // 同时设置到 body 标签
+    document.body.setAttribute('data-bs-theme', theme)
+    document.body.setAttribute('data-color-theme', 'blue')
+    // #endif
+
+    // #ifdef APP-PLUS
+    // App 端:使用原生 API
+    uni.getSystemInfo({
+      success: (res) => {
+        let theme = res.osTheme || 'light'
+        globalStore.setGlobalTheme(theme)
+      },
+    })
+    uni.onThemeChange((res) => {
+      globalStore.setGlobalTheme(res.theme)
+    })
+    // #endif
+  }
+
+
+  onLaunch((options) => {
+    // updateRoute();
+    // checkUpdate()
+    // 调用初始化
+    // initTheme()
+
+    // #ifdef APP-PLUS
+    uni.getSystemInfo({
+      success: res => {       // android且非谷歌渠道才执行
+        if(res.platform=="android"){
+          // 区分是否谷歌打包:用渠道名/manifest自定义参数
+          let channel = plus.runtime.channel;
+          if(channel != "google"){
+            // 仅国内APK执行代码
+            checkUpdate()
+            // console.log('普通APK专属逻辑')
+          }
+        }     }
+    })
+    // checkWgtUpdate()
+
+    // #endif
+
+    // #ifdef H5
+    // 处理 signup 路径
+    document.title = 'CWGMarkets'
+    // 防止后面又被改掉,再加个定时器兜底
+    setInterval(() => {
+      if (!document.title) document.title = 'CWGMarkets'
+    }, 500)
+    // #endif
+
+  })
+
+  // 解析 URL 参数
+  const parseUrlParams = () => {
+    const params = {}
+
+    // #ifdef H5
+    // H5 端:直接从浏览器 URL 解析
+    if (typeof window !== 'undefined' && window.location) {
+      const href = window.location.href
+      // 解析 hash 部分
+      const hashIndex = href.indexOf('#')
+      if (hashIndex !== -1) {
+        const hash = href.substring(hashIndex + 1)
+        // 解析路径
+        const pathMatch = hash.match(/^\/([^/?]+)/)
+        if (pathMatch) {
+          params.path = pathMatch[1]
+        }
+        // 解析路径参数 signup/19628/RHOP4WVa/B0
+        const pathParams = hash.match(/^\/signup\/([^/]+)\/?([^/]+)?\/?([^/]+)?/)
+        if (pathParams) {
+          params.path = 'signup'
+          params.p1 = pathParams[1]
+          params.p2 = pathParams[2]
+          params.p3 = pathParams[3]
+        }
+        // 解析 query 参数
+        const queryIndex = hash.indexOf('?')
+        if (queryIndex !== -1) {
+          const queryStr = hash.substring(queryIndex + 1)
+          const pairs = queryStr.split('&')
+          pairs.forEach(pair => {
+            const [key, value] = pair.split('=')
+            if (key && value) {
+              params[key] = decodeURIComponent(value)
+            }
+          })
+        }
+      }
+    }
+    // #endif
+
+    // #ifndef H5
+    // App 端:从 options 参数获取
+    if (typeof options === 'object' && options !== null) {
+      Object.assign(params, options)
+    }
+    // #endif
+
+    return params
+  }
+
+  // #ifdef H5
+  /** 当前 hash 路径(不含 query) */
+  const getHashPath = () => {
+    if (typeof window === 'undefined' || !window.location?.href) return ''
+    const hashIndex = window.location.href.indexOf('#')
+    if (hashIndex === -1) return ''
+    let hash = window.location.href.substring(hashIndex + 1)
+    const queryIndex = hash.indexOf('?')
+    if (queryIndex !== -1) hash = hash.substring(0, queryIndex)
+    if (!hash) return '/'
+    return hash.startsWith('/') ? hash : `/${hash}`
+  }
+
+  /** hash 是否在 __uniRoutes 白名单内(匹配 path / alias / meta.route) */
+  const isInUniRoutes = (hashPath) => {
+    if (typeof __uniRoutes === 'undefined' || !__uniRoutes?.length) return true
+    const normalized = (hashPath || '/').replace(/\/$/, '') || '/'
+    return __uniRoutes.some((route) => {
+      const candidates = [
+        route.path,
+        route.alias,
+        route.meta?.route ? `/${route.meta.route.replace(/^\//, '')}` : '',
+      ].filter(Boolean)
+      return candidates.some((p) => {
+        const item = (p || '/').replace(/\/$/, '') || '/'
+        return normalized === item
+      })
+    })
+  }
+
+  /** 未登录可访问:登录 / 注册 / 修改密码 */
+  const AUTH_PUBLIC_PATHS = [
+    '/pages/login/index',
+    '/pages/login/regist',
+    '/pages/login/reset',
+  ]
+
+  const isAuthPublicPath = (hashPath) => {
+    const normalized = (hashPath || '/').replace(/\/$/, '') || '/'
+    return AUTH_PUBLIC_PATHS.includes(normalized)
+  }
+  // #endif
+
+  // 处理 signup 和 signin 路径(仅 H5 端)
+  const handleSignupRoute = (options) => {
+    // #ifdef H5
+    // 解析 URL 参数(从浏览器 URL 解析)
+    const query = parseUrlParams()
+    console.log('解析到的参数:', query)
+
+    // 处理 signin 路径(自动登录)
+    if (query.path === 'signin') {
+
+      // 跳转到登录页面 有就携带 token 参数
+      const loginUrl = query?.sysLoginToken ? `/pages/login/index?sysLoginToken=${encodeURIComponent(query.sysLoginToken)}` : '/pages/login/index'
+      console.log('跳转到登录页面:', loginUrl)
+
+      uni.reLaunch({
+        url: loginUrl,
+        success: () => {
+          console.log('跳转成功')
+        },
+        fail: (err) => {
+          console.error('跳转失败:', err)
+        },
+      })
+      return
+    }
+
+    // 判断是否是 signup 路径
+    const isSignup = query.path === 'signup' || query.s || query.signup || query.activeTab === '2'
+
+    if (!isSignup) {
+      const hashPath = getHashPath()
+      // 未登录:仅允许登录 / 注册 / 修改密码
+      if (!userToken.value) {
+        if (!isAuthPublicPath(hashPath)) {
+          uni.reLaunch({ url: '/pages/login/index' })
+        }
+        return
+      }
+      // 已登录:不在 __uniRoutes 内的 hash 路径跳转登录页
+      if (!isInUniRoutes(hashPath)) {
+        uni.reLaunch({ url: '/pages/login/index' })
+      }
+      return
+    }
+
+    // 已在登录页注册 Tab(含代理参数),无需重复 reLaunch
+    const hashPath = getHashPath()
+    if (hashPath === '/pages/login/index' && String(query.activeTab) === '2') {
+      return
+    }
+
+    // 获取参数
+    const id = query.id || query.agentId || query.p1 || ''
+    const subId = query.subId || query.w || query.p2 || ''
+    const code = query.code || query.oc || query.p3 || ''
+
+    // 构建登录页面 URL
+    let loginUrl = '/pages/login/index?activeTab=2'
+    // 携带参数
+    if (id) loginUrl += `&id=${id}`
+    if (subId) loginUrl += `&subId=${subId}`
+    if (code) loginUrl += `&code=${code}`
+
+    console.log('跳转到:', loginUrl)
+
+    // 跳转到注册页面
+    uni.reLaunch({
+      url: loginUrl,
+      success: () => {
+        console.log('跳转成功')
+      },
+      fail: (err) => {
+        console.error('跳转失败:', err)
+      },
+    })
+    // #endif
+  }
+
+
+  watch(locale, () => {
+    // const currentPath = route.path;
+    // menu.value.forEach((item, index) => {
+    // 	if (item.children) {
+    // 		const isActive = item.children.some(child => child.path.includes(currentPath));
+    // 		menu.value[index].isOpenMenu = isActive;
+    // 		if (isActive) {
+    // 			nextTick(() => {
+    // 				updateSubmenuHeight(index);
+    // 			});
+    // 		}
+    // 	}
+    // });
+  }, { immediate: true })
+
+  // 检测版本号更新
+  const checkWgtUpdate = async () => {
     console.log(Host80)
-		const currentVersion = await getCurrentVersion()
-		const res = await uni.request({
-			url: `${Host80}/wgt/list.json?_t=${Date.now()}`,
-			method: 'GET',
-			timeout: 5000
-		})
-    console.log('up:filedata',res)
-		const files = res.data?.files || []
-		if (!files.length) return
-		const latestFile = files[files.length - 1]
-		const latestVersion = latestFile
-    console.log('last',latestFile,latestVersion)
-		if (!latestFile) return
-		const lastInstalled = uni.getStorageSync('lastWgtVersion')
-		console.log(lastInstalled, 'lastInstalled');
-		if (latestVersion === lastInstalled) return
-		if (compareVersion(latestVersion, currentVersion) > 0) {
-			downloadAndInstall(latestVersion)
-		}
-	} catch (e) {
-		console.log('[wgt] update check failed', e)
-	}
-}
-
-// 下载并安装
-const downloadAndInstall = (version) => {
-	//TODO: 需要根据版本来确定url
-	const url = `https://ucard.44a5c8109e4.com/wgt/__UNI__EFA7490.wgt`
-	console.log(url, 'downloadurl');
-
-	uni.downloadFile({
-		url,
-		success: (res) => {
-			if (res.statusCode === 200) {
-				const filePath = res.tempFilePath
-				plus.runtime.install(
-					filePath, {
-					force: true
-				},
-					() => {
-						uni.setStorageSync('lastWgtVersion', version)
-						console.log('[wgt] install success:', version)
-						uni.setStorageSync('wgtNeedRestart', true)
-					},
-					(err) => {
-						console.error('[wgt] install failed:', err)
-					}
-				)
-			} else {
-				console.error('[wgt] download status error:', res.statusCode)
-			}
-		},
-		fail: (err) => {
-			console.error('[wgt] download failed:', err)
-		}
-	})
-}
-// 获取当前版本
-const getCurrentVersion = async () => {
-	return new Promise((resolve, reject) => {
-		// #ifdef APP-PLUS
-		try {
-			plus.runtime.getProperty(plus.runtime.appid, (info) => {
-				resolve(info.version)
-			}, (error) => {
-				reject(error)
-			})
-		} catch (error) {
-			reject(error)
-		}
-		// #endif
-		// #ifndef APP-PLUS
-		reject(new Error('Not in APP-PLUS environment'))
-		// #endif
-	})
-}
-// 对比版本号
-const compareVersion = (v1, v2) => {
-	const s1 = v1.split('.').map(Number)
-	const s2 = v2.split('.').map(Number)
-	const len = Math.max(s1.length, s2.length)
-
-	for (let i = 0; i < len; i++) {
-		const n1 = s1[i] || 0
-		const n2 = s2[i] || 0
-		if (n1 > n2) return 1
-		if (n1 < n2) return -1
-	}
-	return 0
-}
-
-onMounted(() => {
-	const sysInfo = uni.getSystemInfoSync();
-	globalStore.setBarHeight(sysInfo.statusBarHeight || 60);
-
-	// ---------- 新增 H5 端专属初始化 ----------
-	// 仅在 H5 端执行(通过环境判断)
-	// #ifdef H5
-	if (typeof window !== 'undefined') {
-		const instance = getCurrentInstance()
-		if (instance) {
-			window.vm = instance.proxy
-		}
-	}
-	window.addEventListener('hashchange', handleSignupRoute)
-	// #endif
-});
-onUnmounted(() => {
-	// #ifdef H5
-	window.removeEventListener('hashchange', handleSignupRoute)
-	// #endif
-})
+    try {
+      console.log(Host80)
+      const currentVersion = await getCurrentVersion()
+      const res = await uni.request({
+        url: `${Host80}/wgt/list.json?_t=${Date.now()}`,
+        method: 'GET',
+        timeout: 5000,
+      })
+      console.log('up:filedata', res)
+      console.log(currentVersion, 'currentVersion')
+      const files = res.data?.files || []
+      if (!files.length) return
+      const latestFile = files[files.length - 1]
+      const latestVersion = latestFile
+      console.log('last', latestFile, latestVersion)
+      if (!latestFile) return
+      const lastInstalled = uni.getStorageSync('lastWgtVersion')
+      console.log(lastInstalled, 'lastInstalled')
+
+      if (latestVersion === lastInstalled) return
+      console.log('版本对比', compareVersion(latestVersion, currentVersion))
+      if (compareVersion(latestVersion, currentVersion) > 0) {
+        downloadAndInstall(latestVersion)
+      }
+    } catch (e) {
+      console.log('[wgt] update check failed', e)
+    }
+  }
+
+  // 下载并安装
+  const downloadAndInstall = (version) => {
+    //TODO: 需要根据版本来确定url
+    const url = `${Host80}/wgt/CwgApp_${version}.wgt`
+    console.log(url, 'downloadurl')
+
+    uni.downloadFile({
+      url,
+      success: (res) => {
+        if (res.statusCode === 200) {
+          const filePath = res.tempFilePath
+          plus.runtime.install(
+            filePath, {
+              force: true,
+            },
+            () => {
+              uni.setStorageSync('lastWgtVersion', version)
+              console.log('[wgt] install success:', version)
+              uni.setStorageSync('wgtNeedRestart', true)
+              uni.showToast({
+                  title: t('mine.p37'),
+                  icon: 'success',
+                },
+              )
+              plus.runtime.restart()
+            },
+            (err) => {
+              console.error('[wgt] install failed:', err)
+            },
+          )
+        } else {
+          console.error('[wgt] download status error:', res.statusCode)
+        }
+      },
+      fail: (err) => {
+        console.error('[wgt] download failed:', err)
+      },
+    })
+  }
+  // 获取当前版本
+  const getCurrentVersion = async () => {
+    return new Promise((resolve, reject) => {
+      // #ifdef APP-PLUS
+      try {
+        plus.runtime.getProperty(plus.runtime.appid, (info) => {
+          resolve(info.version)
+        }, (error) => {
+          reject(error)
+        })
+      } catch (error) {
+        reject(error)
+      }
+      // #endif
+      // #ifndef APP-PLUS
+      reject(new Error('Not in APP-PLUS environment'))
+      // #endif
+    })
+  }
+  // 对比版本号
+  const compareVersion = (v1, v2) => {
+    const s1 = v1.split('.').map(Number)
+    const s2 = v2.split('.').map(Number)
+    const len = Math.max(s1.length, s2.length)
+
+    for (let i = 0; i < len; i++) {
+      const n1 = s1[i] || 0
+      const n2 = s2[i] || 0
+      if (n1 > n2) return 1
+      if (n1 < n2) return -1
+    }
+    return 0
+  }
+
+  onMounted(() => {
+    const sysInfo = uni.getSystemInfoSync()
+    globalStore.setBarHeight(sysInfo.statusBarHeight || 60)
+
+    // ---------- 新增 H5 端专属初始化 ----------
+    // 仅在 H5 端执行(通过环境判断)
+    // #ifdef H5
+    if (typeof window !== 'undefined') {
+      const instance = getCurrentInstance()
+      if (instance) {
+        window.vm = instance.proxy
+      }
+    }
+    window.addEventListener('hashchange', handleSignupRoute)
+    // #endif
+  })
+  onUnmounted(() => {
+    // #ifdef H5
+    window.removeEventListener('hashchange', handleSignupRoute)
+    // #endif
+  })
 </script>
 
 <style>
-/*每个页面公共css */
+  /*每个页面公共css */
 </style>
 
 <style lang="scss">
-/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
-@import "uview-plus/index.scss";
-@import "@/static/scss/global/global.scss";
-@import "@/static/scss/global/vu.css";
-@import "/static/scss/style.scss";
-
-@font-face {
-	font-family: 'Google Sans';
-	src: url('/static/Google_Sans/GoogleSans-VariableFont_GRAD,opsz,wght.ttf') format('truetype-variations');
-	font-weight: 100 900;
-	font-style: normal;
-	font-display: swap;
-}
-
-/* 全局字体,不破坏 uni-icons 图标 */
-view,
-text,
-button,
-input,
-textarea,
-label {
-	font-family: 'Google Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-	font-weight: 400;
-}
-
-/* 专门保护 uni-icons 不被覆盖 */
-.uni-icon,
-[class*="uni-icons-"],
-.uni-icons {
-	font-family: uniicons !important;
-}
-
-/* 让整个项目文字都能选中 */
-* {
-	-webkit-user-select: text !important;
-	user-select: text !important;
-}
-
-/* 修复滚动层无法选中 */
-view,
-text,
-div,
-span {
-	-webkit-user-select: text !important;
-	user-select: text !important;
-}
-
-/* 强制修复 uni-datetime-picker 重复渲染双日历 */
-// .uni-calendar+.uni-calendar {
-// 	display: none !important;
-// }
-
-:deep(.u-toolbar__wrapper__confirm) {
-	font-size: 20px !important;
-}
-
-:deep(.u-toolbar__wrapper__cancel) {
-	font-size: 20px !important;
-}
-
-.page {
-	/* padding: 31px 31px 110px 31px; */
-	box-sizing: border-box;
-	/* background: var(--main-bg); */
-}
-
-html {
-	--bs-bg-opacity: 1;
-	background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
-	font-size: 16px !important;
-}
-
-uni-page-body {
-	height: 100%;
-}
-
-page {
-	--bs-bg-opacity: 1;
-	background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
-}
+  /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
+  @import "uview-plus/index.scss";
+  @import "@/static/scss/global/global.scss";
+  @import "@/static/scss/global/vu.css";
+  @import "/static/scss/style.scss";
+
+  @font-face {
+    font-family: 'Google Sans';
+    src: url('/static/Google_Sans/GoogleSans-VariableFont_GRAD,opsz,wght.ttf') format('truetype-variations');
+    font-weight: 100 900;
+    font-style: normal;
+    font-display: swap;
+  }
+
+  /* 全局字体,不破坏 uni-icons 图标 */
+  view,
+  text,
+  button,
+  input,
+  textarea,
+  label {
+    font-family: 'Google Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+    font-weight: 400;
+  }
+
+  /* 专门保护 uni-icons 不被覆盖 */
+  .uni-icon,
+  [class*="uni-icons-"],
+  .uni-icons {
+    font-family: uniicons !important;
+  }
+
+  /* 让整个项目文字都能选中 */
+  * {
+    -webkit-user-select: text !important;
+    user-select: text !important;
+  }
+
+  /* 修复滚动层无法选中 */
+  view,
+  text,
+  div,
+  span {
+    -webkit-user-select: text !important;
+    user-select: text !important;
+  }
+
+  /* 强制修复 uni-datetime-picker 重复渲染双日历 */
+  // .uni-calendar+.uni-calendar {
+  // 	display: none !important;
+  // }
+
+  :deep(.u-toolbar__wrapper__confirm) {
+    font-size: 20px !important;
+  }
+
+  :deep(.u-toolbar__wrapper__cancel) {
+    font-size: 20px !important;
+  }
+
+  .page {
+    /* padding: 31px 31px 110px 31px; */
+    box-sizing: border-box;
+    /* background: var(--main-bg); */
+  }
+
+  html {
+    --bs-bg-opacity: 1;
+    background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
+    font-size: 16px !important;
+  }
+
+  uni-page-body {
+    height: 100%;
+  }
+
+  page {
+    --bs-bg-opacity: 1;
+    background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
+  }
 </style>

+ 557 - 539
hooks/useAppUpdate.ts

@@ -4,79 +4,82 @@ import { useProgress } from './useProgress'
 import useUserStore from '@/stores/use-user-store'
 import { ucardApi } from '@/api/ucard'
 import { userToken } from '@/composables/config'
+import config from '@/config'
+import { trim } from 'lodash'
+
 // ================== 类型声明 ==================
 
 declare const plus: any
 declare const uni: any
 
 interface PlusDownloaderDownload {
-    filename: string
-    pause?: () => void
-    resume?: () => void
-    start: () => void
-    abort: () => void
-    addEventListener: (event: string, callback: (data: any) => void) => void
-    removeEventListener?: (event: string, callback: (data: any) => void) => void
+  filename: string
+  pause?: () => void
+  resume?: () => void
+  start: () => void
+  abort: () => void
+  addEventListener: (event: string, callback: (data: any) => void) => void
+  removeEventListener?: (event: string, callback: (data: any) => void) => void
 }
 
 // ================== 常量定义 ==================
 
 /** 存储键名 */
 const STORAGE_KEYS = {
-    LAST_CHECK: 'last_update_check_time',
-    SKIP_VERSION: 'skip_update_version',
-    DOWNLOAD_CACHE: 'app_download_cache'
+  LAST_CHECK: 'last_update_check_time',
+  SKIP_VERSION: 'skip_update_version',
+  DOWNLOAD_CACHE: 'app_download_cache',
 } as const
 
 /** 下载状态码 */
 enum DownloadState {
-    DOWNLOADING = 3, // 下载中
-    COMPLETED = 4    // 下载完成
+  DOWNLOADING = 3, // 下载中
+  COMPLETED = 4    // 下载完成
 }
 
 /** HTTP 成功状态码 */
 enum HttpStatus {
-    OK = 200,            // 成功
-    PARTIAL_CONTENT = 206 // 部分内容(断点续传)
+  OK = 200,            // 成功
+  PARTIAL_CONTENT = 206 // 部分内容(断点续传)
 }
 
 /** 下载配置 */
 const DOWNLOAD_CONFIG = {
-    FILE_PATH: '_downloads/app_update.wgt',
-    MAX_RETRY: 3,              // 最大重试次数
-    RETRY_DELAY: 2000,         // 重试延迟(毫秒)
-    TOAST_DURATION: 2000       // Toast 显示时长
+  FILE_PATH: '_downloads/app_update.wgt',
+  MAX_RETRY: 3,              // 最大重试次数
+  RETRY_DELAY: 2000,         // 重试延迟(毫秒)
+  TOAST_DURATION: 2000,       // Toast 显示时长
 } as const
 
 // ================== 类型定义 ==================
 
 /** 更新信息 */
 interface UpdateInfo {
-    version: string
-    forceUpdate: boolean
-    wgtUrl?: string
-    iosStoreUrl?: string
+  version: string
+  forceUpdate: boolean
+  wgtUrl?: string
+  iosStoreUrl?: string
 }
 
 /** 下载缓存 */
 interface DownloadCache {
-    url: string
-    progress: number
-    time: number
+  url: string
+  progress: number
+  time: number
 }
 
 /** API 响应 */
 interface ApiResponse<T = any> {
-    code: number
-    data?: T
-    message?: string
+  code: number
+  data?: T
+  message?: string
 }
 
 /** 下载状态变化事件 */
 interface DownloadStateEvent {
-    state: number
-    downloadedSize: number
-    totalSize: number
+  state: number
+  downloadedSize: number
+  totalSize: number
 }
 
 /** 平台类型 */
@@ -91,22 +94,22 @@ type EquipmentType = 'ios' | 'Android'
  * 获取当前应用版本
  */
 function getCurrentVersion(): Promise<string> {
-    return new Promise((resolve, reject) => {
-        // #ifdef APP-PLUS
-        try {
-            plus.runtime.getProperty(plus.runtime.appid, (info) => {
-                resolve(info.version)
-            }, (error) => {
-                reject(error)
-            })
-        } catch (error) {
-            reject(error)
-        }
-        // #endif
-        // #ifndef APP-PLUS
-        reject(new Error('Not in APP-PLUS environment'))
-        // #endif
-    })
+  return new Promise((resolve, reject) => {
+    // #ifdef APP-PLUS
+    try {
+      plus.runtime.getProperty(plus.runtime.appid, (info) => {
+        resolve(info.version)
+      }, (error) => {
+        reject(error)
+      })
+    } catch (error) {
+      reject(error)
+    }
+    // #endif
+    // #ifndef APP-PLUS
+    reject(new Error('Not in APP-PLUS environment'))
+    // #endif
+  })
 }
 
 /**
@@ -114,589 +117,604 @@ function getCurrentVersion(): Promise<string> {
  * @returns 1: v1 > v2, -1: v1 < v2, 0: v1 === v2
  */
 function compareVersion(v1: string, v2: string): number {
-    const normalizeVersion = (v: string): number[] => {
-        return v.split('.').map(segment => parseInt(segment || '0', 10))
-    }
-
-    const parts1 = normalizeVersion(v1)
-    const parts2 = normalizeVersion(v2)
-    const maxLength = Math.max(parts1.length, parts2.length)
-
-    for (let i = 0; i < maxLength; i++) {
-        const num1 = parts1[i] || 0
-        const num2 = parts2[i] || 0
-        if (num1 > num2) return 1
-        if (num1 < num2) return -1
-    }
-    return 0
+  const normalizeVersion = (v: string): number[] => {
+    return v.split('.').map(segment => parseInt(segment || '0', 10))
+  }
+
+  const parts1 = normalizeVersion(v1)
+  const parts2 = normalizeVersion(v2)
+  const maxLength = Math.max(parts1.length, parts2.length)
+
+  for (let i = 0; i < maxLength; i++) {
+    const num1 = parts1[i] || 0
+    const num2 = parts2[i] || 0
+    if (num1 > num2) return 1
+    if (num1 < num2) return -1
+  }
+  return 0
 }
 
 /**
  * 获取平台类型
  */
 function getPlatform(): PlatformType {
-    // #ifdef APP-PLUS
-    try {
-        const platform = uni.getSystemInfoSync().platform
-        return platform === 'ios' ? 'ios' : 'android'
-    } catch (error) {
-        //  console.error('获取平台类型失败:', error)
-        return 'android'
-    }
-    // #endif
-    // #ifndef APP-PLUS
+  // #ifdef APP-PLUS
+  try {
+    const platform = uni.getSystemInfoSync().platform
+    return platform === 'ios' ? 'ios' : 'android'
+  } catch (error) {
+    //  console.error('获取平台类型失败:', error)
     return 'android'
-    // #endif
+  }
+  // #endif
+  // #ifndef APP-PLUS
+  return 'android'
+  // #endif
 }
 
 /**
  * 获取设备类型(API 参数格式)
  */
 function getEquipmentType(): EquipmentType {
-    return getPlatform() === 'ios' ? 'ios' : 'Android'
+  return getPlatform() === 'ios' ? 'ios' : 'Android'
 }
 
 /**
  * 显示 Toast 提示
  */
 function showToast(message: string, duration = DOWNLOAD_CONFIG.TOAST_DURATION): void {
-    uni.showToast({
-        title: message,
-        icon: 'none',
-        duration
-    })
+  uni.showToast({
+    title: message,
+    icon: 'none',
+    duration,
+  })
 }
 
 /**
  * 安全地获取存储值
  */
 function getStorageSync<T = any>(key: string, defaultValue: T | null = null): T | null {
-    try {
-        return uni.getStorageSync(key) || defaultValue
-    } catch (error) {
-        //  console.warn(`获取存储失败: ${key}`, error)
-        return defaultValue
-    }
+  try {
+    return uni.getStorageSync(key) || defaultValue
+  } catch (error) {
+    //  console.warn(`获取存储失败: ${key}`, error)
+    return defaultValue
+  }
 }
 
 /**
  * 安全地设置存储值
  */
 function setStorageSync(key: string, value: any): boolean {
-    try {
-        uni.setStorageSync(key, value)
-        return true
-    } catch (error) {
-        //  console.warn(`设置存储失败: ${key}`, error)
-        return false
-    }
+  try {
+    uni.setStorageSync(key, value)
+    return true
+  } catch (error) {
+    //  console.warn(`设置存储失败: ${key}`, error)
+    return false
+  }
 }
 
 /**
  * 安全地移除存储值
  */
 function removeStorageSync(key: string): boolean {
-    try {
-        uni.removeStorageSync(key)
-        return true
-    } catch (error) {
-        //  console.warn(`移除存储失败: ${key}`, error)
-        return false
-    }
+  try {
+    uni.removeStorageSync(key)
+    return true
+  } catch (error) {
+    //  console.warn(`移除存储失败: ${key}`, error)
+    return false
+  }
 }
 
 // ================== 主函数 ==================
 
 export function useAppUpdate() {
-    const { t } = useI18n()
-    const userStore = useUserStore()
-    const progress = useProgress()
-
-    const checking = ref(false)
-    const updating = ref(false)
-
-    let downloadTask: PlusDownloaderDownload | null = null
-    let networkListener: ((res: any) => void) | null = null
-    let downloadUrl = ''
-    let retryCount = 0
-    let stateChangeHandler: ((d: any) => void) | null = null
-
-    // ================== 对外入口 ==================
-
-    /**
-     * 检查应用更新
-     */
-    async function checkUpdate(): Promise<void> {
-        // #ifdef APP-PLUS
-        if (checking.value) {
-            //  console.warn('更新检查已在进行中')
-            return
-        }
+  const { t } = useI18n()
+  const { Host80 } = config
+  const userStore = useUserStore()
+  const progress = useProgress()
 
-        checking.value = true
-
-        try {
-            const equipmentType = getEquipmentType()
-            if (!userToken.value) {
-                return
-            }
-            const res: ApiResponse<UpdateInfo> = await ucardApi.getAppVersionDetail({ equipmentType })
-
-            if (res.code !== 200 || !res.data) {
-                const errorMsg = res.message || '获取版本信息失败'
-                //  console.warn(errorMsg)
-                return
-            }
-
-            const update = res.data
-            const currentVersion = await getCurrentVersion()
-            const needUpdate = compareVersion(update.version, currentVersion) > 0
-
-            // 保存版本信息
-            userStore.saveAppVersion({
-                currentVersion,
-                version: update.version,
-                isUpdate: !needUpdate
-            })
-
-            if (!needUpdate) {
-                //  console.log('当前已是最新版本')
-                return
-            }
-
-            // 检查是否已跳过此版本
-            // const skipVersion = getStorageSync<string>(STORAGE_KEYS.SKIP_VERSION)
-            // if (!update.forceUpdate && skipVersion === update.version) {
-            //     //  console.log('用户已跳过此版本更新')
-            //     return
-            // }
-
-            // 显示更新提示
-            if (update.forceUpdate) {
-                showForceUpdate(update)
-            } else {
-                showOptionalUpdate(update)
-            }
-        } catch (error) {
-            //  console.error('检查更新失败:', error)
-            const errorMsg = error instanceof Error ? error.message : String(error)
-            showToast(t('mine.p28') || `检查更新失败: ${errorMsg}`)
-        } finally {
-            checking.value = false
-        }
-        // #endif
-    }
+  const checking = ref(false)
+  const updating = ref(false)
 
-    // ================== 更新流程 ==================
+  const lastVersion = ref('')
 
-    /**
-     * 显示强制更新弹窗
-     */
-    function showForceUpdate(update: UpdateInfo): void {
-        uni.showModal({
-            title: t('mine.p22'),
-            content: t('mine.p23'),
-            showCancel: false,
-            confirmText: t('mine.p35'),
-            success: () => doUpdate(update)
-        })
-    }
+  let downloadTask: PlusDownloaderDownload | null = null
+  let networkListener: ((res: any) => void) | null = null
+  let downloadUrl = ''
+  let retryCount = 0
+  let stateChangeHandler: ((d: any) => void) | null = null
+
+  // ================== 对外入口 ==================
 
-    /**
-     * 显示可选更新弹窗
-     */
-    function showOptionalUpdate(update: UpdateInfo): void {
-        uni.showModal({
-            title: t('mine.p24'),
-            content: t('mine.p25', { version: `v${update.version}` }),
-            confirmText: t('mine.p35'),
-            cancelText: t('mine.p36'),
-            success: (res) => {
-                if (res.confirm) {
-                    doUpdate(update)
-                } else {
-                    // 记录跳过的版本
-                    setStorageSync(STORAGE_KEYS.SKIP_VERSION, update.version)
-                }
-            }
-        })
+  /**
+   * 检查应用更新
+   */
+  async function checkUpdate(): Promise<void> {
+    // #ifdef APP-PLUS
+    if (checking.value) {
+      //  console.warn('更新检查已在进行中')
+      return
     }
 
-    /**
-     * 执行更新
-     */
-    function doUpdate(update: UpdateInfo): void {
-        const platform = getPlatform()
+    checking.value = true
 
-        if (platform === 'ios') {
-            handleIosUpdate(update)
+    try {
+
+      const res = await uni.request({
+        url: `${Host80}/wgt/list.json?_t=${Date.now()}`,
+        method: 'GET',
+        timeout: 5000,
+      })
+
+      console.log('up:filedata', res)
+      const currentVersion = await getCurrentVersion()
+      console.log(currentVersion, 'currentVersion')
+      const files = res.data?.files || []
+      if (!files.length) return
+      const latestFile = files[files.length - 1]
+      const latestVersion = latestFile
+      console.log('last', latestFile, latestVersion)
+      if (!latestFile) return
+      lastVersion.value = latestVersion
+      const lastInstalled = uni.getStorageSync('lastWgtVersion')
+      console.log(lastInstalled, 'lastInstalled')
+
+      if (latestVersion === lastInstalled) return
+      console.log('版本对比', compareVersion(latestVersion, currentVersion))
+      const needUpdate = compareVersion(latestVersion, currentVersion) > 0
+
+      // 保存版本信息
+      userStore.saveAppVersion({
+        currentVersion,
+        version: latestVersion,
+        isUpdate: !needUpdate,
+      })
+
+      if (!needUpdate) {
+        //  console.log('当前已是最新版本')
+        return
+      }
+
+      // 检查是否已跳过此版本
+      // const skipVersion = getStorageSync<string>(STORAGE_KEYS.SKIP_VERSION)
+      // if (!update.forceUpdate && skipVersion === update.version) {
+      //     //  console.log('用户已跳过此版本更新')
+      //     return
+      // }
+
+      // 显示更新提示
+      const url = `${Host80}/wgt/CwgApp_${latestVersion}.wgt`
+      console.log('url',url)
+      showForceUpdate({ version: latestVersion, forceUpdate: true, wgtUrl: url })
+    } catch (error) {
+      //  console.error('检查更新失败:', error)
+      const errorMsg = error instanceof Error ? error.msg : String(error)
+      showToast(t('mine.p28') || `检查更新失败: ${errorMsg}`)
+    } finally {
+      checking.value = false
+    }
+    // #endif
+  }
+
+  // ================== 更新流程 ==================
+
+  /**
+   * 显示强制更新弹窗
+   */
+  function showForceUpdate(update: UpdateInfo): void {
+    uni.showModal({
+      title: t('mine.p22'),
+      content: t('mine.p23'),
+      showCancel: false,
+      confirmText: t('mine.p35'),
+      success: () => doUpdate(update),
+    })
+  }
+
+  /**
+   * 显示可选更新弹窗
+   */
+  function showOptionalUpdate(update: UpdateInfo): void {
+    uni.showModal({
+      title: t('mine.p24'),
+      content: t('mine.p25', { version: `v${update.version}` }),
+      confirmText: t('mine.p35'),
+      cancelText: t('mine.p36'),
+      success: (res) => {
+        if (res.confirm) {
+          doUpdate(update)
         } else {
-            handleAndroidUpdate(update)
+          // 记录跳过的版本
+          setStorageSync(STORAGE_KEYS.SKIP_VERSION, update.version)
         }
+      },
+    })
+  }
+
+  /**
+   * 执行更新
+   */
+  function doUpdate(update: UpdateInfo): void {
+    console.log(update)
+    const platform = getPlatform()
+
+    // ios不走这里面
+    if (platform === 'ios') {
+      // handleIosUpdate(update)
+    } else {
+      handleAndroidUpdate(update)
+    }
+  }
+
+  /**
+   * 处理 iOS 更新
+   */
+  function handleIosUpdate(update: UpdateInfo): void {
+    if (!update.iosStoreUrl) {
+      showToast(t('mine.p28') || 'iOS 更新链接不存在')
+      return
     }
 
-    /**
-     * 处理 iOS 更新
-     */
-    function handleIosUpdate(update: UpdateInfo): void {
-        if (!update.iosStoreUrl) {
-            showToast(t('mine.p28') || 'iOS 更新链接不存在')
-            return
-        }
-
-        try {
-            plus.runtime.openURL(update.iosStoreUrl)
-        } catch (error) {
-            //  console.error('打开 App Store 失败:', error)
-            showToast(t('mine.p28') || '打开 App Store 失败')
-        }
+    try {
+      plus.runtime.openURL(update.iosStoreUrl)
+    } catch (error) {
+      //  console.error('打开 App Store 失败:', error)
+      showToast(t('mine.p28') || '打开 App Store 失败')
+    }
+  }
+
+  /**
+   * 处理 Android 更新
+   */
+  function handleAndroidUpdate(update: UpdateInfo): void {
+    console.log('up2',update)
+    if (!update.wgtUrl) {
+        showToast(t('mine.p28') || '更新包链接不存在')
+        return
     }
 
-    /**
-     * 处理 Android 更新
-     */
-    function handleAndroidUpdate(update: UpdateInfo): void {
-        if (!update.wgtUrl) {
-            showToast(t('mine.p28') || '更新包链接不存在')
-            return
-        }
+    downloadWgt(update.wgtUrl)
+  }
 
-        downloadWgt(update.wgtUrl)
-    }
+  // ================== 下载核心 ==================
 
-    // ================== 下载核心 ==================
+  /**
+   * 下载 wgt 更新包
+   */
+  function downloadWgt(url: string): void {
+    // #ifdef APP-PLUS
+    if (downloadTask) {
+       console.log('下载任务已存在')
+      return
+    }
 
-    /**
-     * 下载 wgt 更新包
-     */
-    function downloadWgt(url: string): void {
-        // #ifdef APP-PLUS
-        if (downloadTask) {
-            //  console.warn('下载任务已存在')
-            return
-        }
+    if (!url || !isValidUrl(url)) {
+      handleDownloadFail(t('mine.p28') || '下载链接无效')
+      return
+    }
 
-        if (!url || !isValidUrl(url)) {
-            handleDownloadFail(t('mine.p28') || '下载链接无效')
-            return
-        }
+    downloadUrl = url
+    retryCount = 0
+    updating.value = true
+    progress.show(t('mine.p29'))
 
-        downloadUrl = url
-        retryCount = 0
-        updating.value = true
-        progress.show(t('mine.p29'))
+    // 初始化网络监听
+    initNetworkType()
+    startNetworkMonitor()
 
-        // 初始化网络监听
-        initNetworkType()
-        startNetworkMonitor()
+    createDownloadTask(url)
+    // #endif
+  }
 
-        createDownloadTask(url)
-        // #endif
+  /**
+   * 创建下载任务
+   */
+  function createDownloadTask(url: string): void {
+    try {
+      downloadTask = plus.downloader.createDownload(
+        url,
+        { filename: DOWNLOAD_CONFIG.FILE_PATH },
+        handleDownloadComplete,
+      )
+
+      if (!downloadTask) {
+        throw new Error('创建下载任务失败')
+      }
+
+      // 创建状态变化处理器
+      stateChangeHandler = handleDownloadStateChanged
+      downloadTask.addEventListener('statechanged', stateChangeHandler)
+      downloadTask.start()
+    } catch (error) {
+      //  console.error('创建下载任务失败:', error)
+      downloadTask = null
+      handleDownloadFail(t('mine.p28') || '创建下载任务失败')
     }
+  }
 
-    /**
-     * 创建下载任务
-     */
-    function createDownloadTask(url: string): void {
-        try {
-            downloadTask = plus.downloader.createDownload(
-                url,
-                { filename: DOWNLOAD_CONFIG.FILE_PATH },
-                handleDownloadComplete
-            )
-
-            if (!downloadTask) {
-                throw new Error('创建下载任务失败')
-            }
-
-            // 创建状态变化处理器
-            stateChangeHandler = handleDownloadStateChanged
-            downloadTask.addEventListener('statechanged', stateChangeHandler)
-            downloadTask.start()
-        } catch (error) {
-            //  console.error('创建下载任务失败:', error)
-            downloadTask = null
-            handleDownloadFail(t('mine.p28') || '创建下载任务失败')
-        }
+  /**
+   * 验证 URL 格式
+   */
+  function isValidUrl(url: string): boolean {
+    try {
+      return /^https?:\/\/.+/.test(url)
+    } catch {
+      return false
     }
-
-    /**
-     * 验证 URL 格式
-     */
-    function isValidUrl(url: string): boolean {
-        try {
-            return /^https?:\/\/.+/.test(url)
-        } catch {
-            return false
-        }
+  }
+
+  /**
+   * 处理下载完成回调
+   */
+  function handleDownloadComplete(download: PlusDownloaderDownload, status: number): void {
+    const isSuccess = status === HttpStatus.OK || status === HttpStatus.PARTIAL_CONTENT
+
+    if (isSuccess) {
+      //  console.log('下载成功,准备安装')
+      clearCache()
+      stopNetworkMonitor()
+      installWgt(download.filename)
+    } else {
+      //  console.error('下载失败,状态码:', status)
+      retryDownload()
     }
-
-    /**
-     * 处理下载完成回调
-     */
-    function handleDownloadComplete(download: PlusDownloaderDownload, status: number): void {
-        const isSuccess = status === HttpStatus.OK || status === HttpStatus.PARTIAL_CONTENT
-
-        if (isSuccess) {
-            //  console.log('下载成功,准备安装')
-            clearCache()
-            stopNetworkMonitor()
-            installWgt(download.filename)
-        } else {
-            //  console.error('下载失败,状态码:', status)
-            retryDownload()
-        }
+  }
+
+  /**
+   * 处理下载状态变化
+   */
+  function handleDownloadStateChanged(event: DownloadStateEvent): void {
+    if (event.state === DownloadState.DOWNLOADING && event.totalSize > 0) {
+      const percent = Math.min(100, Math.floor((event.downloadedSize / event.totalSize) * 100))
+      const progressText = `${t('mine.p29')} ${percent}%`
+      progress.update(percent, progressText)
+      saveCache(percent)
     }
-
-    /**
-     * 处理下载状态变化
-     */
-    function handleDownloadStateChanged(event: DownloadStateEvent): void {
-        if (event.state === DownloadState.DOWNLOADING && event.totalSize > 0) {
-            const percent = Math.min(100, Math.floor((event.downloadedSize / event.totalSize) * 100))
-            const progressText = `${t('mine.p29')} ${percent}%`
-            progress.update(percent, progressText)
-            saveCache(percent)
-        }
+  }
+
+  /**
+   * 重试下载
+   */
+  function retryDownload(): void {
+    if (retryCount >= DOWNLOAD_CONFIG.MAX_RETRY) {
+      //  console.error(`下载失败,已重试 ${retryCount} 次`)
+      handleDownloadFail(t('mine.p28') || '下载失败')
+      return
     }
 
-    /**
-     * 重试下载
-     */
-    function retryDownload(): void {
-        if (retryCount >= DOWNLOAD_CONFIG.MAX_RETRY) {
-            //  console.error(`下载失败,已重试 ${retryCount} 次`)
-            handleDownloadFail(t('mine.p28') || '下载失败')
-            return
-        }
-
-        retryCount++
-        //  console.log(`下载失败,${DOWNLOAD_CONFIG.RETRY_DELAY / 1000}秒后重试 (${retryCount}/${DOWNLOAD_CONFIG.MAX_RETRY})`)
-
-        cleanupDownloadTask()
+    retryCount++
+    //  console.log(`下载失败,${DOWNLOAD_CONFIG.RETRY_DELAY / 1000}秒后重试 (${retryCount}/${DOWNLOAD_CONFIG.MAX_RETRY})`)
+
+    cleanupDownloadTask()
+
+    setTimeout(() => {
+      if (downloadUrl) {
+        createDownloadTask(downloadUrl)
+      }
+    }, DOWNLOAD_CONFIG.RETRY_DELAY)
+  }
+
+  /**
+   * 初始化网络类型
+   */
+  function initNetworkType(): void {
+    uni.getNetworkType({
+      success: (res) => {
+        //  console.log('当前网络类型:', res.networkType)
+      },
+      fail: (error) => {
+        //  console.warn('获取网络类型失败:', error)
+      },
+    })
+  }
 
-        setTimeout(() => {
-            if (downloadUrl) {
-                createDownloadTask(downloadUrl)
-            }
-        }, DOWNLOAD_CONFIG.RETRY_DELAY)
-    }
+  // ================== 网络处理 ==================
 
-    /**
-     * 初始化网络类型
-     */
-    function initNetworkType(): void {
-        uni.getNetworkType({
-            success: (res) => {
-                //  console.log('当前网络类型:', res.networkType)
-            },
-            fail: (error) => {
-                //  console.warn('获取网络类型失败:', error)
-            }
-        })
+  /**
+   * 启动网络监听
+   */
+  function startNetworkMonitor(): void {
+    // #ifdef APP-PLUS
+    if (networkListener) {
+      //  console.warn('网络监听已存在')
+      return
     }
 
-    // ================== 网络处理 ==================
-
-    /**
-     * 启动网络监听
-     */
-    function startNetworkMonitor(): void {
-        // #ifdef APP-PLUS
-        if (networkListener) {
-            //  console.warn('网络监听已存在')
-            return
-        }
+    networkListener = (res: any) => {
+      if (!downloadTask || !updating.value) {
+        return
+      }
 
-        networkListener = (res: any) => {
-            if (!downloadTask || !updating.value) {
-                return
-            }
+      if (!res.isConnected) {
+        // 网络断开,暂停下载
+        pauseDownload()
+        return
+      }
 
-            if (!res.isConnected) {
-                // 网络断开,暂停下载
-                pauseDownload()
-                return
-            }
+      // 网络恢复,继续下载
+      resumeDownload()
+    }
 
-            // 网络恢复,继续下载
-            resumeDownload()
-        }
+    uni.onNetworkStatusChange(networkListener)
+    // #endif
+  }
 
-        uni.onNetworkStatusChange(networkListener)
-        // #endif
-    }
+  /**
+   * 暂停下载
+   */
+  function pauseDownload(): void {
+    if (!downloadTask) return
 
-    /**
-     * 暂停下载
-     */
-    function pauseDownload(): void {
-        if (!downloadTask) return
-
-        try {
-            if (typeof downloadTask.pause === 'function') {
-                downloadTask.pause()
-            }
-        } catch (error) {
-            //  console.error('暂停下载失败:', error)
-        }
+    try {
+      if (typeof downloadTask.pause === 'function') {
+        downloadTask.pause()
+      }
+    } catch (error) {
+      //  console.error('暂停下载失败:', error)
     }
+  }
 
-    /**
-     * 恢复下载
-     */
-    function resumeDownload(): void {
-        if (!downloadTask) return
-
-        try {
-            if (typeof downloadTask.resume === 'function') {
-                downloadTask.resume()
-            } else if (typeof downloadTask.start === 'function') {
-                downloadTask.start()
-            }
-        } catch (error) {
-            //  console.error('恢复下载失败,尝试重新开始:', error)
-            // 失败时尝试重新开始
-            try {
-                if (downloadTask.start) {
-                    downloadTask.start()
-                }
-            } catch (e2) {
-                //  console.error('重新开始下载也失败:', e2)
-            }
-        }
-    }
+  /**
+   * 恢复下载
+   */
+  function resumeDownload(): void {
+    if (!downloadTask) return
 
-    /**
-     * 停止网络监听
-     */
-    function stopNetworkMonitor(): void {
-        if (networkListener) {
-            uni.offNetworkStatusChange(networkListener)
-            networkListener = null
+    try {
+      if (typeof downloadTask.resume === 'function') {
+        downloadTask.resume()
+      } else if (typeof downloadTask.start === 'function') {
+        downloadTask.start()
+      }
+    } catch (error) {
+      //  console.error('恢复下载失败,尝试重新开始:', error)
+      // 失败时尝试重新开始
+      try {
+        if (downloadTask.start) {
+          downloadTask.start()
         }
+      } catch (e2) {
+        //  console.error('重新开始下载也失败:', e2)
+      }
     }
-
-    // ================== 安装 ==================
-
-    /**
-     * 安装 wgt 更新包
-     */
-    function installWgt(path: string): void {
-        // #ifdef APP-PLUS
-        try {
-            plus.runtime.install(
-                path,
-                { force: false },
-                () => {
-                    // 安装成功
-                    progress.hide()
-                    updating.value = false
-                    uni.showModal({
-                        title: t('mine.p37'),
-                        content: t('mine.p38'),
-                        showCancel: false,
-                        success: () => {
-                            plus.runtime.restart()
-                        }
-                    })
-                },
-                (error) => {
-                    // 安装失败
-                    //  console.error('安装失败:', error)
-                    handleDownloadFail(t('mine.p33'))
-                }
-            )
-        } catch (error) {
-            //  console.error('安装异常:', error)
-            handleDownloadFail(t('mine.p33'))
-        }
-        // #endif
+  }
+
+  /**
+   * 停止网络监听
+   */
+  function stopNetworkMonitor(): void {
+    if (networkListener) {
+      uni.offNetworkStatusChange(networkListener)
+      networkListener = null
     }
+  }
 
-    // ================== 缓存管理 ==================
+  // ================== 安装 ==================
 
-    /**
-     * 保存下载缓存
-     */
-    function saveCache(progressPercent: number): void {
-        const cache: DownloadCache = {
-            url: downloadUrl,
-            progress: progressPercent,
-            time: Date.now()
-        }
-        setStorageSync(STORAGE_KEYS.DOWNLOAD_CACHE, cache)
+  /**
+   * 安装 wgt 更新包
+   */
+  function installWgt(path: string): void {
+    // #ifdef APP-PLUS
+    try {
+      plus.runtime.install(
+        path,
+        { force: true },
+        () => {
+          // 安装成功
+          progress.hide()
+          updating.value = false
+          uni.showModal({
+            title: t('mine.p37'),
+            content: t('mine.p38'),
+            showCancel: false,
+            success: () => {
+              uni.setStorageSync('lastWgtVersion', lastVersion.value)
+              console.log('[wgt] install success:', lastVersion.value)
+              uni.setStorageSync('wgtNeedRestart', true)
+              plus.runtime.restart()
+            },
+          })
+        },
+        (error) => {
+          // 安装失败
+          //  console.error('安装失败:', error)
+          handleDownloadFail(t('mine.p33'))
+        },
+      )
+    } catch (error) {
+      //  console.error('安装异常:', error)
+      handleDownloadFail(t('mine.p33'))
     }
-
-    /**
-     * 清除下载缓存
-     */
-    function clearCache(): void {
-        removeStorageSync(STORAGE_KEYS.DOWNLOAD_CACHE)
+    // #endif
+  }
+
+  // ================== 缓存管理 ==================
+
+  /**
+   * 保存下载缓存
+   */
+  function saveCache(progressPercent: number): void {
+    const cache: DownloadCache = {
+      url: downloadUrl,
+      progress: progressPercent,
+      time: Date.now(),
     }
+    setStorageSync(STORAGE_KEYS.DOWNLOAD_CACHE, cache)
+  }
+
+  /**
+   * 清除下载缓存
+   */
+  function clearCache(): void {
+    removeStorageSync(STORAGE_KEYS.DOWNLOAD_CACHE)
+  }
+
+  // ================== 错误处理 ==================
+
+  /**
+   * 处理下载失败
+   */
+  function handleDownloadFail(msg: string): void {
+    progress.hide()
+    updating.value = false
+    retryCount = 0
+    stopNetworkMonitor()
+    cleanupDownloadTask()
+    showToast(msg)
+  }
+
+  /**
+   * 清理下载任务
+   */
+  function cleanupDownloadTask(): void {
+    if (!downloadTask) return
 
-    // ================== 错误处理 ==================
-
-    /**
-     * 处理下载失败
-     */
-    function handleDownloadFail(msg: string): void {
-        progress.hide()
-        updating.value = false
-        retryCount = 0
-        stopNetworkMonitor()
-        cleanupDownloadTask()
-        showToast(msg)
-    }
+    try {
+      // 移除事件监听
+      if (stateChangeHandler && downloadTask.removeEventListener) {
+        downloadTask.removeEventListener('statechanged', stateChangeHandler)
+      }
 
-    /**
-     * 清理下载任务
-     */
-    function cleanupDownloadTask(): void {
-        if (!downloadTask) return
-
-        try {
-            // 移除事件监听
-            if (stateChangeHandler && downloadTask.removeEventListener) {
-                downloadTask.removeEventListener('statechanged', stateChangeHandler)
-            }
-
-            // 中止下载
-            downloadTask.abort()
-        } catch (error) {
-            //  console.warn('清理下载任务失败:', error)
-        } finally {
-            downloadTask = null
-            stateChangeHandler = null
-        }
+      // 中止下载
+      downloadTask.abort()
+    } catch (error) {
+      //  console.warn('清理下载任务失败:', error)
+    } finally {
+      downloadTask = null
+      stateChangeHandler = null
     }
-
-    /**
-     * 取消更新
-     */
-    function cancelUpdate(): void {
-        if (!updating.value) {
-            //  console.warn('当前没有正在进行的更新')
-            return
-        }
-
-        //  console.log('用户取消更新')
-        handleDownloadFail(t('mine.p39') || '已取消更新')
+  }
+
+  /**
+   * 取消更新
+   */
+  function cancelUpdate(): void {
+    if (!updating.value) {
+      //  console.warn('当前没有正在进行的更新')
+      return
     }
 
-    // ================== 生命周期 ==================
-
-    onUnmounted(() => {
-        //  console.log('useAppUpdate 组件卸载,清理资源')
-        stopNetworkMonitor()
-        cleanupDownloadTask()
-        retryCount = 0
-    })
-
-    return {
-        checkUpdate,
-        cancelUpdate,
-        checking,
-        updating
-    }
+    //  console.log('用户取消更新')
+    handleDownloadFail(t('mine.p39') || '已取消更新')
+  }
+
+  // ================== 生命周期 ==================
+
+  onUnmounted(() => {
+    //  console.log('useAppUpdate 组件卸载,清理资源')
+    stopNetworkMonitor()
+    cleanupDownloadTask()
+    retryCount = 0
+  })
+
+  return {
+    checkUpdate,
+    cancelUpdate,
+    checking,
+    updating,
+  }
 }

+ 5 - 2
pages/login/index.vue

@@ -673,7 +673,7 @@ const getRegistLoginInfo = async () => {
       showToast(t('Msg.LoginSuccess'))
       setTimeout(() => {
         uni.reLaunch({
-          url: '/pages/customer/index',
+          url: '/pages/customer/dashboard',
         })
       }, 1000)
     } else {
@@ -844,6 +844,9 @@ onMounted(() => {
     uni.removeStorageSync('systemListCache')
   }
   uni.$emit('updateSystemList', 'login')
+  uni.$on('updateAppSuccess',()=>{
+    uni.showToast('')
+  })
   const accountInfo = userStore.accountInfo
   if (accountInfo?.rememberPassword) {
     form.value.loginName = accountInfo?.loginName || ''
@@ -873,7 +876,7 @@ const handleChatIconClick = () => {
     return
   }
   if (isMobile.value) {
-    // router.push('/pages/common/chat')
+    router.push('/pages/common/chat')
   } else {
     if (LiveChatService) {
       LiveChatService.showChat()

+ 28 - 24
pages/mine/improveImmediately.vue

@@ -672,6 +672,7 @@ import icon_mobile from '@/static/icons/icon_mobile.svg'
 import icon_arrowR from '@/static/icons/icon_arrowR.svg'
 import { useWindowWidth } from '@/composables/useWindowWidth'
 import { usePopup } from '@/hooks/usePopup'
+import useUserStore from '@/stores/use-user-store'
 const { confirm , toast } = usePopup()
 const router = useRouter()
 const { t, locale } = useI18n()
@@ -684,6 +685,7 @@ const qrCodeStatus = ref(false)
 const addressTipPopup = ref()
 const windowWidth = useWindowWidth(300)
 const isMobile = computed(() => windowWidth.value <= 991)
+const userStore = useUserStore()
 
 // 新增的响应式数据
 const divActiveHelf = ref(false)
@@ -884,72 +886,72 @@ function goStep(step: number) {
 }
 
 // 选项数据
-const customerTypeOptions = [
+const customerTypeOptions = computed(()=>[
   { value: 1, text: t('ImproveImmediately.Label.CustomerType1') },
   { value: 2, text: t('ImproveImmediately.Label.CustomerType2') },
-]
+])
 
-const identityTypes = ref([
+const identityTypes = computed(()=>[
   { text: t('ImproveImmediately.Label.IDCard'), value: 2 },
   { text: t('ImproveImmediately.Label.Passport'), value: 3 },
 ])
 
-const genderOptions = [
+const genderOptions = computed(()=>[
   { value: 1, text: t('PersonalManagement.Label.Men') },
   { value: 2, text: t('PersonalManagement.Label.Women') },
-]
-const radioList = [
+])
+const radioList = computed(()=>[
   { value: 1, text: t('ImproveImmediately.Label.Yes') },
   { value: 0, text: t('ImproveImmediately.Label.No') },
-]
+])
 
-const educationOptions = [
+const educationOptions = computed(()=>[
   { value: 1, text: t('ImproveImmediately.Label.Education1') },
   { value: 2, text: t('ImproveImmediately.Label.Education2') },
   { value: 3, text: t('ImproveImmediately.Label.Education3') },
   { value: 4, text: t('ImproveImmediately.Label.Education4') },
   { value: 5, text: t('ImproveImmediately.Label.Education5') },
-]
+])
 
-const employmentOptions = [
+const employmentOptions =computed(()=> [
   { value: 1, text: t('ImproveImmediately.Label.OnJob1') },
   { value: 2, text: t('ImproveImmediately.Label.OnJob2') },
   { value: 3, text: t('ImproveImmediately.Label.OnJob3') },
   { value: 4, text: t('ImproveImmediately.Label.OnJob4') },
   { value: 5, text: t('ImproveImmediately.Label.OnJob5') },
-]
+])
 
-const transactionPurposeOptions = [
+const transactionPurposeOptions =computed(()=> [
   { value: 1, text: t('ImproveImmediately.Label.purposeTransaction1') },
   { value: 2, text: t('ImproveImmediately.Label.purposeTransaction2') },
   { value: 3, text: t('ImproveImmediately.Label.purposeTransaction3') },
   { value: 4, text: t('ImproveImmediately.Label.purposeTransaction4') },
-]
+])
 
-const fundSourceOptions = [
+const fundSourceOptions = computed(()=>[
   { value: 1, text: t('ImproveImmediately.Label.SourceFunds1') },
   { value: 2, text: t('ImproveImmediately.Label.SourceFunds2') },
   { value: 3, text: t('ImproveImmediately.Label.SourceFunds3') },
   { value: 4, text: t('ImproveImmediately.Label.SourceFunds4') },
   { value: 5, text: t('ImproveImmediately.Label.SourceFunds5') },
   { value: 6, text: t('ImproveImmediately.Label.SourceFunds6') },
-]
+])
 
-const annualIncomeOptions = [
+const annualIncomeOptions = computed(()=>[
   { value: 1, text: t('ImproveImmediately.Label.TotalAnnualRevenue1') },
   { value: 2, text: t('ImproveImmediately.Label.TotalAnnualRevenue2') },
   { value: 3, text: t('ImproveImmediately.Label.TotalAnnualRevenue3') },
   { value: 4, text: t('ImproveImmediately.Label.TotalAnnualRevenue4') },
   { value: 5, text: t('ImproveImmediately.Label.TotalAnnualRevenue5') },
-]
+])
 
-const netWorthOptions = [
+const netWorthOptions = computed(()=>[
   { value: 1, text: t('ImproveImmediately.Label.TotalNetAssets1') },
   { value: 2, text: t('ImproveImmediately.Label.TotalNetAssets2') },
   { value: 3, text: t('ImproveImmediately.Label.TotalNetAssets3') },
   { value: 4, text: t('ImproveImmediately.Label.TotalNetAssets4') },
   { value: 5, text: t('ImproveImmediately.Label.TotalNetAssets5') },
-]
+])
 
 const cardTypeOptions = [
   { value: 'ID_CARD', text: 'ID Card' },
@@ -1143,7 +1145,7 @@ function cancle() {
     dialogCheck.value.open()
     dialogCheck1.value = true
   } else {
-    router.push({ path: '/pages/customer/index' })
+    router.push({ path: '/pages/customer/dashboard' })
   }
 }
 
@@ -1153,7 +1155,7 @@ function closeDia() {
 
 function toHome() {
   dialogCheck.value.close()
-  router.push({ path: '/pages/customer/index' })
+  router.push({ path: '/pages/customer/dashboard' })
 }
 
 async function save() {
@@ -1225,7 +1227,7 @@ async function customApply() {
     let res = await personalApi.customApplyReal({})
     if (res.code == Config.Code.StatusOK) {
       isApprove.value = true
-      await getLoginInfo()
+      await getLoginInfo(true)
       dialogCheck.value.open()
       dialogCheck1.value = false
     } else {
@@ -1302,11 +1304,12 @@ async function getCityList(pid: string) {
   }
 }
 
-async function getLoginInfo() {
+async function getLoginInfo(type=false) {
   try {
     let res = await personalApi.CustomLoginInfo()
     if (res.code == Config.Code.StatusOK) {
       formData.value = res.data.customInfo
+      if (type) userStore.saveUserInfo(res.data)
       if (formData.value.addressLines != null && formData.value.addressLines.length) {
         formData.value.addressLines1 = formData.value.addressLines[0]
         formData.value.addressLines2 = formData.value.addressLines[1]
@@ -1635,15 +1638,16 @@ onUnmounted(() => {
   display: flex;
 
   .options {
+    display: flex;
     flex: 1;
     padding: 8px;
     box-sizing: border-box;
-    display: flex;
     justify-content: center;
     align-content: center;
     align-items: center;
     @media screen and (max-width: 990px) {
       flex-direction: column;
+      align-items: flex-start;
     }
 
     uni-button {