|
|
@@ -1,36 +1,68 @@
|
|
|
<template>
|
|
|
<n-modal :show="show" @update:show="newValue => updateShow(newValue)" transform-origin="center">
|
|
|
<div class="share-box">
|
|
|
- <img :src="imgUrl" v-if="imgUrl" alt="" class="block w-5/6 max-w-md" />
|
|
|
- <div class="share-img w-5/6 relative max-w-md" v-else ref="postRef">
|
|
|
- <img src="@/assets/bg_share_card.png" class="block" alt="" />
|
|
|
+ <img :src="imgUrl" v-if="imgUrl" alt="" class="block share-canvas w-5/6 max-w-md" />
|
|
|
+ <div class="share-img w-5/6 relative max-w-md" :class="['share-img-' + shareType]" v-else ref="postRef">
|
|
|
+ <img :src="shareImgs[shareType]" class="block share-bg" alt="" />
|
|
|
<!-- <div class="absolute inset-x-0 top-0">
|
|
|
<user-avatar avatarType="small" onlyAvatar />
|
|
|
</div> -->
|
|
|
<div class="qrcode flex items-center justify-center">
|
|
|
<qrcode-vue :value="shareUrl" :size="300" renderAs="svg" level="M" />
|
|
|
+ <img :src="shareLogo" alt="" class="share-logo" />
|
|
|
</div>
|
|
|
+
|
|
|
+ <div class="user flex items-center" v-if="shareType === 1">
|
|
|
+ <template v-if="isString(userInfo.avatar) && userInfo.avatar.length > 0">
|
|
|
+ <NAvatar :size="31" round :src="userInfo.avatar" :fallback-src="defaultAvatar" />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <NAvatar :size="31" round :src="defaultAvatar" />
|
|
|
+ </template>
|
|
|
+ <span class="text-xs ml-[7px]">{{ userInfo.name }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="share-btns w-5/6 max-w-md flex">
|
|
|
+ <n-button text v-if="isMobile">长按保存图片</n-button>
|
|
|
+ <n-button text v-else @click="save">保存图片</n-button>
|
|
|
+ <n-button text :loading="loading" @click="changeType">换个样式</n-button>
|
|
|
+ <n-button text>复制邀请链接</n-button>
|
|
|
</div>
|
|
|
|
|
|
- <div class="tips" v-if="isMobile">长按保存图片</div>
|
|
|
+ <!-- <div class="tips" v-if="isMobile">长按保存图片</div>
|
|
|
<div class="mt-16" v-else>
|
|
|
<n-button type="primary" @click="save">点击保存图片</n-button>
|
|
|
</div>
|
|
|
|
|
|
- <n-button text class="cancel" @click.stop="updateShow(false)"> 取消 </n-button>
|
|
|
+ <n-button text class="cancel" @click.stop="updateShow(false)"> 取消 </n-button> -->
|
|
|
</div>
|
|
|
</n-modal>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { NModal, NButton } from 'naive-ui'
|
|
|
-import { ref, watch } from 'vue'
|
|
|
+import { NModal, NButton, NAvatar } from 'naive-ui'
|
|
|
+import { ref, watch, computed } from 'vue'
|
|
|
import QrcodeVue from 'qrcode.vue'
|
|
|
import html2canvas from 'html2canvas'
|
|
|
import { useUserStore } from '@/store'
|
|
|
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
|
|
import { Ref } from 'vue'
|
|
|
import { fetchRedirectUrl } from '@/api'
|
|
|
+import { isString } from '@/utils/is'
|
|
|
+import defaultAvatar from '@/assets/avatar.png'
|
|
|
+import shareImg1 from '@/assets/share1.png'
|
|
|
+import shareImg2 from '@/assets/share2.png'
|
|
|
+import shareImg3 from '@/assets/share3.png'
|
|
|
+import shareImg4 from '@/assets/share4.png'
|
|
|
+import shareImg5 from '@/assets/share5.png'
|
|
|
+import shareImg6 from '@/assets/share6.png'
|
|
|
+import shareImg7 from '@/assets/share7.png'
|
|
|
+import shareImg8 from '@/assets/share8.png'
|
|
|
+import shareLogo from '@/assets/share-logo.png'
|
|
|
+
|
|
|
+const shareImgs = [shareImg1, shareImg2, shareImg3, shareImg4, shareImg5, shareImg6, shareImg7, shareImg8]
|
|
|
+const shareType = ref(1)
|
|
|
+const loading = ref(true)
|
|
|
|
|
|
const props = defineProps({
|
|
|
show: {
|
|
|
@@ -51,27 +83,37 @@ const shareUrl = ref('')
|
|
|
fetchRedirectUrl(location.origin + '/ui/home?invitor=' + userStore.userInfo.id).then((res: any) => {
|
|
|
shareUrl.value = res.url
|
|
|
})
|
|
|
+const userInfo = computed(() => userStore.userInfo)
|
|
|
|
|
|
const postRef: Ref<HTMLElement | null> = ref(null)
|
|
|
watch(
|
|
|
() => props.show,
|
|
|
val => {
|
|
|
if (val) {
|
|
|
- setTimeout(() => {
|
|
|
- html2canvas(postRef.value!, {
|
|
|
- useCORS: true,
|
|
|
- allowTaint: true,
|
|
|
- backgroundColor: null,
|
|
|
- scale: 3
|
|
|
- }).then(canvas => {
|
|
|
- console.log(canvas)
|
|
|
- imgUrl.value = canvas.toDataURL('image/png')
|
|
|
- })
|
|
|
- }, 500)
|
|
|
+ changeType()
|
|
|
}
|
|
|
}
|
|
|
)
|
|
|
|
|
|
+function changeType() {
|
|
|
+ loading.value = true
|
|
|
+ imgUrl.value = ''
|
|
|
+ let type = Math.floor(Math.random() * 7)
|
|
|
+ shareType.value = type !== shareType.value ? type : (type + 1) % 7
|
|
|
+ setTimeout(() => {
|
|
|
+ html2canvas(postRef.value!, {
|
|
|
+ useCORS: true,
|
|
|
+ allowTaint: true,
|
|
|
+ backgroundColor: null,
|
|
|
+ scale: 3
|
|
|
+ }).then(canvas => {
|
|
|
+ console.log(canvas)
|
|
|
+ loading.value = false
|
|
|
+ imgUrl.value = canvas.toDataURL('image/png')
|
|
|
+ })
|
|
|
+ }, 500)
|
|
|
+}
|
|
|
+
|
|
|
function save() {
|
|
|
const tempLink = document.createElement('a')
|
|
|
tempLink.style.display = 'none'
|
|
|
@@ -91,27 +133,143 @@ const { isMobile } = useBasicLayout()
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
.share-img {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
.qrcode {
|
|
|
position: absolute;
|
|
|
- top: 48%;
|
|
|
- left: 30%;
|
|
|
+ z-index: 3;
|
|
|
+ bottom: 5.1%;
|
|
|
+ right: 10.6%;
|
|
|
background-color: #fff;
|
|
|
- box-shadow: 0px 0px 4px 0px rgba(163, 121, 255, 0.5);
|
|
|
- padding: 6px;
|
|
|
- border-radius: 8px;
|
|
|
- width: 40%;
|
|
|
- height: 29%;
|
|
|
+ padding: 1px;
|
|
|
+ border-radius: 0px;
|
|
|
+ width: 15.4%;
|
|
|
+ height: 14.5%;
|
|
|
+
|
|
|
:deep(svg) {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
+ z-index: 1;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+
|
|
|
+ .share-logo {
|
|
|
+ width: 20%;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ z-index: 2;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .user {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 3.5%;
|
|
|
+ left: 11.5%;
|
|
|
+ z-index: 3;
|
|
|
+ height: 13.1%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.share-btns {
|
|
|
+ background-color: #fff;
|
|
|
+ padding-top: 20px;
|
|
|
+ transform: translateY(-20px);
|
|
|
+ border-radius: 0 0 14px 14px;
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ .n-button {
|
|
|
+ width: 33%;
|
|
|
+ height: 48px;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &:not(:last-child) {
|
|
|
+ &::after {
|
|
|
+ content: '';
|
|
|
+ width: 1px;
|
|
|
+ height: 14px;
|
|
|
+ background: #3b3b3b;
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.share-img-1 {
|
|
|
+ .qrcode {
|
|
|
+ bottom: 3.5%;
|
|
|
+ right: 11.5%;
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 4px;
|
|
|
+ border-radius: 4px;
|
|
|
+ width: 14.1%;
|
|
|
+ height: 13.1%;
|
|
|
+ }
|
|
|
+}
|
|
|
+.share-img-4 {
|
|
|
+ .qrcode {
|
|
|
+ top: 30.3%;
|
|
|
+ left: 9.8%;
|
|
|
+ background-color: #fff;
|
|
|
+ // box-shadow: 0px 0px 4px 0px rgba(163, 121, 255, 0.5);
|
|
|
+ padding: 5px;
|
|
|
+ border-radius: 0px;
|
|
|
+ width: 25.5%;
|
|
|
+ height: 24.1%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.share-img-5 {
|
|
|
+ .qrcode {
|
|
|
+ top: 24.2%;
|
|
|
+ left: 50%;
|
|
|
+ background-color: #fff;
|
|
|
+ // box-shadow: 0px 0px 4px 0px rgba(163, 121, 255, 0.5);
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ width: 43.4%;
|
|
|
+ height: 36%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.share-img-6 {
|
|
|
+ .qrcode {
|
|
|
+ background-color: #fff;
|
|
|
+ bottom: 3.7%;
|
|
|
+ right: 10.8%;
|
|
|
+ padding: 3px;
|
|
|
+ border-radius: 0px;
|
|
|
+ width: 14.8%;
|
|
|
+ height: 9.9%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.share-img-7 {
|
|
|
+ .qrcode {
|
|
|
+ background-color: #fff;
|
|
|
+ top: 5.3%;
|
|
|
+ right: 14.8%;
|
|
|
+ padding: 4px;
|
|
|
+ border-radius: 4px;
|
|
|
+ width: 14.8%;
|
|
|
+ height: 9.8%;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.share-box {
|
|
|
.f-col();
|
|
|
align-items: center;
|
|
|
--n-box-shadow: none;
|
|
|
+ .share-bg {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ }
|
|
|
+ .share-canvas {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.tips {
|