1
This commit is contained in:
773
src/pageHome/welfare/certificate-list.vue
Normal file
773
src/pageHome/welfare/certificate-list.vue
Normal file
@ -0,0 +1,773 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="certificate-list-container" :class="{ 'empty-container': !certificateList || certificateList.length === 0 }">
|
||||
<template v-if="certificateList && certificateList.length > 0">
|
||||
<view v-for="(item, index) in certificateList" :key="item.id || index" class="certificate-item" @click="openModal(item, index)">
|
||||
<image :src="item.certificate_url" mode="aspectFit" class="certificate-image" />
|
||||
</view>
|
||||
</template>
|
||||
<view v-else class="certificate-placeholder">
|
||||
<image :src="`${imgPrefix}certificatePlaceholder.png`" mode="aspectFit" class="placeholder-image" />
|
||||
<text class="placeholder-text">暂无内容</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 遮罩层 -->
|
||||
<view v-if="showModal" class="modal-overlay" @click="closeModal">
|
||||
<view class="modal-content" @click.stop>
|
||||
<scroll-view class="scroll-container" scroll-x @scroll="onScroll">
|
||||
<view class="scroll-content">
|
||||
<view
|
||||
v-for="(item, index) in certificateList"
|
||||
:key="item.id || index"
|
||||
class="certificate-modal-item"
|
||||
:class="{ 'first-item': index === 0, 'not-last-item': index !== certificateList.length - 1 }"
|
||||
:style="{ backgroundImage: `url(${imgPrefix}certificateGround.png)` }"
|
||||
>
|
||||
<!-- 主要内容容器 - 居中 -->
|
||||
<view class="certificate-main-content">
|
||||
<!-- 证书标题 -->
|
||||
<view class="certificate-title-section">
|
||||
<text class="certificate-title">{{ item.title || '为爱续航证书' }}</text>
|
||||
<text class="certificate-title-en">{{ item.title_en || 'Certificate of Love Endurance' }}</text>
|
||||
<image class="certificate-line" :src="`${imgPrefix}certificateLine.png`" mode="aspectFit" />
|
||||
</view>
|
||||
|
||||
<!-- 用户名称 -->
|
||||
<view class="user-name-section">
|
||||
<text class="user-name">{{ userName || '周佳佳' }}</text>
|
||||
<text class="user-title">先生/女士</text>
|
||||
</view>
|
||||
|
||||
<!-- 证书描述 -->
|
||||
<view class="certificate-description description-text">{{ `您累计捐赠${item.source_value}克粮,为毛孩子奉献爱心,点燃希望,感谢您的捐赠让世界变得更温暖。` }}</view>
|
||||
<!-- 证书结尾 -->
|
||||
<view class="certificate-ending ending-text">特发此证,以表谢忱!</view>
|
||||
</view>
|
||||
|
||||
<!-- 证书图标和编号 - 右下角 -->
|
||||
<view class="certificate-footer-info">
|
||||
<view class="certificate-badge">
|
||||
<image :src="item.certificate_url" mode="aspectFit" class="badge-image" />
|
||||
</view>
|
||||
<text class="certificate-number">证书编号: {{ item.certificate_no || item.id || '234546678896666788' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 右边距占位元素 -->
|
||||
<view class="right-spacer"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 计数器 -->
|
||||
<view class="certificate-counter">
|
||||
<text class="counter-text">{{ currentPage }}/{{ certificateList.length }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="certificate-actions">
|
||||
<button class="action-btn" @click.stop="saveCurrentImage">保存当前图片</button>
|
||||
<!-- <button class="action-btn" @click.stop="shareCertificate">分享</button> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 隐藏的 wxml-to-canvas 组件用于生成证书图片 -->
|
||||
<wxml-to-canvas class="widget" :width="canvasWidth" :height="canvasHeight" style="position: fixed; left: -9999px; top: -9999px;"></wxml-to-canvas>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCertificates as getCertificatesApi } from '@/api/user';
|
||||
import { imgPrefix } from '@/utils/common';
|
||||
|
||||
export default {
|
||||
name: 'CertificateList',
|
||||
data() {
|
||||
return {
|
||||
imgPrefix,
|
||||
certificateList: [],
|
||||
showModal: false,
|
||||
currentItem: null,
|
||||
currentIndex: 0,
|
||||
currentPage: 1,
|
||||
canvasWidth: 317,
|
||||
canvasHeight: 224,
|
||||
currentCertificateItem: null // 存储当前要生成图片的证书信息
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
userName() {
|
||||
// 从 Vuex store 中获取用户信息
|
||||
const userInfo = this.$store.state?.user?.userInfo || {};
|
||||
return userInfo.username;
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.getCertificates();
|
||||
},
|
||||
onReady() {
|
||||
// 获取 wxml-to-canvas 组件实例
|
||||
this.widget = this.$refs.widget || this.selectComponent('.widget');
|
||||
},
|
||||
methods: {
|
||||
getCertificates(data) {
|
||||
getCertificatesApi(data).then((res) => {
|
||||
const list = res?.data;
|
||||
this.certificateList = list;
|
||||
});
|
||||
},
|
||||
openModal(item, index) {
|
||||
this.currentItem = item;
|
||||
this.currentIndex = index;
|
||||
this.currentPage = index + 1;
|
||||
this.showModal = true;
|
||||
},
|
||||
closeModal() {
|
||||
this.showModal = false;
|
||||
},
|
||||
onScroll(e) {
|
||||
// 获取滚动位置(单位:px)
|
||||
const scrollLeft = e.detail.scrollLeft;
|
||||
// 获取系统信息,计算 rpx 到 px 的转换比例
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const rpxToPx = systemInfo.windowWidth / 750;
|
||||
// 每个证书项的宽度(634rpx)加上间距(20rpx)
|
||||
const itemWidth = (634 + 20) * rpxToPx;
|
||||
// 计算当前显示的索引(四舍五入)
|
||||
const index = Math.round(scrollLeft / itemWidth);
|
||||
// 更新当前页码(从1开始,最大不超过列表长度)
|
||||
const newPage = Math.min(Math.max(index + 1, 1), this.certificateList.length);
|
||||
if (newPage !== this.currentPage) {
|
||||
this.currentPage = newPage;
|
||||
}
|
||||
},
|
||||
async saveCurrentImage() {
|
||||
// 保存当前图片 - 使用 wxml-to-canvas 生成
|
||||
const currentIndex = this.currentPage - 1;
|
||||
const currentItem = this.certificateList[currentIndex];
|
||||
if (!currentItem) {
|
||||
uni.showToast({
|
||||
title: '证书信息加载中,请稍候',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 存储当前证书信息到 data,供模板使用
|
||||
this.currentCertificateItem = currentItem;
|
||||
|
||||
// 获取组件实例 - 多种方式尝试
|
||||
if (!this.widget) {
|
||||
this.widget = this.$refs.widget;
|
||||
}
|
||||
if (!this.widget) {
|
||||
this.widget = this.selectComponent('.widget');
|
||||
}
|
||||
if (!this.widget) {
|
||||
// 延迟重试一次
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
this.widget = this.$refs.widget || this.selectComponent('.widget');
|
||||
}
|
||||
|
||||
if (!this.widget) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '组件初始化失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
console.error('wxml-to-canvas 组件获取失败');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查组件方法是否可用
|
||||
if (typeof this.widget.renderToCanvas !== 'function') {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '组件方法不可用,请重试',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
console.error('renderToCanvas 方法不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showLoading({
|
||||
title: '生成图片中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
try {
|
||||
// 固定画布尺寸
|
||||
const canvasWidth = 317;
|
||||
const canvasHeight = 224;
|
||||
|
||||
// 更新 canvas 尺寸
|
||||
this.canvasWidth = canvasWidth;
|
||||
this.canvasHeight = canvasHeight;
|
||||
|
||||
await this.$nextTick();
|
||||
|
||||
// 生成证书的 wxml 和 style(使用固定尺寸)
|
||||
const { wxml, style } = this.generateCertificateTemplate();
|
||||
|
||||
// 渲染到 canvas
|
||||
const container = await this.widget.renderToCanvas({ wxml, style });
|
||||
|
||||
// 转换为图片
|
||||
const res = await this.widget.canvasToTempFilePath({
|
||||
fileType: 'png',
|
||||
quality: 1,
|
||||
width: this.canvasWidth,
|
||||
height: this.canvasHeight
|
||||
});
|
||||
|
||||
if (!res || !res.tempFilePath) {
|
||||
throw new Error('生成图片路径失败');
|
||||
}
|
||||
|
||||
// 保存到相册
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
const errMsg = err?.errMsg || '未知错误';
|
||||
uni.showToast({
|
||||
title: '保存失败,请检查相册权限',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
console.error('保存图片失败:', errMsg, err);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
const errorMsg = error?.message || error?.toString() || '未知错误';
|
||||
const errorInfo = `生成图片失败: ${errorMsg}`;
|
||||
console.log(errorInfo, '--=')
|
||||
uni.showToast({
|
||||
title: errorInfo.length > 20 ? '生成图片失败,请重试' : errorInfo,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
// 使用多种方式记录错误,确保线上环境能捕获
|
||||
console.error('生成证书图片失败:', error);
|
||||
console.error('错误详情:', {
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
error: error
|
||||
});
|
||||
// 如果 console 不可用,尝试通过其他方式记录
|
||||
if (typeof uni.reportError === 'function') {
|
||||
uni.reportError({
|
||||
error: errorInfo,
|
||||
errorInfo: JSON.stringify(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
generateCertificateTemplate() {
|
||||
// 使用存储的证书信息
|
||||
const item = this.currentCertificateItem;
|
||||
if (!item) {
|
||||
throw new Error('证书信息不存在');
|
||||
}
|
||||
|
||||
// 固定容器尺寸
|
||||
const width = 317;
|
||||
const height = 224;
|
||||
// 固定内容宽度和位置(根据设计图调整)
|
||||
const mainContentWidth = 250;
|
||||
const mainContentLeft = (width - mainContentWidth) / 2;
|
||||
|
||||
// 确保数据正确转义
|
||||
const title = (item.title || '为爱续航证书').replace(/"/g, '"');
|
||||
const titleEn = (item.title_en || 'Certificate of Love Endurance').replace(/"/g, '"');
|
||||
const rawUserName = this.userName || '周佳佳';
|
||||
const sanitizedUserName = rawUserName.replace(/"/g, '"');
|
||||
const description = `您累计捐赠${item.source_value || 0}克粮,为毛孩子奉献爱心,点燃希望,感谢您的捐赠让世界变得更温暖。`.replace(/"/g, '"');
|
||||
const certificateNo = `证书编号: ${item.certificate_no || item.id || '234546678896666788'}`.replace(/"/g, '"');
|
||||
const nameLength = rawUserName.length;
|
||||
const estimatedCharWidth = 18;
|
||||
const minNameWidth = estimatedCharWidth * 2;
|
||||
const maxNameWidth = mainContentWidth - 60;
|
||||
const nameWrapperWidth = Math.min(maxNameWidth, Math.max(estimatedCharWidth * nameLength, minNameWidth));
|
||||
|
||||
const wxml = `
|
||||
<view class="container">
|
||||
<image class="bg-image" src="${this.imgPrefix}certificateGround.png"></image>
|
||||
<view class="main-content">
|
||||
<view class="title-section">
|
||||
<text class="title">${title}</text>
|
||||
<text class="title-en">${titleEn}</text>
|
||||
<image class="line-image" src="${this.imgPrefix}certificateLine.png"></image>
|
||||
</view>
|
||||
<view class="user-section">
|
||||
<view class="name-wrapper">
|
||||
<text class="user-name">${sanitizedUserName}</text>
|
||||
<view class="underline"></view>
|
||||
</view>
|
||||
<text class="user-title">先生/女士</text>
|
||||
</view>
|
||||
<view class="description">
|
||||
<text class="description-text">${description}</text>
|
||||
</view>
|
||||
<view class="ending">
|
||||
<text class="ending-text">特发此证,以表谢忱!</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer-info">
|
||||
<view class="badge">
|
||||
<image class="badge-image" src="${item.certificate_url || ''}"></image>
|
||||
</view>
|
||||
<text class="certificate-number">${certificateNo}</text>
|
||||
</view>
|
||||
</view>
|
||||
`;
|
||||
|
||||
const style = {
|
||||
container: {
|
||||
width: width,
|
||||
height: height,
|
||||
position: 'relative',
|
||||
backgroundColor: '#ffffff',
|
||||
left: 0,
|
||||
top: 0,
|
||||
overflow: 'hidden'
|
||||
},
|
||||
bgImage: {
|
||||
width: width,
|
||||
height: height,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
zIndex: 0
|
||||
},
|
||||
mainContent: {
|
||||
width: mainContentWidth,
|
||||
height: height - 100,
|
||||
position: 'absolute',
|
||||
left: mainContentLeft,
|
||||
top: 38,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center'
|
||||
},
|
||||
titleSection: {
|
||||
width: mainContentWidth,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginBottom: 7
|
||||
},
|
||||
title: {
|
||||
width: mainContentWidth,
|
||||
height: 25,
|
||||
fontSize: 20,
|
||||
color: '#FF19A0',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
lineHeight: 20,
|
||||
marginBottom: 1
|
||||
},
|
||||
titleEn: {
|
||||
width: mainContentWidth,
|
||||
height: 15,
|
||||
fontSize: 8,
|
||||
color: '#FF19A0',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
lineHeight: 8,
|
||||
marginBottom: 4
|
||||
},
|
||||
lineImage: {
|
||||
width: mainContentWidth,
|
||||
height: 2
|
||||
},
|
||||
userSection: {
|
||||
width: mainContentWidth,
|
||||
height: 15,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'baseline',
|
||||
marginBottom: 4
|
||||
},
|
||||
nameWrapper: {
|
||||
width: nameWrapperWidth,
|
||||
height: 15,
|
||||
flexDirection: 'column',
|
||||
marginRight: 2,
|
||||
position: 'relative'
|
||||
},
|
||||
userName: {
|
||||
width: nameWrapperWidth,
|
||||
height: 18,
|
||||
fontSize: 14,
|
||||
color: '#FF19A0',
|
||||
verticalAlign: 'top',
|
||||
lineHeight: 14
|
||||
},
|
||||
underline: {
|
||||
width: nameWrapperWidth,
|
||||
height: 1,
|
||||
backgroundColor: '#FF19A0',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 15
|
||||
},
|
||||
userTitle: {
|
||||
width: 50,
|
||||
height: 15,
|
||||
fontSize: 11,
|
||||
color: '#333333',
|
||||
verticalAlign: 'top',
|
||||
lineHeight: 11
|
||||
},
|
||||
description: {
|
||||
width: mainContentWidth,
|
||||
height: 75,
|
||||
marginBottom: 4
|
||||
},
|
||||
descriptionText: {
|
||||
width: mainContentWidth,
|
||||
height: 75,
|
||||
fontSize: 11,
|
||||
color: '#333333',
|
||||
textAlign: 'left',
|
||||
verticalAlign: 'top',
|
||||
lineHeight: 16.5
|
||||
},
|
||||
ending: {
|
||||
width: mainContentWidth,
|
||||
height: 11
|
||||
},
|
||||
endingText: {
|
||||
width: mainContentWidth,
|
||||
height: 15,
|
||||
fontSize: 11,
|
||||
color: '#333333',
|
||||
textAlign: 'left',
|
||||
verticalAlign: 'top',
|
||||
lineHeight: 11
|
||||
},
|
||||
footerInfo: {
|
||||
width: 100,
|
||||
height: 60,
|
||||
position: 'absolute',
|
||||
right: 17,
|
||||
bottom: 17,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end'
|
||||
},
|
||||
badge: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
marginBottom: 10
|
||||
},
|
||||
badgeImage: {
|
||||
width: 40,
|
||||
height: 40
|
||||
},
|
||||
certificateNumber: {
|
||||
width: 100,
|
||||
height: 10,
|
||||
fontSize: 7,
|
||||
color: '#FF19A0',
|
||||
textAlign: 'right',
|
||||
verticalAlign: 'top',
|
||||
lineHeight: 7
|
||||
}
|
||||
};
|
||||
|
||||
return { wxml, style };
|
||||
},
|
||||
shareCertificate() {
|
||||
// 分享证书
|
||||
const currentIndex = this.currentPage - 1;
|
||||
const currentItem = this.certificateList[currentIndex];
|
||||
if (!currentItem) {
|
||||
uni.showToast({
|
||||
title: '证书信息加载中,请稍候',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用微信小程序的分享功能
|
||||
uni.showShareMenu({
|
||||
withShareTicket: true,
|
||||
menus: ['shareAppMessage', 'shareTimeline']
|
||||
});
|
||||
|
||||
// 或者显示分享提示
|
||||
uni.showToast({
|
||||
title: '请点击右上角分享',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.certificate-list-container {
|
||||
margin: 20rpx;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&.empty-container {
|
||||
min-height: calc(100vh - 80rpx);
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.certificate-item {
|
||||
flex: 0 0 calc(100% / 3);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.certificate-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
}
|
||||
|
||||
.certificate-placeholder {
|
||||
width: 100%;
|
||||
min-height: 400rpx;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx 20rpx;
|
||||
}
|
||||
|
||||
.placeholder-image {
|
||||
width: 213.15px;
|
||||
height: 160px;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.placeholder-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
// 遮罩层样式
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.scroll-content{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.certificate-modal-item.not-last-item {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.right-spacer {
|
||||
flex-shrink: 0;
|
||||
width: 40rpx;
|
||||
height: 1rpx;
|
||||
}
|
||||
|
||||
.certificate-counter {
|
||||
// position: absolute;
|
||||
// bottom: 40rpx;
|
||||
// left: 50%;
|
||||
// transform: translateX(-50%);
|
||||
// z-index: 1000;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.counter-text {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.certificate-actions {
|
||||
display: flex;
|
||||
margin-top: 40rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 152.5px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
border-radius: 4rpx;
|
||||
background: #FF19A0;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 400rpx;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.action-btn:first-child {
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.action-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
|
||||
.certificate-modal-item {
|
||||
width: calc(100vw - 80rpx);
|
||||
height: 448rpx;
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.certificate-modal-item.first-item {
|
||||
margin-left: 40rpx;
|
||||
}
|
||||
|
||||
.certificate-main-content {
|
||||
width: 502rpx;
|
||||
position: absolute;
|
||||
top: 76rpx;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.certificate-title-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 14rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.certificate-title {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
color: #FF19A0;
|
||||
margin-bottom: 2rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.certificate-title-en {
|
||||
font-size: 16rpx;
|
||||
color: #FF19A0;
|
||||
text-align: center;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.certificate-line {
|
||||
width: 100%;
|
||||
height: 4rpx;
|
||||
}
|
||||
|
||||
.user-name-section {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 8rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 28rpx;
|
||||
color: #FF19A0;
|
||||
margin-right: 4rpx;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.user-title {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.certificate-description {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 8rpx;
|
||||
font-size: 22rpx;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.certificate-ending {
|
||||
width: 100%;
|
||||
font-size: 22rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.certificate-footer-info {
|
||||
position: absolute;
|
||||
bottom: 34rpx;
|
||||
right: 34rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.certificate-badge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.badge-image {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-bottom: 36rpx;
|
||||
margin-right: 36rpx;
|
||||
}
|
||||
|
||||
|
||||
.certificate-number {
|
||||
font-size: 14rpx;
|
||||
color: #FF19A0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.modal-certificate-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-width: 600rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user