From db685b04e52efd75213ef7540fdc0bed7dccfd9e Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期一, 26 十月 2026 21:13:37 +0800
Subject: [PATCH] 更新小程序

---
 cool/utils/comm.ts                                             |   33 ++
 cool/service/request.ts                                        |   75 +++++
 pages/goods/detail.vue                                         |    3 
 uni_modules/cool-ui/components/cl-popup/cl-popup.vue           |    5 
 uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue |    3 
 App.vue                                                        |   56 +++
 cool/hooks/wx.ts                                               |    4 
 cool/utils/qrcode.ts                                           |  199 +++++++++++++---
 vite.config.ts                                                 |    5 
 uni_modules/cool-ui/components/cl-guide/cl-guide.vue           |    3 
 uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue         |    4 
 locale/index.ts                                                |    2 
 cool/utils/storage.ts                                          |   15 
 pages/goods/components/filter-bar.vue                          |   13 
 config/proxy.ts                                                |    4 
 cool/mini-login.ts                                             |   81 ++++++
 cool/store/user.ts                                             |    7 
 pages/recycle/banner.vue                                       |   45 +--
 uni_modules/mp-html/components/mp-html/node/node.vue           |    2 
 pages/recycle/home.vue                                         |   50 +--
 uni_modules/cool-ui/components/cl-topbar/cl-topbar.vue         |    5 
 manifest.json                                                  |   13 
 uni_modules/mp-html/components/mp-html/parser.js               |    4 
 components/phone-auth.vue                                      |   48 ++-
 uni_modules/cool-ui/components/cl-page/cl-page.vue             |    4 
 25 files changed, 513 insertions(+), 170 deletions(-)

diff --git a/App.vue b/App.vue
index d6cd1d8..9ef2341 100644
--- a/App.vue
+++ b/App.vue
@@ -1,23 +1,57 @@
 <script setup lang="ts">
-import { useStore } from "/@/cool";
+import { useStore, storage } from "/@/cool";
+import { miniAutoLogin, phoneAuthState } from "/@/cool/mini-login";
+import { i18n } from "/@/locale";
 import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
+
+let booted = false;
+
+function boot() {
+	if (booted) {
+		return;
+	}
+	booted = true;
+
+	const { dict, user } = useStore();
+	const authState = phoneAuthState();
+
+	try {
+		const locale = uni.getLocale();
+		if (locale) {
+			i18n.global.locale = locale;
+		}
+	} catch (err) {
+		console.error(err);
+	}
+
+	dict.refresh()?.catch(() => undefined);
+
+	// #ifdef MP-WEIXIN
+	miniAutoLogin()
+		.catch(() => false)
+		.finally(() => {
+			authState.ready = true;
+			if (user.token && !storage.isExpired("token")) {
+				user.get()?.catch(() => undefined);
+			}
+		});
+	// #endif
+
+	// #ifndef MP-WEIXIN
+	authState.ready = true;
+	if (user.token) {
+		user.get()?.catch(() => undefined);
+	}
+	// #endif
+}
 
 onLaunch(() => {
 	console.log("App Launch");
-
-	const { dict, user } = useStore();
-
-	// 鑾峰彇瀛楀吀
-	dict.refresh();
-
-	if (user.token) {
-		// 鑾峰彇鐧诲綍鐢ㄦ埛淇℃伅
-		user.get();
-	}
 });
 
 onShow(() => {
 	console.log("App Show");
+	setTimeout(boot, 0);
 });
 
 onHide(() => {
diff --git a/components/phone-auth.vue b/components/phone-auth.vue
index 9747ff1..23185ff 100644
--- a/components/phone-auth.vue
+++ b/components/phone-auth.vue
@@ -24,9 +24,10 @@
 import { computed, ref } from "vue";
 import { onShow } from "@dcloudio/uni-app";
 import { useCool, useStore, useWx } from "/@/cool";
+import { phoneAuthState } from "/@/cool/mini-login";
 import { useUi } from "/$/cool-ui";
 
-const authState = ((globalThis as any).__phoneAuthState ||= { dismissed: false });
+const authState = phoneAuthState();
 
 const { service, router } = useCool();
 const { user } = useStore();
@@ -37,7 +38,7 @@
 
 const visible = computed(() => {
 	tick.value;
-	return !authState.dismissed && !user.info?.phone;
+	return authState.ready && !authState.dismissed && (!user.token || !user.info?.phone);
 });
 
 function later() {
@@ -87,23 +88,34 @@
 	submitting.value = true;
 	ui.showLoading();
 
-	const payload = phonePayload(detail);
-	const task = user.token
-		? service.user.info.miniPhone(payload).then(async (phone: string) => {
-				const info = user.info || (await service.user.info.person());
-				if (info) {
-					user.set({ ...info, phone });
-				}
-				return phone;
-			})
-		: service.user.login.miniPhone(payload).then(async (res) => {
-				user.setToken(res);
-				const info = await service.user.info.person();
-				if (info) {
-					user.set(info);
-				}
-				return info?.phone as string | undefined;
+	const task = new Promise<string>((resolve) => {
+		uni.login({
+			provider: "weixin",
+			success: (res) => resolve(res.code || ""),
+			fail: () => resolve(""),
+		});
+	})
+		.then((loginCode) => {
+			return service.user.login.miniPhone({
+				...phonePayload(detail),
+				loginCode,
 			});
+		})
+		.then(async (res) => {
+		user.setToken(res);
+		let info = user.info;
+		try {
+			info = (await service.user.info.person()) || info;
+		} catch (err) {
+			console.error(err);
+		}
+		const phone = info?.phone || res.phone;
+		user.set({
+			...(info || {}),
+			phone,
+		});
+		return phone as string | undefined;
+	});
 
 	task
 		.then((phone) => {
diff --git a/config/proxy.ts b/config/proxy.ts
index 7a7959f..807ef0d 100644
--- a/config/proxy.ts
+++ b/config/proxy.ts
@@ -1,12 +1,12 @@
 const proxy = {
 	"/dev/": {
-		target: "http://127.0.0.1:8001",
+		target: "http://womp.jsbogang.com:8001",
 		changeOrigin: true,
 		rewrite: (path: string) => path.replace(/^\/dev/, ""),
 	},
 
 	"/prod/": {
-		target: "https://show.cool-admin.com",
+		target: "https://womp.jsbogang.com:8001",
 		changeOrigin: true,
 		rewrite: (path: string) => path.replace(/^\/prod/, "/api"),
 	},
diff --git a/cool/hooks/wx.ts b/cool/hooks/wx.ts
index 32ac1e9..621d646 100644
--- a/cool/hooks/wx.ts
+++ b/cool/hooks/wx.ts
@@ -1,7 +1,7 @@
 import { ref } from "vue";
 import { onReady, onShow } from "@dcloudio/uni-app";
 import { config } from "/@/config";
-import { getUrlParam, storage } from "../utils";
+import { getSystemInfo, getUrlParam, storage } from "../utils";
 import { service } from "../service";
 import { useI18n } from "vue-i18n";
 // #ifdef H5
@@ -9,7 +9,7 @@
 // #endif
 
 export function useWx() {
-	const { platform } = uni.getSystemInfoSync();
+	const { platform } = getSystemInfo();
 	const { t } = useI18n();
 
 	// 鎺堟潈鐮�
diff --git a/cool/mini-login.ts b/cool/mini-login.ts
new file mode 100644
index 0000000..703a8d1
--- /dev/null
+++ b/cool/mini-login.ts
@@ -0,0 +1,81 @@
+import { reactive } from "vue";
+import { BaseService } from "./service/base";
+import { useUserStore } from "./store/user";
+import { storage } from "./utils";
+
+export type PhoneAuthState = {
+	dismissed: boolean;
+	ready: boolean;
+};
+
+export function phoneAuthState(): PhoneAuthState {
+	const host = globalThis as any;
+	if (!host.__phoneAuthState) {
+		host.__phoneAuthState = reactive({
+			dismissed: false,
+			ready: false,
+		});
+	}
+	return host.__phoneAuthState;
+}
+
+function wxLoginCode() {
+	return new Promise<string>((resolve) => {
+		uni.login({
+			provider: "weixin",
+			success: (res) => resolve(res.code || ""),
+			fail: () => resolve(""),
+		});
+	});
+}
+
+let pending: Promise<boolean> | null = null;
+
+/**
+ * 宸叉巿鏉冭繃鎵嬫満鍙风殑寰俊鐢ㄦ埛锛屽啀娆℃墦寮�鏃剁敤 openid 鎹㈠洖鐧诲綍鎬併��
+ */
+export function miniAutoLogin(force = false) {
+	if (pending && !force) {
+		return pending;
+	}
+	const task = runMiniAutoLogin(force).finally(() => {
+		if (pending === task) {
+			pending = null;
+		}
+	});
+	pending = task;
+	return task;
+}
+
+async function runMiniAutoLogin(force = false) {
+	const user = useUserStore();
+	if (!force && user.token && user.info?.phone && !storage.isExpired("token")) {
+		return true;
+	}
+
+	const code = await wxLoginCode();
+	if (!code) {
+		return false;
+	}
+
+	const res = await new BaseService("app/user/login").request({
+		url: "/miniAuto",
+		method: "POST",
+		data: { code },
+	});
+
+	if (!res?.token) {
+		return false;
+	}
+
+	user.setToken(res);
+	user.set({
+		...(user.info || {}),
+		id: res.id,
+		unionid: res.unionid,
+		phone: res.phone,
+		nickName: res.nickName || user.info?.nickName,
+		avatarUrl: res.avatarUrl || user.info?.avatarUrl,
+	});
+	return true;
+}
diff --git a/cool/service/request.ts b/cool/service/request.ts
index 11eae91..a78b730 100644
--- a/cool/service/request.ts
+++ b/cool/service/request.ts
@@ -10,6 +10,33 @@
 // Token 鏄惁鍒锋柊涓�
 let isRefreshing = false;
 
+let reloginTask: Promise<boolean> | null = null;
+
+function dropToken() {
+	const { user } = useStore();
+	user.token = "";
+	storage.remove("token");
+	storage.remove("token_deadtime");
+	storage.remove("refreshToken");
+	storage.remove("refreshToken_deadtime");
+}
+
+function recoverLogin() {
+	if (reloginTask) {
+		return reloginTask;
+	}
+	reloginTask = import("../mini-login")
+		.then(({ miniAutoLogin }) => {
+			dropToken();
+			return miniAutoLogin(true);
+		})
+		.catch(() => false)
+		.finally(() => {
+			reloginTask = null;
+		});
+	return reloginTask;
+}
+
 export default function request(options: any) {
 	const { user } = useStore();
 
@@ -45,6 +72,23 @@
 						message: string;
 						data: any;
 					};
+
+					const invalid = res.statusCode === 401 || message === "鐧诲綍澶辨晥~";
+					const skipRelogin = /miniAuto|refreshToken/.test(options.url || "");
+					if (invalid && !skipRelogin && !options.__retried) {
+						options.__retried = true;
+						recoverLogin()
+							.then((ok) => {
+								if (!ok) {
+									reject({ message: message || "鐧诲綍澶辨晥~", code: code || 1001 });
+									return;
+								}
+								Authorization = useStore().user.token || "";
+								next();
+							})
+							.catch((err) => reject(err));
+						return;
+					}
 
 					// 鏃犳潈闄�
 					if (res.statusCode === 401) {
@@ -95,9 +139,18 @@
 				// 鍒ゆ柇 token 鏄惁杩囨湡
 				if (storage.isExpired("token")) {
 					// 鍒ゆ柇 refreshToken 鏄惁杩囨湡
-					if (storage.isExpired("refreshToken")) {
-						// 閫�鍑虹櫥褰�
-						return user.logout();
+					if (!storage.get("refreshToken") || storage.isExpired("refreshToken")) {
+						recoverLogin()
+							.then((ok) => {
+								if (!ok) {
+									reject({ message: "鐧诲綍澶辨晥~", code: 1001 });
+									return;
+								}
+								Authorization = useStore().user.token || "";
+								next();
+							})
+							.catch((err) => reject(err));
+						return;
 					}
 
 					// 鏄惁鍦ㄥ埛鏂颁腑
@@ -109,9 +162,19 @@
 								requests = [];
 								isRefreshing = false;
 							})
-							.catch((err) => {
-								user.logout();
-								reject(err);
+							.catch(() => {
+								isRefreshing = false;
+								requests = [];
+								recoverLogin()
+									.then((ok) => {
+										if (!ok) {
+											reject({ message: "鐧诲綍澶辨晥~", code: 1001 });
+											return;
+										}
+										Authorization = useStore().user.token || "";
+										next();
+									})
+									.catch((err) => reject(err));
 							});
 					}
 
diff --git a/cool/store/user.ts b/cool/store/user.ts
index 39b3c8c..e37bd35 100644
--- a/cool/store/user.ts
+++ b/cool/store/user.ts
@@ -5,10 +5,9 @@
 import { service } from "../service";
 import type { User } from "../types";
 
-// 鏈湴缂撳瓨
-const data = storage.info();
-
 const useUserStore = defineStore("user", function () {
+	const data = storage.info();
+
 	// 鏍囪瘑
 	const token = ref(data.token || "");
 
@@ -75,7 +74,7 @@
 				return res;
 			})
 			.catch(() => {
-				logout();
+				return undefined;
 			});
 	}
 
diff --git a/cool/utils/comm.ts b/cool/utils/comm.ts
index ce4a490..4ee372a 100644
--- a/cool/utils/comm.ts
+++ b/cool/utils/comm.ts
@@ -1,12 +1,33 @@
 import { orderBy } from "lodash-es";
 
-export const { platform } = uni.getSystemInfoSync();
+let systemInfo: any;
+export let platform = "";
+export let isAndroid = false;
+export let isIos = false;
 
-// 鏄惁瀹夊崜
-export const isAndroid = platform == "android";
-
-// 鏄惁鑻规灉
-export const isIos = platform == "ios";
+export function getSystemInfo() {
+	if (systemInfo) {
+		return systemInfo;
+	}
+	const api = uni as any;
+	if (
+		typeof api.getWindowInfo === "function" &&
+		typeof api.getDeviceInfo === "function" &&
+		typeof api.getAppBaseInfo === "function"
+	) {
+		systemInfo = {
+			...api.getAppBaseInfo(),
+			...api.getDeviceInfo(),
+			...api.getWindowInfo(),
+		};
+	} else {
+		systemInfo = uni.getSystemInfoSync();
+	}
+	platform = systemInfo?.platform || "";
+	isAndroid = platform == "android";
+	isIos = platform == "ios";
+	return systemInfo;
+}
 
 // 鏄惁灏忔暟
 export function isDecimal(value: any): boolean {
diff --git a/cool/utils/qrcode.ts b/cool/utils/qrcode.ts
index 47af253..17f6237 100644
--- a/cool/utils/qrcode.ts
+++ b/cool/utils/qrcode.ts
@@ -1,39 +1,173 @@
 import QRCode from "qrcode";
 
-const QRCODE_KEY = "recycleQrcodeBase64";
+function u32(buf: Uint8Array, offset: number, value: number) {
+	buf[offset] = (value >>> 24) & 255;
+	buf[offset + 1] = (value >>> 16) & 255;
+	buf[offset + 2] = (value >>> 8) & 255;
+	buf[offset + 3] = value & 255;
+}
 
-export function generateQrcode(text: string): Promise<string> {
-	return new Promise((resolve) => {
-		QRCode.toDataURL(
-			text,
-			{
-				width: 300,
-				margin: 2,
-			},
-			(err, url) => {
-				if (err) {
-					console.error("鉂� 浜岀淮鐮佺敓鎴愬け璐�", err);
-					resolve("");
-					return;
-				}
-				resolve(url);
-			},
-		);
+function crc32(data: Uint8Array) {
+	let c = 0xffffffff;
+	for (let i = 0; i < data.length; i++) {
+		c ^= data[i];
+		for (let k = 0; k < 8; k++) {
+			c = (c >>> 1) ^ (c & 1 ? 0xedb88320 : 0);
+		}
+	}
+	return (c ^ 0xffffffff) >>> 0;
+}
+
+function adler32(data: Uint8Array) {
+	let a = 1;
+	let b = 0;
+	for (let i = 0; i < data.length; i++) {
+		a = (a + data[i]) % 65521;
+		b = (b + a) % 65521;
+	}
+	return ((b << 16) | a) >>> 0;
+}
+
+function chunk(type: string, data: Uint8Array) {
+	const out = new Uint8Array(12 + data.length);
+	u32(out, 0, data.length);
+	out[4] = type.charCodeAt(0);
+	out[5] = type.charCodeAt(1);
+	out[6] = type.charCodeAt(2);
+	out[7] = type.charCodeAt(3);
+	out.set(data, 8);
+	u32(out, 8 + data.length, crc32(out.subarray(4, 8 + data.length)));
+	return out;
+}
+
+function concat(parts: Uint8Array[]) {
+	const len = parts.reduce((sum, part) => sum + part.length, 0);
+	const out = new Uint8Array(len);
+	let offset = 0;
+	for (const part of parts) {
+		out.set(part, offset);
+		offset += part.length;
+	}
+	return out;
+}
+
+function zlibStore(raw: Uint8Array) {
+	const blocks: Uint8Array[] = [];
+	let offset = 0;
+	while (offset < raw.length) {
+		const len = Math.min(65535, raw.length - offset);
+		const last = offset + len >= raw.length;
+		const block = new Uint8Array(5 + len);
+		block[0] = last ? 1 : 0;
+		block[1] = len & 255;
+		block[2] = (len >>> 8) & 255;
+		const nlen = (~len) & 0xffff;
+		block[3] = nlen & 255;
+		block[4] = (nlen >>> 8) & 255;
+		block.set(raw.subarray(offset, offset + len), 5);
+		blocks.push(block);
+		offset += len;
+	}
+	const bodyLen = blocks.reduce((sum, block) => sum + block.length, 0);
+	const out = new Uint8Array(2 + bodyLen + 4);
+	out[0] = 0x78;
+	out[1] = 0x01;
+	let cursor = 2;
+	for (const block of blocks) {
+		out.set(block, cursor);
+		cursor += block.length;
+	}
+	u32(out, cursor, adler32(raw));
+	return out;
+}
+
+function bytesToBase64(bytes: Uint8Array) {
+	const api = typeof uni === "undefined" ? undefined : uni;
+	if (api && typeof api.arrayBufferToBase64 === "function") {
+		const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
+		return api.arrayBufferToBase64(buffer as ArrayBuffer);
+	}
+	const table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+	let out = "";
+	for (let i = 0; i < bytes.length; i += 3) {
+		const a = bytes[i];
+		const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
+		const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
+		const n = (a << 16) | (b << 8) | c;
+		out += table[(n >> 18) & 63];
+		out += table[(n >> 12) & 63];
+		out += i + 1 < bytes.length ? table[(n >> 6) & 63] : "=";
+		out += i + 2 < bytes.length ? table[n & 63] : "=";
+	}
+	return out;
+}
+
+/** 涓嶄緷璧栨祻瑙堝櫒 canvas锛岀洿鎺ョ敾鍑哄彲鍦ㄥ皬绋嬪簭 image 涓樉绀虹殑 PNG銆� */
+export function createQrPng(text: string) {
+	const qr = QRCode.create(text, { errorCorrectionLevel: "M" });
+	const modules = qr.modules;
+	const count = modules.size;
+	const margin = 4;
+	const scale = 8;
+	const size = (count + margin * 2) * scale;
+	const raw = new Uint8Array(size * (size + 1));
+	let cursor = 0;
+	for (let y = 0; y < size; y++) {
+		raw[cursor++] = 0;
+		const row = Math.floor(y / scale) - margin;
+		for (let x = 0; x < size; x++) {
+			const col = Math.floor(x / scale) - margin;
+			const dark =
+				row >= 0 && col >= 0 && row < count && col < count && !!modules.get(row, col);
+			raw[cursor++] = dark ? 0 : 255;
+		}
+	}
+	const ihdr = new Uint8Array(13);
+	u32(ihdr, 0, size);
+	u32(ihdr, 4, size);
+	ihdr[8] = 8;
+	const signature = Uint8Array.from([137, 80, 78, 71, 13, 10, 26, 10]);
+	return concat([
+		signature,
+		chunk("IHDR", ihdr),
+		chunk("IDAT", zlibStore(raw)),
+		chunk("IEND", new Uint8Array(0)),
+	]);
+}
+
+function fileName(text: string) {
+	let hash = 0;
+	for (let i = 0; i < text.length; i++) {
+		hash = (hash * 31 + text.charCodeAt(i)) >>> 0;
+	}
+	return hash.toString(16);
+}
+
+function savePng(bytes: Uint8Array, text: string) {
+	const base64 = bytesToBase64(bytes);
+	const dataUrl = `data:image/png;base64,${base64}`;
+	const root = (globalThis as any).wx?.env?.USER_DATA_PATH;
+	if (!root || typeof uni === "undefined" || typeof uni.getFileSystemManager !== "function") {
+		return Promise.resolve(dataUrl);
+	}
+	const filePath = `${root}/recycle-qr-${fileName(text)}.png`;
+	return new Promise<string>((resolve) => {
+		uni.getFileSystemManager().writeFile({
+			filePath,
+			data: base64,
+			encoding: "base64",
+			success: () => resolve(filePath),
+			fail: () => resolve(dataUrl),
+		});
 	});
 }
 
-export function generateRecycleQrcode(text: string): Promise<string> {
-	return new Promise((resolve) => {
-		const cached = uni.getStorageSync(QRCODE_KEY);
-		if (cached) return resolve(cached);
+export function generateQrcode(text: string) {
+	return savePng(createQrPng(text), text);
+}
 
-		generateQrcode(text).then((url) => {
-			if (url) {
-				uni.setStorageSync(QRCODE_KEY, url);
-			}
-			resolve(url);
-		});
-	});
+export function generateRecycleQrcode(text: string) {
+	return generateQrcode(text);
 }
 
 /**
@@ -43,10 +177,3 @@
 export function clearQrcodeCache(key: string) {
 	uni.removeStorageSync(key);
 }
-
-/**
- * 娓呴櫎鎵�鏈変簩缁寸爜缂撳瓨
- */
-export function clearAllQrcodeCache() {
-	uni.clearStorageSync();
-}
\ No newline at end of file
diff --git a/cool/utils/storage.ts b/cool/utils/storage.ts
index d12606b..6cf639f 100644
--- a/cool/utils/storage.ts
+++ b/cool/utils/storage.ts
@@ -34,10 +34,7 @@
 		uni.setStorageSync(key, value);
 
 		if (expires) {
-			uni.setStorageSync(
-				`${key}${this.suffix}`,
-				Date.parse(String(new Date())) + expires * 1000
-			);
+			uni.setStorageSync(`${key}${this.suffix}`, Date.now() + expires * 1000);
 		}
 	},
 
@@ -46,7 +43,15 @@
 	 * @param {*} key 鍏抽敭瀛�
 	 */
 	isExpired(key: string): boolean {
-		return uni.getStorageSync(`${key}${this.suffix}`) - Date.parse(String(new Date())) <= 0;
+		const raw = uni.getStorageSync(`${key}${this.suffix}`);
+		if (raw === "" || raw === null || raw === undefined) {
+			return false;
+		}
+		const dead = Number(raw);
+		if (!dead) {
+			return true;
+		}
+		return dead - Date.now() <= 0;
 	},
 
 	/**
diff --git a/locale/index.ts b/locale/index.ts
index eab9db6..c15ceac 100644
--- a/locale/index.ts
+++ b/locale/index.ts
@@ -6,7 +6,7 @@
 import fr from "./fr.json";
 
 const i18n = createI18n({
-	locale: uni.getLocale(),
+	locale: "zh-Hans",
 
 	// 閰嶇疆鍚庯紝浣跨敤鍛戒护 cool-i18n create 缈昏瘧锛屼細鑷姩鏇存柊 locale 鐩綍
 	messages: {
diff --git a/manifest.json b/manifest.json
index 86962f6..22d74b2 100644
--- a/manifest.json
+++ b/manifest.json
@@ -68,21 +68,21 @@
                     },
                     "weixin" : {
                         "__platform__" : [ "ios", "android" ],
-                        "appid" : "wx348f72db1512fa2e",
+                        "appid" : "wx88c344d1b0db243a",
                         "UniversalLinks" : ""
                     }
                 },
                 "ad" : {},
                 "share" : {
                     "weixin" : {
-                        "appid" : "wx348f72db1512fa2e",
+                        "appid" : "wx88c344d1b0db243a",
                         "UniversalLinks" : ""
                     }
                 },
                 "oauth" : {
                     "weixin" : {
-                        "appid" : "wx348f72db1512fa2e",
-                        "appsecret" : "test",
+                        "appid" : "wx88c344d1b0db243a",
+                        "appsecret" : "0188e38c7b797cef569a391f37272891",
                         "UniversalLinks" : ""
                     },
                     "apple" : {}
@@ -154,7 +154,10 @@
         "appid" : "wx88c344d1b0db243a",
         "setting" : {
             "urlCheck" : true,
-            "es6" : false
+            "es6" : true,
+            "enhance" : true,
+            "postcss" : true,
+            "minified" : true
         },
         "usingComponents" : true
     },
diff --git a/pages/goods/components/filter-bar.vue b/pages/goods/components/filter-bar.vue
index 1b7bbd7..ac3ddc5 100644
--- a/pages/goods/components/filter-bar.vue
+++ b/pages/goods/components/filter-bar.vue
@@ -324,7 +324,8 @@
 			overflow: hidden;
 			flex: 1;
 
-			button {
+			.reset,
+			.confirm {
 				height: 64rpx;
 				line-height: 64rpx;
 				padding: 0;
@@ -337,12 +338,12 @@
 				&::after {
 					border: 0;
 				}
+			}
 
-				&.reset {
-					color: $cl-color-primary;
-					background-color: #fff;
-					border-radius: 80rpx 0 80rpx 80rpx;
-				}
+			.reset {
+				color: $cl-color-primary;
+				background-color: #fff;
+				border-radius: 80rpx 0 80rpx 80rpx;
 			}
 		}
 	}
diff --git a/pages/goods/detail.vue b/pages/goods/detail.vue
index d2bdcf1..f31795c 100644
--- a/pages/goods/detail.vue
+++ b/pages/goods/detail.vue
@@ -67,6 +67,7 @@
 <script lang="ts" setup>
 import { reactive, ref } from "vue";
 import { useCool } from "/@/cool";
+import { getSystemInfo } from "/@/cool/utils";
 import { onPageScroll, onReady } from "@dcloudio/uni-app";
 import { last } from "lodash-es";
 import { useShoppingCart, useSpec } from "/@/hooks";
@@ -78,7 +79,7 @@
 const { service, router, refs, setRefs } = useCool();
 const spec = useSpec();
 const spCart = useShoppingCart();
-const { statusBarHeight = 0 } = uni.getSystemInfoSync();
+const { statusBarHeight = 0 } = getSystemInfo();
 
 // 椤堕儴閫夐」鏍�
 const tabs = reactive({
diff --git a/pages/recycle/banner.vue b/pages/recycle/banner.vue
index 24b0018..b25dad6 100644
--- a/pages/recycle/banner.vue
+++ b/pages/recycle/banner.vue
@@ -72,10 +72,8 @@
 					<text class="qrcode-title">鎴戠殑鍥炴敹鐮�</text>
 					<text class="qrcode-desc">鍚戝洖鏀跺憳鍑虹ず姝ょ爜瀹屾垚鍥炴敹</text>
 					<view class="qrcode-image-wrap">
-						<image class="qrcode-image" :src="qrcodeUrl" mode="aspectFit" />
-						
+						<image v-if="qrcodeUrl" class="qrcode-image" :src="qrcodeUrl" mode="aspectFit" />
 					</view>
-					<text class="qrcode-code">鍥炴敹鐮侊細{{ userCode }}</text>
 					<view class="qrcode-close" @tap="showQrcode = false">
 						<cl-icon name="close" :size="36" color="#999" />
 					</view>
@@ -114,7 +112,6 @@
 	});
 
 	const showQrcode = ref(false);
-	const userCode = ref("");
 	const qrcodeUrl = ref("");
 
 	// ========== 鍒濆鍖栧姞杞� ==========
@@ -126,14 +123,18 @@
 	async function loadDashboard() {
 		try {
 			const unionid = user.info?.phone||"18918594752";
-			service.user.info.dashboard({ unionid:unionid  }).then((res) => {
-				console.log("銆愬啀鐢熻祫婧愮湅鏉挎暟鎹��", res);
-				dashboard.value = {
-					carbonPoints: res.carbonPoints ?? 0,
-					recycleCount: res.recycleCount ?? 0,
-					overPercent: res.overPercent ?? 0,
-				};
-			});
+			service.user.info
+				.dashboard({ unionid })
+				.then((res) => {
+					dashboard.value = {
+						carbonPoints: res.carbonPoints ?? 0,
+						recycleCount: res.recycleCount ?? 0,
+						overPercent: res.overPercent ?? 0,
+					};
+				})
+				.catch((err) => {
+					console.error("銆愬啀鐢熻祫婧愮湅鏉垮姞杞藉け璐ャ��", err);
+				});
 		} catch (e) {
 			console.error("銆愬啀鐢熻祫婧愮湅鏉垮姞杞藉け璐ャ��", e);
 		}
@@ -141,15 +142,17 @@
 
 	/** 鍔犺浇鐢ㄦ埛鍥炴敹鐮� */
 	async function loadMyCode() {
+		const phone = user.info?.phone;
+		if (!phone) {
+			uni.showToast({ title: "璇峰厛鎺堟潈鎵嬫満鍙�", icon: "none" });
+			showQrcode.value = false;
+			return;
+		}
 		try {
-			const phone = user.info?.phone ?? "18918594752";
-			const res = await generateRecycleQrcode(phone);
-			userCode.value = phone;
-			qrcodeUrl.value = res;
+			qrcodeUrl.value = await generateRecycleQrcode(phone);
 		} catch (e) {
 			console.error("銆愬洖鏀剁爜鍔犺浇澶辫触銆�", e);
-			// 鍏滃簳锛氭病鏈夋帴鍙f椂缁欎釜榛樿鍊�
-			userCode.value = "RC-LOADING";
+			uni.showToast({ title: "鍥炴敹鐮佺敓鎴愬け璐�", icon: "none" });
 		}
 	}
 
@@ -347,12 +350,6 @@
 		.qrcode-image {
 			width: 100%;
 			height: 100%;
-		}
-
-		.qrcode-code {
-			font-size: 26rpx;
-			color: #666;
-			letter-spacing: 2rpx;
 		}
 
 		.qrcode-close {
diff --git a/pages/recycle/home.vue b/pages/recycle/home.vue
index cded755..e3b8601 100644
--- a/pages/recycle/home.vue
+++ b/pages/recycle/home.vue
@@ -72,14 +72,8 @@
 					<text class="qrcode-title">鎴戠殑鍥炴敹鐮�</text>
 					<text class="qrcode-desc">鍚戝洖鏀跺憳鍑虹ず姝ょ爜瀹屾垚鍥炴敹</text>
 					<view class="qrcode-image-wrap">
-						<!--<image class="qrcode-image" :src="qrcodeUrl" mode="aspectFit" /> -->
-						<canvas
-							canvas-id="recycleQrcode"
-							id="recycleQrcode"
-							style="width: 300px; height: 300px;"
-						/>
+						<image v-if="qrcodeUrl" class="qrcode-image" :src="qrcodeUrl" mode="aspectFit" />
 					</view>
-					<text class="qrcode-code">鍥炴敹鐮侊細{{ userCode }}</text>
 					<view class="qrcode-close" @tap="showQrcode = false">
 						<cl-icon name="close" :size="36" color="#999" />
 					</view>
@@ -120,7 +114,6 @@
 	});
 
 	const showQrcode = ref(false);
-	const userCode = ref("");
 	const qrcodeUrl = ref("");
 
 	// ========== 鍒濆鍖栧姞杞� ==========
@@ -132,14 +125,18 @@
 	async function loadDashboard() {
 		try {
 			const unionid = user.info?.phone||"18918594752";
-			service.user.info.dashboard({ unionid:unionid  }).then((res) => {
-				console.log("銆愬啀鐢熻祫婧愮湅鏉挎暟鎹��", res);
-				dashboard.value = {
-					carbonPoints: res.carbonPoints ?? 0,
-					recycleCount: res.recycleCount ?? 0,
-					overPercent: res.overPercent ?? 0,
-				};
-			});
+			service.user.info
+				.dashboard({ unionid })
+				.then((res) => {
+					dashboard.value = {
+						carbonPoints: res.carbonPoints ?? 0,
+						recycleCount: res.recycleCount ?? 0,
+						overPercent: res.overPercent ?? 0,
+					};
+				})
+				.catch((err) => {
+					console.error("銆愬啀鐢熻祫婧愮湅鏉垮姞杞藉け璐ャ��", err);
+				});
 		} catch (e) {
 			console.error("銆愬啀鐢熻祫婧愮湅鏉垮姞杞藉け璐ャ��", e);
 		}
@@ -147,16 +144,17 @@
 
 	/** 鍔犺浇鐢ㄦ埛鍥炴敹鐮� */
 	async function loadMyCode() {
+		const phone = user.info?.phone;
+		if (!phone) {
+			uni.showToast({ title: "璇峰厛鎺堟潈鎵嬫満鍙�", icon: "none" });
+			showQrcode.value = false;
+			return;
+		}
 		try {
-			const phone = user.info?.phone ?? "18918594752";
-			const res = await generateRecycleQrcode(phone);
-			console.log("銆愭垜鐨勫洖鏀剁爜銆�", res);
-			userCode.value = phone;
-			qrcodeUrl.value = res;
+			qrcodeUrl.value = await generateRecycleQrcode(phone);
 		} catch (e) {
 			console.error("銆愬洖鏀剁爜鍔犺浇澶辫触銆�", e);
-			// 鍏滃簳锛氭病鏈夋帴鍙f椂缁欎釜榛樿鍊�
-			userCode.value = "RC-LOADING";
+			uni.showToast({ title: "鍥炴敹鐮佺敓鎴愬け璐�", icon: "none" });
 		}
 	}
 
@@ -354,12 +352,6 @@
 		.qrcode-image {
 			width: 100%;
 			height: 100%;
-		}
-
-		.qrcode-code {
-			font-size: 26rpx;
-			color: #666;
-			letter-spacing: 2rpx;
 		}
 
 		.qrcode-close {
diff --git a/uni_modules/cool-ui/components/cl-guide/cl-guide.vue b/uni_modules/cool-ui/components/cl-guide/cl-guide.vue
index d686433..82b5f3b 100644
--- a/uni_modules/cool-ui/components/cl-guide/cl-guide.vue
+++ b/uni_modules/cool-ui/components/cl-guide/cl-guide.vue
@@ -70,6 +70,7 @@
 	watch,
 	type PropType,
 } from "vue";
+import { getSystemInfo } from "/@/cool/utils";
 
 export default defineComponent({
 	name: "cl-guide",
@@ -88,7 +89,7 @@
 	},
 
 	setup(props, { emit }) {
-		const { windowHeight } = uni.getSystemInfoSync();
+		const { windowHeight } = getSystemInfo();
 		const { proxy }: any = getCurrentInstance();
 
 		// 搴忓彿
diff --git a/uni_modules/cool-ui/components/cl-page/cl-page.vue b/uni_modules/cool-ui/components/cl-page/cl-page.vue
index e2991d1..7f7d852 100644
--- a/uni_modules/cool-ui/components/cl-page/cl-page.vue
+++ b/uni_modules/cool-ui/components/cl-page/cl-page.vue
@@ -50,7 +50,7 @@
 <script lang="ts">
 import { computed, defineComponent, reactive, getCurrentInstance, onMounted } from "vue";
 import { useApp, useCool } from "/@/cool";
-import { parseRpx } from "/@/cool/utils";
+import { getSystemInfo, parseRpx } from "/@/cool/utils";
 import { isString } from "lodash-es";
 import { useI18n } from "vue-i18n";
 
@@ -86,7 +86,7 @@
 			screenHeight,
 			windowHeight,
 			safeAreaInsets,
-		} = uni.getSystemInfoSync();
+		} = getSystemInfo();
 
 		const { proxy }: any = getCurrentInstance();
 
diff --git a/uni_modules/cool-ui/components/cl-popup/cl-popup.vue b/uni_modules/cool-ui/components/cl-popup/cl-popup.vue
index 432a1d2..62186cd 100644
--- a/uni_modules/cool-ui/components/cl-popup/cl-popup.vue
+++ b/uni_modules/cool-ui/components/cl-popup/cl-popup.vue
@@ -46,10 +46,8 @@
 
 <script lang="ts">
 import { computed, defineComponent, ref, watch, type PropType } from "vue";
-import { parseRpx } from "/@/cool/utils";
+import { getSystemInfo, parseRpx } from "/@/cool/utils";
 import { router } from "/@/cool";
-
-const { statusBarHeight = 0 } = uni.getSystemInfoSync();
 
 let id = 1;
 
@@ -115,6 +113,7 @@
 	emits: ["update:modelValue", "open", "opened", "close", "closed"],
 
 	setup(props, { emit }) {
+		const { statusBarHeight = 0 } = getSystemInfo();
 		// 鏄惁鍙
 		const visible = ref(false);
 
diff --git a/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue b/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue
index 5865297..0dcb7aa 100644
--- a/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue
+++ b/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue
@@ -22,6 +22,7 @@
 <script lang="ts">
 import { computed, defineComponent } from "vue";
 import { useCool } from "/@/cool";
+import { getSystemInfo } from "/@/cool/utils";
 
 export default defineComponent({
 	name: "cl-status-bar",
@@ -37,7 +38,7 @@
 	},
 
 	setup(props) {
-		const { statusBarHeight } = uni.getSystemInfoSync();
+		const { statusBarHeight } = getSystemInfo();
 		const { router } = useCool();
 
 		// 鐘舵�佹爮楂樺害
diff --git a/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue b/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue
index 081f04f..d733ff5 100644
--- a/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue
+++ b/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue
@@ -11,8 +11,7 @@
 <script lang="ts">
 import { computed, defineComponent } from "vue";
 import { useCool } from "/@/cool";
-
-const { statusBarHeight } = uni.getSystemInfoSync();
+import { getSystemInfo } from "/@/cool/utils";
 
 export default defineComponent({
 	name: "cl-sticky",
@@ -35,6 +34,7 @@
 	},
 
 	setup(props) {
+		const { statusBarHeight = 0 } = getSystemInfo();
 		const { router } = useCool();
 
 		// 鍚搁《楂樺害
diff --git a/uni_modules/cool-ui/components/cl-topbar/cl-topbar.vue b/uni_modules/cool-ui/components/cl-topbar/cl-topbar.vue
index 187f872..9e5ed26 100644
--- a/uni_modules/cool-ui/components/cl-topbar/cl-topbar.vue
+++ b/uni_modules/cool-ui/components/cl-topbar/cl-topbar.vue
@@ -46,9 +46,7 @@
 <script lang="ts">
 import { computed, defineComponent, onMounted, ref } from "vue";
 import { router } from "/@/cool";
-import { isIos } from "/@/cool/utils";
-
-const { statusBarHeight } = uni.getSystemInfoSync();
+import { getSystemInfo, isIos } from "/@/cool/utils";
 
 export default defineComponent({
 	name: "cl-topbar",
@@ -92,6 +90,7 @@
 	},
 
 	setup(props, { emit }) {
+		const { statusBarHeight = 0 } = getSystemInfo();
 		// 鏄惁椤甸潰鏍堢殑绗竴涓�
 		const isFirst = ref(false);
 
diff --git a/uni_modules/mp-html/components/mp-html/node/node.vue b/uni_modules/mp-html/components/mp-html/node/node.vue
index 09252fd..a767949 100644
--- a/uni_modules/mp-html/components/mp-html/node/node.vue
+++ b/uni_modules/mp-html/components/mp-html/node/node.vue
@@ -125,7 +125,7 @@
     return {
       ctrl: {},
       // #ifdef MP-WEIXIN
-      isiOS: uni.getSystemInfoSync().system.includes('iOS')
+      isiOS: ((uni.getDeviceInfo ? uni.getDeviceInfo() : uni.getSystemInfoSync()).system || '').includes('iOS')
       // #endif
     }
   },
diff --git a/uni_modules/mp-html/components/mp-html/parser.js b/uni_modules/mp-html/components/mp-html/parser.js
index 5a93000..731b222 100644
--- a/uni_modules/mp-html/components/mp-html/parser.js
+++ b/uni_modules/mp-html/components/mp-html/parser.js
@@ -81,7 +81,9 @@
   // #ifdef MP-WEIXIN
   system
   // #endif
-} = uni.getSystemInfoSync()
+} = (uni.getWindowInfo && uni.getDeviceInfo
+  ? { ...uni.getDeviceInfo(), ...uni.getWindowInfo() }
+  : uni.getSystemInfoSync())
 const blankChar = makeMap(' ,\r,\n,\t,\f')
 let idIndex = 0
 
diff --git a/vite.config.ts b/vite.config.ts
index a2577a9..333d081 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -54,6 +54,11 @@
 				overlay: true,
 			},
 		},
+		define: {
+			__VUE_I18N_FULL_INSTALL__: true,
+			__VUE_I18N_LEGACY_API__: true,
+			__INTLIFY_PROD_DEVTOOLS__: false,
+		},
 		resolve: {
 			alias: {
 				"/@": resolve("./"),

--
Gitblit v1.9.1