Files
ss-tiku-manage-h5/src/pages/exception/profit.vue
2026-01-30 14:08:23 +08:00

748 lines
16 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
<view class="profit-exception-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">分润异常提醒</view>
<view class="header-right" @click="refreshData">
<view class="refresh-btn">刷新</view>
</view>
</view>
<!-- 异常统计 -->
<view class="stats-section">
<view class="stats-grid">
<view class="stat-card">
<view class="stat-icon">💰</view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.total }}</view>
<view class="stat-label">总异常数</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.pending }}</view>
<view class="stat-label">待处理</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.resolved }}</view>
<view class="stat-label">已解决</view>
</view>
</view>
</view>
</view>
<!-- 异常列表 -->
<view class="exception-section">
<view class="section-header">
<view class="section-title">异常列表</view>
<view class="filter-box">
<view class="filter-tabs">
<view
v-for="tab in filterTabs"
:key="tab.value"
class="filter-tab"
:class="{ active: currentFilter === tab.value }"
@click="currentFilter = tab.value"
>
{{ tab.label }}
</view>
</view>
</view>
</view>
<view class="exception-list">
<view
v-for="exception in filteredExceptions"
:key="exception.id"
class="exception-item"
:class="{ 'pending': exception.status === 'pending', 'resolved': exception.status === 'resolved' }"
@click="viewExceptionDetail(exception.id)"
>
<view class="exception-header">
<view class="exception-title">{{ exception.title }}</view>
<view class="exception-status">{{ getStatusText(exception.status) }}</view>
</view>
<view class="exception-content">
<view class="exception-desc">{{ exception.description }}</view>
<view class="exception-info">
<view class="info-item">
<view class="info-label">关联账户</view>
<view class="info-value">{{ exception.accountName }}</view>
</view>
<view class="info-item">
<view class="info-label">异常金额</view>
<view class="info-value">{{ exception.amount }}</view>
</view>
<view class="info-item">
<view class="info-label">异常时间</view>
<view class="info-value">{{ exception.createTime }}</view>
</view>
</view>
</view>
<view class="exception-actions">
<view
v-if="exception.status === 'pending'"
class="action-btn primary"
@click.stop="resolveException(exception.id)"
>
处理
</view>
<view
class="action-btn secondary"
@click.stop="viewExceptionDetail(exception.id)"
>
详情
</view>
</view>
</view>
<view v-if="filteredExceptions.length === 0" class="empty-state">
<view class="empty-icon">📭</view>
<view class="empty-text">暂无相关异常</view>
</view>
</view>
</view>
<!-- 操作提示 -->
<view class="tips-section">
<view class="tips-title">操作提示</view>
<view class="tips-content">
<view class="tip-item"> 账户余额不足时系统会暂停分润发放</view>
<view class="tip-item"> 请及时充值以确保分润正常发放</view>
<view class="tip-item"> 处理异常后系统会自动重试分润发放</view>
<view class="tip-item"> 如遇持续异常请联系平台客服</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 异常统计
const exceptionStats = ref({
total: 5,
pending: 2,
resolved: 3
})
// 异常列表
const exceptions = ref([
{
id: 1,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 1250.00,
status: 'pending',
createTime: '2026-01-29 10:15:30'
},
{
id: 2,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 890.50,
status: 'pending',
createTime: '2026-01-29 09:45:12'
},
{
id: 3,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 678.20,
status: 'resolved',
createTime: '2026-01-28 16:30:45'
},
{
id: 4,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 1560.80,
status: 'resolved',
createTime: '2026-01-28 14:20:18'
},
{
id: 5,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 980.00,
status: 'resolved',
createTime: '2026-01-28 11:05:33'
}
])
// 过滤标签
const filterTabs = ref([
{ label: '全部', value: 'all' },
{ label: '待处理', value: 'pending' },
{ label: '已解决', value: 'resolved' }
])
const currentFilter = ref('all')
// 过滤后的异常列表
const filteredExceptions = computed(() => {
if (currentFilter.value === 'all') {
return exceptions.value
}
return exceptions.value.filter(exception => exception.status === currentFilter.value)
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 刷新数据
function refreshData() {
uni.showLoading({ title: '刷新中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '刷新成功', icon: 'success' })
}, 1000)
}
// 获取状态文本
function getStatusText(status) {
switch (status) {
case 'pending':
return '待处理'
case 'resolved':
return '已解决'
default:
return '未知'
}
}
// 查看异常详情
function viewExceptionDetail(exceptionId) {
uni.navigateTo({
url: `/pages/exception/profit-detail?id=${exceptionId}`
})
}
// 处理异常
function resolveException(exceptionId) {
uni.showModal({
title: '处理异常',
content: '是否确认处理该异常?\n\n处理后系统会自动重试分润发放',
success: function(res) {
if (res.confirm) {
uni.showLoading({ title: '处理中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '处理成功', icon: 'success' })
// 更新异常状态
const exception = exceptions.value.find(e => e.id === exceptionId)
if (exception) {
exception.status = 'resolved'
// 更新统计数据
exceptionStats.value.pending--
exceptionStats.value.resolved++
}
}, 1500)
}
}
})
}
onMounted(() => {
// 实际项目中应从接口获取异常数据
// fetchExceptionData()
})
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.profit-exception-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.refresh-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 异常统计 */
.stats-section {
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.stats-grid {
display: flex;
justify-content: space-between;
gap: 16rpx;
}
.stat-card {
flex: 1;
display: flex;
align-items: center;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
}
.stat-icon {
font-size: 48rpx;
margin-right: 24rpx;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 24rpx;
color: #606266;
}
/* 异常列表 */
.exception-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.filter-tabs {
display: flex;
gap: 16rpx;
}
.filter-tab {
padding: 12rpx 24rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
font-size: 24rpx;
color: #606266;
cursor: pointer;
}
.filter-tab.active {
background-color: #409eff;
color: #fff;
}
.exception-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.exception-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
transition: all 0.3s ease;
}
.exception-item.pending {
border-left: 8rpx solid #f56c6c;
}
.exception-item.resolved {
border-left: 8rpx solid #67c23a;
}
.exception-item:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.exception-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.exception-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.exception-status {
padding: 8rpx 16rpx;
border-radius: 8rpx;
font-size: 20rpx;
font-weight: 600;
}
.exception-item.pending .exception-status {
background-color: #fef0f0;
color: #f56c6c;
}
.exception-item.resolved .exception-status {
background-color: #f0f9eb;
color: #67c23a;
}
.exception-content {
margin-bottom: 20rpx;
}
.exception-desc {
font-size: 24rpx;
color: #606266;
margin-bottom: 16rpx;
line-height: 1.4;
}
.exception-info {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.info-item {
display: flex;
align-items: center;
}
.info-label {
font-size: 22rpx;
color: #909399;
margin-right: 8rpx;
}
.info-value {
font-size: 22rpx;
font-weight: 600;
color: #303133;
}
.exception-actions {
display: flex;
gap: 16rpx;
justify-content: flex-end;
}
.action-btn {
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 24rpx;
font-weight: 600;
cursor: pointer;
}
.action-btn.primary {
background-color: #409eff;
color: #fff;
}
.action-btn.secondary {
background-color: #f9f9f9;
color: #606266;
border: 1rpx solid #e4e7ed;
}
/* 操作提示 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
text-align: center;
}
.empty-icon {
font-size: 100rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.profit-exception-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.stats-section {
margin: 32rpx;
padding: 40rpx;
}
.exception-section {
margin: 0 32rpx 24rpx;
padding: 40rpx;
}
.tips-section {
margin: 0 32rpx 32rpx;
padding: 40rpx;
}
.page-header {
padding: 0 48rpx;
}
.header-title {
font-size: 36rpx;
}
.refresh-btn {
font-size: 30rpx;
}
.stats-grid {
gap: 24rpx;
}
.stat-card {
padding: 32rpx;
}
.stat-icon {
font-size: 56rpx;
margin-right: 32rpx;
}
.stat-value {
font-size: 36rpx;
}
.stat-label {
font-size: 26rpx;
}
.section-title {
font-size: 36rpx;
}
.filter-tab {
padding: 16rpx 32rpx;
font-size: 26rpx;
}
.exception-item {
padding: 32rpx;
}
.exception-title {
font-size: 32rpx;
}
.exception-status {
padding: 12rpx 24rpx;
font-size: 22rpx;
}
.exception-desc {
font-size: 26rpx;
}
.info-label {
font-size: 24rpx;
}
.info-value {
font-size: 24rpx;
}
.action-btn {
padding: 16rpx 32rpx;
font-size: 26rpx;
}
.tips-title {
font-size: 32rpx;
}
.tips-content {
font-size: 26rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.profit-exception-container {
max-width: 1000px;
}
.header-title {
font-size: 40rpx;
}
.refresh-btn {
font-size: 32rpx;
}
.stat-icon {
font-size: 64rpx;
}
.stat-value {
font-size: 40rpx;
}
.stat-label {
font-size: 28rpx;
}
.section-title {
font-size: 40rpx;
}
.filter-tab {
font-size: 28rpx;
}
.exception-title {
font-size: 34rpx;
}
.exception-desc {
font-size: 28rpx;
}
.info-label {
font-size: 26rpx;
}
.info-value {
font-size: 26rpx;
}
.action-btn {
font-size: 28rpx;
}
.tips-title {
font-size: 34rpx;
}
.tips-content {
font-size: 28rpx;
}
}
</style>