Compare commits

...

3 Commits

Author SHA1 Message Date
dzq c319a349e8 feat(个人中心): 添加生成动态码功能用于绑定汇邦云
新增动态码生成功能,用户可通过点击按钮生成动态码并在企业微信中绑定汇邦云账号。包含以下修改:
- 添加动态码生成API调用及相关状态管理
- 实现动态码弹窗展示组件
- 处理生成过程中的错误提示
2025-11-06 17:14:55 +08:00
dzq a0df240aaf feat(用户): 添加动态码生成功能
- 新增 DynamicCodeResponse 类型定义
- 添加 generateDynamicCode API 方法
- 在首页登录流程中调用动态码生成接口
2025-11-06 15:23:12 +08:00
dzq 8e031231c1 feat(微信登录): 扩展微信登录返回用户信息
修改mpCodeToOpenId接口返回类型为WxUserDTO,包含完整的微信用户信息
更新相关页面调用逻辑,将openId改为wxUser
新增WxUserDTO类型定义,包含微信用户相关字段
2025-11-06 11:05:21 +08:00
5 changed files with 107 additions and 9 deletions

View File

@ -1,5 +1,5 @@
import { http } from "@/http/http"; import { http } from "@/http/http";
import type { CurrentUserResponseData } from './types'; import type { CurrentUserResponseData, WxUserDTO, DynamicCodeResponse } from './types';
/** 获取当前登录用户详情 */ /** 获取当前登录用户详情 */
export async function getCurrentUserApi() { export async function getCurrentUserApi() {
@ -7,5 +7,10 @@ export async function getCurrentUserApi() {
} }
export async function mpCodeToOpenId(code: string) { export async function mpCodeToOpenId(code: string) {
return await http.get<string>("wx/mpCodeToOpenId", { code }); return await http.get<WxUserDTO>("wx/mpCodeToOpenId", { code });
}
/** 根据openid获取动态码 */
export async function generateDynamicCode(openid: string) {
return await http.get<DynamicCodeResponse>("wx/generateDynamicCode", { openid });
} }

View File

@ -1,3 +1,37 @@
export type CurrentUserResponseData = { export type CurrentUserResponseData = {
data: { username: string, roles: string[] } data: { username: string, roles: string[] }
} }
/** 微信用户DTO */
export interface WxUserDTO {
/** 主键ID */
wxUserId?: number;
/** openid */
openid?: string;
/** 汇邦云用户ID */
ab98UserId?: number;
/** 企业用户ID */
qyUserId?: number;
/** 昵称 */
nickName?: string;
/** 手机号码 */
tel?: string;
/** 余额(分) */
wxBalance?: number;
/** 余额(元) */
wxBalanceYuan?: number;
/** 创建时间 */
createTime?: string;
/** 更新时间 */
updateTime?: string;
/** 备注 */
remark?: string;
}
/** 动态码响应数据 */
export interface DynamicCodeResponse {
/** 动态码 */
dynamicCode: string;
/** 有效时间(分钟) */
validityMinutes: string;
}

View File

@ -6,7 +6,7 @@ import { useCartStore } from '@/pinia/stores/cart'
import { getShopListApi } from '@/api/shop' import { getShopListApi } from '@/api/shop'
import type { ShopEntity } from '@/api/shop/types' import type { ShopEntity } from '@/api/shop/types'
import ProductContainer from './components/product-container.vue'; import ProductContainer from './components/product-container.vue';
import { mpCodeToOpenId } from '@/api/users' import { generateDynamicCode, mpCodeToOpenId } from '@/api/users'
import { toHttpsUrl } from '@/utils' import { toHttpsUrl } from '@/utils'
definePage({ definePage({
@ -31,8 +31,14 @@ onMounted(async () => {
uni.login({ uni.login({
provider: 'weixin', //使 provider: 'weixin', //使
success: function (loginRes) { success: function (loginRes) {
mpCodeToOpenId(loginRes.code).then((openId) => { mpCodeToOpenId(loginRes.code).then((wxUser) => {
console.log('openId:', openId) console.log('wxUser:', wxUser);
wxStore.setOpenid(wxUser.data.openid);
generateDynamicCode(wxUser.data.openid).then((dynamicCode) => {
console.log('dynamicCode:', dynamicCode);
}).catch((e) => {
console.error('generateDynamicCode error:', e)
})
}).catch((e) => { }).catch((e) => {
console.error('mpCodeToOpenId error:', e) console.error('mpCodeToOpenId error:', e)
}) })

View File

@ -73,8 +73,8 @@ const login = () => {
uni.login({ uni.login({
provider: 'weixin', //使 provider: 'weixin', //使
success: function (loginRes) { success: function (loginRes) {
mpCodeToOpenId(loginRes.code).then((openId) => { mpCodeToOpenId(loginRes.code).then((wxUser) => {
console.log('openId:', openId) console.log('openId:', wxUser)
loading.value = false loading.value = false
}).catch((e) => { }).catch((e) => {
loading.value = false loading.value = false

View File

@ -1,9 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted } from 'vue' import { computed, onMounted, ref } from 'vue'
import { useWxStore } from '@/pinia/stores/wx' import { useWxStore } from '@/pinia/stores/wx'
import { useAb98UserStore } from '@/pinia/stores/ab98-user' import { useAb98UserStore } from '@/pinia/stores/ab98-user'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { toHttpsUrl } from '@/utils' import { toHttpsUrl } from '@/utils'
import { generateDynamicCode } from '@/api/users'
import { DynamicCodeResponse } from '@/api/users/types'
import { useToast } from 'wot-design-uni'
definePage({ definePage({
style: { style: {
@ -23,6 +26,11 @@ const name = computed(() => {
const userAvatar = computed(() => face_img.value ? toHttpsUrl(face_img.value) : '/static/favicon.ico') const userAvatar = computed(() => face_img.value ? toHttpsUrl(face_img.value) : '/static/favicon.ico')
//
const dynamicCodeActionSheet = ref<boolean>(false)
const dynamicCodeData = ref<DynamicCodeResponse | null>(null)
const toast = useToast()
const ab98BalanceInYuan = computed(() => { const ab98BalanceInYuan = computed(() => {
if (ab98User.value && ab98User.value.ab98Balance !== undefined) { if (ab98User.value && ab98User.value.ab98Balance !== undefined) {
return (ab98User.value.ab98Balance / 100).toFixed(2) return (ab98User.value.ab98Balance / 100).toFixed(2)
@ -72,6 +80,27 @@ const navigateToPage = (pagePath: string, options: { type?: 'navigateTo' | 'swit
onMounted(() => { onMounted(() => {
wxStore.refreshBalance() wxStore.refreshBalance()
}) })
//
const handleGenerateDynamicCode = async () => {
if (!wxStore.openid) {
toast.show('用户信息异常,请重新登录')
return
}
try {
const res = await generateDynamicCode(wxStore.openid)
if (res && res.code == 0) {
dynamicCodeData.value = res.data
dynamicCodeActionSheet.value = true
} else {
toast.show(res?.msg || '获取动态码失败')
}
} catch (error) {
console.error('获取动态码失败:', error)
toast.show('获取动态码失败')
}
}
</script> </script>
<template> <template>
@ -135,7 +164,10 @@ onMounted(() => {
<wd-icon name="star" size="20px" color="#fff"></wd-icon> <wd-icon name="star" size="20px" color="#fff"></wd-icon>
<text>我的柜子</text> <text>我的柜子</text>
</view> </view>
<view class="button-placeholder"></view> <view class="button-item" @click="handleGenerateDynamicCode">
<wd-icon name="qrcode" size="20px" color="#fff"></wd-icon>
<text>绑定汇邦云</text>
</view>
<view class="button-placeholder"></view> <view class="button-placeholder"></view>
<!-- <view v-if="wxStore.isCabinetAdmin" class="button-item" @click="navigateToPage('/pages/cabinet/index')"> <!-- <view v-if="wxStore.isCabinetAdmin" class="button-item" @click="navigateToPage('/pages/cabinet/index')">
<wd-icon name="tools" size="20px" color="#fff"></wd-icon> <wd-icon name="tools" size="20px" color="#fff"></wd-icon>
@ -154,6 +186,27 @@ onMounted(() => {
<view class="button-placeholder"></view> <view class="button-placeholder"></view>
</view> --> </view> -->
</view> </view>
<!-- 动态码弹窗 -->
<wd-action-sheet
v-model="dynamicCodeActionSheet"
title="动态码"
cancel-text="关闭"
:close-on-click-modal="true"
@close="dynamicCodeActionSheet = false"
>
<view style="padding: 30px 30px 80px 30px; text-align: center;">
<view style="font-size: 24px; font-weight: bold; color: #409EFF; margin-bottom: 8px;">
{{ dynamicCodeData?.dynamicCode || '' }}
</view>
<view style="font-size: 14px; color: #999; margin-top: 8px;">
有效时间{{ dynamicCodeData?.validityMinutes || '0' }} 分钟
</view>
<view style="font-size: 12px; color: #666; margin-top: 16px; padding: 8px 12px; background: #f5f5f5; border-radius: 4px;">
请使用该动态码在企业微信中绑定汇邦云账号
</view>
</view>
</wd-action-sheet>
</view> </view>
</template> </template>