438 lines
11 KiB
Vue
438 lines
11 KiB
Vue
<template>
|
|
<view class="batch-container">
|
|
<common-header title="批量返利" theme="rebate" @back="goBack" />
|
|
|
|
<view class="batch-content">
|
|
<view class="batch-actions">
|
|
<uni-button type="primary" size="small" @click="selectAll">全选</uni-button>
|
|
<uni-button type="default" size="small" @click="clearSelection">清空</uni-button>
|
|
<uni-button type="primary" size="small" @click="batchApprove" :disabled="selectedRebates.length === 0">
|
|
批量审批 ({{ selectedRebates.length }})
|
|
</uni-button>
|
|
<uni-button type="warn" size="small" @click="batchReject" :disabled="selectedRebates.length === 0">
|
|
批量拒绝 ({{ selectedRebates.length }})
|
|
</uni-button>
|
|
</view>
|
|
|
|
<view class="filter-section">
|
|
<uni-search-bar
|
|
v-model="searchText"
|
|
placeholder="搜索返利记录"
|
|
@confirm="searchRebates"
|
|
@clear="clearSearch" />
|
|
</view>
|
|
|
|
<scroll-view
|
|
class="scroll-view"
|
|
scroll-y
|
|
:refresher-enabled="true"
|
|
:refresher-triggered="refreshing"
|
|
@refresherrefresh="onRefresh"
|
|
@scrolltolower="onLoadMore">
|
|
|
|
<view v-if="!loading && rebateList.length === 0" class="empty-state">
|
|
<uni-icons type="wallet" size="80" color="#ddd" />
|
|
<text class="empty-text">暂无返利记录</text>
|
|
</view>
|
|
|
|
<view v-else class="rebate-list">
|
|
<view
|
|
v-for="(item, index) in rebateList"
|
|
:key="item.id || index"
|
|
class="rebate-item"
|
|
:class="{ 'selected': selectedRebates.includes(item.id) }"
|
|
@click="toggleSelection(item.id)">
|
|
|
|
<view class="item-checkbox">
|
|
<uni-icons
|
|
:type="selectedRebates.includes(item.id) ? 'checkbox-filled' : 'checkbox'"
|
|
size="20"
|
|
:color="selectedRebates.includes(item.id) ? '#ff9500' : '#ccc'" />
|
|
</view>
|
|
|
|
<view class="item-content">
|
|
<view class="item-header">
|
|
<text class="user-name">{{ item.userName }}</text>
|
|
<text class="amount">¥{{ item.amount || 0 }}</text>
|
|
</view>
|
|
|
|
<view class="item-info">
|
|
<text class="order-no">订单: {{ item.orderNo || '无' }}</text>
|
|
<text class="rebate-type">{{ getTypeText(item.type) }}</text>
|
|
</view>
|
|
|
|
<view class="item-footer">
|
|
<text class="rebate-time">{{ formatTime(item.rebateTime) }}</text>
|
|
<view class="status-badge" :class="{
|
|
'pending': item.status === 0,
|
|
'approved': item.status === 1,
|
|
'paid': item.status === 2,
|
|
'rejected': item.status === 3
|
|
}">
|
|
{{ getStatusText(item.status) }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<uni-load-more
|
|
:status="loadStatus"
|
|
:content-text="loadText"
|
|
@clickLoadMore="onLoadMore" />
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import CommonHeader from '@/components/common-header/common-header.vue'
|
|
|
|
export default {
|
|
name: 'RebateBatch',
|
|
components: {
|
|
CommonHeader
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
rebateList: [],
|
|
selectedRebates: [],
|
|
loading: false,
|
|
refreshing: false,
|
|
searchText: '',
|
|
page: 1,
|
|
pageSize: 20,
|
|
hasMore: true,
|
|
loadStatus: 'more',
|
|
loadText: {
|
|
contentdown: '上拉加载更多',
|
|
contentrefresh: '正在加载...',
|
|
contentnomore: '没有更多了'
|
|
}
|
|
}
|
|
},
|
|
|
|
onLoad() {
|
|
this.loadRebateList()
|
|
},
|
|
|
|
methods: {
|
|
async loadRebateList(isRefresh = false) {
|
|
if (isRefresh) {
|
|
this.page = 1
|
|
this.hasMore = true
|
|
}
|
|
|
|
if (!this.hasMore && !isRefresh) return
|
|
|
|
this.loading = true
|
|
this.loadStatus = 'loading'
|
|
|
|
try {
|
|
const params = {
|
|
page: this.page,
|
|
pageSize: this.pageSize,
|
|
search: this.searchText
|
|
}
|
|
|
|
// TODO: Replace with actual API call
|
|
const response = await this.$http.get('/brewery/rebate', { params })
|
|
const { list, total } = response.data || {}
|
|
|
|
if (isRefresh) {
|
|
this.rebateList = list || []
|
|
this.selectedRebates = []
|
|
} else {
|
|
this.rebateList = [...this.rebateList, ...(list || [])]
|
|
}
|
|
|
|
this.hasMore = this.rebateList.length < total
|
|
this.loadStatus = this.hasMore ? 'more' : 'noMore'
|
|
|
|
} catch (error) {
|
|
console.error('加载返利列表失败:', error)
|
|
this.$modal.showToast('加载失败')
|
|
this.loadStatus = 'more'
|
|
} finally {
|
|
this.loading = false
|
|
this.refreshing = false
|
|
}
|
|
},
|
|
|
|
onRefresh() {
|
|
this.refreshing = true
|
|
this.loadRebateList(true)
|
|
},
|
|
|
|
onLoadMore() {
|
|
if (this.hasMore && !this.loading) {
|
|
this.page++
|
|
this.loadRebateList()
|
|
}
|
|
},
|
|
|
|
searchRebates() {
|
|
this.loadRebateList(true)
|
|
},
|
|
|
|
clearSearch() {
|
|
this.searchText = ''
|
|
this.loadRebateList(true)
|
|
},
|
|
|
|
toggleSelection(rebateId) {
|
|
const index = this.selectedRebates.indexOf(rebateId)
|
|
if (index > -1) {
|
|
this.selectedRebates.splice(index, 1)
|
|
} else {
|
|
this.selectedRebates.push(rebateId)
|
|
}
|
|
},
|
|
|
|
selectAll() {
|
|
// 只选择待审批的返利
|
|
this.selectedRebates = this.rebateList.filter(item => item.status === 0).map(item => item.id)
|
|
},
|
|
|
|
clearSelection() {
|
|
this.selectedRebates = []
|
|
},
|
|
|
|
batchApprove() {
|
|
if (this.selectedRebates.length === 0) {
|
|
this.$modal.showToast('请先选择返利记录')
|
|
return
|
|
}
|
|
|
|
uni.showModal({
|
|
title: '确认审批',
|
|
content: `确定要批量审批选中的 ${this.selectedRebates.length} 个返利记录吗?`,
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
this.doBatchApprove()
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
async doBatchApprove() {
|
|
try {
|
|
// TODO: Replace with actual API call
|
|
const response = await this.$http.post('/brewery/rebate/batch-approve', {
|
|
rebateIds: this.selectedRebates
|
|
})
|
|
|
|
this.$modal.showToast('批量审批成功')
|
|
this.clearSelection()
|
|
this.loadRebateList(true)
|
|
} catch (error) {
|
|
console.error('批量审批失败:', error)
|
|
this.$modal.showToast('批量审批失败')
|
|
}
|
|
},
|
|
|
|
batchReject() {
|
|
if (this.selectedRebates.length === 0) {
|
|
this.$modal.showToast('请先选择返利记录')
|
|
return
|
|
}
|
|
|
|
uni.showModal({
|
|
title: '确认拒绝',
|
|
content: `确定要批量拒绝选中的 ${this.selectedRebates.length} 个返利记录吗?`,
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
this.doBatchReject()
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
async doBatchReject() {
|
|
try {
|
|
// TODO: Replace with actual API call
|
|
const response = await this.$http.post('/brewery/rebate/batch-reject', {
|
|
rebateIds: this.selectedRebates
|
|
})
|
|
|
|
this.$modal.showToast('批量拒绝成功')
|
|
this.clearSelection()
|
|
this.loadRebateList(true)
|
|
} catch (error) {
|
|
console.error('批量拒绝失败:', error)
|
|
this.$modal.showToast('批量拒绝失败')
|
|
}
|
|
},
|
|
|
|
getStatusText(status) {
|
|
const statusMap = {
|
|
0: '待审批',
|
|
1: '已审批',
|
|
2: '已支付',
|
|
3: '已拒绝'
|
|
}
|
|
return statusMap[status] || '未知'
|
|
},
|
|
|
|
getTypeText(type) {
|
|
const typeMap = {
|
|
order: '订单返利',
|
|
referral: '推荐返利',
|
|
loyalty: '忠诚返利',
|
|
promotion: '促销返利',
|
|
other: '其他返利'
|
|
}
|
|
return typeMap[type] || '未知'
|
|
},
|
|
|
|
formatTime(time) {
|
|
if (!time) return ''
|
|
return time.substring(0, 16)
|
|
},
|
|
|
|
goBack() {
|
|
uni.navigateBack()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.batch-container {
|
|
min-height: 100vh;
|
|
background: #f5f7fa;
|
|
}
|
|
|
|
.batch-content {
|
|
padding: 20rpx;
|
|
}
|
|
|
|
.batch-actions {
|
|
display: flex;
|
|
gap: 20rpx;
|
|
margin-bottom: 20rpx;
|
|
padding: 20rpx;
|
|
background: #fff;
|
|
border-radius: 16rpx;
|
|
}
|
|
|
|
.filter-section {
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.scroll-view {
|
|
height: calc(100vh - 280rpx);
|
|
}
|
|
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 120rpx 0;
|
|
|
|
.empty-text {
|
|
font-size: 28rpx;
|
|
color: #999;
|
|
margin-top: 20rpx;
|
|
}
|
|
}
|
|
|
|
.rebate-list {
|
|
.rebate-item {
|
|
display: flex;
|
|
align-items: center;
|
|
background: #fff;
|
|
border-radius: 16rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
|
|
|
&.selected {
|
|
background: #fff7e6;
|
|
border: 2rpx solid #ff9500;
|
|
}
|
|
|
|
.item-checkbox {
|
|
margin-right: 20rpx;
|
|
}
|
|
|
|
.item-content {
|
|
flex: 1;
|
|
|
|
.item-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 12rpx;
|
|
|
|
.user-name {
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.amount {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #ff9500;
|
|
}
|
|
}
|
|
|
|
.item-info {
|
|
margin-bottom: 12rpx;
|
|
|
|
.order-no {
|
|
display: block;
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
margin-bottom: 4rpx;
|
|
}
|
|
|
|
.rebate-type {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
|
|
.item-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
|
|
.rebate-time {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
|
|
.status-badge {
|
|
padding: 6rpx 12rpx;
|
|
border-radius: 16rpx;
|
|
font-size: 22rpx;
|
|
|
|
&.pending {
|
|
background: #fff2e8;
|
|
color: #fa8c16;
|
|
}
|
|
|
|
&.approved {
|
|
background: #e6f7ff;
|
|
color: #1890ff;
|
|
}
|
|
|
|
&.paid {
|
|
background: #e8f5e8;
|
|
color: #52c41a;
|
|
}
|
|
|
|
&.rejected {
|
|
background: #ffebee;
|
|
color: #f44336;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |