370 lines
9.4 KiB
Vue
370 lines
9.4 KiB
Vue
<template>
|
||
<view class="content">
|
||
<!-- <view class="top-heder">-->
|
||
<!-- <view class="t-left" @click="handleBack">-->
|
||
<!-- <uni-icons type="left" size="18"></uni-icons>-->
|
||
<!-- </view>-->
|
||
<!-- <view class="c-title">个人信息</view>-->
|
||
<!-- <view style="width: 5%; height: 10px;"></view>-->
|
||
<!-- </view>-->
|
||
|
||
<headersVue titles="个人信息" style="position: static !important;">
|
||
<u-icon name="arrow-left" color="#fff" size="18"></u-icon>
|
||
</headersVue>
|
||
|
||
<view class="body">
|
||
<view class="formItem">
|
||
<image class="formIcon" mode="aspectFit" src="@/static/icons/userInfo_1.png"></image>
|
||
<text class="formLabel">头像</text>
|
||
<view class="formValue">
|
||
<image style="width: 64rpx;height: 64rpx;border-radius: 50%;"
|
||
v-if="customInfo && customInfo.avatar === null" :src="defaultAvatar" mode="scaleToFill"
|
||
class="avatar"></image>
|
||
<image v-else :src="customInfo.avatar" class="avatar" mode="scaleToFill"
|
||
style="width: 64rpx;height: 64rpx;border-radius: 50%;"></image>
|
||
</view>
|
||
</view>
|
||
<view class="formItem">
|
||
<image class="formIcon" mode="aspectFit" src="@/static/icons/userInfo_2.png"></image>
|
||
<text class="formLabel">账号昵称</text>
|
||
<text class="formValue">{{ customInfo.nickname }}</text>
|
||
<!-- <u-icon color="#999" name="arrow-right" size="12"></u-icon>-->
|
||
</view>
|
||
<view class="formItem">
|
||
<image class="formIcon" mode="aspectFit" src="@/static/icons/userInfo_3.png"></image>
|
||
<text class="formLabel">绑定电话</text>
|
||
<text class="formValue">{{ customInfo.mobile }}</text>
|
||
<!-- <u-icon color="#999" name="arrow-right" size="12"></u-icon>-->
|
||
</view>
|
||
<view class="formItem">
|
||
<image class="formIcon" mode="aspectFit" src="../../static/icons/userInfo_3.png"></image>
|
||
<text class="formLabel">我的邀请码</text>
|
||
<text class="formValue"></text>
|
||
</view>
|
||
<view style="padding-bottom: 60rpx;" class="formItem">
|
||
<canvas id="qrcode" canvas-id="qrcode" style="width: 200px;height: 200px;margin: auto"
|
||
@longpress="saveQRCode"></canvas>
|
||
</view>
|
||
<text
|
||
style="display: block; font-weight: bold; text-align: center; color: #000000; font-size: 30rpx; border-bottom: 1px solid #ddd;">
|
||
长按邀请码可保存到相册
|
||
</text>
|
||
<canvas canvas-id="saveCanvas"
|
||
style="position: fixed; left: -9999px; width: 240px; height: 240px;"></canvas>
|
||
|
||
<view class="btns">
|
||
<view class="btn" @click="logout">
|
||
退出登录
|
||
</view>
|
||
<view class="btn" @click="changePassword">
|
||
修改密码
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<uni-popup ref="alertDialog" type="dialog">
|
||
<uni-popup-dialog :type="msgType" cancelText="关闭" confirmText="同意" title="通知" content="您确认要退出登录吗"
|
||
@confirm="dialogConfirm" @close="dialogClose"></uni-popup-dialog>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
getStorageWithExpiry,
|
||
setStorageWithExpiry
|
||
} from "../../utils/auth";
|
||
import request from '../../utils/request';
|
||
import config from '@/config'
|
||
const UQRCode = require('uqrcodejs');
|
||
import headersVue from "@/components/header/headers.vue";
|
||
export default {
|
||
name: "UserInfo",
|
||
components: {
|
||
headersVue
|
||
},
|
||
data() {
|
||
return {
|
||
customInfo: {},
|
||
defaultAvatar: require('@/static/icons/avatar.png'),
|
||
msgType: 'success',
|
||
shareUrl: config.shareUrl,
|
||
}
|
||
},
|
||
mounted() {
|
||
this.getCustomInfo()
|
||
},
|
||
methods: {
|
||
changePassword() {
|
||
uni.navigateTo({
|
||
url: '/pages/Login/modify'
|
||
})
|
||
},
|
||
dialogConfirm() {
|
||
uni.clearStorageSync();
|
||
uni.reLaunch({
|
||
url: '/pages/Login/login'
|
||
})
|
||
|
||
},
|
||
dialogClose() {},
|
||
logout() {
|
||
this.$refs.alertDialog.open()
|
||
},
|
||
getCustomInfo() {
|
||
let roleNames = getStorageWithExpiry("roleNames")
|
||
if (!roleNames) {
|
||
request({
|
||
url: '/inspection/util/getRoleName',
|
||
method: 'get'
|
||
}).then(res => {
|
||
roleNames = res.data
|
||
setStorageWithExpiry("roleNames", roleNames)
|
||
})
|
||
}
|
||
const data = getStorageWithExpiry("userInfo")
|
||
if (!data || !data.uniqueCode) {
|
||
request({
|
||
url: '/inspectionStaff/get',
|
||
method: 'get',
|
||
params: {
|
||
id: uni.getStorageSync('userId')
|
||
}
|
||
}).then(res => {
|
||
this.customInfo = res.data
|
||
if (this.customInfo) {
|
||
setStorageWithExpiry("userInfo", this.customInfo)
|
||
this.generateUniCode(this.customInfo.uniqueCode)
|
||
if (this.customInfo.avatar) {
|
||
this.customInfo.avatar = config.baseImageUrl + this.customInfo.avatar
|
||
}
|
||
this.customInfo.roleNames = roleNames
|
||
}
|
||
|
||
})
|
||
} else {
|
||
this.customInfo = data
|
||
this.generateUniCode(this.customInfo.uniqueCode)
|
||
}
|
||
},
|
||
handleBack() {
|
||
uni.navigateBack()
|
||
},
|
||
generateUniCode(code) {
|
||
this.$nextTick(() => {
|
||
// 获取uQRCode实例
|
||
const qr = new UQRCode();
|
||
// 设置二维码内容
|
||
qr.data = this.shareUrl + code;
|
||
// 设置二维码大小,必须与canvas设置的宽高一致
|
||
qr.size = 200;
|
||
// 调用制作二维码方法
|
||
qr.make();
|
||
// 获取canvas上下文
|
||
const canvasContext = uni.createCanvasContext('qrcode', this); // 如果是组件,this必须传入
|
||
// 设置uQRCode实例的canvas上下文
|
||
qr.canvasContext = canvasContext;
|
||
// 调用绘制方法将二维码图案绘制到canvas上
|
||
qr.drawCanvas();
|
||
})
|
||
},
|
||
// 弹窗提示
|
||
saveQRCode() {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要保存邀请码到相册吗?',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
this.doSaveQRCode();
|
||
}
|
||
}
|
||
});
|
||
},
|
||
// 保存邀请码
|
||
async doSaveQRCode() {
|
||
uni.showLoading({
|
||
title: '保存中...',
|
||
mask: true
|
||
});
|
||
|
||
try {
|
||
// 获取原始二维码图片路径
|
||
const tempPath = await this.getCanvasTempPath('qrcode');
|
||
|
||
// 创建一个带留白的新canvas
|
||
const paddedPath = await this.createPaddedImage(tempPath);
|
||
|
||
// 保存带留白的图片
|
||
await this.saveToAlbum(paddedPath);
|
||
|
||
uni.showToast({
|
||
title: '保存成功',
|
||
icon: 'success'
|
||
});
|
||
} catch (err) {
|
||
console.error('保存失败:', err);
|
||
uni.showToast({
|
||
title: '保存失败: ' + (err.errMsg || '未知错误'),
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
} finally {
|
||
uni.hideLoading();
|
||
}
|
||
},
|
||
getCanvasTempPath(canvasId) {
|
||
return new Promise((resolve, reject) => {
|
||
uni.canvasToTempFilePath({
|
||
canvasId: canvasId,
|
||
success: resolve,
|
||
fail: reject
|
||
}, this);
|
||
});
|
||
},
|
||
createPaddedImage(tempPath) {
|
||
return new Promise((resolve, reject) => {
|
||
const padding = 20; // 留白大小(单位:px)
|
||
const qrSize = 200; // 二维码原始大小
|
||
const canvasSize = qrSize + padding * 2; // 带留白的总大小
|
||
const nameHeight = 30; // 姓名区域高度
|
||
const totalHeight = canvasSize + nameHeight; // 总高度(二维码 + 姓名)
|
||
|
||
const ctx = uni.createCanvasContext('saveCanvas', this);
|
||
|
||
// 1. 绘制白色背景(扩展到包含姓名区域)
|
||
ctx.setFillStyle('#ffffff');
|
||
ctx.fillRect(0, 0, canvasSize, totalHeight);
|
||
|
||
// 2. 绘制姓名(居中显示)
|
||
ctx.setFontSize(16); // 字体大小
|
||
ctx.setFillStyle('#000000'); // 字体颜色
|
||
ctx.setTextAlign('center'); // 水平居中
|
||
console.log('当前信息', this.customInfo);
|
||
ctx.fillText(this.customInfo.nickname || '未设置姓名', canvasSize / 2, nameHeight - 5);
|
||
|
||
// 3. 绘制二维码(在姓名下方)
|
||
ctx.drawImage(tempPath.tempFilePath, padding, nameHeight, qrSize, qrSize);
|
||
|
||
ctx.draw(false, () => {
|
||
setTimeout(() => {
|
||
this.getCanvasTempPath('saveCanvas')
|
||
.then(resolve)
|
||
.catch(reject);
|
||
}, 300);
|
||
});
|
||
});
|
||
},
|
||
saveToAlbum(filePath) {
|
||
return new Promise((resolve, reject) => {
|
||
uni.saveImageToPhotosAlbum({
|
||
filePath: filePath.tempFilePath,
|
||
success: resolve,
|
||
fail: (err) => {
|
||
// 处理权限问题
|
||
if (err.errMsg.includes('auth')) {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '需要相册权限才能保存图片',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
uni.openSetting();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
reject(err);
|
||
}
|
||
});
|
||
});
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.top-heder {
|
||
width: 100%;
|
||
height: 88px;
|
||
background: white;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
box-sizing: border-box;
|
||
padding: 5px 15px;
|
||
padding-top: 45px;
|
||
}
|
||
|
||
.t-left {
|
||
width: 10%;
|
||
}
|
||
|
||
.c-title {
|
||
font-weight: bold;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.body {
|
||
border-top: 1px solid #ddd;
|
||
padding: 20rpx 32rpx;
|
||
}
|
||
|
||
.formItem {
|
||
box-sizing: border-box;
|
||
padding: 40rpx 0;
|
||
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
column-gap: 20rpx;
|
||
}
|
||
|
||
.formIcon {
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
}
|
||
|
||
.formLabel {
|
||
font-size: 32rpx;
|
||
color: #333333;
|
||
}
|
||
|
||
.formValue {
|
||
flex: 1;
|
||
width: 0;
|
||
text-align: right;
|
||
font-size: 32rpx;
|
||
color: #999999;
|
||
}
|
||
|
||
.formBtn {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.avatar {
|
||
width: 108rpx;
|
||
height: 108rpx;
|
||
}
|
||
|
||
.btn {
|
||
width: 520rpx;
|
||
height: 80rpx;
|
||
border-radius: 40rpx 40rpx 40rpx 40rpx;
|
||
border: 1rpx solid #999999;
|
||
|
||
margin: 60rpx auto;
|
||
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
font-size: 32rpx;
|
||
color: #999999;
|
||
}
|
||
|
||
.btns {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 20px;
|
||
}
|
||
</style> |