Add min-w-0, w-full, and block classes to flex child elements and text nodes across various UI components to ensure text truncation works correctly. Remove outdated hardcoded card item width styles from global SCSS and replace them with inline responsive width classes where appropriate.
247 lines
7.4 KiB
Vue
247 lines
7.4 KiB
Vue
<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 items-center justify-between pt-[12px] pb-[12px] relative">
|
||
<view class="flex flex-col items-center flex-1 ">
|
||
<view class="flex-1 text-[16px] text-[#0B5C2D] text-center">核销凭证</view>
|
||
<view class="flex-1 text-[12px] text-[#02C34E] text-center mt-[4px]">请向工作人员出示此码</view>
|
||
</view>
|
||
<!-- 关闭按钮 -->
|
||
<uni-icons class="close absolute" type="close" size="20" color="#CACFD8" @click="handleClose" />
|
||
</view>
|
||
|
||
<view class="bg-white rounded-[12px] flex flex-col items-center justify-center p-[12px] mb-[12px] mx-[12px]">
|
||
|
||
<view class="flex w-full flex-row items-center justify-between py-[4px]">
|
||
<view class="min-w-0 flex-1">
|
||
<view class="w-full text-[16px] font-[500] text-[#000000] leading-[24px] truncate">
|
||
{{ selectedVoucher.name }}
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="selectedVoucher" class="flex flex-row">
|
||
<view class="bg-[#f5f7fa] text-[#02C34E] text-[12px] p-[4px] rounded-[4px] mr-[4px]">总计{{
|
||
selectedVoucher.count
|
||
}}{{
|
||
selectedVoucher.unit }}
|
||
</view>
|
||
<view class="bg-[#F0F8F3] text-[#0CCD58] text-[12px] p-[4px] rounded-[4px]">剩{{ selectedVoucher.count -
|
||
selectedVoucher.writeOffCount }}{{ selectedVoucher.unit }}可用</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view
|
||
class="flex flex-col w-full items-center justify-center rounded-[8px] border border-[#e5e8ee] pt-[16px] pb-[32px] mt-[12px]">
|
||
<view class="flex flex-row justify-between w-full px-[12px]">
|
||
<view class="bg-[#F0F8F3] text-[#0CCD58] text-[14px] px-[12px] leading-[24px] rounded-[12px]">凭证{{
|
||
selectedVoucherList.length > 1 ? currentVoucherIndex + 1 : '' }}</view>
|
||
<view class="text-[#0CCD58] text-[14px] px-[12px] leading-[24px] rounded-[12px]">此码仅可核销{{
|
||
selectedVoucher.count
|
||
-
|
||
selectedVoucher.writeOffCount }}份</view>
|
||
</view>
|
||
|
||
<view class="flex items-center justify-center mt-[20px] p-[20px] rounded-[12px] border border-[#e5e8ee]"
|
||
: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-[20px] bg-[#F0F8F3] text-[#0CCD58] text-[14px] px-[12px] leading-[24px] rounded-[12px]">
|
||
{{ selectedVoucher.name }}
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="selectedVoucherList.length > 1"
|
||
class="flex flex-row w-full items-center justify-between mt-[16px] mb-[24px]">
|
||
<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 justify-center items-center">
|
||
<view class="theme-color-500 text-[16px]">{{ currentVoucherIndex + 1 }}</view>
|
||
<view class="text-[#02C34E] text-[12px]">/{{ selectedVoucherList.length }}</view>
|
||
</view>
|
||
|
||
<view class="text-[#02C34E] text-[14px]">扫码后点击下一张</view>
|
||
</view>
|
||
|
||
<view class="actions-btn" @click.stop="downAction">
|
||
<uni-icons type="right" size="16" color="#171717" />
|
||
</view>
|
||
</view>
|
||
<view v-else class="mb-[24px]"></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>
|