添加 useWx 方法,支持微信小程序登录等

This commit is contained in:
icssoa
2025-08-26 18:46:57 +08:00
parent 75c90c7964
commit 6c691c7653
5 changed files with 292 additions and 25 deletions

View File

@@ -8,6 +8,11 @@ export const isDev = process.env.NODE_ENV == "development";
// 忽略 token 校验的接口路径
export const ignoreTokens: string[] = [];
// 微信配置
type WxConfig = {
debug: boolean;
};
// 配置类型定义
type Config = {
name: string; // 应用名称
@@ -19,6 +24,7 @@ type Config = {
showDarkButton: boolean; // 是否显示暗色模式切换按钮
isCustomTabBar: boolean; // 是否自定义 tabBar
backTop: boolean; // 是否显示回到顶部按钮
wx: WxConfig; // 微信配置
};
// 根据环境导出最终配置
@@ -30,6 +36,9 @@ export const config = {
showDarkButton: isMp() ? false : true,
isCustomTabBar: true,
backTop: true,
wx: {
debug: false
},
...(isDev ? dev() : prod())
} as Config;

View File

@@ -1,5 +1,6 @@
export * from "./refs";
export * from "./pager";
export * from "./long-press";
export * from "./cache";
export * from "./long-press";
export * from "./pager";
export * from "./parent";
export * from "./refs";
export * from "./wx";

239
cool/hooks/wx.ts Normal file
View File

@@ -0,0 +1,239 @@
import { ref } from "vue";
import { assign, getUrlParam, storage } from "../utils";
import { service } from "../service";
import { t } from "@/locale";
import { config } from "@/config";
// #ifdef H5
import wx from "weixin-js-sdk";
// #endif
// 微信配置类型
type WxConfig = {
appId: string;
};
// 微信相关功能封装类
export class Wx {
// 微信登录code
code = ref("");
/**
* 获取微信登录code
*/
async getCode(): Promise<string> {
return new Promise((resolve) => {
// #ifdef MP-WEIXIN
uni.login({
provider: "weixin",
success: (res) => {
this.code.value = res.code;
resolve(res.code);
}
});
// #endif
// #ifndef MP-WEIXIN
resolve("");
// #endif
});
}
// #ifdef H5
// 公众号配置
mpConfig: WxConfig = {
appId: ""
};
/**
* 判断当前是否为微信浏览器
*/
isWxBrowser() {
const ua: string = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) != null) {
return true;
} else {
return false;
}
}
/**
* 获取公众号配置信息并初始化微信JS-SDK
*/
getMpConfig() {
if (this.isWxBrowser()) {
service.user.comm
.wxMpConfig({
url: `${location.origin}${location.pathname}`
})
.then((res) => {
wx.config({
debug: config.wx.debug,
jsApiList: ["chooseWXPay"],
...res
});
// 合并配置到mpConfig
assign(this.mpConfig, res);
});
}
}
/**
* 跳转到微信授权页面
*/
mpAuth() {
const { appId } = this.mpConfig;
const redirect_uri = encodeURIComponent(
`${location.origin}${location.pathname}#/pages/user/login`
);
const response_type = "code";
const scope = "snsapi_userinfo";
const state = "STATE";
const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=${response_type}&scope=${scope}&state=${state}#wechat_redirect`;
location.href = url;
}
/**
* 公众号登录获取code
*/
mpLogin() {
return new Promise((resolve) => {
const code = getUrlParam("code");
const mpCode = storage.get("mpCode");
// 去除url中的code参数避免重复
const url = window.location.href.replace(/(\?[^#]*)#/, "#");
window.history.replaceState({}, "", url);
if (code != mpCode) {
storage.set("mpCode", code, 1000 * 60 * 5);
resolve(code);
} else {
resolve(null);
}
});
}
/**
* 公众号微信支付
* @param params 支付参数
*/
mpPay(params: wx.IchooseWXPay & { timeStamp: number }): Promise<void> {
return new Promise((resolve, reject) => {
if (!this.isWxBrowser()) {
return reject({ message: t("请在微信浏览器中打开") });
}
wx.chooseWXPay({
...params,
timestamp: params.timeStamp,
success() {
resolve();
},
complete(e: { errMsg: string }) {
switch (e.errMsg) {
case "chooseWXPay:cancel":
reject({ message: t("已取消支付") });
break;
default:
reject({ message: t("支付失败") });
}
}
});
});
}
// #endif
// #ifdef MP
/**
* 小程序登录获取用户信息和code
*/
miniLogin(): Promise<{
code: string;
iv: string;
encryptedData: string;
signature: string;
rawData: string;
}> {
return new Promise((resolve, reject) => {
// 兼容 MacMac 端需用 getUserInfo
const k = uni.getDeviceInfo().platform === "mac" ? "getUserInfo" : "getUserProfile";
uni[k]({
lang: "zh_CN",
desc: t("授权信息仅用于用户登录"),
success: ({ iv, encryptedData, signature, rawData }) => {
const next = () => {
resolve({
iv,
encryptedData,
signature,
rawData,
code: this.code.value
});
};
// 检查登录状态是否过期
uni.checkSession({
success: () => {
next();
},
fail: () => {
this.getCode().then(() => {
next();
});
}
});
},
fail: (err) => {
console.error(`[useWx.miniLogin] error`, err);
this.getCode();
reject(t("登录授权失败"));
}
});
});
}
/**
* 小程序微信支付
* @param params 支付参数
*/
miniPay(params: any): Promise<void> {
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: "wxpay",
...params,
success() {
resolve();
},
fail() {
reject(t("已取消支付"));
}
});
});
}
// #endif
}
/**
* useWx 钩子函数,后续可扩展
*/
export const useWx = (): Wx => {
const wx = new Wx();
onReady(() => {
wx.getCode();
// #ifdef H5
wx.getMpConfig();
// #endif
});
return wx;
};

View File

@@ -74,7 +74,7 @@
</template>
<script setup lang="ts">
import { service, upload, useStore, type Response } from "@/cool";
import { parse, router, service, upload, useStore, useWx, type Response, type Token } from "@/cool";
import { t } from "@/locale";
import { useUi } from "@/uni_modules/cool-ui";
import { reactive, ref } from "vue";
@@ -83,6 +83,7 @@ const emit = defineEmits(["success"]);
const { user } = useStore();
const ui = useUi();
const wx = useWx();
// 是否显示编辑
const editVisible = ref(false);
@@ -142,6 +143,9 @@ async function editSave() {
// 关闭弹窗
editClose();
// 跳转首页
router.nextLogin();
})
.catch((err) => {
// 上传失败,提示错误信息
@@ -168,16 +172,38 @@ function onEditClose() {
// 微信小程序登录
async function miniLogin() {
// #ifdef MP
ui.showLoading(t("登录中"));
await wx.miniLogin().then(async (data) => {
await service.user.login
.mini({})
.then((res) => {
emit("success", res);
.mini(data)
.then(async (res) => {
// 设置token
user.setToken(parse<Token>(res)!);
// 获取用户信息
await user.get();
// 是否首次注册,根据业务情况调整判断逻辑
if (user.info.nickName == "微信用户") {
// 打开编辑弹窗
editOpen();
} else {
// 跳转首页
router.nextLogin();
}
})
.catch((err) => {
ui.showToast({
message: (err as Response).message!
});
});
});
ui.hideLoading();
// #endif
}
// 微信APP登录
@@ -185,21 +211,13 @@ function appLogin() {}
// 微信登录
async function login() {
ui.showToast({
message: t("开发中,敬请期待")
});
return;
// #ifdef MP-WEIXIN
// #ifdef MP
miniLogin();
// #endif
// #ifdef APP
appLogin();
// #endif
emit("success");
}
defineExpose({

View File

@@ -21,7 +21,7 @@
<login-phone :form="form" @success="toLogin"></login-phone>
<!-- 微信登录 -->
<login-wx :ref="refs.set('loginWx')" @success="toLogin"></login-wx>
<login-wx :ref="refs.set('loginWx')"></login-wx>
<!-- 协议 -->
<view class="mt-6 flex flex-row flex-wrap items-center justify-center">
@@ -94,9 +94,9 @@ const form = reactive<LoginForm>({
const agree = ref(false);
// 登录成功
function toLogin(res: any) {
async function toLogin(res: any) {
user.setToken(parse<Token>(res)!);
router.home();
router.nextLogin();
}
// 跳转文档