App.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <script setup>
  2. import { ref, onMounted, nextTick, watch, onBeforeUnmount, getCurrentInstance } from 'vue';
  3. import { useI18n } from "vue-i18n";
  4. import config from '@/config'
  5. const { locale } = useI18n();
  6. const { Host80 } = config
  7. import {
  8. onLoad,
  9. onShow,
  10. onLaunch
  11. } from '@dcloudio/uni-app'
  12. import {
  13. updateRoute
  14. } from "@/hooks/useRoute";
  15. import useGlobalStore from "@/stores/use-global-store";
  16. // import { useAppUpdate } from '@/hooks/useAppUpdate'
  17. // const { checkUpdate } = useAppUpdate()
  18. const globalStore = useGlobalStore()
  19. onLoad((options) => {
  20. updateRoute();
  21. // checkUpdate()
  22. })
  23. onShow((options) => {
  24. updateRoute();
  25. // checkUpdate()
  26. handleSignupRoute(options)
  27. })
  28. // App.vue 或你的初始化文件中
  29. function initTheme() {
  30. // #ifdef H5
  31. // H5 端:使用 matchMedia 主动获取当前系统主题
  32. const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
  33. const theme = isDarkMode ? 'dark' : 'light'
  34. globalStore.setGlobalTheme(theme)
  35. // 监听变化(你的 onThemeChange 已经能工作,但可以再加一层保险)
  36. const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)')
  37. const handleChange = (e) => {
  38. const newTheme = e.matches ? 'dark' : 'light'
  39. globalStore.setGlobalTheme(newTheme)
  40. }
  41. // 兼容旧版浏览器
  42. if (darkModeQuery.addEventListener) {
  43. darkModeQuery.addEventListener('change', handleChange)
  44. } else {
  45. darkModeQuery.addListener(handleChange)
  46. }
  47. // 设置 data-bs-theme 属性到 html 标签
  48. document.documentElement.setAttribute('data-bs-theme', theme);
  49. document.documentElement.setAttribute('data-color-theme', 'blue');
  50. // 同时设置到 body 标签
  51. document.body.setAttribute('data-bs-theme', theme);
  52. document.body.setAttribute('data-color-theme', 'blue');
  53. // #endif
  54. // #ifdef APP-PLUS
  55. // App 端:使用原生 API
  56. uni.getSystemInfo({
  57. success: (res) => {
  58. let theme = res.osTheme || 'light'
  59. globalStore.setGlobalTheme(theme)
  60. }
  61. })
  62. uni.onThemeChange((res) => {
  63. globalStore.setGlobalTheme(res.theme)
  64. })
  65. // #endif
  66. }
  67. onLaunch((options) => {
  68. // updateRoute();
  69. // checkUpdate()
  70. // 调用初始化
  71. // initTheme()
  72. // checkWgtUpdate()
  73. // #ifdef H5
  74. // 处理 signup 路径
  75. document.title = 'CWGMarkets'
  76. // 防止后面又被改掉,再加个定时器兜底
  77. setInterval(() => {
  78. if (!document.title) document.title = 'CWGMarkets'
  79. }, 500)
  80. // #endif
  81. })
  82. // 解析 URL 参数
  83. const parseUrlParams = () => {
  84. const params = {}
  85. // #ifdef H5
  86. // H5 端:直接从浏览器 URL 解析
  87. if (typeof window !== 'undefined' && window.location) {
  88. const href = window.location.href
  89. // 解析 hash 部分
  90. const hashIndex = href.indexOf('#')
  91. if (hashIndex !== -1) {
  92. const hash = href.substring(hashIndex + 1)
  93. // 解析路径
  94. const pathMatch = hash.match(/^\/([^/?]+)/)
  95. if (pathMatch) {
  96. params.path = pathMatch[1]
  97. }
  98. // 解析路径参数 signup/19628/RHOP4WVa/B0
  99. const pathParams = hash.match(/^\/signup\/([^/]+)\/?([^/]+)?\/?([^/]+)?/)
  100. if (pathParams) {
  101. params.path = 'signup'
  102. params.p1 = pathParams[1]
  103. params.p2 = pathParams[2]
  104. params.p3 = pathParams[3]
  105. }
  106. // 解析 query 参数
  107. const queryIndex = hash.indexOf('?')
  108. if (queryIndex !== -1) {
  109. const queryStr = hash.substring(queryIndex + 1)
  110. const pairs = queryStr.split('&')
  111. pairs.forEach(pair => {
  112. const [key, value] = pair.split('=')
  113. if (key && value) {
  114. params[key] = decodeURIComponent(value)
  115. }
  116. })
  117. }
  118. }
  119. }
  120. // #endif
  121. // #ifndef H5
  122. // App 端:从 options 参数获取
  123. if (typeof options === 'object' && options !== null) {
  124. Object.assign(params, options)
  125. }
  126. // #endif
  127. return params
  128. }
  129. // 处理 signup 和 signin 路径(仅 H5 端)
  130. const handleSignupRoute = (options) => {
  131. // #ifdef H5
  132. // 解析 URL 参数(从浏览器 URL 解析)
  133. const query = parseUrlParams()
  134. console.log('解析到的参数:', query);
  135. // 处理 signin 路径(自动登录)
  136. if (query.path === 'signin') {
  137. // 跳转到登录页面 有就携带 token 参数
  138. const loginUrl = query?.sysLoginToken ? `/pages/login/index?sysLoginToken=${encodeURIComponent(query.sysLoginToken)}` : '/pages/login/index'
  139. console.log('跳转到登录页面:', loginUrl);
  140. uni.reLaunch({
  141. url: loginUrl,
  142. success: () => {
  143. console.log('跳转成功');
  144. },
  145. fail: (err) => {
  146. console.error('跳转失败:', err);
  147. }
  148. })
  149. return
  150. }
  151. // 判断是否是 signup 路径
  152. const isSignup = query.path === 'signup' || query.s || query.signup || query.activeTab === '2'
  153. if (!isSignup) return
  154. // 获取参数
  155. const id = query.id || query.agentId || query.p1 || ''
  156. const subId = query.subId || query.w || query.p2 || ''
  157. const code = query.code || query.oc || query.p3 || ''
  158. // 构建登录页面 URL
  159. let loginUrl = '/pages/login/index?activeTab=2'
  160. // 携带参数
  161. if (id) loginUrl += `&id=${id}`
  162. if (subId) loginUrl += `&subId=${subId}`
  163. if (code) loginUrl += `&code=${code}`
  164. console.log('跳转到:', loginUrl);
  165. // 跳转到注册页面
  166. uni.reLaunch({
  167. url: loginUrl,
  168. success: () => {
  169. console.log('跳转成功');
  170. },
  171. fail: (err) => {
  172. console.error('跳转失败:', err);
  173. }
  174. })
  175. // #endif
  176. }
  177. watch(locale, () => {
  178. // const currentPath = route.path;
  179. // menu.value.forEach((item, index) => {
  180. // if (item.children) {
  181. // const isActive = item.children.some(child => child.path.includes(currentPath));
  182. // menu.value[index].isOpenMenu = isActive;
  183. // if (isActive) {
  184. // nextTick(() => {
  185. // updateSubmenuHeight(index);
  186. // });
  187. // }
  188. // }
  189. // });
  190. }, { immediate: true })
  191. // 检测版本号更新
  192. const checkWgtUpdate = async () => {
  193. try {
  194. console.log(Host80)
  195. const currentVersion = await getCurrentVersion()
  196. const res = await uni.request({
  197. url: `${Host80}/wgt/list.json?_t=${Date.now()}`,
  198. method: 'GET',
  199. timeout: 5000
  200. })
  201. console.log('up:filedata',res)
  202. const files = res.data?.files || []
  203. if (!files.length) return
  204. const latestFile = files[files.length - 1]
  205. const latestVersion = latestFile
  206. console.log('last',latestFile,latestVersion)
  207. if (!latestFile) return
  208. const lastInstalled = uni.getStorageSync('lastWgtVersion')
  209. console.log(lastInstalled, 'lastInstalled');
  210. if (latestVersion === lastInstalled) return
  211. if (compareVersion(latestVersion, currentVersion) > 0) {
  212. downloadAndInstall(latestVersion)
  213. }
  214. } catch (e) {
  215. console.log('[wgt] update check failed', e)
  216. }
  217. }
  218. // 下载并安装
  219. const downloadAndInstall = (version) => {
  220. //TODO: 需要根据版本来确定url
  221. const url = `https://ucard.44a5c8109e4.com/wgt/__UNI__EFA7490.wgt`
  222. console.log(url, 'downloadurl');
  223. uni.downloadFile({
  224. url,
  225. success: (res) => {
  226. if (res.statusCode === 200) {
  227. const filePath = res.tempFilePath
  228. plus.runtime.install(
  229. filePath, {
  230. force: true
  231. },
  232. () => {
  233. uni.setStorageSync('lastWgtVersion', version)
  234. console.log('[wgt] install success:', version)
  235. uni.setStorageSync('wgtNeedRestart', true)
  236. },
  237. (err) => {
  238. console.error('[wgt] install failed:', err)
  239. }
  240. )
  241. } else {
  242. console.error('[wgt] download status error:', res.statusCode)
  243. }
  244. },
  245. fail: (err) => {
  246. console.error('[wgt] download failed:', err)
  247. }
  248. })
  249. }
  250. // 获取当前版本
  251. const getCurrentVersion = async () => {
  252. return new Promise((resolve, reject) => {
  253. // #ifdef APP-PLUS
  254. try {
  255. plus.runtime.getProperty(plus.runtime.appid, (info) => {
  256. resolve(info.version)
  257. }, (error) => {
  258. reject(error)
  259. })
  260. } catch (error) {
  261. reject(error)
  262. }
  263. // #endif
  264. // #ifndef APP-PLUS
  265. reject(new Error('Not in APP-PLUS environment'))
  266. // #endif
  267. })
  268. }
  269. // 对比版本号
  270. const compareVersion = (v1, v2) => {
  271. const s1 = v1.split('.').map(Number)
  272. const s2 = v2.split('.').map(Number)
  273. const len = Math.max(s1.length, s2.length)
  274. for (let i = 0; i < len; i++) {
  275. const n1 = s1[i] || 0
  276. const n2 = s2[i] || 0
  277. if (n1 > n2) return 1
  278. if (n1 < n2) return -1
  279. }
  280. return 0
  281. }
  282. onMounted(() => {
  283. const sysInfo = uni.getSystemInfoSync();
  284. globalStore.setBarHeight(sysInfo.statusBarHeight || 60);
  285. // ---------- 新增 H5 端专属初始化 ----------
  286. // 仅在 H5 端执行(通过环境判断)
  287. // #ifdef H5
  288. if (typeof window !== 'undefined') {
  289. const instance = getCurrentInstance()
  290. if (instance) {
  291. window.vm = instance.proxy
  292. }
  293. }
  294. // #endif
  295. });
  296. </script>
  297. <style>
  298. /*每个页面公共css */
  299. </style>
  300. <style lang="scss">
  301. /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
  302. @import "uview-plus/index.scss";
  303. @import "@/static/scss/global/global.scss";
  304. @import "@/static/scss/global/vu.css";
  305. @import "/static/scss/style.scss";
  306. @font-face {
  307. font-family: 'Google Sans';
  308. src: url('/static/Google_Sans/GoogleSans-VariableFont_GRAD,opsz,wght.ttf') format('truetype-variations');
  309. font-weight: 100 900;
  310. font-style: normal;
  311. font-display: swap;
  312. }
  313. /* 全局字体,不破坏 uni-icons 图标 */
  314. view,
  315. text,
  316. button,
  317. input,
  318. textarea,
  319. label {
  320. font-family: 'Google Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  321. font-weight: 400;
  322. }
  323. /* 专门保护 uni-icons 不被覆盖 */
  324. .uni-icon,
  325. [class*="uni-icons-"],
  326. .uni-icons {
  327. font-family: uniicons !important;
  328. }
  329. /* 让整个项目文字都能选中 */
  330. * {
  331. -webkit-user-select: text !important;
  332. user-select: text !important;
  333. }
  334. /* 修复滚动层无法选中 */
  335. view,
  336. text,
  337. div,
  338. span {
  339. -webkit-user-select: text !important;
  340. user-select: text !important;
  341. }
  342. /* 强制修复 uni-datetime-picker 重复渲染双日历 */
  343. // .uni-calendar+.uni-calendar {
  344. // display: none !important;
  345. // }
  346. :deep(.u-toolbar__wrapper__confirm) {
  347. font-size: 20px !important;
  348. }
  349. :deep(.u-toolbar__wrapper__cancel) {
  350. font-size: 20px !important;
  351. }
  352. .page {
  353. /* padding: 31px 31px 110px 31px; */
  354. box-sizing: border-box;
  355. /* background: var(--main-bg); */
  356. }
  357. html {
  358. --bs-bg-opacity: 1;
  359. background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  360. font-size: 16px !important;
  361. }
  362. uni-page-body {
  363. height: 100%;
  364. }
  365. page {
  366. --bs-bg-opacity: 1;
  367. background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  368. }
  369. </style>