alipay-emulator/components/balance-list/balance-list.vue

254 lines
5.1 KiB
Vue

<template>
<view class="balance-list-container">
<view>
<view v-for="item in props.list" :key="item.name" class="balance-item"
:class="{ 'flex-align-center': isBalance }" @click="onClick(item)"
@touchstart="handleTouchStart($event, item)" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
<image class="img" :src="item.imgUrl" mode="aspectFill"></image>
<view class="balance-item-text-container">
<view class="balance-item-text flex-align-center">
<view class="name" :class="{ 'line-height-51rpx': isBalance }">
{{ item.name }}
</view>
<view class="money alipay-font"
:class="item.isAdd ? (isBalance ? 'add-color' : 'red-add-color') : 'minus-color', { 'line-height-51rpx': isBalance }">
{{ item.isAdd ? '+' : '-' }}{{ Number(item.money).toFixed(2) }}
</view>
</view>
<view class="balance-item-text flex-align-center text-right" :class="{ 'flex-between': isBalance }">
<view class="left">
<view v-if="!isBalance" class="bill-classify" :class="{ 'item-box': !isBalance }"
style="display: flex; align-items: center;">
<text v-if="item.classification" class="time secondary">{{ item.classification }}</text>
<view
v-if="item.merchantOption && item.merchantOption.tag && item.merchantOption.tag.length > 0"
class="tag-container" style="display: flex; margin-left: 12rpx;">
<view v-for="(tag, index) in item.merchantOption.tag.slice(0, 2)" :key="index"
class="tag-item">
{{ tag }}
</view>
<view v-if="item.merchantOption.tag.length > 2" class="text-omit">...</view>
</view>
</view>
<view class="time-box" :class="{ 'item-box': !isBalance }">
<text class="time secondary wx-font-regular">{{ item.time }}</text>
</view>
</view>
<view class="right">
<view v-if="item.isRefund" class="refund" :class="{ 'item-box': !isBalance }">已全额退款</view>
<view v-if="isBalance" class="balance secondary" :class="{ 'item-box': !isBalance }">余额
<text class="balance-text wx-font-regular">{{
Number(item.balance).toFixed(2)
}}</text>元
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
onMounted,
reactive
} from 'vue'
// 定义组件属性
const props = defineProps({
list: {
type: Array,
default: () => []
},
isBalance: {
type: Boolean,
default: true
}
})
// 定义事件
const emit = defineEmits(['onBill', 'longPress'])
const data = reactive({})
let timer = null
let isLongPressTriggered = false
let touchStartX = 0
let touchStartY = 0
const handleTouchStart = (e, item) => {
isLongPressTriggered = false
if (e.touches && e.touches.length > 0) {
touchStartX = e.touches[0].clientX
touchStartY = e.touches[0].clientY
}
timer = setTimeout(() => {
isLongPressTriggered = true
emit('longPress', {
event: e,
item
})
}, 1500)
}
const handleTouchMove = (e) => {
if (e.touches && e.touches.length > 0) {
const moveX = e.touches[0].clientX
const moveY = e.touches[0].clientY
// If moved significantly, cancel long press
if (Math.abs(moveX - touchStartX) > 10 || Math.abs(moveY - touchStartY) > 10) {
clearTimeout(timer)
}
} else {
clearTimeout(timer)
}
}
const handleTouchEnd = () => {
clearTimeout(timer)
}
const onClick = (item) => {
if (isLongPressTriggered) return
emit('onBill', item)
}
onMounted(() => { })
</script>
<style>
@import '../../common/main.css';
</style>
<style lang="less">
.balance-list-container {
width: 100%;
}
.balance-item {
display: flex;
width: 100%;
flex-direction: row;
padding: 0;
.balance-item-text-container {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 12px;
position: relative;
padding: 12px 12px 12px 0;
&::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 3px;
background-color: #F0F0EE;
transform: scaleY(0.1);
transform-origin: 0 100%;
}
}
.img {
margin: 12px 0;
width: 30px;
height: 30px;
border-radius: 50%;
margin-left: 12px;
}
.balance-item-text {
display: flex;
justify-content: space-between;
text-align: left;
.name {
font-size: 28rpx;
color: #343434;
line-height: 20px;
}
.line-height-51rpx {
line-height: 51rpx;
}
.secondary {
color: var(--text-secondary);
font-size: 24rpx;
}
.money {
font-size: 17px;
font-weight: 500;
line-height: 20px;
}
.add-color {
color: #F6610F;
}
.red-add-color {
color: #F53646;
}
.minus-color {
color: #333333;
}
.balance-text {
margin-right: 2px;
}
.bill-classify {
text-align: left;
}
.item-box {
margin-top: 14rpx;
}
.tag-container {
display: flex;
align-items: flex-end;
.text-omit {
color: #969696;
font-size: 24rpx;
}
}
}
.refund {
color: #EA6B48;
margin-top: 14rpx;
font-size: 12px;
}
.text-right {
align-items: flex-start;
}
.tag-item {
background-color: #E6F2FF;
color: #2788D1;
font-size: 22rpx;
padding: 4rpx 8rpx;
border-radius: 4rpx;
margin-right: 8rpx;
}
}
</style>