836 lines
26 KiB
Vue
836 lines
26 KiB
Vue
<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>
|
||
|
||
<canvas
|
||
id="myCanvas"
|
||
type="2d"
|
||
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
|
||
style="position: fixed; left: -9999px; top: -9999px;"
|
||
></canvas>
|
||
|
||
<!-- 隐藏的 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;
|
||
},
|
||
wrapText(ctx, text, x, y, maxWidth, lineHeight) {
|
||
const words = text.split('');
|
||
let line = '';
|
||
let currentY = y;
|
||
|
||
for (let i = 0; i < words.length; i++) {
|
||
const testLine = line + words[i];
|
||
const metrics = ctx.measureText(testLine);
|
||
const testWidth = metrics.width;
|
||
|
||
if (testWidth > maxWidth && i > 0) {
|
||
ctx.fillText(line, x, currentY);
|
||
line = words[i];
|
||
currentY += lineHeight;
|
||
} else {
|
||
line = testLine;
|
||
}
|
||
}
|
||
|
||
ctx.fillText(line, x, currentY);
|
||
},
|
||
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 loadImage(src) {
|
||
console.log('正在加载图片:', src);
|
||
return new Promise((resolve, reject) => {
|
||
tt.downloadFile({
|
||
url: src,
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
console.log('图片加载成功:', res.tempFilePath);
|
||
resolve(res.tempFilePath);
|
||
} else {
|
||
console.error('图片加载失败,状态码:', res.statusCode);
|
||
reject(new Error(`图片加载失败,状态码: ${res.statusCode}`));
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('图片加载失败:', err.errMsg);
|
||
reject(new Error(`图片加载失败: ${err.errMsg}`));
|
||
}
|
||
});
|
||
});
|
||
},
|
||
|
||
async saveCurrentImage() {
|
||
const currentIndex = this.currentPage - 1;
|
||
const currentItem = this.certificateList[currentIndex];
|
||
|
||
if (!currentItem) {
|
||
uni.showToast({
|
||
title: '证书信息加载中,请稍候',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
this.currentCertificateItem = currentItem;
|
||
|
||
uni.showLoading({
|
||
title: '生成图片中...',
|
||
mask: true
|
||
});
|
||
|
||
try {
|
||
// 获取 Canvas 节点
|
||
const query = tt.createSelectorQuery();
|
||
const canvasNode = await new Promise((resolve, reject) => {
|
||
query
|
||
.select('#myCanvas')
|
||
.fields({ node: true, size: true })
|
||
.exec((res) => {
|
||
if (res[0]) {
|
||
resolve(res[0].node);
|
||
} else {
|
||
reject(new Error('Canvas 节点获取失败'));
|
||
}
|
||
});
|
||
});
|
||
|
||
// 获取 2D 上下文
|
||
const ctx = canvasNode.getContext('2d');
|
||
const dpr = tt.getSystemInfoSync().pixelRatio;
|
||
canvasNode.width = this.canvasWidth * dpr;
|
||
canvasNode.height = this.canvasHeight * dpr;
|
||
ctx.scale(dpr, dpr);
|
||
|
||
// 清空画布
|
||
ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||
|
||
// 加载并绘制背景图
|
||
const backgroundImgPath = await this.loadImage(`${this.imgPrefix}certificateGround.png`);
|
||
const backgroundImg = canvasNode.createImage();
|
||
backgroundImg.src = backgroundImgPath;
|
||
await new Promise((resolve) => {
|
||
backgroundImg.onload = () => {
|
||
ctx.drawImage(backgroundImg, 0, 0, this.canvasWidth, this.canvasHeight);
|
||
resolve();
|
||
};
|
||
});
|
||
|
||
// 设置字体样式
|
||
ctx.font = '20px sans-serif';
|
||
ctx.fillStyle = '#FF19A0';
|
||
ctx.textAlign = 'center';
|
||
|
||
// 绘制证书标题
|
||
const title = currentItem.title || '为爱续航证书';
|
||
ctx.fillText(title, this.canvasWidth / 2, 50);
|
||
|
||
// 绘制英文标题
|
||
ctx.font = '12px sans-serif';
|
||
const titleEn = currentItem.title_en || 'Certificate of Love Endurance';
|
||
ctx.fillText(titleEn, this.canvasWidth / 2, 70);
|
||
|
||
// 绘制用户名
|
||
ctx.font = '16px sans-serif';
|
||
const userName = this.userName || '周佳佳';
|
||
ctx.fillText(userName, this.canvasWidth / 2, 100);
|
||
|
||
// 绘制描述文本
|
||
ctx.font = '12px sans-serif';
|
||
ctx.fillStyle = '#333333';
|
||
ctx.textAlign = 'left';
|
||
const description = `您累计捐赠${currentItem.source_value || 0}克粮,为毛孩子奉献爱心,点燃希望,感谢您的捐赠让世界变得更温暖。`;
|
||
this.wrapText(ctx, description, 20, 130, this.canvasWidth - 40, 16);
|
||
|
||
// 绘制结尾文字
|
||
ctx.fillText('特发此证,以表谢忱!', 20, 200);
|
||
|
||
// 绘制证书编号
|
||
ctx.font = '10px sans-serif';
|
||
ctx.fillStyle = '#FF19A0';
|
||
ctx.textAlign = 'right';
|
||
const certificateNo = `证书编号: ${currentItem.certificate_no || currentItem.id || '234546678896666788'}`;
|
||
ctx.fillText(certificateNo, this.canvasWidth - 20, this.canvasHeight - 20);
|
||
|
||
// 绘制证书图标
|
||
const badgeImgPath = await this.loadImage(currentItem.certificate_url);
|
||
const badgeImg = canvasNode.createImage();
|
||
badgeImg.src = badgeImgPath;
|
||
await new Promise((resolve) => {
|
||
badgeImg.onload = () => {
|
||
ctx.drawImage(badgeImg, this.canvasWidth - 60, this.canvasHeight - 80, 40, 40);
|
||
resolve();
|
||
};
|
||
});
|
||
|
||
// 导出为 base64 数据
|
||
const dataURL = canvasNode.toDataURL('image/png');
|
||
const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, '');
|
||
|
||
// 将 base64 数据写入临时文件
|
||
const tempFilePath = `${tt.env.USER_DATA_PATH}/temp_certificate.png`;
|
||
const fs = tt.getFileSystemManager();
|
||
fs.writeFileSync(tempFilePath, base64Data, 'base64');
|
||
|
||
// 保存到相册
|
||
uni.saveImageToPhotosAlbum({
|
||
filePath: 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() || '未知错误';
|
||
uni.showToast({
|
||
title: errorMsg.length > 20 ? '生成图片失败,请重试' : errorMsg,
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
console.error('生成证书图片失败:', 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>
|