| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- <template>
- <view class="finance-container">
- <view class="finance-stats">
- <view class="stat-card">
- <text class="stat-title">今日营收</text>
- <text class="stat-value">¥{{ formatAmount(todayRevenue || 0) }}</text>
- <view class="stat-change" :class="getChangeClass(todayRevenueChange)">
- <AppIcon :name="todayRevenueChange >= 0 ? 'arrow-up' : 'arrow-down'" :size="22" :color="todayRevenueChange >= 0 ? '#52C41A' : '#F44336'" />
- <text>{{ Math.abs(todayRevenueChange) }}%</text>
- </view>
- </view>
- <view class="stat-card">
- <text class="stat-title">本月营收</text>
- <text class="stat-value">¥{{ formatAmount(monthRevenue || 0) }}</text>
- <view class="stat-change" :class="getChangeClass(monthRevenueChange)">
- <AppIcon :name="monthRevenueChange >= 0 ? 'arrow-up' : 'arrow-down'" :size="22" :color="monthRevenueChange >= 0 ? '#52C41A' : '#F44336'" />
- <text>{{ Math.abs(monthRevenueChange) }}%</text>
- </view>
- </view>
- <view class="stat-card">
- <text class="stat-title">待提现金额</text>
- <text class="stat-value">¥{{ formatAmount(pendingWithdraw || 0) }}</text>
- <text class="stat-footnote">站点待提现</text>
- </view>
- <view class="stat-card">
- <text class="stat-title">累计分账</text>
- <text class="stat-value">¥{{ formatAmount(totalSplitAmount || 0) }}</text>
- <text class="stat-footnote">平台分账总额</text>
- </view>
- </view>
- <!-- 快捷功能入口 -->
- <view class="finance-menu">
- <view class="menu-item" @click="navigateTo('/pages/finance/withdraw')">
- <AppIcon name="credit-card" :size="40" color="#C6171E" class="menu-icon" />
- <text class="menu-title">提现管理</text>
- <AppIcon name="chevron-right" :size="28" color="#B0B0B0" />
- </view>
- <view class="menu-item" @click="navigateTo('/pages/finance/refund')">
- <AppIcon name="rotate-ccw" :size="40" color="#C6171E" class="menu-icon" />
- <text class="menu-title">退款清单</text>
- <AppIcon name="chevron-right" :size="28" color="#B0B0B0" />
- </view>
- <view class="menu-item" @click="navigateTo('/pages/finance/settlement')">
- <AppIcon name="clipboard" :size="40" color="#C6171E" class="menu-icon" />
- <text class="menu-title">结算记录</text>
- <AppIcon name="chevron-right" :size="28" color="#B0B0B0" />
- </view>
- <view class="menu-item" @click="navigateTo('/pages/finance/split-record')">
- <AppIcon name="trending-up" :size="40" color="#C6171E" class="menu-icon" />
- <text class="menu-title">分账记录</text>
- <AppIcon name="chevron-right" :size="28" color="#B0B0B0" />
- </view>
- </view>
- <view class="finance-tabs">
- <view class="segmented-control">
- <view
- v-for="(option, index) in tabOptions"
- :key="index"
- class="segment-item"
- :class="{ 'active': activeTab === index }"
- @click="activeTab = index; handleTabChange(index)"
- >
- <text>{{ option }}</text>
- </view>
- </view>
- </view>
-
- <view class="finance-content">
- <!-- 站点账户列表 -->
- <view v-if="activeTab === 0" class="account-list">
- <view
- v-for="account in stationAccounts"
- :key="account.id"
- class="account-item"
- >
- <view class="account-header">
- <view class="account-info">
- <text class="station-name">{{ account.stationName }}</text>
- <text class="station-id">站点ID: {{ account.stationId }}</text>
- </view>
- <view class="account-balance">
- <text class="balance-label">账户余额:</text>
- <text class="balance-value">¥{{ formatAmount(account.balance || 0) }}</text>
- </view>
- </view>
- <view class="account-content">
- <view class="account-stats">
- <view class="stat-column">
- <text class="stat-period">今日营收</text>
- <text class="stat-amount">¥{{ formatAmount(account.todayRevenue || 0) }}</text>
- </view>
- <view class="stat-column">
- <text class="stat-period">本月营收</text>
- <text class="stat-amount">¥{{ formatAmount(account.monthRevenue || 0) }}</text>
- </view>
- <view class="stat-column">
- <text class="stat-period">累计营收</text>
- <text class="stat-amount">¥{{ formatAmount(account.totalRevenue || 0) }}</text>
- </view>
- </view>
- <button class="withdraw-btn" @click="navigateToWithdraw(account)">
- 提现管理
- </button>
- </view>
- </view>
- </view>
-
- <!-- 分账记录列表 -->
- <view v-else-if="activeTab === 1" class="split-list">
- <view
- v-for="record in splitRecords"
- :key="record.id"
- class="split-item"
- >
- <view class="split-header">
- <view class="split-info">
- <text class="split-no">分账编号: {{ record.splitNo }}</text>
- <text class="split-time">{{ formatTime(record.createTime) }}</text>
- </view>
- <view class="split-amount">
- <text class="amount-label">分账金额:</text>
- <text class="amount-value">¥{{ formatAmount(record.amount || 0) }}</text>
- </view>
- </view>
- <view class="split-content">
- <view class="split-detail">
- <text class="detail-label">分账类型:</text>
- <text class="detail-value">{{ getSplitTypeText(record.splitType) }}</text>
- </view>
- <view class="split-detail">
- <text class="detail-label">站点名称:</text>
- <text class="detail-value">{{ record.stationName || '平台' }}</text>
- </view>
- <view class="split-detail">
- <text class="detail-label">分账状态:</text>
- <text class="detail-value" :style="getSplitStatusStyle(record.status)">
- {{ getSplitStatusText(record.status) }}
- </text>
- </view>
- </view>
- </view>
- </view>
- </view>
-
- <view class="empty-state" v-if="(stationAccounts.length === 0 && activeTab === 0) || (splitRecords.length === 0 && activeTab === 1)">
- <view class="empty-icon-wrapper"><AppIcon name="inbox" :size="80" color="#B0B0B0" /></view>
- <text>暂无数据</text>
- </view>
-
- <!-- 加载指示器 -->
- <view class="loading-overlay" v-if="loading">
- <view class="loading-spinner"></view>
- </view>
- </view>
- </template>
- <script setup>
- import { ref, onMounted } from 'vue'
- import { getStationAccounts, getSplitRecords } from '../../api/finance.js'
- import { getDashboardData } from '../../api/stat.js'
- import { formatTime, showToast, formatAmount, storage, fmtDictName, getDictColor } from '../../utils/index.js'
- import { loadDicts } from '../../utils/dict.js'
- const activeTab = ref(0)
- const tabOptions = ['站点账户', '分账记录']
- // 真实数据
- const todayRevenue = ref(0.00)
- const monthRevenue = ref(0.00)
- const pendingWithdraw = ref(0.00)
- const totalSplitAmount = ref(0.00)
- // 环比变化
- const todayRevenueChange = ref(0.0)
- const monthRevenueChange = ref(0.0)
- const loading = ref(false)
- // 数据列表
- const stationAccounts = ref([])
- const splitRecords = ref([])
- onMounted(async () => {
- await loadDicts()
- loadFinanceData()
- loadStationAccounts()
- loadSplitRecords()
- })
- // 加载财务概览数据
- const loadFinanceData = async () => {
- loading.value = true
- try {
- // 使用仪表盘API获取财务数据
- const res = await getDashboardData()
- if (res && res.code === 200) {
- const data = res.data
- todayRevenue.value = data.todayIncome || 0.00
- monthRevenue.value = data.monthIncome || 0.00
- // 其他财务数据可能需要调用专门的API获取
- }
- } catch (error) {
- showToast('加载财务数据失败')
- } finally {
- loading.value = false
- }
- }
- const loadStationAccounts = async () => {
- loading.value = true
- try {
- const res = await getStationAccounts({ page: 1, pageSize: 10 })
-
- if (res && res.code === 200) {
- const data = res.data
- // 适配不同的数据结构
- stationAccounts.value = data.records || data.list || data
- }
- } catch (error) {
- showToast('获取站点账户失败')
- } finally {
- loading.value = false
- }
- }
- const loadSplitRecords = async () => {
- loading.value = true
- try {
- const res = await getSplitRecords({ page: 1, pageSize: 10 })
-
- if (res && res.code === 200) {
- const data = res.data
- // 适配不同的数据结构
- splitRecords.value = data.records || data.list || data
- }
- } catch (error) {
- showToast('获取分账记录失败')
- } finally {
- loading.value = false
- }
- }
- const handleTabChange = (index) => {
- activeTab.value = index
- }
- const navigateToWithdraw = (account) => {
- uni.navigateTo({
- url: `/pages/finance/withdraw?stationId=${account.stationId}&stationName=${account.stationName}`
- })
- }
- const navigateTo = (url) => {
- uni.navigateTo({ url })
- }
- const getChangeClass = (change) => {
- return change >= 0 ? 'change-up' : 'change-down'
- }
- const getSplitTypeText = (type) => {
- return fmtDictName('SplitRecord.type', type)
- }
- // 从字典获取分账状态文本
- const getSplitStatusText = (status) => {
- return fmtDictName('SplitRecord.status', status)
- }
- // 从字典获取分账状态内联样式
- const getSplitStatusStyle = (status) => {
- const color = getDictColor('SplitRecord.status', status)
- if (color) {
- return {
- color: color,
- backgroundColor: `${color}1A`
- }
- }
- return {}
- }
- </script>
- <style scoped>
- .finance-container {
- padding: 30rpx;
- background-color: #F5F7FA;
- min-height: 100vh;
- box-sizing: border-box;
- padding-bottom: 120rpx;
- }
- /* 财务概览卡片 */
- .finance-stats {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: 20rpx;
- margin-bottom: 30rpx;
- }
- .stat-card {
- background-color: #FFFFFF;
- padding: 30rpx;
- border-radius: 24rpx;
- text-align: center;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
- transition: all 0.3s;
- }
- .stat-card:active {
- transform: translateY(-4rpx);
- box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
- }
- .stat-title {
- font-size: 24rpx;
- color: #999999;
- margin-bottom: 16rpx;
- display: block;
- }
- .stat-value {
- font-size: 40rpx;
- font-weight: 700;
- color: #1A1A1A;
- margin-bottom: 12rpx;
- display: block;
- }
- .stat-change {
- font-size: 24rpx;
- font-weight: 600;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 4rpx;
- }
- .change-up {
- color: #52C41A;
- }
- .change-down {
- color: #F44336;
- }
- .stat-footnote {
- font-size: 22rpx;
- color: #B0B0B0;
- display: block;
- }
- /* 快捷功能入口 */
- .finance-menu {
- background-color: #FFFFFF;
- border-radius: 24rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
- margin-bottom: 30rpx;
- overflow: hidden;
- }
- .menu-item {
- display: flex;
- align-items: center;
- padding: 28rpx 30rpx;
- border-bottom: 1rpx solid #F0F0F0;
- }
- .menu-item:last-child {
- border-bottom: none;
- }
- .menu-item:active {
- background-color: #F5F7FA;
- }
- .menu-icon {
- margin-right: 20rpx;
- }
- .menu-title {
- flex: 1;
- font-size: 28rpx;
- color: #1A1A1A;
- font-weight: 500;
- }
- /* 切换标签 */
- .finance-tabs {
- background-color: #FFFFFF;
- padding: 20rpx;
- border-radius: 24rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
- margin-bottom: 30rpx;
- }
- .segmented-control {
- display: flex;
- width: 100%;
- border-radius: 16rpx;
- overflow: hidden;
- background-color: #F5F5F5;
- padding: 6rpx;
- gap: 6rpx;
- }
- .segment-item {
- flex: 1;
- text-align: center;
- padding: 16rpx 0;
- font-size: 26rpx;
- color: #666666;
- transition: all 0.3s;
- border-radius: 12rpx;
- font-weight: 500;
- }
- .segment-item.active {
- color: #FFFFFF;
- font-weight: 600;
- background: #C6171E;
- box-shadow: 0 4rpx 12rpx rgba(198, 23, 30, 0.3);
- }
- /* 内容区域 */
- .finance-content {
- background-color: #FFFFFF;
- border-radius: 24rpx;
- padding: 30rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
- }
- /* 空状态 */
- .empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 120rpx 0;
- color: #999999;
- text-align: center;
- }
- .empty-state text {
- margin-top: 16rpx;
- font-size: 28rpx;
- display: block;
- }
- /* 加载状态 */
- .loading-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.4);
-
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 999;
- }
- .loading-spinner {
- width: 60rpx;
- height: 60rpx;
- border: 4rpx solid rgba(255, 255, 255, 0.3);
- border-top-color: #FFFFFF;
- border-radius: 50%;
- animation: spin 0.8s linear infinite;
- }
- /* ===== 站点账户列表 ===== */
- .account-list {
- max-height: 1000rpx;
- overflow-y: auto;
- }
- .account-item {
- padding: 30rpx 0;
- border-bottom: 2rpx solid #F0F0F0;
- }
- .account-item:last-child {
- border-bottom: none;
- }
- .account-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 24rpx;
- }
- .account-info {
- flex: 1;
- }
- .station-name {
- font-size: 32rpx;
- font-weight: 600;
- color: #1A1A1A;
- margin-bottom: 12rpx;
- display: block;
- }
- .station-id {
- font-size: 24rpx;
- color: #999999;
- display: block;
- }
- .account-balance {
- text-align: right;
- }
- .balance-label {
- font-size: 24rpx;
- color: #999999;
- margin-bottom: 12rpx;
- display: block;
- }
- .balance-value {
- font-size: 40rpx;
- font-weight: 700;
- color: #52C41A;
- display: block;
- }
- .account-content {
- display: flex;
- align-items: center;
- gap: 20rpx;
- }
- .account-stats {
- flex: 1;
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 20rpx;
- padding: 20rpx;
- background: rgba(0, 0, 0, 0.02);
- border-radius: 12rpx;
- }
- .stat-column {
- text-align: center;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 8rpx;
- }
- .stat-period {
- font-size: 22rpx;
- color: #999999;
- display: block;
- }
- .stat-amount {
- font-size: 28rpx;
- font-weight: 600;
- color: #1A1A1A;
- display: block;
- }
- .withdraw-btn {
- padding: 20rpx 32rpx;
- background: #C6171E;
- color: #FFFFFF;
- border: none;
- border-radius: 16rpx;
- font-size: 26rpx;
- font-weight: 500;
- white-space: nowrap;
- transition: all 0.3s;
- }
- .withdraw-btn:active {
- transform: scale(0.95);
- opacity: 0.9;
- }
- /* ===== 分账记录列表 ===== */
- .split-list {
- max-height: 1000rpx;
- overflow-y: auto;
- }
- .split-item {
- padding: 30rpx 0;
- border-bottom: 2rpx solid #F0F0F0;
- }
- .split-item:last-child {
- border-bottom: none;
- }
- .split-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 24rpx;
- }
- .split-info {
- flex: 1;
- }
- .split-no {
- font-size: 28rpx;
- font-weight: 600;
- color: #1A1A1A;
- margin-bottom: 12rpx;
- display: block;
- }
- .split-time {
- font-size: 24rpx;
- color: #999999;
- }
- .split-amount {
- text-align: right;
- }
- .amount-label {
- font-size: 24rpx;
- color: #999999;
- margin-bottom: 12rpx;
- display: block;
- }
- .amount-value {
- font-size: 40rpx;
- font-weight: 700;
- color: #C6171E;
- }
- .split-content {
- display: flex;
- flex-direction: column;
- gap: 12rpx;
- padding-top: 16rpx;
- }
- .split-detail {
- display: flex;
- align-items: center;
- font-size: 26rpx;
- }
- .detail-label {
- color: #999999;
- width: 160rpx;
- flex-shrink: 0;
- }
- .detail-value {
- color: #1A1A1A;
- font-weight: 500;
- }
- </style>
|