Files
YGChatCS/src/pages-order/order/components/OrderQrcode/index.vue
2026-03-16 22:28:24 +08:00

242 lines
7.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<uni-popup
ref="popupRef"
type="bottom"
:safe-area="false"
@maskClick="handleClose"
@change="handlePopupChange"
>
<view class="refund-popup bg-F5F7FA border-box">
<view class="border-box flex flex-items-center justify-between pt-12 pb-12 relative">
<view class="flex flex-col flex-items-center flex-full ">
<view class="flex-full font-size-16 text-color-900 text-center">核销凭证</view>
<view class="flex-full font-size-12 text-color-600 text-center mt-4">请向工作人员出示此码</view>
</view>
<!-- 关闭按钮 -->
<uni-icons class="close absolute" type="close" size="20" color="#CACFD8" @click="handleClose" />
</view>
<view class="bg-white border-box rounded-12 flex flex-col flex-items-center flex-justify-center p-12 mb-12 mx-12">
<view class="flex w-full flex-row flex-items-center flex-justify-between py-4">
<view >
<view class="font-size-16 font-500 color-000 line-height-24 ellipsis-1">
{{ selectedVoucher.name }}
</view>
</view>
<view v-if="selectedVoucher" class="flex flex-row">
<view class="bg-F5F7FA text-color-600 font-size-12 p-4 rounded-4 mr-4">总计{{ selectedVoucher.count }}{{ selectedVoucher.unit }}
</view>
<view class="bg-theme-color-50 theme-color-500 font-size-12 p-4 rounded-4">{{ selectedVoucher.count - selectedVoucher.writeOffCount }}{{ selectedVoucher.unit }}可用</view>
</view>
</view>
<view class="flex flex-col w-full flex-items-center flex-justify-center border-box rounded-8 border pt-16 pb-32 mt-12">
<view class="flex flex-row flex-justify-between border-box w-full px-12">
<view class="bg-theme-color-50 theme-color-500 font-size-14 px-12 line-height-24 rounded-12">凭证{{ selectedVoucherList.length > 1 ? currentVoucherIndex + 1 : '' }}</view>
<view class="text-color-500 font-size-14 px-12 line-height-24 rounded-12">此码仅可核销{{ selectedVoucher.count - selectedVoucher.writeOffCount }}</view>
</view>
<view class="flex flex-items-center flex-justify-center mt-20 p-20 rounded-12 border borderColor"
:style="{ borderColor: selectedVoucher?.color }">
<Qrcode v-if="showQrcode" :size="props.size" :unit="props.unit" :val="qrcodeVal" :loadMake="true"
:onval="true" />
</view>
<view v-if="false" class="mt-20 bg-theme-color-50 theme-color-500 font-size-14 px-12 line-height-24 rounded-12">
{{ selectedVoucher.name }}
</view>
</view>
<view v-if="selectedVoucherList.length > 1" class="flex flex-row w-full flex-items-center flex-justify-between mt-16 mb-24">
<view class="actions-btn" @click.stop="upAction">
<uni-icons type="left" size="16" color="#171717" />
</view>
<view class="flex flex-col">
<view class="flex flex-row flex-justify-center flex-items-center">
<view class="theme-color-500 font-size-16">{{ currentVoucherIndex + 1 }}</view>
<view class="text-color-600 font-size-12">/{{ selectedVoucherList.length }}</view>
</view>
<view class="text-color-600 font-size-14">扫码后点击下一张</view>
</view>
<view class="actions-btn" @click.stop="downAction">
<uni-icons type="right" size="16" color="#171717" />
</view>
</view>
<view v-else class="mb-24"></view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import Qrcode from "@/components/Qrcode/index.vue";
import { defineProps, defineEmits } from "vue";
import { ref, watch, computed, nextTick } from "vue";
const props = defineProps({
// 弹窗显示状态
modelValue: {
type: Boolean,
default: false,
},
orderData: {
type: Object,
required: true,
default: () => ({}),
},
selectedVoucher: {
type: Object,
required: false,
default: null,
},
selectedVoucherIndex: {
type: Number,
required: false,
default: 0,
},
size: {
type: Number,
default: 132,
},
unit: {
type: String,
default: "px",
},
});
// Events定义
const emit = defineEmits(["close", "update:modelValue", "update:selectedVoucherIndex"]);
// 弹窗引用
const popupRef = ref(null);
// 控制二维码渲染
const showQrcode = ref(false);
// 当前选择的凭证索引
const currentVoucherIndex = ref(props.selectedVoucherIndex || 0);
const selectedVoucherList = computed(() => {
const list = props.orderData?.commodityPackageConfig || [];
if (!Array.isArray(list)) return [];
return list.filter((item) => item?.packageStatus === 0);
});
// 二维码内容
const selectedVoucher = computed(() => {
const list = selectedVoucherList.value || [];
if (!list.length) return null;
const idx = Math.min(Math.max(Number(currentVoucherIndex.value || 0), 0), list.length - 1);
return list[idx] || null;
});
const qrcodeVal = computed(() => {
const orderId = props.orderData?.orderId || "";
const voucherName = selectedVoucher.value?.name || "";
return orderId ? `${orderId}&${voucherName}` : "";
});
// 方法定义
const show = () => popupRef.value && popupRef.value.open();
const hide = () => popupRef.value && popupRef.value.close();
const handlePopupChange = ({ show }) => {
// popup 真实打开后再渲染二维码,避免 canvas 尺寸为 0 报错
if (show) {
nextTick(() => {
showQrcode.value = true;
});
} else {
showQrcode.value = false;
}
};
// 监听modelValue变化
watch(
() => props.modelValue,
(newVal) => {
if (newVal) {
showQrcode.value = false;
show();
} else {
showQrcode.value = false;
hide();
}
},
{ immediate: true }
);
// 同步外部 prop -> 内部 index初始化/外部变更)
watch(
() => props.selectedVoucherIndex,
(newIdx) => {
const len = selectedVoucherList.value.length;
let idx = Number(newIdx || 0);
if (len && idx >= len) idx = 0;
currentVoucherIndex.value = idx;
},
{ immediate: true }
);
// 当可用凭证列表变化时,确保 currentVoucherIndex 不越界
watch(
selectedVoucherList,
(list) => {
const len = list.length;
if (len === 0) {
if (currentVoucherIndex.value !== 0) {
currentVoucherIndex.value = 0;
}
return;
}
if (currentVoucherIndex.value >= len) {
currentVoucherIndex.value = 0;
}
},
{ immediate: true }
);
// 当内部索引变化时,通知父组件(避免无用循环)
watch(
() => currentVoucherIndex.value,
(val, oldVal) => {
if (val !== props.selectedVoucherIndex) {
emit("update:selectedVoucherIndex", val);
}
}
);
const handleClose = () => {
emit("update:modelValue", false);
emit("close");
};
const upAction = () => {
const len = selectedVoucherList.value.length;
if (!len) return;
let idx = Number(currentVoucherIndex.value || 0) - 1;
if (idx < 0) idx = len - 1;
currentVoucherIndex.value = idx;
};
const downAction = () => {
const len = selectedVoucherList.value.length;
if (!len) return;
let idx = Number(currentVoucherIndex.value || 0) + 1;
if (idx >= len) idx = 0;
currentVoucherIndex.value = idx;
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>