|
@@ -0,0 +1,421 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="hb-list">
|
|
|
|
|
+ <view class="hb-tabs">
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="hb-tab"
|
|
|
|
|
+ :class="{ active: tabIndex == index }"
|
|
|
|
|
+ v-for="(item, index) in tabs"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ @tap="changeTab(index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <text class="tab-name">{{ item.name }}</text>
|
|
|
|
|
+ <text class="tab-count">{{ item.value }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <scroll-view
|
|
|
|
|
+ scroll-y="true"
|
|
|
|
|
+ class="hb-scroll"
|
|
|
|
|
+ :style="{ height: scrollHeight }"
|
|
|
|
|
+ :scroll-top="scrollTop"
|
|
|
|
|
+ :lower-threshold="50"
|
|
|
|
|
+ @scrolltolower="loadMore"
|
|
|
|
|
+ >
|
|
|
|
|
+ <block v-if="hbData.length > 0">
|
|
|
|
|
+ <view class="hb-table">
|
|
|
|
|
+ <view class="hb-card" v-for="(item, index) in hbData" :key="index">
|
|
|
|
|
+ <view class="card-header">
|
|
|
|
|
+ <view class="user-info">
|
|
|
|
|
+ <text class="name">{{ item.customName }}</text>
|
|
|
|
|
+ <text class="amount">¥ {{ item.amountText }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="status" :class="item.statusClass">{{ item.statusText }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="card-body">
|
|
|
|
|
+ <view class="row">开始时间:{{ item.beginTimeText }}</view>
|
|
|
|
|
+ <view class="row">到期时间:{{ item.endTimeText }}</view>
|
|
|
|
|
+ <view class="row">有效时长:{{ item.durationText }}</view>
|
|
|
|
|
+ <view class="row">最低消费:{{ item.minConsumeText }}</view>
|
|
|
|
|
+ <view class="row">获得方式:{{ item.getTypeText }}</view>
|
|
|
|
|
+ <view class="row">获得时间:{{ item.createdAtText }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="loading-more" v-if="loading && !finished">
|
|
|
|
|
+ <text class="loading-text">加载中...</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="no-more" v-if="finished">
|
|
|
|
|
+ <text class="no-more-text">没有更多数据了</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </block>
|
|
|
|
|
+ <block v-else>
|
|
|
|
|
+ <view class="empty-data">暂无数据</view>
|
|
|
|
|
+ </block>
|
|
|
|
|
+ </scroll-view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import { hbList } from '@/api/hb'
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: "hbList",
|
|
|
|
|
+ props: {
|
|
|
|
|
+ customId: {
|
|
|
|
|
+ type: [Number, String],
|
|
|
|
|
+ default: 0
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ tabIndex: 0,
|
|
|
|
|
+ scrollTop: 0,
|
|
|
|
|
+ scrollHeight: '600px',
|
|
|
|
|
+ hbData: [],
|
|
|
|
|
+ page: 1,
|
|
|
|
|
+ pageSize: 20,
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ finished: false,
|
|
|
|
|
+ tabs: [
|
|
|
|
|
+ { name: '全部', value: 0, status: '' },
|
|
|
|
|
+ { name: '待使用', value: 0, status: '0' },
|
|
|
|
|
+ { name: '已使用', value: 0, status: '1' },
|
|
|
|
|
+ { name: '已失效', value: 0, status: '-1' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ this.setScrollHeight()
|
|
|
|
|
+ },
|
|
|
|
|
+ watch: {
|
|
|
|
|
+ customId(newId, oldId) {
|
|
|
|
|
+ if (newId !== oldId) {
|
|
|
|
|
+ this.refresh()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ init() {},
|
|
|
|
|
+ setScrollHeight() {
|
|
|
|
|
+ const info = uni.getSystemInfoSync()
|
|
|
|
|
+ const tabHeight = uni.upx2px ? uni.upx2px(32) : 16
|
|
|
|
|
+ const height = Math.max(info.windowHeight - tabHeight, 100)
|
|
|
|
|
+ this.scrollHeight = height + 'px'
|
|
|
|
|
+ },
|
|
|
|
|
+ refresh() {
|
|
|
|
|
+ this.hbData = []
|
|
|
|
|
+ this.page = 1
|
|
|
|
|
+ this.finished = false
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ this.scrollTop = 0
|
|
|
|
|
+ if (!this.customId) {
|
|
|
|
|
+ this.resetTabs()
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.getHbList()
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ loadMore() {
|
|
|
|
|
+ if (!this.customId || this.finished || this.loading) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.getHbList()
|
|
|
|
|
+ },
|
|
|
|
|
+ changeTab(index) {
|
|
|
|
|
+ if (this.tabIndex == index) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.tabIndex = index
|
|
|
|
|
+ this.refresh()
|
|
|
|
|
+ },
|
|
|
|
|
+ async getHbList() {
|
|
|
|
|
+ if (this.loading) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ const status = this.tabs[this.tabIndex].status
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await hbList({
|
|
|
|
|
+ status: status,
|
|
|
|
|
+ page: this.page,
|
|
|
|
|
+ limit: this.pageSize,
|
|
|
|
|
+ customId: this.customId
|
|
|
|
|
+ })
|
|
|
|
|
+ this.setListData(res)
|
|
|
|
|
+ this.updateTabs(res)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ setListData(res) {
|
|
|
|
|
+ if (!res || res.code !== 1) {
|
|
|
|
|
+ this.finished = true
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = res.data || {}
|
|
|
|
|
+ const rows = data.list || data.data || []
|
|
|
|
|
+ const currentList = rows.map(item => this.normalizeItem(item))
|
|
|
|
|
+ this.hbData = this.page == 1 ? currentList : this.hbData.concat(currentList)
|
|
|
|
|
+ if (!data.moreData) {
|
|
|
|
|
+ this.finished = true
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.page++
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ normalizeItem(item) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ id: item.id,
|
|
|
|
|
+ customName: item.customName || '',
|
|
|
|
|
+ amountText: item.amount ? parseFloat(item.amount) : 0,
|
|
|
|
|
+ statusText: this.statusText(item.status),
|
|
|
|
|
+ statusClass: this.statusClass(item.status),
|
|
|
|
|
+ beginTimeText: this.formatDateTime(item.beginTime),
|
|
|
|
|
+ endTimeText: this.formatEndTime(item.endTime),
|
|
|
|
|
+ durationText: Number(item.duration) == 0 ? '永久' : item.duration + '天',
|
|
|
|
|
+ minConsumeText: this.formatMinConsume(item.minConsume),
|
|
|
|
|
+ getTypeText: this.formatGetType(item.getType),
|
|
|
|
|
+ createdAtText: this.formatCreatedAt(item.createdAt)
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ updateTabs(res) {
|
|
|
|
|
+ const data = res.data || {}
|
|
|
|
|
+ this.tabs[0].value = Number(data.all) || 0
|
|
|
|
|
+ this.tabs[1].value = Number(data.unUse) || 0
|
|
|
|
|
+ this.tabs[2].value = Number(data.used) || 0
|
|
|
|
|
+ this.tabs[3].value = Number(data.expired) || 0
|
|
|
|
|
+ },
|
|
|
|
|
+ resetTabs() {
|
|
|
|
|
+ this.tabs.forEach(item => {
|
|
|
|
|
+ item.value = 0
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ statusText(status) {
|
|
|
|
|
+ if (Number(status) == 0) return '待使用'
|
|
|
|
|
+ if (Number(status) == 1) return '已使用'
|
|
|
|
|
+ if (Number(status) == -1) return '已失效'
|
|
|
|
|
+ return '未知'
|
|
|
|
|
+ },
|
|
|
|
|
+ statusClass(status) {
|
|
|
|
|
+ if (Number(status) == 0) return 'status-wait'
|
|
|
|
|
+ if (Number(status) == 1) return 'status-used'
|
|
|
|
|
+ if (Number(status) == -1) return 'status-expired'
|
|
|
|
|
+ return ''
|
|
|
|
|
+ },
|
|
|
|
|
+ formatDateTime(inputTime) {
|
|
|
|
|
+ if (!inputTime) return ''
|
|
|
|
|
+ let date = new Date(inputTime)
|
|
|
|
|
+ if (/^\d{10}$/.test(String(inputTime))) {
|
|
|
|
|
+ date = new Date(inputTime * 1000)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNaN(date.getTime())) {
|
|
|
|
|
+ return ''
|
|
|
|
|
+ }
|
|
|
|
|
+ const y = date.getFullYear()
|
|
|
|
|
+ let m = date.getMonth() + 1
|
|
|
|
|
+ m = m < 10 ? '0' + m : m
|
|
|
|
|
+ let d = date.getDate()
|
|
|
|
|
+ d = d < 10 ? '0' + d : d
|
|
|
|
|
+ let h = date.getHours()
|
|
|
|
|
+ h = h < 10 ? '0' + h : h
|
|
|
|
|
+ let minute = date.getMinutes()
|
|
|
|
|
+ minute = minute < 10 ? '0' + minute : minute
|
|
|
|
|
+ return y + '-' + m + '-' + d + ' ' + h + ':' + minute
|
|
|
|
|
+ },
|
|
|
|
|
+ formatEndTime(endTime) {
|
|
|
|
|
+ if (Number(endTime) == 4102416000) {
|
|
|
|
|
+ return '永久有效'
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.formatDateTime(endTime)
|
|
|
|
|
+ },
|
|
|
|
|
+ formatMinConsume(minConsume) {
|
|
|
|
|
+ if (Number(minConsume) == 0) {
|
|
|
|
|
+ return '无门槛'
|
|
|
|
|
+ }
|
|
|
|
|
+ return (minConsume ? parseFloat(minConsume) : 0) + '元'
|
|
|
|
|
+ },
|
|
|
|
|
+ formatCreatedAt(createdAt) {
|
|
|
|
|
+ if (!createdAt) return ''
|
|
|
|
|
+ return String(createdAt).substr(0, 16)
|
|
|
|
|
+ },
|
|
|
|
|
+ formatGetType(type) {
|
|
|
|
|
+ const typeMap = {
|
|
|
|
|
+ 0: '新人领取',
|
|
|
|
|
+ 1: '门店发放',
|
|
|
|
|
+ 2: '充值赠送'
|
|
|
|
|
+ }
|
|
|
|
|
+ return typeMap[Number(type)] || '未知方式'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.hb-list {
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ max-height: 100vh;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ background: #f5f5f5;
|
|
|
|
|
+
|
|
|
|
|
+ .hb-tabs {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-bottom: 1upx solid #eeeeee;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .hb-tab {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 32upx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ border-right: 1upx solid #eeeeee;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ border-right: none;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ color: #09C567;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ background: #f3fff8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tab-name {
|
|
|
|
|
+ font-size: 10upx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tab-count {
|
|
|
|
|
+ min-width: 14upx;
|
|
|
|
|
+ height: 14upx;
|
|
|
|
|
+ line-height: 14upx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ margin-left: 4upx;
|
|
|
|
|
+ padding: 0 4upx;
|
|
|
|
|
+ border-radius: 7upx;
|
|
|
|
|
+ background: #f1f1f1;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ font-size: 8upx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.active .tab-count {
|
|
|
|
|
+ background: #09C567;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .hb-scroll {
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .empty-data {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 20upx 0;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ font-size: 10upx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .loading-more,
|
|
|
|
|
+ .no-more {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 10upx 0;
|
|
|
|
|
+
|
|
|
|
|
+ .loading-text,
|
|
|
|
|
+ .no-more-text {
|
|
|
|
|
+ font-size: 8upx;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.hb-table {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ padding: 5upx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.hb-card {
|
|
|
|
|
+ margin-bottom: 8upx;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 6upx;
|
|
|
|
|
+ box-shadow: 0 1upx 4upx #0000000D;
|
|
|
|
|
+ border: 1upx solid #f0f0f0;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .card-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ padding: 8upx 10upx;
|
|
|
|
|
+ border-bottom: 1upx solid #f5f5f5;
|
|
|
|
|
+
|
|
|
|
|
+ .user-info {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+
|
|
|
|
|
+ .name {
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ font-size: 10upx;
|
|
|
|
|
+ margin-right: 6upx;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .amount {
|
|
|
|
|
+ color: #f56c6c;
|
|
|
|
|
+ font-size: 12upx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .status {
|
|
|
|
|
+ font-size: 9upx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ margin-left: 6upx;
|
|
|
|
|
+
|
|
|
|
|
+ &.status-wait {
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.status-used {
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.status-expired {
|
|
|
|
|
+ color: #f56c6c;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .card-body {
|
|
|
|
|
+ padding: 8upx 10upx;
|
|
|
|
|
+
|
|
|
|
|
+ .row {
|
|
|
|
|
+ font-size: 9upx;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ line-height: 1.45;
|
|
|
|
|
+ margin-bottom: 4upx;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|