|
|
@@ -6,6 +6,7 @@ import { getReportSchemeMethod } from '@/request/api/report.api';
|
|
|
import { useRouteParams } from '@vueuse/router';
|
|
|
import { useWatcher } from 'alova/client';
|
|
|
import { useRouter } from 'vue-router';
|
|
|
+import QrcodeVue from 'qrcode.vue';
|
|
|
|
|
|
import MiniProgram from '@/components/MiniProgram.vue';
|
|
|
|
|
|
@@ -51,18 +52,19 @@ const panelConfig = reactive({
|
|
|
onError() {},
|
|
|
onComplete(event?: Event) {},
|
|
|
});
|
|
|
+const pageHeader = useTemplateRef('page-header');
|
|
|
const container = useTemplateRef('container');
|
|
|
const getHeightAndScrollTop = (value?: HTMLElement | string) => {
|
|
|
const el = typeof value === 'string' ? container.value?.querySelector<HTMLDivElement>(`#${value}`) : value;
|
|
|
if (!el) return true;
|
|
|
el.scrollIntoView({ behavior: 'instant', block: 'start' });
|
|
|
- const rect = el.getBoundingClientRect();
|
|
|
- const maxHeight = window.innerHeight - rect.top;
|
|
|
- const height = maxHeight - rect.height;
|
|
|
+ const maxHeight = window.innerHeight - (pageHeader.value?.getBoundingClientRect().height ?? 0);
|
|
|
+ const height = window.innerHeight - el.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(el).marginBottom);
|
|
|
panelConfig.anchors = [0, height, maxHeight];
|
|
|
panelConfig.height = height;
|
|
|
panelConfig.fullHeight = maxHeight;
|
|
|
};
|
|
|
+let lastFrameSrc: string;
|
|
|
async function openGoodsPanel(goods: SchemeGoodsProps, event?: Event | string) {
|
|
|
if (panelConfig.goods === goods) {
|
|
|
panelConfig.height = panelConfig.anchors[panelConfig.anchors.length - 1];
|
|
|
@@ -70,16 +72,20 @@ async function openGoodsPanel(goods: SchemeGoodsProps, event?: Event | string) {
|
|
|
}
|
|
|
|
|
|
if (goods.type === 'link') {
|
|
|
- const toast = Toast.loading(500);
|
|
|
+ const toast = lastFrameSrc !== goods.value ? Toast.loading(500) : void 0;
|
|
|
+ lastFrameSrc = goods.value;
|
|
|
panelConfig.goods = goods;
|
|
|
panelConfig.onComplete = () => {
|
|
|
- toast.close();
|
|
|
+ toast?.close();
|
|
|
panelConfig.height = panelConfig.anchors[panelConfig.anchors.length - 1];
|
|
|
};
|
|
|
panelConfig.onError = () => {
|
|
|
Toast.error(`链接加载错误`)
|
|
|
panelConfig.height = 0;
|
|
|
};
|
|
|
+ if (!toast) setTimeout(panelConfig.onComplete, 100);
|
|
|
+ } else if (goods.type === 'miniprogram') {
|
|
|
+ return openGoodsScan(goods);
|
|
|
} else {
|
|
|
Toast.warning(`暂不支持该操作 (${goods.type})`);
|
|
|
return;
|
|
|
@@ -89,13 +95,37 @@ async function openGoodsPanel(goods: SchemeGoodsProps, event?: Event | string) {
|
|
|
const height = window.innerHeight * 0.8;
|
|
|
panelConfig.anchors = [0, height];
|
|
|
panelConfig.height = height;
|
|
|
- panelConfig.fullHeight = window.innerHeight;
|
|
|
+ panelConfig.fullHeight = window.innerHeight - (pageHeader.value?.getBoundingClientRect().height ?? 0);
|
|
|
}
|
|
|
}
|
|
|
+const qrConfig = reactive({
|
|
|
+ size: 300,
|
|
|
+ margin: 2,
|
|
|
+ background: '#0f2925',
|
|
|
+ foreground: '#38ff6e',
|
|
|
+});
|
|
|
+const scanConfig = reactive({
|
|
|
+ show: false,
|
|
|
+ title: '微信扫一扫购买',
|
|
|
+ mode: 'img' as 'img' | 'qr',
|
|
|
+ url: '',
|
|
|
+});
|
|
|
+async function openGoodsScan(goods: SchemeGoodsProps) {
|
|
|
+ if (goods.type === 'link') {
|
|
|
+ scanConfig.mode = 'qr';
|
|
|
+ } else if (goods.type === 'miniprogram') {
|
|
|
+ scanConfig.mode = 'img';
|
|
|
+ } else {
|
|
|
+ Toast.warning(`暂不支持该操作 (${goods.type})`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ scanConfig.url = goods.value;
|
|
|
+ scanConfig.show = true;
|
|
|
+}
|
|
|
</script>
|
|
|
<template>
|
|
|
<div>
|
|
|
- <div class="page-header flex py-4 px-4">
|
|
|
+ <div ref="page-header" class="page-header flex py-4 px-4">
|
|
|
<div class="grow shrink-0 h-full min-w-16"></div>
|
|
|
<div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
|
|
|
<div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
|
|
|
@@ -145,7 +175,7 @@ async function openGoodsPanel(goods: SchemeGoodsProps, event?: Event | string) {
|
|
|
</div>
|
|
|
|
|
|
<PreviewLinkSlot v-slot="{ src, complete, error }">
|
|
|
- <iframe v-if="src" :src="src" @load="complete!" @error="error!"></iframe>
|
|
|
+ <iframe v-if="src" :src="src" :style="{ maxHeight: panelConfig.height - 30 + 'px' }" @load="complete!" @error="error!"></iframe>
|
|
|
</PreviewLinkSlot>
|
|
|
<van-floating-panel
|
|
|
ref="panel-wrapper-ref"
|
|
|
@@ -157,13 +187,27 @@ async function openGoodsPanel(goods: SchemeGoodsProps, event?: Event | string) {
|
|
|
>
|
|
|
<template #header>
|
|
|
<div class="van-floating-panel__header !justify-between">
|
|
|
- <div></div>
|
|
|
+ <div><van-icon class="pl-2" name="qr" @click="panelConfig.height = 0;openGoodsScan(panelConfig.goods)" /></div>
|
|
|
<div class="van-floating-panel__header-bar"></div>
|
|
|
<van-icon class="pr-2" name="cross" @click="panelConfig.height = 0" />
|
|
|
</div>
|
|
|
</template>
|
|
|
<ReusePreviewLink v-if="panelConfig.goods?.type === 'link'" :src="panelConfig.goods?.value" :complete="panelConfig.onComplete"></ReusePreviewLink>
|
|
|
</van-floating-panel>
|
|
|
+ <van-dialog
|
|
|
+ v-model:show="scanConfig.show"
|
|
|
+ :title="scanConfig.title"
|
|
|
+ cancel-button-text="好的"
|
|
|
+ show-cancel-button
|
|
|
+ :show-confirm-button="false"
|
|
|
+ close-on-click-overlay
|
|
|
+ >
|
|
|
+ <div class="scan-content">
|
|
|
+ <qrcode-vue v-if="scanConfig.mode === 'qr'" :value="scanConfig.url" v-bind="qrConfig"></qrcode-vue>
|
|
|
+ <img v-else-if="scanConfig.mode === 'img'" :src="scanConfig.url" alt="二维码">
|
|
|
+ <div v-else>{{ scanConfig.url }}</div>
|
|
|
+ </div>
|
|
|
+ </van-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
<style scoped lang="scss">
|
|
|
@@ -198,6 +242,17 @@ async function openGoodsPanel(goods: SchemeGoodsProps, event?: Event | string) {
|
|
|
--van-floating-panel-border-radius: 0;
|
|
|
}
|
|
|
|
|
|
+.scan-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ img {
|
|
|
+ padding: 10px 0;
|
|
|
+ object-fit: scale-down;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.has-link {
|
|
|
display: flex;
|
|
|
justify-content: center;
|