feat(profile): 新增个人资料设置页面及功能
添加个人资料设置页面,支持用户设置头像和昵称。主要变更包括: 1. 新增 profile 页面路由配置 2. 扩展用户类型定义,增加 profileDone 字段 3. 添加更新用户信息的 API 接口 4. 实现头像上传、压缩和保存功能 5. 在首页检查用户资料完成状态并跳转 6. 优化用户信息处理逻辑,提取公共方法
This commit is contained in:
parent
c6df25cfff
commit
a1e4a46656
|
|
@ -21,7 +21,8 @@
|
|||
"Bash(mkdir -p \"E:\\code\\智柜宝\\wx\\src\\pages\\rental\")",
|
||||
"Bash(cat /E/code/智柜宝/wx/README.md)",
|
||||
"Bash(cat /E/code/智柜宝/wx/package.json)",
|
||||
"Bash(cat /E/code/智柜宝/wx/manifest.config.ts)"
|
||||
"Bash(cat /E/code/智柜宝/wx/manifest.config.ts)",
|
||||
"Bash(tree:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -18,3 +18,8 @@ export async function getWxUserByOpenid(openid: string) {
|
|||
export async function generateDynamicCode(openid: string) {
|
||||
return await http.get<DynamicCodeResponse>("wx/generateDynamicCode", { openid });
|
||||
}
|
||||
|
||||
/** 根据openid更新用户昵称和头像 */
|
||||
export async function updateUserByOpenid(openid: string, nickName?: string, avatar?: string) {
|
||||
return await http.get<WxUserDTO>("wx/updateUserByOpenid", { openid, nickName, avatar });
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@ export interface WxUserDTO {
|
|||
nickName?: string;
|
||||
/** 头像 */
|
||||
avatar?: string;
|
||||
/** 是否完成个人信息填写 */
|
||||
profileDone?: boolean;
|
||||
/** 手机号码 */
|
||||
tel?: string;
|
||||
/** 余额(分) */
|
||||
|
|
@ -32,6 +34,7 @@ export interface WxUserDTO {
|
|||
ab98Name?: string;
|
||||
/** 汇邦云用户头像 */
|
||||
ab98FaceImg?: string;
|
||||
|
||||
/** 企业用户信息 */
|
||||
qyUser?: {
|
||||
/** 企业用户ID */
|
||||
|
|
|
|||
|
|
@ -128,6 +128,13 @@
|
|||
"navigationBarTitleText": "支付成功"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/profile/index",
|
||||
"type": "page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置头像昵称"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/QrScanner/index",
|
||||
"type": "page",
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import { ref, onMounted } from 'vue'
|
|||
import { useWxStore } from '@/pinia/stores/wx'
|
||||
import { useProductStore } from '@/pinia/stores/product'
|
||||
import { useCartStore } from '@/pinia/stores/cart'
|
||||
import { getCorpidById, getShopListApi } from '@/api/shop'
|
||||
import { getShopListApi } from '@/api/shop'
|
||||
import type { ShopEntity } from '@/api/shop/types'
|
||||
import ProductContainer from './components/product-container.vue';
|
||||
import { generateDynamicCode, getWxUserByOpenid, mpCodeToOpenId } from '@/api/users'
|
||||
import { toHttpsUrl } from '@/utils'
|
||||
import { toHttpsUrl, uniLogin } from '@/utils'
|
||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useWxParamsStore } from '@/pinia/stores/wx-params'
|
||||
|
|
@ -29,6 +29,8 @@ const showShopList = ref<boolean>(true)
|
|||
const shopList = ref<ShopEntity[]>([])
|
||||
const shopId = ref<number>(0)
|
||||
|
||||
|
||||
|
||||
// 页面加载
|
||||
onMounted(async () => {
|
||||
})
|
||||
|
|
@ -67,75 +69,75 @@ function handleCheckout() {
|
|||
|
||||
onLoad(async (query) => {
|
||||
const wxParamsStore = useWxParamsStore();
|
||||
const { wxUserDTO } = storeToRefs(wxStore);
|
||||
console.log('page index onLoad query: ', query);
|
||||
// scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
|
||||
|
||||
// 解析scene参数
|
||||
if (query && query.scene) {
|
||||
const scene = decodeURIComponent(query.scene);
|
||||
wxParamsStore.parseScene(scene);
|
||||
}
|
||||
|
||||
// 获取企业ID
|
||||
const cid = wxParamsStore.getNumberParam('cid', -1);
|
||||
let corpid = uni.getStorageSync('local_corpid');
|
||||
|
||||
// 企业ID获取逻辑:根据不同的条件获取企业ID并缓存到本地
|
||||
if (cid > 0) {
|
||||
// 如果存在有效的企业ID参数(cid > 0),则通过API获取对应的企业ID
|
||||
corpid = (await getCorpidById(cid)).data;
|
||||
// 将获取到的企业ID存储到本地缓存中
|
||||
uni.setStorageSync('local_corpid', corpid || '');
|
||||
} else if (corpid) {
|
||||
// 如果本地已存在企业ID,则直接使用,无需重新获取
|
||||
// 空语句块,表示保持现有的corpid值不变
|
||||
} else {
|
||||
// 如果既没有有效的cid参数,也没有本地缓存的corpid,则获取默认企业ID(cid=0)
|
||||
corpid = (await getCorpidById(0)).data;
|
||||
// 将默认企业ID存储到本地缓存中
|
||||
uni.setStorageSync('local_corpid', corpid || '');
|
||||
}
|
||||
const corpid = await wxStore.getCorpid(cid);
|
||||
|
||||
// 用户登录处理
|
||||
let openid = uni.getStorageSync('local_openid');
|
||||
try {
|
||||
if (!openid) {
|
||||
uni.login({
|
||||
provider: 'weixin', //使用微信登录
|
||||
success: function (loginRes) {
|
||||
mpCodeToOpenId(loginRes.code).then((wxUser) => {
|
||||
// 首次登录
|
||||
const loginRes = await uniLogin({ provider: 'weixin' });
|
||||
const wxUser = await mpCodeToOpenId(loginRes.code);
|
||||
console.log('wxUser:', wxUser);
|
||||
wxStore.wxMpCallback(wxUser.data, corpid);
|
||||
uni.setStorageSync('local_openid', wxUser.data.openid || '');
|
||||
if (wxUser.data.ab98UserId) {
|
||||
ab98UserStore.setAb98UserName(wxUser.data.ab98Name || wxUser.data.nickName || '')
|
||||
ab98UserStore.setAb98UserFaceImg(wxUser.data.ab98FaceImg || '')
|
||||
}
|
||||
}).catch((e) => {
|
||||
console.error('mpCodeToOpenId error:', e)
|
||||
})
|
||||
},
|
||||
});
|
||||
await wxStore.processUserInfo(wxUser.data, corpid);
|
||||
} else {
|
||||
// 从本地缓存中获取用户信息
|
||||
// 已有本地缓存
|
||||
const wxUser = await getWxUserByOpenid(openid);
|
||||
console.log('wxUser:', wxUser);
|
||||
wxStore.wxMpCallback(wxUser.data, corpid);
|
||||
uni.setStorageSync('local_openid', wxUser.data.openid || '');
|
||||
if (wxUser.data.ab98UserId) {
|
||||
ab98UserStore.setAb98UserName(wxUser.data.ab98Name || wxUser.data.nickName || '')
|
||||
ab98UserStore.setAb98UserFaceImg(wxUser.data.ab98FaceImg || '')
|
||||
}
|
||||
}
|
||||
|
||||
if (showShopList.value) {
|
||||
try {
|
||||
// 等待 handleWxCallback 完成
|
||||
await wxStore.waitForHandleWxCallbackComplete();
|
||||
const res = await getShopListApi(wxStore.corpid || '');
|
||||
console.log('获取店铺列表:', res)
|
||||
if (res?.code === 0 && res?.data?.length > 0) {
|
||||
shopList.value = res.data;
|
||||
|
||||
// shopList.value = [...shopList.value, ...res.data, ...res.data, ...res.data];
|
||||
await wxStore.processUserInfo(wxUser.data, corpid);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取店铺列表失败:', error)
|
||||
console.error('用户登录处理失败:', error);
|
||||
}
|
||||
|
||||
// 检查是否需要跳转到个人资料设置页面
|
||||
// 条件:未绑定 ab98UserId 且 profileDone 不为真
|
||||
if (wxUserDTO.value && !wxUserDTO.value.ab98UserId && wxUserDTO.value.profileDone !== true) {
|
||||
console.log('用户需要完善资料,跳转到个人资料设置页面');
|
||||
uni.navigateTo({
|
||||
url: '/pages/profile/index'
|
||||
});
|
||||
return; // 跳转后不执行后续逻辑
|
||||
}
|
||||
|
||||
// 获取店铺列表
|
||||
if (showShopList.value) {
|
||||
try {
|
||||
await wxStore.waitForHandleWxCallbackComplete();
|
||||
const res = await getShopListApi(wxStore.corpid || '');
|
||||
console.log('获取店铺列表:', res);
|
||||
if (res?.code === 0 && res?.data?.length > 0) {
|
||||
shopList.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取店铺列表失败:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onShow(async () => {
|
||||
// 获取店铺列表
|
||||
if (showShopList.value) {
|
||||
try {
|
||||
await wxStore.waitForHandleWxCallbackComplete();
|
||||
const res = await getShopListApi(wxStore.corpid || '');
|
||||
console.log('获取店铺列表:', res);
|
||||
if (res?.code === 0 && res?.data?.length > 0) {
|
||||
shopList.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取店铺列表失败:', error);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
|||
import { useWxParamsStore } from '@/pinia/stores/wx-params'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { toHttpsUrl } from '@/utils'
|
||||
import { generateDynamicCode } from '@/api/users'
|
||||
import { generateDynamicCode, getWxUserByOpenid } from '@/api/users'
|
||||
import { DynamicCodeResponse } from '@/api/users/types'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
|
||||
|
|
@ -30,7 +30,8 @@ const name = computed(() => {
|
|||
return userName.value || qyName.value || '未知用户'
|
||||
})
|
||||
|
||||
const userAvatar = computed(() => face_img.value ? toHttpsUrl(face_img.value) : '/static/favicon.ico')
|
||||
const userAvatar = computed(() => face_img.value ? toHttpsUrl(face_img.value) :
|
||||
wxUserDTO.value?.avatar ? toHttpsUrl(wxUserDTO.value.avatar) : '/static/favicon.ico')
|
||||
|
||||
// 动态码相关
|
||||
const dynamicCodeActionSheet = ref<boolean>(false)
|
||||
|
|
@ -80,8 +81,10 @@ onMounted(() => {
|
|||
wxStore.refreshBalance()
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
wxStore.refreshBalance()
|
||||
onShow(async () => {
|
||||
const wxUser = await getWxUserByOpenid(wxStore.openid);
|
||||
console.log('wxUser:', wxUser);
|
||||
await wxStore.processUserInfo(wxUser.data, wxStore.corpid);
|
||||
});
|
||||
|
||||
// 生成动态码
|
||||
|
|
@ -114,7 +117,7 @@ const handleGenerateDynamicCode = async () => {
|
|||
<view class="avatar-wrapper">
|
||||
<image
|
||||
class="avatar"
|
||||
:src="wxUserDTO?.ab98FaceImg"
|
||||
:src="wxUserDTO?.ab98FaceImg || wxUserDTO?.avatar || '/static/favicon.ico'"
|
||||
mode="aspectFill"
|
||||
@click="handleShowWxParams"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,429 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useWxStore } from '@/pinia/stores/wx'
|
||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { getWxUserByOpenid, updateUserByOpenid } from '@/api/users'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import { getEnvBaseUploadUrl, toHttpsUrl } from '@/utils'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '设置头像昵称',
|
||||
},
|
||||
})
|
||||
|
||||
const wxStore = useWxStore()
|
||||
const ab98UserStore = useAb98UserStore()
|
||||
const toast = useToast()
|
||||
|
||||
const { wxUserDTO, openid } = storeToRefs(wxStore)
|
||||
const { name: userName, face_img } = storeToRefs(ab98UserStore)
|
||||
|
||||
// 头像相关
|
||||
const avatarUrl = ref('')
|
||||
const tempAvatarPath = ref('') // 临时头像路径,用于预览
|
||||
|
||||
// 昵称相关
|
||||
const nickName = ref('')
|
||||
|
||||
// 初始化数据
|
||||
onMounted(() => {
|
||||
// 优先使用微信用户信息,其次使用企业用户信息
|
||||
if (wxUserDTO.value) {
|
||||
avatarUrl.value = wxUserDTO.value.avatar || ''
|
||||
nickName.value = wxUserDTO.value.nickName || ''
|
||||
}
|
||||
|
||||
// 如果没有微信头像,使用企业用户头像
|
||||
if (!avatarUrl.value && face_img.value) {
|
||||
avatarUrl.value = toHttpsUrl(face_img.value)
|
||||
}
|
||||
|
||||
// 如果没有微信昵称,使用企业用户名
|
||||
if (!nickName.value && userName.value) {
|
||||
nickName.value = userName.value
|
||||
}
|
||||
|
||||
// 默认头像
|
||||
if (!avatarUrl.value) {
|
||||
avatarUrl.value = '/static/favicon.ico'
|
||||
}
|
||||
})
|
||||
|
||||
// 图片上传相关
|
||||
const uploadUrl = `${getEnvBaseUploadUrl()}/file/upload`
|
||||
const uploading = ref(false)
|
||||
|
||||
// 图片压缩处理 - 参考审批提交页面的实现
|
||||
const compressImage = (src: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果是网络图片,需要先下载到本地再压缩
|
||||
if (src && (src.startsWith('http://') || src.startsWith('https://'))) {
|
||||
// 先下载图片
|
||||
uni.downloadFile({
|
||||
url: src,
|
||||
success: (downloadResult) => {
|
||||
console.log('网络图片下载完成:', downloadResult.tempFilePath)
|
||||
// 下载成功后压缩图片
|
||||
compressLocalImage(downloadResult.tempFilePath)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('网络图片下载失败:', err)
|
||||
reject(new Error('网络图片下载失败'))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 本地图片直接压缩
|
||||
compressLocalImage(src)
|
||||
}
|
||||
|
||||
// 压缩本地图片的函数
|
||||
function compressLocalImage(localSrc: string) {
|
||||
uni.compressImage({
|
||||
src: localSrc,
|
||||
quality: 0.8,
|
||||
maxWidth: 980,
|
||||
maxHeight: 980,
|
||||
success: (res) => {
|
||||
console.log('头像图片压缩成功:', res)
|
||||
resolve(res.tempFilePath)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('头像图片压缩失败,使用原图:', err)
|
||||
// 压缩失败时使用原图
|
||||
resolve(localSrc)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 上传头像图片
|
||||
const uploadAvatar = async (filePath: string): Promise<string> => {
|
||||
uploading.value = true
|
||||
try {
|
||||
// 先压缩图片
|
||||
const compressedPath = await compressImage(filePath)
|
||||
console.log('头像压缩完成:', compressedPath)
|
||||
|
||||
// 上传到服务器
|
||||
const uploadResult = await new Promise<any>((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: uploadUrl,
|
||||
filePath: compressedPath,
|
||||
name: 'file',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
try {
|
||||
const response = JSON.parse(res.data)
|
||||
resolve(response)
|
||||
} catch (e) {
|
||||
reject(new Error('上传响应解析失败'))
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`上传失败,状态码: ${res.statusCode}`))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 解析上传响应
|
||||
if (uploadResult.code === 0 && uploadResult.data && uploadResult.data.url) {
|
||||
const avatarUrl = toHttpsUrl(uploadResult.data.url)
|
||||
console.log('头像上传成功:', avatarUrl)
|
||||
return avatarUrl
|
||||
} else {
|
||||
throw new Error(uploadResult.msg || '上传失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('头像上传失败:', error)
|
||||
throw error
|
||||
} finally {
|
||||
uploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 选择头像并自动压缩上传
|
||||
const onChooseAvatar = async (e: any) => {
|
||||
const { avatarUrl: tempUrl } = e.detail
|
||||
tempAvatarPath.value = tempUrl
|
||||
avatarUrl.value = tempUrl
|
||||
|
||||
// 显示上传提示
|
||||
uni.showLoading({
|
||||
title: '正在压缩上传头像...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
try {
|
||||
// 上传头像到服务器
|
||||
const uploadedUrl = await uploadAvatar(tempUrl)
|
||||
// 使用上传成功后的URL更新显示
|
||||
avatarUrl.value = uploadedUrl
|
||||
tempAvatarPath.value = uploadedUrl
|
||||
|
||||
uni.showToast({
|
||||
title: '头像上传成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('头像上传失败:', error)
|
||||
uni.showToast({
|
||||
title: '头像上传失败,请重试',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
// 上传失败时,保持本地图片预览,但提交时会使用本地路径
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
// 提交更新
|
||||
const loading = ref(false)
|
||||
const handleSubmit = async () => {
|
||||
if (!openid.value) {
|
||||
toast.show('用户信息获取失败,请重新登录')
|
||||
return
|
||||
}
|
||||
|
||||
if (!nickName.value.trim()) {
|
||||
toast.show('请输入昵称')
|
||||
return
|
||||
}
|
||||
|
||||
// 获取要使用的头像路径
|
||||
const finalAvatarPath = tempAvatarPath.value || avatarUrl.value
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
// 使用网络URL或静态资源URL更新用户信息
|
||||
const result = await updateUserByOpenid(
|
||||
openid.value,
|
||||
nickName.value.trim(),
|
||||
finalAvatarPath
|
||||
)
|
||||
|
||||
if (result?.code === 0) {
|
||||
// 更新store中的用户信息
|
||||
const wxUser = await getWxUserByOpenid(openid.value);
|
||||
console.log('wxUser:', wxUser);
|
||||
await wxStore.processUserInfo(wxUser.data, wxStore.corpid);
|
||||
|
||||
toast.show('更新成功')
|
||||
// 返回上一页
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
toast.show(result?.msg || '更新失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新用户信息失败:', error)
|
||||
toast.show('更新失败,请稍后重试')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="profile-setting-page">
|
||||
<!-- 头像设置区域 -->
|
||||
<view class="setting-card">
|
||||
<view class="section-title">设置头像</view>
|
||||
<view class="avatar-section">
|
||||
<view class="current-avatar">
|
||||
<image class="avatar" :src="avatarUrl" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="avatar-hint">当前头像</view>
|
||||
</view>
|
||||
|
||||
<!-- 微信小程序选择头像按钮 -->
|
||||
<view class="choose-avatar-btn">
|
||||
<button
|
||||
class="avatar-button"
|
||||
open-type="chooseAvatar"
|
||||
@chooseavatar="onChooseAvatar"
|
||||
>
|
||||
选择头像
|
||||
</button>
|
||||
<view class="avatar-tip">点击按钮选择微信头像</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 昵称设置区域 -->
|
||||
<view class="setting-card">
|
||||
<view class="section-title">设置昵称</view>
|
||||
<view class="nickname-section">
|
||||
<input
|
||||
class="nickname-input"
|
||||
type="nickname"
|
||||
v-model="nickName"
|
||||
placeholder="请输入昵称"
|
||||
:maxlength="20"
|
||||
/>
|
||||
<view class="nickname-tip">输入时键盘上方会展示微信昵称</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-section">
|
||||
<wd-button
|
||||
type="primary"
|
||||
block
|
||||
:loading="loading"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
{{ loading ? '更新中...' : '保存设置' }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.profile-setting-page {
|
||||
background: #f7f8fa;
|
||||
min-height: 100vh;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.setting-card {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 20px 16px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 20px;
|
||||
padding-left: 8px;
|
||||
position: relative;
|
||||
letter-spacing: 0.5px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 3px;
|
||||
height: 16px;
|
||||
background: linear-gradient(135deg, #409EFF 0%, #66B1FF 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.current-avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 4px solid rgba(64, 158, 255, 0.2);
|
||||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
|
||||
margin-bottom: 12px;
|
||||
|
||||
.avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-hint {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.choose-avatar-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.avatar-button {
|
||||
width: 200px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
background: linear-gradient(135deg, #409EFF 0%, #66B1FF 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-tip {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.nickname-section {
|
||||
.nickname-input {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
background: #f7f8fa;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 24px;
|
||||
font-size: 16px;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:focus {
|
||||
border-color: #409EFF;
|
||||
background: white;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.nickname-tip {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
padding-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-section {
|
||||
margin-top: 24px;
|
||||
|
||||
::v-deep .wd-button {
|
||||
height: 48px;
|
||||
border-radius: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(135deg, #409EFF 0%, #66B1FF 100%);
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { pinia } from "@/pinia"
|
||||
import { getOpenIdApi, getBalanceApi, qyLogin, getBalanceByQyUserid, fakeQyLoginApi, getUserBalance } from "@/api/shop"
|
||||
import { getOpenIdApi, getBalanceApi, qyLogin, getBalanceByQyUserid, fakeQyLoginApi, getUserBalance, getCorpidById } from "@/api/shop"
|
||||
import { ab98UserDTO, GetBalanceResponse } from "@/api/shop/types"
|
||||
import { useAb98UserStore } from "./ab98-user"
|
||||
import { defineStore } from "pinia"
|
||||
|
|
@ -199,10 +199,39 @@ export const useWxStore = defineStore("wx", () => {
|
|||
refreshBalance();
|
||||
}
|
||||
|
||||
// 处理用户信息的通用函数
|
||||
const processUserInfo = async (userData: any, corpid_: string) => {
|
||||
wxMpCallback(userData, corpid_)
|
||||
uni.setStorageSync('local_openid', userData.openid || '')
|
||||
if (userData.ab98UserId) {
|
||||
const ab98UserStore = useAb98UserStore();
|
||||
ab98UserStore.setAb98UserName(userData.ab98Name || userData.nickName || '')
|
||||
ab98UserStore.setAb98UserFaceImg(userData.ab98FaceImg || '')
|
||||
}
|
||||
}
|
||||
|
||||
// 获取企业ID
|
||||
const getCorpid = async (cidParam: number): Promise<string> => {
|
||||
let corpid = uni.getStorageSync('local_corpid')
|
||||
const cid = cidParam
|
||||
|
||||
if (cid > 0) {
|
||||
corpid = (await getCorpidById(cid)).data
|
||||
} else if (!corpid) {
|
||||
corpid = (await getCorpidById(0)).data
|
||||
}
|
||||
// 如果 corpid 有值,缓存它
|
||||
if (corpid) {
|
||||
uni.setStorageSync('local_corpid', corpid)
|
||||
}
|
||||
return corpid || ''
|
||||
}
|
||||
|
||||
return { code, state, openid, corpid, userid, balance, useBalance,
|
||||
balanceLimit, isCabinetAdmin, corpidLogin, name, ab98User, qyUserId, isFakeQyLogin,
|
||||
isHandleWxCallbackComplete, wxUserDTO, ab98UserId, setOpenid, setBalance, setIsCabinetAdmin,
|
||||
refreshBalance, setAb98User, waitForHandleWxCallbackComplete, wxMpCallback, setAb98UserId }
|
||||
refreshBalance, setAb98User, waitForHandleWxCallbackComplete, wxMpCallback, setAb98UserId,
|
||||
processUserInfo, getCorpid }
|
||||
})
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -194,3 +194,22 @@ export const isDoubleTokenMode = import.meta.env.VITE_AUTH_MODE === 'double'
|
|||
* 通常为 /pages/index/index
|
||||
*/
|
||||
export const HOME_PAGE = `/${pages.find(page => page.type === 'home')?.path || pages[0].path}`
|
||||
|
||||
/**
|
||||
* uni.login 的 Promise 封装,使其能够使用 await 进行等待
|
||||
* @param options - uni.login 的配置选项
|
||||
* @returns Promise<UniApp.LoginRes>
|
||||
*/
|
||||
export function uniLogin(options?: UniApp.LoginOptions): Promise<UniApp.LoginRes> {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.login({
|
||||
...options,
|
||||
success: (res) => {
|
||||
resolve(res)
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue