hookehuyr

✨ feat(证书组件): 证书直接生成为图片方便用户下载

客户要求
...@@ -4,11 +4,11 @@ VITE_BASE = / ...@@ -4,11 +4,11 @@ VITE_BASE = /
4 # 测试open-id 4 # 测试open-id
5 # VITE_OPENID = api-test-openid 5 # VITE_OPENID = api-test-openid
6 # VITE_OPENID = o8BRf1gLDWieH3Y3JvbrI_4IjaME 6 # VITE_OPENID = o8BRf1gLDWieH3Y3JvbrI_4IjaME
7 -VITE_OPENID = oJLZq5t9PIKLW9tm1oSUNAuPwssA 7 +VITE_OPENID = oJLZq5hXgSv4zI1b8px22Wl7EuNA
8 # VITE_OPENID = oJLZq5uT_6GwIh2tQWh1F9IoHZ3U 8 # VITE_OPENID = oJLZq5uT_6GwIh2tQWh1F9IoHZ3U
9 9
10 # B端账号 10 # B端账号
11 VITE_ID = 13761653761 11 VITE_ID = 13761653761
12 12
13 # 验证码 13 # 验证码
14 -VITE_PIN = 14 +VITE_PIN =
......
...@@ -36,24 +36,20 @@ declare module 'vue' { ...@@ -36,24 +36,20 @@ declare module 'vue' {
36 Template: typeof import('./src/components/template/index.vue')['default'] 36 Template: typeof import('./src/components/template/index.vue')['default']
37 Test: typeof import('./src/components/LoginBox/test.vue')['default'] 37 Test: typeof import('./src/components/LoginBox/test.vue')['default']
38 VanActionSheet: typeof import('vant/es')['ActionSheet'] 38 VanActionSheet: typeof import('vant/es')['ActionSheet']
39 - VanCellGroup: typeof import('vant/es')['CellGroup']
40 VanCheckbox: typeof import('vant/es')['Checkbox'] 39 VanCheckbox: typeof import('vant/es')['Checkbox']
41 VanCol: typeof import('vant/es')['Col'] 40 VanCol: typeof import('vant/es')['Col']
42 VanEmpty: typeof import('vant/es')['Empty'] 41 VanEmpty: typeof import('vant/es')['Empty']
43 VanField: typeof import('vant/es')['Field'] 42 VanField: typeof import('vant/es')['Field']
44 VanIcon: typeof import('vant/es')['Icon'] 43 VanIcon: typeof import('vant/es')['Icon']
45 VanImage: typeof import('vant/es')['Image'] 44 VanImage: typeof import('vant/es')['Image']
46 - VanList: typeof import('vant/es')['List']
47 VanLoading: typeof import('vant/es')['Loading'] 45 VanLoading: typeof import('vant/es')['Loading']
48 VanOverlay: typeof import('vant/es')['Overlay'] 46 VanOverlay: typeof import('vant/es')['Overlay']
49 - VanPicker: typeof import('vant/es')['Picker']
50 VanPopover: typeof import('vant/es')['Popover'] 47 VanPopover: typeof import('vant/es')['Popover']
51 VanPopup: typeof import('vant/es')['Popup'] 48 VanPopup: typeof import('vant/es')['Popup']
52 VanRow: typeof import('vant/es')['Row'] 49 VanRow: typeof import('vant/es')['Row']
53 VanStepper: typeof import('vant/es')['Stepper'] 50 VanStepper: typeof import('vant/es')['Stepper']
54 - VanSticky: typeof import('vant/es')['Sticky'] 51 + VanSwipe: typeof import('vant/es')['Swipe']
55 - VanTab: typeof import('vant/es')['Tab'] 52 + VanSwipeItem: typeof import('vant/es')['SwipeItem']
56 - VanTabs: typeof import('vant/es')['Tabs']
57 VanTag: typeof import('vant/es')['Tag'] 53 VanTag: typeof import('vant/es')['Tag']
58 VideoBar: typeof import('./src/components/MuiVideo/videoBar.vue')['default'] 54 VideoBar: typeof import('./src/components/MuiVideo/videoBar.vue')['default']
59 VideoCard: typeof import('./src/components/VideoCard/index.vue')['default'] 55 VideoCard: typeof import('./src/components/VideoCard/index.vue')['default']
......
1 <template> 1 <template>
2 - <div class="donate-certificate"> 2 + <div v-if="flag" ref="canvasRef" class="donate-certificate">
3 <div class="header-bg"> 3 <div class="header-bg">
4 - <van-image width="100" height="100" fit="contain" :src="icon_cert" style="margin-top: 15vh;" /> 4 + <img src="http://gyzs.onwall.cn/zhengshu@2x1.png" style="margin-top: 18vh; margin-bottom: 1vh; width: 100px; height: 100%; object-fit: contain;" />
5 </div> 5 </div>
6 <div class="title"> 6 <div class="title">
7 <van-row align="center"> 7 <van-row align="center">
...@@ -26,10 +26,10 @@ ...@@ -26,10 +26,10 @@
26 <p>上海市儿童基金会</p> 26 <p>上海市儿童基金会</p>
27 <p>上海初心为爱公益基金会</p> 27 <p>上海初心为爱公益基金会</p>
28 <div style="position: absolute; width: 50%; height: 100%; top: 0; left: 0;"> 28 <div style="position: absolute; width: 50%; height: 100%; top: 0; left: 0;">
29 - <van-image height="100%" fit="contain" :src="icon_stamp01" /> 29 + <img style="height: 100%; object-fit: contain;" src="http://gyzs.onwall.cn/stamp011.png" />
30 </div> 30 </div>
31 <div style="position: absolute; width: 50%; height: 100%; top: 0; right: 0;"> 31 <div style="position: absolute; width: 50%; height: 100%; top: 0; right: 0;">
32 - <van-image height="100%" fit="contain" :src="icon_stamp02" /> 32 + <img style="height: 100%; object-fit: contain;" src="http://gyzs.onwall.cn/stamp021.png" />
33 </div> 33 </div>
34 </div> 34 </div>
35 </div> 35 </div>
...@@ -40,28 +40,92 @@ ...@@ -40,28 +40,92 @@
40 <div style="height: 3rem;" /> 40 <div style="height: 3rem;" />
41 <div class="wrapper-border"> 41 <div class="wrapper-border">
42 <div class="top-bg"> 42 <div class="top-bg">
43 - <van-image :src="donate_top" style="width: 100%; height: 10rem;" /> 43 + <img src="http://gyzs.onwall.cn/donate_top1.png" style="width: 100%; height: 10rem;" />
44 </div> 44 </div>
45 <div class="center-bg"> 45 <div class="center-bg">
46 - <img :src="donate_center" :style="styleObject"> 46 + <img src="http://gyzs.onwall.cn/donate_center_1.png" :style="styleObject">
47 </div> 47 </div>
48 <div class="bottom-bg"> 48 <div class="bottom-bg">
49 - <van-image :src="donate_bottom" style="width: 100%;" /> 49 + <img src="http://gyzs.onwall.cn/donate_bottom_1.png" style="width: 100%;" />
50 </div> 50 </div>
51 <div style="height: 3rem;" /> 51 <div style="height: 3rem;" />
52 </div> 52 </div>
53 </div> 53 </div>
54 + <div v-if="imgUrl">
55 + <img :src="imgUrl" crossOrigin="anonymous" :style="{ width: ref_width, height: ref_height }">
56 + </div>
54 </template> 57 </template>
55 58
56 <script setup> 59 <script setup>
57 -import icon_cert from '@images/zhengshu@2x.png' 60 +// import icon_cert from '@images/zhengshu@2x.png'
58 import icon_stamp01 from '@images/stamp01.png' 61 import icon_stamp01 from '@images/stamp01.png'
59 import icon_stamp02 from '@images/stamp02.png' 62 import icon_stamp02 from '@images/stamp02.png'
60 -import donate_top from '@images/donate_top.png' 63 +// import donate_top from '@images/donate_top.png'
61 -import donate_center from '@images/donate_center.png' 64 +// import donate_center from '@images/donate_center.png'
62 -import donate_bottom from '@images/donate_bottom.png' 65 +// import donate_bottom from '@images/donate_bottom.png'
63 import $ from 'jquery' 66 import $ from 'jquery'
67 +import html2canvas from "html2canvas";
68 +
69 +const canvasRef = ref(null);
70 +const imgUrl = ref('');
71 +const imgSrc = ref('');
72 +const flag = ref(true);
73 +const ref_width = ref('');
74 +const ref_height = ref('');
64 75
76 +onMounted(() => {
77 + nextTick(() => {
78 + let canvasDom = canvasRef.value;
79 + ref_width.value = canvasDom.offsetWidth + 'px';
80 + ref_height.value = canvasDom.offsetHeight + 'px';
81 + });
82 + createImage();
83 +});
84 +
85 +// 获取像素比
86 +const DPR = () => {
87 + // 获取设备dpi
88 + if (window.devicePixelRatio && window.devicePixelRatio > 1) {
89 + return window.devicePixelRatio * 2
90 + }
91 + // 直接返回高像素比
92 + return 8
93 +}
94 +
95 +const createImage = () => {
96 + nextTick(() => {
97 + // 获取要生成图片的 DOM 元素
98 + let canvasDom = canvasRef.value;
99 + const options = {
100 + backgroundColor: '#fff',
101 + // canvas: canvas,
102 + useCORS: true,//配置允许跨域
103 + scale: DPR(),
104 + // windowWidth: document.body.scrollWidth,
105 + // windowHeight: document.body.scrollHeight,
106 + // x: 0,
107 + // y: window.pageYOffset,
108 + // allowTaint: true,
109 + // background: "#d21f2c", // 一定要添加背景颜色,否则出来的图片,背景全部都是透明的
110 + dpi: 500 // 处理模糊问题
111 + };
112 + // console.log("获取指定的宽高", width, height, canvas);
113 + html2canvas(canvasDom, options)
114 + .then(canvas => {
115 + try {
116 + // 生成图片地址
117 + imgUrl.value = canvas.toDataURL("image/png");
118 + flag.value = false;
119 + } catch (e) {
120 + alert("图片跨域,保存失败");
121 + }
122 + })
123 + .catch(error => {
124 + console.error("绘制失败");
125 + console.error(error);
126 + });
127 + });
128 +}
65 </script> 129 </script>
66 130
67 <script> 131 <script>
......