hookehuyr

新增页面,添加页面逻辑

......@@ -8,10 +8,10 @@ VITE_PROXY_TARGET = http://voice.onwall.cn
VITE_PROXY_PREFIX = /srv/
# 打包输出文件夹名称
VITE_OUTDIR = voice
VITE_OUTDIR = carbon
# 是否开启调试
VITE_CONSOLE = 0
VITE_CONSOLE = 1
# appID相关
VITE_APPID=微信appID
......
# 资源公共路径
VITE_BASE = /f/voice/
VITE_BASE = /f/carbon/
# 测试open-id
VITE_APP_OPENID =
......
......@@ -13,3 +13,4 @@ src/test/mocha/test.js
cypress.json
src/test
.idea
carbon
......
......@@ -7,37 +7,12 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
'图形验证码': typeof import('./src/components/图形验证码.vue')['default']
Agreement: typeof import('./src/components/DonateFlower/agreement.vue')['default']
AuditVideoCard: typeof import('./src/components/AuditVideoCard/index.vue')['default']
Banner: typeof import('./src/components/MuiVideo/banner.vue')['default']
BookCard: typeof import('./src/components/BookCard/index.vue')['default']
BVideoCard: typeof import('./src/components/BVideoCard/index.vue')['default']
CommentBox: typeof import('./src/components/CommentBox/index.vue')['default']
CommentList: typeof import('./src/components/CommentList/index.vue')['default']
DonateBar: typeof import('./src/components/DonateBar/index.vue')['default']
DonateBook: typeof import('./src/components/DonateBook/index.vue')['default']
DonateCert: typeof import('./src/components/DonateCert/index.vue')['default']
DonateCertPost: typeof import('./src/components/DonateCertPost/index.vue')['default']
DonateFlower: typeof import('./src/components/DonateFlower/index.vue')['default']
FlowerIcon: typeof import('./src/components/FlowerIcon/index.vue')['default']
ImageSliderVerify: typeof import('./src/components/ImageSliderVerify/index.vue')['default']
LocalismBox: typeof import('./src/components/LocalismBox/index.vue')['default']
LoginBox: typeof import('./src/components/LoginBox/index.vue')['default']
MuiVideo: typeof import('./src/components/MuiVideo/index.vue')['default']
MyButton: typeof import('./src/components/MyButton/index.vue')['default']
NoticeOverlay: typeof import('./src/components/NoticeOverlay/index.vue')['default']
NoticeOverlayModule: typeof import('./src/components/NoticeOverlayModule/index.vue')['default']
RankingItem: typeof import('./src/components/RankingItem/index.vue')['default']
RightSideList: typeof import('./src/components/RightSideList/index.vue')['default']
Danmaku: typeof import('./src/components/danmaku.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ShortcutFixed: typeof import('./src/components/ShortcutFixed/index.vue')['default']
Status: typeof import('./src/components/MuiVideo/status.vue')['default']
Template: typeof import('./src/components/template/index.vue')['default']
Test: typeof import('./src/components/LoginBox/test.vue')['default']
VideoBar: typeof import('./src/components/MuiVideo/videoBar.vue')['default']
VideoCard: typeof import('./src/components/VideoCard/index.vue')['default']
VideoDetail: typeof import('./src/components/VideoDetail/index.vue')['default']
VanIcon: typeof import('vant/es')['Icon']
VanImage: typeof import('vant/es')['Image']
VanLoading: typeof import('vant/es')['Loading']
VanUploader: typeof import('vant/es')['Uploader']
}
}
......
......@@ -28,6 +28,7 @@
"vite-plugin-dynamic-import": "^0.9.6",
"vite-plugin-mp": "^1.6.1",
"vue": "^3.2.36",
"vue3-danmaku": "^1.6.0",
"weixin-js-sdk": "^1.6.5"
},
"devDependencies": {
......@@ -5928,6 +5929,14 @@
"vue": "^3.2.0"
}
},
"node_modules/vue3-danmaku": {
"version": "1.6.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/vue3-danmaku/-/vue3-danmaku-1.6.0.tgz",
"integrity": "sha512-XjwVKIelupDD3PWn6k22l5qS8y+SCdFUYq4sSpcPInqk7CyzXWSAfz2BL6WWx9HU9CRWS3x2oDMkepLkJoWvNQ==",
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/webpack-sources": {
"version": "3.2.3",
"resolved": "https://mirrors.cloud.tencent.com/npm/webpack-sources/-/webpack-sources-3.2.3.tgz",
......@@ -10380,6 +10389,12 @@
"@vue/devtools-api": "^6.5.0"
}
},
"vue3-danmaku": {
"version": "1.6.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/vue3-danmaku/-/vue3-danmaku-1.6.0.tgz",
"integrity": "sha512-XjwVKIelupDD3PWn6k22l5qS8y+SCdFUYq4sSpcPInqk7CyzXWSAfz2BL6WWx9HU9CRWS3x2oDMkepLkJoWvNQ==",
"requires": {}
},
"webpack-sources": {
"version": "3.2.3",
"resolved": "https://mirrors.cloud.tencent.com/npm/webpack-sources/-/webpack-sources-3.2.3.tgz",
......
......@@ -9,7 +9,13 @@
"build-watch": "vite build --watch",
"build-ts": "vue-tsc --noEmit && vite build",
"serve": "vite preview",
"cypress:open": "cypress open"
"cypress:open": "cypress open",
"tar": "tar -czvpf dist.tar.gz carbon",
"build_tar": "npm run build && npm run tar",
"scp-oa": "scp dist.tar.gz itomix@ipadbiz.cn:/opt/voice/f/",
"dec-oa": "ssh itomix@ipadbiz.cn 'cd /opt/voice/f/ && tar -xzvf dist.tar.gz && rm -rf dist.tar.gz'",
"remove_tar": "rm -rf dist.tar.gz",
"oa_upload": "npm run build_tar && npm run scp-oa && npm run dec-oa && npm run remove_tar"
},
"dependencies": {
"@vitejs/plugin-legacy": "^1.8.2",
......@@ -32,6 +38,7 @@
"vite-plugin-dynamic-import": "^0.9.6",
"vite-plugin-mp": "^1.6.1",
"vue": "^3.2.36",
"vue3-danmaku": "^1.6.0",
"weixin-js-sdk": "^1.6.5"
},
"devDependencies": {
......
......@@ -14,7 +14,7 @@ set -e
path=/Users/huyirui/program/itomix/git/isp/f
# 编译输出文件夹
output=voice
output=carbon
# 打包
npm run build
......@@ -37,4 +37,4 @@ git commit -m '前端网页更新'
git push
# 更新SSH服务器上文件
# ssh -p 22 itomix@ipadbiz.cn 'cd /opt/voice/f/voice && git pull'``
# ssh -p 22 itomix@ipadbiz.cn 'cd /opt/voice/f/carbon && git pull'``
......
......@@ -2,8 +2,8 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-26 23:52:36
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-01-02 13:59:58
* @FilePath: /tswj/src/App.vue
* @LastEditTime: 2024-04-11 09:50:51
* @FilePath: /fxPark/src/App.vue
* @Description:
-->
<template>
......
......@@ -2,8 +2,8 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-06-09 13:32:44
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-06-14 14:47:01
* @FilePath: /tswj/src/api/wx/config.js
* @LastEditTime: 2024-04-11 06:06:06
* @FilePath: /fxPark/src/api/wx/config.js
* @Description:
*/
import { fn, fetch } from '@/api/fn';
......
<!--
* @Date: 2024-04-10 14:16:36
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-04-10 14:22:14
* @FilePath: /fxPark/src/components/danmaku.vue
* @Description: 文件描述
-->
<template>
<div class="danmaku-page">
<vue-danmaku ref="danmaku" v-model:danmus="danmus" useSlot loop :channels="4" :speeds="50" :top="20" style="height:12rem; width:100vw; position: absolute; top:0; z-index: 10;">
<template v-slot:dm="{ index, danmu }">
<span style="background-color: rgba(48, 48, 48, 0.50); padding: 0.25rem 1rem; border-radius: 14px;">{{ index }}{{ danmu.name }}:{{ danmu.text }}</span>
</template>
</vue-danmaku>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import vueDanmaku from 'vue3-danmaku'
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const danmaku = ref(null)
const danmus = ref([{ avatar: 'http://a.com/a.jpg', name: 'a', text: 'aaa' }, { avatar: 'http://a.com/b.jpg', name: 'b', text: 'bbb' }])
</script>
<style lang="less" scoped>
.danmaku-page {}
</style>
/*
* @Date: 2024-04-07 10:14:17
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-04-07 10:28:36
* @LastEditTime: 2024-04-11 09:39:29
* @FilePath: /fxPark/src/router/routes/modules/fxPark/index.js
* @Description: 文件描述
*/
const index = [{
path: '/fxPark',
path: '/',
name: '“碳”寻复兴公园',
component: () => import('@/views/fxPark/index.vue'),
redirect: '',
......@@ -14,6 +14,42 @@ const index = [{
title: '“碳”寻复兴公园',
},
children: [],
}, {
path: '/audio',
name: '植物之声',
component: () => import('@/views/fxPark/audio.vue'),
redirect: '',
meta: {
title: '植物之声',
},
children: [],
}, {
path: '/intro',
name: '植被介绍',
component: () => import('@/views/fxPark/intro.vue'),
redirect: '',
meta: {
title: '植被介绍',
},
children: [],
}, {
path: '/share',
name: '生成海报±',
component: () => import('@/views/fxPark/share.vue'),
redirect: '',
meta: {
title: '生成海报±',
},
children: [],
}, {
path: '/poster',
name: '生成海报',
component: () => import('@/views/fxPark/poster.vue'),
redirect: '',
meta: {
title: '生成海报',
},
children: [],
},]
export default index;
......
......@@ -2,8 +2,8 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-28 10:17:40
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-01-02 18:02:31
* @FilePath: /tswj/src/utils/axios.js
* @LastEditTime: 2024-04-10 17:37:44
* @FilePath: /fxPark/src/utils/axios.js
* @Description:
*/
import axios from 'axios';
......@@ -13,7 +13,8 @@ import { strExist } from '@/utils/tools'
// import { parseQueryString } from '@/utils/tools'
axios.defaults.params = {
f: 'voice',
f: 'carbon',
client_id: 313939,
};
/**
......
......@@ -17,7 +17,7 @@ onMounted(() => {
*/
let raw_url = encodeURIComponent(location.origin + location.pathname + $route.query.href); // 未授权的地址
// TAG: 开发环境测试数据
const short_url = `/srv/?f=voice&a=openid_${$route.query.prefixAPI}&res=${raw_url}`;
const short_url = `/srv/?f=carbon&a=openid_c&res=${raw_url}`;
location.href = import.meta.env.DEV
? `${short_url}&input_openid=${import.meta.env.VITE_OPENID}`
: `${short_url}`;
......
<!--
* @Date: 2024-04-10 15:08:08
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-04-10 15:54:46
* @FilePath: /fxPark/src/views/fxPark/audio.vue
* @Description: 文件描述
-->
<template>
<div class="audio-page">
<div class="audio-player">
<div style="margin-right: 1rem;">
<van-icon name="circle" size="5rem" />
</div>
<div>
<div style="margin-bottom: 1rem;">微风轻轻吹树叶的声音</div>
<div style="display: flex; justify-content: space-between;">
<van-icon name="arrow-left" size="1.5rem" />
<van-icon name="play" size="1.5rem" @click="audioPlayer.play()" />
<van-icon name="pause" size="1.5rem" @click="audioPlayer.pause()" />
<van-icon name="arrow" size="1.5rem" />
</div>
</div>
<div>
<audio ref="audioPlayer" loop="loop" id="audios" src="https://m10.music.126.net/20240410161841/940e4a035f48a82b1b4d4b01b2e7b1f1/ymusic/5353/0f0f/0358/d99739615f8e5153d77042092f07fd77.mp3" preoload></audio>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const audioPlayer = ref(null);
</script>
<style lang="less" scoped>
.audio-page {
height: 100vh;
position: relative;
background-color: #47A3E4;
display: flex;
justify-content: center;
.audio-player {
border: 1px solid #fff;
border-radius: 10px;
padding: 1rem 2rem 1rem 1rem;
position: absolute;
top: 5rem;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>
<!--
* @Date: 2024-04-07 10:15:55
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-04-07 10:19:13
* @LastEditTime: 2024-04-10 15:01:38
* @FilePath: /fxPark/src/views/fxPark/index.vue
* @Description: 文件描述
-->
<template>
<div class="">123</div>
<div class="fxPark-page">
<danmaku />
<div class="quick-entrance-wrapper">
<div class="quick-entrance-item" style="">
<van-icon name="chat-o" />&nbsp;&nbsp;<span>植物之声</span>
</div>
</div>
<div class="container" v-for="(item, index) in img_list" :key="index" @click="onClick(item)">
<img :src="item.src" class="img">
</div>
</div>
</template>
<script setup>
......@@ -17,12 +27,76 @@ import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
import danmaku from '@/components/danmaku.vue'
// 初始化WX环境
import wx from 'weixin-js-sdk'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const img_list = ref([{
src:'https://cdn.ipadbiz.cn/tmp/fx_park/s1.png' ,
}, {
src:'https://cdn.ipadbiz.cn/tmp/fx_park/s2.png' ,
}, {
src:'https://cdn.ipadbiz.cn/tmp/fx_park/s3.png' ,
}, {
src:'https://cdn.ipadbiz.cn/tmp/fx_park/s4.png' ,
}, {
src:'https://cdn.ipadbiz.cn/tmp/fx_park/s5.png' ,
}, {
src:'https://cdn.ipadbiz.cn/tmp/fx_park/s6.png' ,
},])
const onClick = (item) => {
wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
console.log("🚀 ~ file: index.vue:73 ~ onClick ~ result:", result);
},
fail: function (res) {
console.log("🚀 ~ file: index.vue:77 ~ onClick ~ res:", res);
}
});
}
</script>
<style lang="less" scoped>
.fxPark-page {
.quick-entrance-wrapper {
.quick-entrance-item {
position: absolute;
right: 0;
top: 1.5rem;
color: white;
background-color: green;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
z-index: 20;
font-size: 0.9rem;
padding: 0.5rem;
}
}
.container {
width: 100%;
height: 100%;
background-size: contain;
position: absolute;
z-index: 1;
top: 0;
left: 0;
background-repeat: no-repeat;
.img {
position: absolute;
top: 0;
left: 0;
width: 100%;
object-fit: cover;
}
}
}
</style>
......
<!--
* @Date: 2024-04-10 16:08:09
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-04-10 17:24:25
* @FilePath: /fxPark/src/views/fxPark/intro.vue
* @Description: 文件描述
-->
<template>
<div class="intro-page">
<div></div>
<div style="margin: 1rem;">
<div style="margin-bottom: 1rem;">
<span style="font-size: 1.25rem;">悬铃木</span>
<span style="font-size: 0.85rem;">智者长老</span>
</div>
<div style="border: 1px solid #000; padding: 1rem; border-radius: 8px;">
<div style="margin-bottom: 1.5rem;"><span style="background-color: #D0FCF0; padding: 0.5rem 0.75rem; border-radius: 1rem;">植被类型:</span>&nbsp;待补充</div>
<div style="margin-bottom: 1.5rem;"><span style="background-color: #D0FCF0; padding: 0.5rem 0.75rem; border-radius: 1rem;">植被学名:</span>&nbsp;待补充</div>
<div style="margin-bottom: 1.5rem;">
截至2022年累计固定二氧化碳约7.7吨,可抵消用煤炭发电7.7万度所排放的二氧化碳量,或者可抵消一辆轻型汽车行驶绕地球1周排放的二氧化碳量。
</div>
<div style="margin-bottom: 1rem;"><span style="background-color: #D0FCF0; padding: 0.5rem 0.75rem; border-radius: 1rem;">植被介绍:</span></div>
<div>
这棵悬铃木已经有120岁,胸径为123cm,被称为“沪上老二”,拥有悠久的历史和深厚的底蕴。<br/>
悬铃木生长快,成型后树大荫浓,是作为庭荫树和行道树的优良树种,是上海最常见的行道树种之一。
</div>
</div>
</div>
<div class="task-tips">
<div class="title-wrapper">
<span class="title-text">任务卡</span>
</div>
<div class="task-wrapper">
<div class="task-title">自带咖啡杯</div>
<div>去咖啡店时自带咖啡杯,<br/>代替一次性纸杯。</div>
</div>
</div>
<div class="light-up-text">恭喜您植被已被点亮</div>
<div style="margin: 1rem 1rem 2rem 1rem; color: white; text-align: center;">
<div style="background-color: #F68015; display: inline-block; padding: 0.7rem 2rem; border-radius: 1.5rem;">生成海报</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
</script>
<style lang="less" scoped>
.intro-page {
display: flex;
flex-direction: column;
.task-tips {
.title-wrapper {
text-align: center;
.title-text {
font-size: 24px;
font-weight: bold;
color: #BBFEE2; /* 文字颜色 */
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
}
}
.task-wrapper {
border: 1px solid #000;
margin: 1rem;
padding: 1rem;
border-radius: 10px;
background: linear-gradient(to bottom, #FBFFE9, #BEE9F8);
text-align: center;
.task-title {
background-color: #D6F4BD;
padding: 0.5rem 1.5rem;
border-radius: 1.5rem;
display: inline-block;
font-weight: bold;
margin-bottom: 1rem;
}
}
}
.light-up-text {
text-align: center;
font-size: 24px;
font-weight: bold;
color: #F8E9C1; /* 文字颜色 */
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
margin: 1rem 0;
}
}
</style>
<template>
<div class="poster-page">
<div style="height: calc(83vh - 2rem); padding: 1rem;">
<div v-if="flag" ref="canvasRef" style="position: relative; padding: 1rem; background-color: #fff;">
<div style="position: absolute; top: 3rem; left: 2rem; color: #FFF; writing-mode: vertical-lr; text-orientation: upright;">
<div style="position: relative;">
<span style="font-size: 2.5rem; font-weight: bolder; letter-spacing: 5px;">悬铃木</span>
<div style="position: absolute; bottom: -1rem; letter-spacing: 5px;">智者长老</div>
</div>
</div>
<img :src="imgSrc" style="width: 100%; height: 67vh;">
<div style="color: #CCCCCC; margin-top: 1rem;">
<div style="font-weight: bold; text-decoration: underline; margin-bottom: 0.5rem;">自带咖啡杯</div>
<div style="font-size: 0.9rem;">去咖啡店时自带咖啡杯,代替一次性纸杯。</div>
</div>
</div>
<div v-if="imgUrl">
<img :src="imgUrl" alt="" crossOrigin="anonymous" :style="{ width: ref_width, height: ref_height }">
</div>
</div>
<div class="poster-control-wrapper">
<p class="save-text">长按保存到相册</p>
<div class="poster-control">
<div class="poster-prev">上一个</div>
<van-uploader :before-read="beforeRead" :after-read="afterRead" :max-size="1000 * 1024" accept="file">
<div v-if="!upload_loading" class="poster-upload-btn" style="">上传图片</div>
<van-loading v-else size="24px" color="#E82D2D" text-color="#E82D2D" vertical>上传中...</van-loading>
</van-uploader>
<div class="poster-next">下一个</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { v4 as uuidv4 } from 'uuid';
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common';
import html2canvas from "html2canvas";
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const canvasRef = ref(null);
const imgUrl = ref('');
const imgSrc = ref('https://picsum.photos/800');
const flag = ref(true);
const ref_width = ref('');
const ref_height = ref('');
onMounted(async () => {
nextTick(() => {
let canvasDom = canvasRef.value;
ref_width.value = canvasDom.offsetWidth + 'px';
ref_height.value = canvasDom.offsetHeight + 'px';
// const screenWidth = window.innerWidth;
// alert(screenWidth); // 输出移动设备屏幕的宽度
});
createImage();
});
// 获取像素比
const DPR = () => {
// 获取设备dpi
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio * 2
}
// 直接返回高像素比
return 8
}
const createImage = () => {
nextTick(() => {
// 获取要生成图片的 DOM 元素
let canvasDom = canvasRef.value;
const options = {
backgroundColor: '#fff',
// canvas: canvas,
useCORS: true,//配置允许跨域
scale: DPR(),
// windowWidth: document.body.scrollWidth,
// windowHeight: document.body.scrollHeight,
// x: 0,
// y: window.pageYOffset,
// allowTaint: true,
// background: "#d21f2c", // 一定要添加背景颜色,否则出来的图片,背景全部都是透明的
// dpi: 300 // 处理模糊问题
};
// console.log("获取指定的宽高", width, height, canvas);
html2canvas(canvasDom, options)
.then(canvas => {
try {
// 生成图片地址
imgUrl.value = canvas.toDataURL("image/png");
// console.log("canvas.toDataURL('image/png')", this.imgUrl);
flag.value = false;
} catch (e) {
alert("图片跨域,保存失败");
}
})
.catch(error => {
console.error("绘制失败");
console.error(error);
});
});
}
const upload_loading = ref(false);
const beforeRead = (file) => {
// if (file.type.indexOf('audio') < 0) {
// showToast('请上传音频格式');
// return false;
// }
return true;
};
const afterRead = async (res) => {
upload_loading.value = true;
let affix = uuidv4();
// 此时可以自行将文件上传至服务器
let dataURL = res.content;
let base64url = dataURL.slice(dataURL.indexOf(',') + 1); // 截取前缀的base64 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnoAAAJeCAYAA.......
// 获取七牛token
const { token, key, code } = await qiniuTokenAPI({ filename: `${affix}_${res.file.name}`, file: base64url });
if (code) {
const config = {
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': 'UpToken ' + token, // UpToken后必须有一个 ' '(空格)
}
}
// 上传七牛服务器
const { filekey, hash, image_info } = await qiniuUploadAPI('http://upload.qiniup.com/putb64/-1/key/' + key, base64url, config)
if (filekey) {
// 保存图片
const { data } = await saveFileAPI({ filekey, hash, format: '0', height: '0', width: '0' });
flag.value = true;
imgUrl.value = '';
imgSrc.value = data.src;
upload_loading.value = false;
createImage();
}
}
};
</script>
<style lang="less" scoped>
.poster-page {
height: 100vh;
background-color: green;
.poster-control-wrapper {
.save-text {
text-align: center;
margin-top: 2rem;
margin-bottom: 1rem;
color: #fff;
font-size: 0.9rem;
}
.poster-control {
display: flex;
justify-content: space-between;
align-items: center;
.poster-prev {
background-color: rgba(0, 0, 0, 0.3);
color: #FFF;
padding: 0.5rem 0.8rem 0.5rem 1rem;
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
font-size: 0.9rem;
}
.poster-next {
background-color: rgba(0, 0, 0, 0.3);
color: #FFF;
padding: 0.5rem 1rem 0.5rem 0.8rem;
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
font-size: 0.9rem;
}
.poster-upload-btn {
display: inline-block;
background-color: #F68015;
color: #fff;
padding: 0.5rem 2.5rem;
border-radius: 1.5rem;
font-size: 0.95rem;
}
}
}
}
</style>
<!--
* @Date: 2023-12-30 22:43:25
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-04-11 13:29:29
* @FilePath: /fxPark/src/views/fxPark/share.vue
* @Description: 文件描述
-->
<template>
<div class="share-page">
<div v-if="flag" ref="canvasRef" class="share-bg">
<div style="width: 90vw; height: 90vh;position: relative; overflow: hidden;">
<img src="https://cdn.ipadbiz.cn/gy/new_year_2024/-h-%E6%96%B0%E5%B9%B4%E7%AD%BE.png" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 100%; max-height: 100%;">
</div>
<div style="text-align: center; position: absolute; top: 27.5vh; left: calc(50% - 10vw); font-size: 0.6rem;color:#000;">交往 · 交流 · 交融</div>
<div class="desc-text" v-for="(item, index) in sloganStyle" :key="index" :style="{ ...item }">{{ stringToArray(slogan)[index] }}</div>
<!-- <img :src="qr_code" :style="{ ...qrCodeStyle }"> -->
<div style="text-align: center; position: absolute; bottom: 11vh; left: calc(50% - 15vw); font-size: 0.8rem;color:#c53447;">收听来自远方的祝福</div>
</div>
<div v-if="imgUrl" class="share-img">
<img :src="imgUrl" alt="" crossOrigin="anonymous" :style="{ width: ref_width, height: ref_height }">
</div>
<div v-if="wish_list.length > 1" class="control-wrapper">
<div class="prev" @click="prevWish">上一个</div>
<div>长按保存到相册分享</div>
<div class="next" @click="nextWish">下一个</div>
</div>
<div v-else class="control-wrapper" style="justify-content: center;">
<div>长按保存到相册分享</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { shareWishListAPI } from '@/api/new_year_2024.js'
import { showToast } from 'vant';
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
// import qr_code from '@images/new_year_2024/http_qr_code.png'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const wish_index = ref(0);
const slogan = ref('');
const wish_list = ref([]);
const canvasRef = ref(null);
const imgUrl = ref('');
const flag = ref(true);
const ref_width = ref('');
const ref_height = ref('');
// TAG: slogan位置配置
const sloganStyle = [{
top: '34vh',
left: '26vw',
fontSize: '14vw'
}, {
top: '34vh',
right: '26vw',
fontSize: '14vw'
}, {
top: '48vh',
left: '26vw',
fontSize: '14vw'
}, {
top: '48vh',
right: '26vw',
fontSize: '14vw'
}];
const qrCodeStyle = ref({
position: 'absolute',
bottom: '15.5vh',
left: '36vw',
width: '19vw',
height: '10vh',
})
onMounted(async () => {
nextTick(() => {
let canvasDom = canvasRef.value;
ref_width.value = canvasDom.offsetWidth + 'px';
ref_height.value = canvasDom.offsetHeight + 'px';
// const screenWidth = window.innerWidth;
// alert(screenWidth); // 输出移动设备屏幕的宽度
});
const { code, data } = await shareWishListAPI();
if (code) {
wish_list.value = data;
if (wish_list.value.length) {
slogan.value = wish_list.value[wish_index.value].slogon;
createImage();
}
}
});
const stringToArray = (str) => {
return str.split('');
}
const prevWish = () => {
if (!wish_index.value) {
showToast('已经是第一张了');
return;
}
wish_index.value -= 1;
slogan.value = wish_list.value[wish_index.value].slogon;
// 生成图片
imgUrl.value = '';
flag.value = true;
createImage();
}
const nextWish = () => {
if (wish_index.value === wish_list.value.length - 1) {
showToast('已经是最后一张了');
return;
}
wish_index.value += 1;
slogan.value = wish_list.value[wish_index.value].slogon;
// 生成图片
imgUrl.value = '';
flag.value = true;
createImage();
}
// 获取像素比
const DPR = () => {
// 获取设备dpi
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio * 2
}
// 直接返回高像素比
return 8
}
const createImage = () => {
nextTick(() => {
// 获取要生成图片的 DOM 元素
let canvasDom = canvasRef.value;
const options = {
backgroundColor: '#d21f2c',
// canvas: canvas,
useCORS: true,//配置允许跨域
scale: DPR(),
// windowWidth: document.body.scrollWidth,
// windowHeight: document.body.scrollHeight,
// x: 0,
// y: window.pageYOffset,
// allowTaint: true,
// background: "#d21f2c", // 一定要添加背景颜色,否则出来的图片,背景全部都是透明的
// dpi: 300 // 处理模糊问题
};
// console.log("获取指定的宽高", width, height, canvas);
html2canvas(canvasDom, options)
.then(canvas => {
try {
// 生成图片地址
imgUrl.value = canvas.toDataURL("image/png");
// console.log("canvas.toDataURL('image/png')", this.imgUrl);
flag.value = false;
} catch (e) {
alert("图片跨域,保存失败");
}
})
.catch(error => {
console.error("绘制失败");
console.error(error);
});
});
}
</script>
<script>
import mixin from 'common/mixin';
import html2canvas from "html2canvas";
import wx from 'weixin-js-sdk'
export default {
mixins: [mixin.init],
data() {
return {
}
},
mounted() {
},
methods: {
}
}
</script>
<style lang="less" scoped>
.share-page {
position: relative;
background-color: #d21f2c;
height: 100vh;
width: 100vw;
.share-bg {
position: absolute;
// top: 8vh;
top: 0;
left: 5vw;
width: 90vw;
height: 90vh;
// background-image: url('https://cdn.ipadbiz.cn/gy/new_year_2024/%E6%96%B0%E5%B9%B4%E7%AD%BE@2x.png');
// background-image: url('https://cdn.ipadbiz.cn/gy/new_year_2024/-h-%E6%96%B0%E5%B9%B4%E7%AD%BE.png');
// background-repeat: no-repeat;
// background-size: contain;
// background-position: center;
.desc-text {
color: #c53447;
// font-size: 13vw;
// font-size: 7vh;
// font-size: 3.5rem;
position: absolute;
font-weight: bold;
}
}
.share-img {
position: absolute;
// top: 8vh;
top: 0;
left: 5vw;
}
.control-wrapper {
display: flex;
position: absolute;
bottom: 5vh;
width: 100%;
justify-content: space-between;
color: #FFF;
align-items: center;
.prev {
background: #B41C1E;
border-radius: 0px 33px 33px 0px;
padding: 0.5rem 1rem 0.5rem 0.35rem;
}
.next {
background: #B41C1E;
border-radius: 33px 0px 0px 33px;
padding: 0.5rem 0.35rem 0.5rem 1rem;
}
}
}
</style>
......@@ -2,7 +2,7 @@
<div>
<!-- 生成图片后隐藏原始结构 -->
<div v-if="flag" ref="canvasRef" style="width: 200px; height: 200px;">
<img :src="logo_image" alt="">
<!-- <img :src="logo_image" alt=""> -->
</div>
<div v-if="imgUrl">
<img :src="imgUrl" alt="" crossOrigin="anonymous" style="width: 300px; height: 300px;">
......@@ -17,7 +17,7 @@
<script setup>
import logo_image from '@images/logo@3x.png'
// import logo_image from '@images/logo@3x.png'
</script>
<script>
......
......@@ -3307,6 +3307,11 @@
"@vue/server-renderer" "3.3.13"
"@vue/shared" "3.3.13"
"vue3-danmaku@^1.6.0":
"integrity" "sha512-XjwVKIelupDD3PWn6k22l5qS8y+SCdFUYq4sSpcPInqk7CyzXWSAfz2BL6WWx9HU9CRWS3x2oDMkepLkJoWvNQ=="
"resolved" "https://mirrors.cloud.tencent.com/npm/vue3-danmaku/-/vue3-danmaku-1.6.0.tgz"
"version" "1.6.0"
"webpack-sources@^3.2.3":
"integrity" "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="
"resolved" "https://mirrors.cloud.tencent.com/npm/webpack-sources/-/webpack-sources-3.2.3.tgz"
......