This commit is contained in:
2026-02-03 21:35:57 +08:00
parent 93b42a277a
commit 3922409a25
105 changed files with 14758 additions and 5861 deletions

View File

@@ -0,0 +1,247 @@
<template>
<view class="finance-balance-record">
<!-- 筛选卡片 -->
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">订单时间:</text>
<view class="date-picker-wrap">
<text class="calendar-icon">📅</text>
<text class="date-placeholder">开始日期 - 结束日期</text>
</view>
</view>
<view class="filter-item">
<text class="filter-label">交易类型:</text>
<view class="select-box">
<text class="select-txt">请选择</text>
<text class="arrow-down">▼</text>
</view>
</view>
</view>
</view>
<!-- 列表表格 -->
<view class="table-container border-shadow">
<view class="table-header">
<view class="th col-id"><text class="th-txt">ID</text></view>
<view class="th col-order"><text class="th-txt">关联订单</text></view>
<view class="th col-time"><text class="th-txt">交易时间</text></view>
<view class="th col-amount"><text class="th-txt">交易金额</text></view>
<view class="th col-user"><text class="th-txt">用户</text></view>
<view class="th col-type"><text class="th-txt">交易类型</text></view>
<view class="th col-remark"><text class="th-txt">备注</text></view>
<view class="th col-op"><text class="th-txt">操作</text></view>
</view>
<scroll-view class="table-body">
<view class="table-row" v-for="item in tableData" :key="item.id">
<view class="td col-id"><text class="td-txt">{{ item.id }}</text></view>
<view class="td col-order text-left"><text class="td-txt">{{ item.order }}</text></view>
<view class="td col-time"><text class="td-txt">{{ item.time }}</text></view>
<view class="td col-amount">
<text :class="['td-txt', item.amount.startsWith('+') ? 'red-txt' : 'green-txt']">{{ item.amount }}</text>
</view>
<view class="td col-user"><text class="td-txt">{{ item.user }}</text></view>
<view class="td col-type"><text class="td-txt">{{ item.type }}</text></view>
<view class="td col-remark text-left"><text class="td-txt">{{ item.remark }}</text></view>
<view class="td col-op">
<text class="btn-link">备注</text>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
interface BalanceRecord {
id: string
order: string
time: string
amount: string
user: string
type: string
remark: string
}
const tableData = ref<BalanceRecord[]>([
{
id: '31216',
order: '新用户注册赠送余额',
time: '2026-02-03 10:30:11',
amount: '+ 88888.00',
user: '1',
type: '新用户注册赠送余额',
remark: '新用户注册赠送88888余额'
},
{
id: '31215',
order: '新用户注册赠送余额',
time: '2026-02-03 10:19:52',
amount: '+ 88888.00',
user: 'circus',
type: '新用户注册赠送余额',
remark: '新用户注册赠送88888余额'
},
{
id: '31214',
order: 'cp541560738494283776',
time: '2026-02-03 10:09:07',
amount: '- 999.00',
user: '1岁上班22岁退休',
type: '余额支付购买商品',
remark: '余额支付999.00元购买商品'
},
{
id: '31213',
order: '新用户注册赠送余额',
time: '2026-02-03 10:07:59',
amount: '+ 88888.00',
user: '1岁上班22岁退休',
type: '新用户注册赠送余额',
remark: '新用户注册赠送88888余额'
},
{
id: '31212',
order: '新用户注册赠送余额',
time: '2026-02-03 02:17:24',
amount: '+ 88888.00',
user: '136****0434',
type: '新用户注册赠送余额',
remark: '新用户注册赠送88888余额'
},
{
id: '31211',
order: '新用户注册赠送余额',
time: '2026-02-03 02:04:17',
amount: '+ 88888.00',
user: '灵境',
type: '新用户注册赠送余额',
remark: '新用户注册赠送88888余额'
},
{
id: '31210',
order: '新用户注册赠送余额',
time: '2026-02-03 00:58:21',
amount: '+ 88888.00',
user: 'J.',
type: '新用户注册赠送余额',
remark: '新用户注册赠送88888余额'
}
])
</script>
<style scoped lang="scss">
.finance-balance-record {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.filter-card { padding: 24px; margin-bottom: 20px; }
.filter-row { display: flex; flex-direction: row; align-items: center; }
.filter-item { display: flex; flex-direction: row; align-items: center; margin-right: 40px; }
.filter-label { font-size: 14px; color: #333; margin-right: 15px; }
.date-picker-wrap {
width: 260px;
height: 36px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.select-box {
width: 200px;
height: 36px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon { font-size: 14px; margin-right: 10px; color: #c0c4cc; }
.date-placeholder, .select-txt { font-size: 14px; color: #c0c4cc; }
.arrow-down { margin-left: auto; font-size: 10px; color: #c0c4cc; }
/* 表格样式 */
.table-container {
display: flex;
flex-direction: column;
min-height: 600px;
}
.table-header {
background-color: #e6f0ff;
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
padding: 4px 0;
}
.th {
padding: 12px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 13px;
font-weight: 500;
color: #606266;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
background-color: #fff;
}
.table-row:hover {
background-color: #f9f9f9;
}
.td {
padding: 16px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 13px;
color: #606266;
}
/* 列宽分配 (参考截图比例) */
.col-id { width: 70px; }
.col-order { flex: 1.5; min-width: 180px; justify-content: flex-start; }
.col-time { width: 160px; }
.col-amount { width: 120px; }
.col-user { width: 120px; }
.col-type { width: 150px; }
.col-remark { flex: 1.8; min-width: 200px; justify-content: flex-start; }
.col-op { width: 80px; }
.text-left { justify-content: flex-start; text-align: left; }
/* 颜色 */
.red-txt { color: #f56c6c; font-weight: 500; }
.green-txt { color: #67c23a; font-weight: 500; }
.btn-link { color: #1890ff; font-size: 13px; cursor: pointer; }
</style>

View File

@@ -0,0 +1,541 @@
<template>
<view class="finance-balance-stats">
<!-- 顶部数据统计卡片 (3列布局) -->
<view class="stats-grid">
<view class="stat-card border-shadow">
<view class="stat-icon-circle bg-blue">
<text class="icon-white">💰</text>
</view>
<view class="stat-content">
<text class="stat-value">1447117274.55</text>
<text class="stat-label">当前余额</text>
</view>
</view>
<view class="stat-card border-shadow">
<view class="stat-icon-circle bg-orange">
<text class="icon-white">🏦</text>
</view>
<view class="stat-content">
<text class="stat-value">1602611838.49</text>
<text class="stat-label">累计余额</text>
</view>
</view>
<view class="stat-card border-shadow">
<view class="stat-icon-circle bg-green">
<text class="icon-white">💳</text>
</view>
<view class="stat-content">
<text class="stat-value">155494563.94</text>
<text class="stat-label">累计消耗余额</text>
</view>
</view>
</view>
<!-- 时间筛选区 -->
<view class="filter-bar border-shadow">
<view class="filter-item">
<text class="filter-label">时间选择:</text>
<view class="date-picker-wrap">
<text class="calendar-icon">📅</text>
<text class="date-range">2026/01/05 - 2026/02/03</text>
</view>
</view>
</view>
<!-- 趋势图表区 (CRMEB 1:1) -->
<view class="chart-box border-shadow">
<view class="chart-header">
<text class="chart-title">余额使用趋势</text>
<view class="chart-legend">
<view class="legend-item">
<view class="dot blue-dot"></view>
<text class="legend-txt">余额积累</text>
</view>
<view class="legend-item">
<view class="dot green-dot"></view>
<text class="legend-txt">余额消耗</text>
</view>
</view>
<view class="chart-ops">
<text class="op-icon">📥</text>
</view>
</view>
<view class="main-chart-wrap">
<EChartsView v-if="trendOption != null" :option="trendOption" class="main-trend-chart" />
</view>
</view>
<!-- 底部双列分析 -->
<view class="bottom-analysis">
<view class="analysis-box border-shadow">
<view class="box-header">
<text class="box-title">余额来源分析</text>
<view class="btn-toggle" @click="toggleSourceStyle">
<text class="toggle-txt">切换样式</text>
</view>
</view>
<view class="chart-container">
<!-- 样式 0: 图表 -->
<EChartsView v-if="sourceStyleMode == 0 && sourceOption != null" :option="sourceOption" class="pie-chart" />
<!-- 样式 1: 列表 -->
<view v-if="sourceStyleMode == 1" class="stats-table">
<view class="table-header">
<text class="th col-idx">序号</text>
<text class="th col-name">来源</text>
<text class="th col-amount">金额</text>
<text class="th col-percent">占比率</text>
</view>
<scroll-view class="table-body">
<view class="table-row" v-for="(item, index) in sourceData" :key="index">
<text class="td col-idx">{{ index + 1 }}</text>
<text class="td col-name">{{ item.name }}</text>
<text class="td col-amount">{{ item.value.toFixed(2) }}</text>
<view class="td col-percent">
<view class="progress-container">
<view class="progress-bar" :style="{ width: item.percent + '%' }"></view>
</view>
<text class="percent-txt">{{ item.percent.toFixed(2) }}%</text>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
<view class="analysis-box border-shadow">
<view class="box-header">
<text class="box-title">余额消耗</text>
<view class="btn-toggle" @click="toggleConsumptionStyle">
<text class="toggle-txt">切换样式</text>
</view>
</view>
<view class="chart-container">
<!-- 样式 0: 图表 -->
<EChartsView v-if="consumptionStyleMode == 0 && consumptionOption != null" :option="consumptionOption" class="pie-chart" />
<!-- 样式 1: 列表 -->
<view v-if="consumptionStyleMode == 1" class="stats-table">
<view class="table-header">
<text class="th col-idx">序号</text>
<text class="th col-name">来源</text>
<text class="th col-amount">金额</text>
<text class="th col-percent">占比率</text>
</view>
<scroll-view class="table-body">
<view class="table-row" v-for="(item, index) in consumptionDataList" :key="index">
<text class="td col-idx">{{ index + 1 }}</text>
<text class="td col-name">{{ item.name }}</text>
<text class="td col-amount">{{ item.value.toFixed(2) }}</text>
<view class="td col-percent">
<view class="progress-container">
<view class="progress-bar" :style="{ width: item.percent + '%' }"></view>
</view>
<text class="percent-txt">{{ item.percent.toFixed(2) }}%</text>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted } from 'vue'
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
const trendOption = ref<any>(null)
const sourceOption = ref<any>(null)
const consumptionOption = ref<any>(null)
// 样式切换状态: 0=图表, 1=列表
const sourceStyleMode = ref(0)
const consumptionStyleMode = ref(0)
// 统计数据 (使用 ref 保证响应式)
const sourceData = ref([
{ value: 125000.00, name: '系统增加', percent: 40.00 },
{ value: 93750.00, name: '用户充值', percent: 30.00 },
{ value: 78125.00, name: '佣金提现', percent: 25.00 },
{ value: 62500.00, name: '抽奖赠送', percent: 20.00 },
{ value: 46875.00, name: '商品退款', percent: 15.00 }
])
const consumptionDataList = ref([
{ value: 435692.51, name: '购买商品', percent: 50.00 },
{ value: 8060.18, name: '购买会员', percent: 20.00 },
{ value: 0.00, name: '充值退款', percent: 15.00 },
{ value: 0.00, name: '系统减少', percent: 15.00 }
])
/**
* 转换 Plain Object 工具
*/
function toPlainObject(obj : any) : any {
if (obj == null) return null
if (typeof obj !== 'object') return obj
if (Array.isArray(obj)) {
return (obj as Array<any>).map((item : any) : any => toPlainObject(item))
}
const plain : Record<string, any> = {}
const keys = Object.keys(obj as Record<string, any>)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (key.startsWith('_') || key == 'toJSON') continue
const value = (obj as Record<string, any>)[key]
if (typeof value == 'function') continue
if (value != null && typeof value == 'object' && !Array.isArray(value)) {
plain[key] = toPlainObject(value)
} else {
plain[key] = value
}
}
return plain
}
onMounted(() => {
setTimeout(() => {
initTrendChart()
initSourceChart()
initConsumptionChart()
}, 300)
})
function initTrendChart() {
const dates = ['01-05', '01-06', '01-07', '01-08', '01-09', '01-10', '01-11', '01-12', '01-13', '01-14', '01-15', '01-16', '01-17', '01-18', '01-19', '01-20', '01-21', '01-22', '01-23', '01-24', '01-25', '01-26', '01-27', '01-28', '01-29', '01-30', '01-31', '02-01', '02-02', '02-03']
const accumulationData = [2500000, 2900000, 1500000, 2400000, 1800000, 1300000, 500000, 2100000, 3000000, 2800000, 2300000, 2200000, 1500000, 1100000, 2300000, 2800000, 2600000, 2700000, 1800000, 1950000, 650000, 1600000, 1750000, 2400000, 2600000, 2000000, 1400000, 550000, 2100000, 550000]
const consumptionData = [10000, 20000, 15000, 120000, 50000, 20000, 10000, 30000, 40000, 35000, 60000, 25000, 30000, 45000, 55000, 110000, 60000, 50000, 40000, 35000, 85000, 45000, 120000, 50000, 45000, 40000, 35000, 55000, 65000, 45000]
const option = {
grid: { left: '3%', right: '4%', bottom: '5%', top: '5%', containLabel: true },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
boundaryGap: false,
data: dates,
axisLine: { lineStyle: { color: '#f0f0f0' } },
axisLabel: { color: '#999', interval: 4 }
},
yAxis: {
type: 'value',
axisLine: { show: false },
splitLine: { lineStyle: { color: '#f5f5f5' } },
axisLabel: { color: '#999' }
},
series: [
{
name: '余额积累',
type: 'line',
smooth: true,
data: accumulationData,
itemStyle: { color: '#1890ff' }
},
{
name: '余额消耗',
type: 'line',
smooth: true,
data: consumptionData,
itemStyle: { color: '#52c41a' }
}
]
}
trendOption.value = toPlainObject(option)
}
function initSourceChart() {
const option = {
tooltip: { trigger: 'item', formatter: '{b}: {c}%' },
legend: { orient: 'vertical', right: '5%', top: 'center', itemWidth: 10, itemHeight: 10 },
color: ['#5b8ff9', '#5ad8a6', '#5d7092', '#f6bd16', '#e8684a'],
series: [
{
name: '余额来源',
type: 'pie',
radius: '70%',
center: ['40%', '50%'],
label: { show: true, fontSize: 11, formatter: '{b}\n{c}%' },
// 关键点:将图表数据映射到 percent 字段
data: sourceData.value.map(item => ({ value: item.percent, name: item.name }))
}
]
}
sourceOption.value = toPlainObject(option)
}
function initConsumptionChart() {
const option = {
tooltip: { trigger: 'item', formatter: '{b}: {c}%' },
legend: { orient: 'vertical', right: '5%', top: 'center', itemWidth: 10, itemHeight: 10 },
color: ['#5b8ff9', '#5ad8a6', '#5d7092', '#f6bd16'],
series: [
{
name: '余额消耗',
type: 'pie',
radius: '70%',
center: ['40%', '50%'],
label: { show: true, fontSize: 11, formatter: '{b}\n{c}%' },
// 关键点:将图表数据映射到 percent 字段
data: consumptionDataList.value.map(item => ({ value: item.percent, name: item.name }))
}
]
}
consumptionOption.value = toPlainObject(option)
}
function toggleSourceStyle() {
sourceStyleMode.value = sourceStyleMode.value === 0 ? 1 : 0
if (sourceStyleMode.value === 0) {
setTimeout(() => initSourceChart(), 50)
}
}
function toggleConsumptionStyle() {
consumptionStyleMode.value = consumptionStyleMode.value === 0 ? 1 : 0
if (consumptionStyleMode.value === 0) {
setTimeout(() => initConsumptionChart(), 50)
}
}
</script>
<style scoped lang="scss">
.finance-balance-stats {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
/* 顶部卡片 */
.stats-grid {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 20px;
}
.stat-card {
flex: 1;
margin: 0 10px;
padding: 24px 30px;
display: flex;
flex-direction: row;
align-items: center;
}
.stats-grid .stat-card:first-child { margin-left: 0; }
.stats-grid .stat-card:last-child { margin-right: 0; }
.stat-icon-circle {
width: 60px;
height: 60px;
border-radius: 30px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
}
.bg-blue { background-color: #40a9ff; }
.bg-orange { background-color: #ffa940; }
.bg-green { background-color: #73d13d; }
.icon-white { color: #fff; font-size: 24px; }
.stat-content {
display: flex;
flex-direction: column;
}
.stat-value {
font-size: 28px;
font-weight: 500;
color: #303133;
line-height: 1.2;
}
.stat-label {
font-size: 14px;
color: #909399;
margin-top: 4px;
}
/* 时间筛选区 */
.filter-bar {
padding: 16px 24px;
margin-bottom: 20px;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-label {
font-size: 14px;
color: #606266;
margin-right: 15px;
}
.date-picker-wrap {
width: 320px;
height: 36px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon { font-size: 14px; color: #c0c4cc; margin-right: 10px; }
.date-range { font-size: 14px; color: #606266; }
/* 趋势图表区 */
.chart-box {
padding: 24px;
margin-bottom: 20px;
}
.chart-header {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 30px;
}
.chart-title { font-size: 16px; font-weight: 600; color: #303133; margin-right: auto; }
.chart-legend {
display: flex;
flex-direction: row;
}
.legend-item { display: flex; flex-direction: row; align-items: center; margin-left: 20px; }
.legend-txt { font-size: 13px; color: #666; }
.dot { width: 10px; height: 10px; border-radius: 5px; margin-right: 8px; }
.blue-dot { background-color: #1890ff; }
.green-dot { background-color: #52c41a; }
.chart-ops { margin-left: 20px; }
.op-icon { font-size: 20px; color: #909399; }
.main-chart-wrap {
height: 400px;
width: 100%;
}
.main-trend-chart {
width: 100%;
height: 100%;
}
/* 底部分析 */
.bottom-analysis {
display: flex;
flex-direction: row;
margin: 0 -10px 40px -10px;
}
.analysis-box {
flex: 1;
margin: 0 10px;
padding: 24px;
}
.box-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.box-title { font-size: 15px; font-weight: 600; color: #303133; }
.btn-toggle {
padding: 4px 12px;
border: 1px solid #dcdfe6;
border-radius: 15px;
cursor: pointer;
}
.toggle-txt { font-size: 12px; color: #606266; }
.chart-container {
height: 300px;
width: 100%;
}
.pie-chart {
width: 100%;
height: 100%;
}
/* 列表样式 */
.stats-table {
display: flex;
flex-direction: column;
}
.table-header {
display: flex;
flex-direction: row;
background-color: #e6f0ff;
padding: 12px 0;
border-radius: 4px;
}
.th {
font-size: 13px;
color: #606266;
text-align: center;
font-weight: 500;
}
.table-row {
display: flex;
flex-direction: row;
padding: 15px 0;
border-bottom: 1px solid #f0f0f0;
align-items: center;
}
.td {
font-size: 13px;
color: #606266;
text-align: center;
}
.col-idx { width: 60px; }
.col-name { flex: 1; }
.col-amount { flex: 1.5; }
.col-percent { flex: 2; display: flex; flex-direction: row; align-items: center; justify-content: center; padding: 0 20px; }
.progress-container {
flex: 1;
height: 8px;
background-color: #f5f5f5;
border-radius: 4px;
margin-right: 10px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: #1890ff;
border-radius: 4px;
}
.percent-txt {
width: 60px;
font-size: 12px;
color: #666;
}
</style>

View File

@@ -0,0 +1,422 @@
<template>
<view class="finance-bill">
<!-- 头部筛选 -->
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">创建时间:</text>
<view class="date-picker-wrap">
<text class="calendar-icon">📅</text>
<text class="date-placeholder">开始日期 - 结束日期</text>
</view>
</view>
</view>
</view>
<!-- 内容区域 -->
<view class="content-card border-shadow">
<!-- 汇总选项卡 -->
<view class="tab-header">
<view class="tab-item active"><text class="tab-txt active-txt">日账单</text></view>
<view class="tab-item"><text class="tab-txt">周账单</text></view>
<view class="tab-item"><text class="tab-txt">月账单</text></view>
</view>
<!-- 表格区域 -->
<view class="table-container">
<view class="table-header">
<view class="th col-id"><text class="th-txt">ID</text></view>
<view class="th col-title"><text class="th-txt">标题</text></view>
<view class="th col-date"><text class="th-txt">日期</text></view>
<view class="th col-income"><text class="th-txt">收入金额</text></view>
<view class="th col-expense"><text class="th-txt">支出金额</text></view>
<view class="th col-entry"><text class="th-txt">入账金额</text></view>
<view class="th col-ops"><text class="th-txt">操作</text></view>
</view>
<view class="table-body">
<view class="table-row" v-for="item in tableData" :key="item.id">
<view class="td col-id"><text class="td-txt">{{ item.id }}</text></view>
<view class="td col-title text-left"><text class="td-txt">{{ item.title }}</text></view>
<view class="td col-date"><text class="td-txt">{{ item.date }}</text></view>
<view class="td col-income"><text class="td-txt red-txt">¥{{ item.income }}</text></view>
<view class="td col-expense"><text class="td-txt green-txt">¥{{ item.expense }}</text></view>
<view class="td col-entry"><text class="td-txt">¥{{ item.entry }}</text></view>
<view class="td col-ops">
<view class="ops-wrap">
<text class="op-link">账单详情</text>
<text class="op-divider">|</text>
<text class="op-link">下载</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
interface BillSumRecord {
id: number
title: string
date: string
income: string
expense: string
entry: string
}
const tableData = ref<BillSumRecord[]>([
{ id: 1, title: '日账单', date: '2026-02-03', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 2, title: '日账单', date: '2026-02-01', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 3, title: '日账单', date: '2026-01-30', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 4, title: '日账单', date: '2026-01-29', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 5, title: '日账单', date: '2026-01-28', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 6, title: '日账单', date: '2026-01-27', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 7, title: '日账单', date: '2026-01-26', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 8, title: '日账单', date: '2026-01-25', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 9, title: '日账单', date: '2026-01-23', income: '0.00', expense: '0.00', entry: '0.00' },
{ id: 10, title: '日账单', date: '2026-01-22', income: '0.00', expense: '0.00', entry: '0.00' }
])
</script>
<style scoped lang="scss">
.finance-bill {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
/* 筛选 */
.filter-card {
padding: 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 12px;
}
.date-picker-wrap {
width: 280px;
height: 36px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon {
font-size: 14px;
margin-right: 8px;
color: #c0c4cc;
}
.date-placeholder {
font-size: 14px;
color: #c0c4cc;
}
/* 内容卡片 */
.content-card {
padding: 0;
overflow: hidden;
}
.tab-header {
display: flex;
flex-direction: row;
padding: 0 20px;
border-bottom: 1px solid #f0f0f0;
}
.tab-item {
padding: 16px 20px;
cursor: pointer;
position: relative;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 20%;
right: 20%;
height: 2px;
background-color: #1890ff;
}
.tab-txt {
font-size: 14px;
color: #666;
}
.active-txt {
color: #1890ff;
font-weight: 500;
}
/* 表格样式 */
.table-container {
display: flex;
flex-direction: column;
}
.table-header {
background-color: #e6f0ff; /* 对应截图的淡蓝色背景 */
display: flex;
flex-direction: row;
}
.th {
padding: 14px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 14px;
font-weight: 600;
color: #303133;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
}
.table-row:hover {
background-color: #fafafa;
}
.td {
padding: 16px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 14px;
color: #606266;
}
/* 列宽分配 */
.col-id { width: 80px; }
.col-title { width: 150px; }
.col-date { width: 220px; }
.col-income { width: 180px; }
.col-expense { width: 180px; }
.col-entry { width: 180px; }
.col-ops { flex: 1; min-width: 150px; }
.text-left {
justify-content: flex-start;
}
/* 颜色 */
.red-txt {
color: #f5222d; /* 收入红色 */
}
.green-txt {
color: #52c41a; /* 支出绿色 */
}
/* 操作项 */
.ops-wrap {
display: flex;
flex-direction: row;
align-items: center;
}
.op-link {
font-size: 14px;
color: #1890ff;
cursor: pointer;
}
.op-divider {
margin: 0 8px;
color: #e8e8e8;
font-size: 12px;
}
</style>
<style scoped lang="scss">
.finance-bill {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.filter-card {
padding: 20px 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 28px;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 10px;
}
.date-picker-wrap, .select-box {
width: 200px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon {
font-size: 12px;
margin-right: 8px;
}
.date-placeholder, .select-txt {
font-size: 13px;
color: #606266;
}
.arrow-down {
margin-left: auto;
font-size: 8px;
color: #c0c4cc;
}
.btn-query, .btn-export {
height: 32px;
padding: 0 20px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 10px;
}
.btn-query {
background-color: #1890ff;
}
.btn-export {
background-color: #fff;
border: 1px solid #dcdfe6;
}
.btn-txt { color: #fff; font-size: 14px; }
.export-txt { color: #606266; font-size: 14px; }
/* 表格样式 */
.table-container {
display: flex;
flex-direction: column;
}
.table-header {
background-color: #f8f9fb;
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.th {
padding: 15px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 14px;
font-weight: 600;
color: #909399;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.td {
padding: 15px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 13px;
color: #606266;
}
.col-id { width: 100px; }
.col-title { width: 150px; }
.col-type { width: 120px; }
.col-amount { width: 120px; }
.col-time { width: 180px; }
.col-remark { flex: 1; min-width: 200px; }
.text-left { justify-content: flex-start; }
.type-tag {
font-size: 12px;
padding: 2px 8px;
border-radius: 2px;
}
.tag-green { background-color: #f0f9eb; color: #67c23a; border: 1px solid #e1f3d8; }
.tag-orange { background-color: #fdf6ec; color: #e6a23c; border: 1px solid #faecd8; }
.green-txt { color: #67c23a; }
.red-txt { color: #f56c6c; }
</style>

View File

@@ -0,0 +1,317 @@
<template>
<view class="finance-capital-flow">
<!-- 头部筛选区 -->
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">订单时间:</text>
<view class="date-picker-wrap">
<text class="calendar-icon">📅</text>
<text class="date-placeholder">开始日期 - 结束日期</text>
</view>
</view>
<view class="filter-item">
<text class="filter-label">交易类型:</text>
<view class="select-box">
<text class="select-txt">请选择</text>
<text class="arrow-down">▼</text>
</view>
</view>
<view class="filter-item search-wrap">
<text class="filter-label">流水搜索:</text>
<input class="search-input" placeholder="订单号/昵称/电话/用户ID" />
</view>
<view class="btn-query">
<text class="btn-txt">查询</text>
</view>
</view>
</view>
<!-- 数据表格 (Flex 模拟) -->
<view class="table-container border-shadow">
<view class="table-header">
<view class="th col-flow"><text class="th-txt">交易单号</text></view>
<view class="th col-order"><text class="th-txt">关联订单</text></view>
<view class="th col-time"><text class="th-txt">交易时间</text></view>
<view class="th col-amount"><text class="th-txt">交易金额</text></view>
<view class="th col-user"><text class="th-txt">交易用户</text></view>
<view class="th col-method"><text class="th-txt">支付方式</text></view>
<view class="th col-remark"><text class="th-txt">备注</text></view>
<view class="th col-ops"><text class="th-txt">操作</text></view>
</view>
<view class="table-body">
<view class="table-row" v-for="item in tableData" :key="item.flowNo">
<view class="td col-flow"><text class="td-txt">{{ item.flowNo }}</text></view>
<view class="td col-order text-left"><text class="td-txt">{{ item.orderNo }}</text></view>
<view class="td col-time"><text class="td-txt">{{ item.time }}</text></view>
<view class="td col-amount"><text class="td-txt red-txt">{{ item.amount }}</text></view>
<view class="td col-user"><text class="td-txt">{{ item.user }}</text></view>
<view class="td col-method"><text class="td-txt">{{ item.method }}</text></view>
<view class="td col-remark"><text class="td-txt">{{ item.remark }}</text></view>
<view class="td col-ops">
<text class="op-link">备注</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
interface FlowRecord {
flowNo: string
orderNo: string
time: string
amount: string
user: string
method: string
remark: string
}
const tableData = ref<FlowRecord[]>([
{
flowNo: 'ZJ202602031258428744',
orderNo: 'hy541422245264752640',
time: '2026-02-03 00:58:42',
amount: '+0.00',
user: 'J.',
method: '微信',
remark: ''
},
{
flowNo: 'ZJ202602011056592117',
orderNo: 'hy541029224517992448',
time: '2026-02-01 22:56:59',
amount: '+0.00',
user: 'dev 王鑫',
method: '微信',
remark: ''
},
{
flowNo: 'ZJ202602010513443817',
orderNo: 'hy540942844546777088',
time: '2026-02-01 17:13:44',
amount: '+0.00',
user: 'Sunshine',
method: '微信',
remark: ''
},
{
flowNo: 'ZJ202602010127248683',
orderNo: 'hy540885887420989440',
time: '2026-02-01 13:27:24',
amount: '+0.00',
user: '132****8769',
method: '微信',
remark: ''
},
{
flowNo: 'ZJ202602011215407366',
orderNo: 'hy540686639874179072',
time: '2026-02-01 00:15:40',
amount: '+0.00',
user: '177****9187',
method: '微信',
remark: ''
},
{
flowNo: 'ZJ202601301026512881',
orderNo: 'hy540296867267739648',
time: '2026-01-30 22:26:51',
amount: '+0.00',
user: '暂未成功人士',
method: '微信',
remark: ''
},
{
flowNo: 'ZJ202601300534267557',
orderNo: 'hy540223279126806528',
time: '2026-01-30 17:34:26',
amount: '+0.00',
user: 'b342865d2077',
method: '微信',
remark: ''
}
])
</script>
<style scoped lang="scss">
.finance-capital-flow {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
/* 筛选卡片 */
.filter-card {
padding: 20px 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 28px;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 10px;
white-space: nowrap;
}
.date-picker-wrap {
width: 220px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon {
font-size: 12px;
margin-right: 8px;
}
.date-placeholder {
font-size: 13px;
color: #c0c4cc;
}
.select-box {
width: 200px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0 12px;
}
.select-txt {
font-size: 13px;
color: #606266;
}
.arrow-down {
font-size: 8px;
color: #c0c4cc;
}
.search-wrap {
flex: 1;
}
.search-input {
flex: 1;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
font-size: 13px;
}
.btn-query {
background-color: #1890ff;
border-radius: 4px;
height: 32px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 10px;
}
.btn-txt {
color: #fff;
font-size: 14px;
}
/* 表格 */
.table-container {
display: flex;
flex-direction: column;
}
.table-header {
background-color: #f8f9fb;
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.th {
padding: 15px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 14px;
font-weight: 600;
color: #909399;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.td {
padding: 15px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 13px;
color: #606266;
}
.col-flow { width: 200px; }
.col-order { width: 220px; }
.col-time { width: 180px; }
.col-amount { width: 120px; }
.col-user { width: 150px; }
.col-method { width: 120px; }
.col-remark { flex: 1; min-width: 100px; }
.col-ops { width: 100px; }
.text-left {
justify-content: flex-start;
}
.red-txt {
color: #f56c6c;
}
.op-link {
font-size: 13px;
color: #1890ff;
}
</style>

View File

@@ -0,0 +1,358 @@
<template>
<view class="finance-commission">
<!-- 筛选卡片 -->
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">昵称/手机号/分销商ID:</text>
<input class="search-input" placeholder="请输入昵称搜索" />
</view>
<view class="btn-query">
<text class="btn-txt">查询</text>
</view>
</view>
</view>
<!-- 列表表格 -->
<view class="table-card border-shadow">
<view class="action-bar">
<view class="btn-export">
<text class="export-txt">导出</text>
</view>
</view>
<view class="table-container">
<view class="table-header">
<view class="th col-user"><text class="th-txt">用户信息</text></view>
<view class="th col-total"><text class="th-txt">总佣金金额</text></view>
<view class="th col-account"><text class="th-txt">账户佣金</text></view>
<view class="th col-withdraw"><text class="th-txt">提现佣金</text></view>
</view>
<view class="table-body">
<view class="table-row" v-for="item in tableData" :key="item.uid">
<view class="td col-user">
<text class="td-txt">{{ item.userInfo }}</text>
</view>
<view class="td col-total">
<text class="td-txt">{{ item.totalAmount }}</text>
</view>
<view class="td col-account">
<text class="td-txt">{{ item.accountAmount }}</text>
</view>
<view class="td col-withdraw">
<text class="td-txt">{{ item.withdrawAmount }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
interface CommissionSummary {
uid: string
userInfo: string
totalAmount: string
accountAmount: string
withdrawAmount: string
}
const tableData = ref<CommissionSummary[]>([
{
uid: '77418',
userInfo: '张迪 | 155****5525 | 77418',
totalAmount: '11.00',
accountAmount: '11.00',
withdrawAmount: '0'
},
{
uid: '69696',
userInfo: "I'm yours - | 69696",
totalAmount: '0.40',
accountAmount: '0.40',
withdrawAmount: '0'
},
{
uid: '68582',
userInfo: 'guan | 68582',
totalAmount: '140.80',
accountAmount: '140.80',
withdrawAmount: '0'
},
{
uid: '65258',
userInfo: '纯爱战神别名王富贵儿 | 158****4881 | 65258',
totalAmount: '11.00',
accountAmount: '11.00',
withdrawAmount: '0'
},
{
uid: '66265',
userInfo: '王伟兴 | 66265',
totalAmount: '11.99',
accountAmount: '11.99',
withdrawAmount: '0'
},
{
uid: '65270',
userInfo: '199****1781 | 199****1781 | 65270',
totalAmount: '31.60',
accountAmount: '31.60',
withdrawAmount: '0'
},
{
uid: '64572',
userInfo: '洒笾菂艸 | 188****2434 | 64572',
totalAmount: '0.20',
accountAmount: '0.20',
withdrawAmount: '0'
},
{
uid: '47952',
userInfo: '那小子 | 134****3573 | 47952',
totalAmount: '19.80',
accountAmount: '19.80',
withdrawAmount: '0'
}
])
</script>
<style scoped lang="scss">
.finance-commission {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
/* 筛选 */
.filter-card {
padding: 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 12px;
}
.search-input {
width: 240px;
height: 36px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
font-size: 14px;
}
.btn-query {
margin-left: 12px;
background-color: #1890ff;
border-radius: 4px;
height: 36px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-txt {
color: #fff;
font-size: 14px;
}
/* 表格区域 */
.table-card {
padding: 0;
}
.action-bar {
padding: 15px 20px;
}
.btn-export {
width: 60px;
height: 32px;
background-color: #e6f7ff;
border: 1px solid #91d5ff;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.export-txt {
color: #1890ff;
font-size: 14px;
}
.table-container {
display: flex;
flex-direction: column;
}
.table-header {
background-color: #e6f0ff; /* 淡蓝色表头 */
display: flex;
flex-direction: row;
}
.th {
padding: 14px 20px;
display: flex;
align-items: center;
}
.th-txt {
font-size: 14px;
font-weight: 500;
color: #606266;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
}
.table-row:hover {
background-color: #fafafa;
}
.td {
padding: 16px 20px;
display: flex;
align-items: center;
}
.td-txt {
font-size: 14px;
color: #606266;
}
/* 列宽分配 */
.col-user { flex: 2; min-width: 300px; justify-content: flex-start; }
.col-total { flex: 1; justify-content: flex-start; }
.col-account { flex: 1; justify-content: flex-start; }
.col-withdraw { flex: 1; justify-content: flex-start; }
</style>
<style scoped lang="scss">
.finance-commission {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.filter-card {
padding: 20px 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 28px;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 10px;
}
.date-picker-wrap {
width: 220px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon { font-size: 12px; margin-right: 8px; }
.date-placeholder { font-size: 13px; color: #c0c4cc; }
.search-wrap { flex: 1; }
.search-input {
width: 200px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
font-size: 13px;
}
.btn-query {
height: 32px;
padding: 0 20px;
background-color: #1890ff;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-txt { color: #fff; font-size: 14px; }
/* 表格 */
.table-container { display: flex; flex-direction: column; }
.table-header { background-color: #f8f9fb; display: flex; flex-direction: row; border-bottom: 1px solid #ebeef5; }
.th { padding: 15px 10px; display: flex; align-items: center; justify-content: center; }
.th-txt { font-size: 14px; font-weight: 600; color: #909399; }
.table-row { display: flex; flex-direction: row; border-bottom: 1px solid #ebeef5; }
.td { padding: 15px 10px; display: flex; align-items: center; justify-content: center; }
.td-txt { font-size: 13px; color: #606266; }
.col-id { width: 80px; }
.col-user { width: 180px; justify-content: flex-start; }
.col-order { width: 180px; }
.col-amount { width: 120px; }
.col-type { width: 120px; }
.col-time { width: 180px; }
.col-status { width: 100px; }
.avatar { width: 32px; height: 32px; border-radius: 16px; margin-right: 10px; }
.user-name { font-size: 13px; color: #606266; }
.green-txt { color: #67c23a; font-weight: bold; }
.status-dot-active {
width: 8px;
height: 8px;
border-radius: 4px;
background-color: #67c23a;
margin-right: 6px;
}
</style>

View File

@@ -0,0 +1,55 @@
.page-container {
padding: 20px;
min-height: 100vh;
background: #f5f5f5;
}
.page-header {
margin-bottom: 20px;
}
.page-title {
display: block;
font-size: 24px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.page-subtitle {
display: block;
font-size: 14px;
color: #999;
}
.page-content {
background: #fff;
border-radius: 4px;
padding: 24px;
}
.placeholder-card {
text-align: center;
padding: 60px 20px;
}
.placeholder-title {
display: block;
font-size: 18px;
font-weight: 600;
color: #666;
margin-bottom: 12px;
}
.placeholder-desc {
display: block;
font-size: 14px;
color: #999;
margin-bottom: 8px;
}
.placeholder-info {
display: block;
font-size: 12px;
color: #1890ff;
}

View File

@@ -0,0 +1,394 @@
<template>
<view class="finance-invoice">
<!-- 头部筛选区 -->
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">创建时间:</text>
<view class="date-picker-wrap">
<text class="calendar-icon">📅</text>
<text class="date-placeholder">开始日期 - 结束日期</text>
</view>
</view>
<view class="filter-item">
<text class="filter-label">搜索:</text>
<view class="search-group">
<view class="select-trigger">
<text class="select-txt">请选择</text>
<text class="arrow-down">▼</text>
</view>
<input class="search-input" placeholder="请输入" />
</view>
</view>
<view class="btn-query">
<text class="btn-txt">查询</text>
</view>
</view>
</view>
<!-- 状态切换选项卡 -->
<view class="tab-section">
<view
v-for="(tab, index) in tabs"
:key="index"
class="tab-item"
:class="{ active: activeTab === index }"
@click="activeTab = index"
>
<text class="tab-title">{{ tab.name }} ({{ tab.count }})</text>
<view class="active-line" v-if="activeTab === index"></view>
</view>
</view>
<!-- 数据表格 (Flex 模拟) -->
<view class="table-container border-shadow">
<view class="table-header">
<view class="th col-order"><text class="th-txt">订单号</text></view>
<view class="th col-amount"><text class="th-txt">订单金额</text></view>
<view class="th col-type"><text class="th-txt">发票类型</text></view>
<view class="th col-header"><text class="th-txt">发票抬头类型</text></view>
<view class="th col-time"><text class="th-txt">下单时间</text></view>
<view class="th col-status-inv"><text class="th-txt">开票状态</text></view>
<view class="th col-status-order"><text class="th-txt">订单状态</text></view>
<view class="th col-ops"><text class="th-txt">操作</text></view>
</view>
<view class="table-body">
<view class="table-row" v-for="item in tableData" :key="item.orderNo">
<view class="td col-order text-left"><text class="td-txt">{{ item.orderNo }}</text></view>
<view class="td col-amount"><text class="td-txt">¥ {{ item.amount }}</text></view>
<view class="td col-type"><text class="td-txt">{{ item.invoiceType }}</text></view>
<view class="td col-header"><text class="td-txt">{{ item.headerType }}</text></view>
<view class="td col-time"><text class="td-txt">{{ item.time }}</text></view>
<view class="td col-status-inv"><text class="td-txt red-cell">{{ item.invStatus }}</text></view>
<view class="td col-status-order"><text class="td-txt">{{ item.orderStatus }}</text></view>
<view class="td col-ops">
<view class="ops-box">
<text class="op-link">操作</text>
<text class="sep">|</text>
<text class="op-link">订单信息</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
const activeTab = ref(0)
const tabs = ref([
{ name: '全部发票', count: 163 },
{ name: '待开发票', count: 105 },
{ name: '已开发票', count: 34 },
{ name: '退款发票', count: 33 }
])
const tableData = ref([
{
orderNo: 'cp538981381384962048',
amount: '999.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2026-01-27 07:19:35',
invStatus: '未开票',
orderStatus: '未发货'
},
{
orderNo: 'cp523490058603331584',
amount: '9.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2025-12-15 13:22:35',
invStatus: '未开票',
orderStatus: '未发货'
},
{
orderNo: 'cp524967077409193984',
amount: '9.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2025-12-19 15:11:44',
invStatus: '未开票',
orderStatus: '未发货'
},
{
orderNo: 'cp521126678106210304',
amount: '11890.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2025-12-09 00:51:22',
invStatus: '未开票',
orderStatus: '未发货'
},
{
orderNo: 'cp521126166883467264',
amount: '11800.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2025-12-09 00:49:20',
invStatus: '未开票',
orderStatus: '未发货'
},
{
orderNo: 'cp517015093888679936',
amount: '142.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2025-11-27 16:33:24',
invStatus: '未开票',
orderStatus: '未发货'
},
{
orderNo: 'cp313601579989073920',
amount: '0.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2024-05-15 08:59:56',
invStatus: '未开票',
orderStatus: '待评价'
},
{
orderNo: 'cp503871643047690240',
amount: '999.00',
invoiceType: '电子普通发票',
headerType: '个人',
time: '2025-10-22 10:06:01',
invStatus: '未开票',
orderStatus: '未发货'
}
])
</script>
<style scoped lang="scss">
.finance-invoice {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
/* 筛选栏 */
.filter-card {
padding: 20px 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 30px;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 8px;
}
.date-picker-wrap {
width: 240px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 10px;
}
.calendar-icon {
margin-right: 8px;
font-size: 12px;
}
.date-placeholder {
font-size: 13px;
color: #c0c4cc;
}
.search-group {
display: flex;
flex-direction: row;
align-items: center;
border: 1px solid #dcdfe6;
border-radius: 4px;
height: 32px;
overflow: hidden;
}
.select-trigger {
width: 90px;
height: 100%;
border-right: 1px solid #dcdfe6;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0 10px;
background-color: #fff;
}
.select-txt {
font-size: 13px;
color: #606266;
}
.arrow-down {
font-size: 8px;
color: #c0c4cc;
}
.search-input {
width: 160px;
height: 100%;
padding: 0 12px;
font-size: 13px;
}
.btn-query {
background-color: #1890ff;
border-radius: 4px;
padding: 0 20px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-txt {
color: #fff;
font-size: 14px;
}
/* 选项卡 */
.tab-section {
display: flex;
flex-direction: row;
margin-bottom: 20px;
border-bottom: 1px solid #e4e7ed;
padding: 0 10px;
}
.tab-item {
padding: 12px 20px;
position: relative;
cursor: pointer;
}
.tab-title {
font-size: 14px;
color: #606266;
transition: all 0.3s;
}
.tab-item.active .tab-title {
color: #1890ff;
font-weight: 600;
}
.active-line {
position: absolute;
bottom: 0;
left: 20px;
right: 20px;
height: 2px;
background-color: #1890ff;
}
/* 表格 */
.table-container {
display: flex;
flex-direction: column;
}
.table-header {
background-color: #f8f9fb;
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.th {
padding: 15px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 14px;
font-weight: 600;
color: #909399;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
transition: background-color 0.3s;
}
.td {
padding: 15px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 13px;
color: #606266;
}
/* 列宽分配 */
.col-order { width: 220px; justify-content: flex-start; padding-left: 20px; }
.col-amount { width: 120px; }
.col-type { width: 150px; }
.col-header { width: 120px; }
.col-time { width: 180px; }
.col-status-inv { width: 120px; }
.col-status-order { width: 120px; }
.col-ops { flex: 1; min-width: 140px; }
.text-left {
justify-content: flex-start;
}
.red-cell {
color: #f56c6c;
}
.ops-box {
display: flex;
flex-direction: row;
align-items: center;
}
.op-link {
font-size: 13px;
color: #1890ff;
cursor: pointer;
}
.sep {
font-size: 12px;
color: #ebeef5;
margin: 0 8px;
}
</style>

View File

@@ -0,0 +1,425 @@
<template>
<view class="finance-recharge">
<!-- 头部筛选区 -->
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">时间选择:</text>
<view class="date-picker-wrap">
<text class="calendar-icon">📅</text>
<text class="date-placeholder">开始日期 - 结束日期</text>
</view>
</view>
<view class="filter-item">
<text class="filter-label">支付类型:</text>
<view class="select-box">
<text class="select-txt">全部</text>
<text class="arrow-down">▼</text>
</view>
</view>
<view class="filter-item search-wrap">
<text class="filter-label">搜索:</text>
<input class="search-input" placeholder="请输入用户昵称、订单号" />
</view>
<view class="btn-query">
<text class="btn-txt">查询</text>
</view>
</view>
</view>
<!-- 统计网格 -->
<view class="stats-grid">
<view class="stat-card border-shadow" v-for="(item, index) in stats" :key="index">
<view class="icon-circle" :class="item.colorClass">
<text class="stat-icon">{{ item.icon }}</text>
</view>
<view class="stat-info">
<text class="stat-value">{{ item.value }}</text>
<text class="stat-label">{{ item.label }}</text>
</view>
</view>
</view>
<!-- 操作区域 -->
<view class="action-section">
<view class="btn-export">
<text class="btn-export-txt">导出</text>
</view>
</view>
<!-- 数据表格 (Flex 模拟) -->
<view class="table-container border-shadow">
<view class="table-header">
<view class="th col-id"><text class="th-txt">ID</text></view>
<view class="th col-avatar"><text class="th-txt">头像</text></view>
<view class="th col-nickname"><text class="th-txt">用户昵称</text></view>
<view class="th col-orderno"><text class="th-txt">订单号</text></view>
<view class="th col-amount"><text class="th-txt">支付金额</text></view>
<view class="th col-paid"><text class="th-txt">是否支付</text></view>
<view class="th col-type"><text class="th-txt">充值类型</text></view>
<view class="th col-time"><text class="th-txt">支付时间</text></view>
<view class="th col-ops"><text class="th-txt">操作</text></view>
</view>
<view class="table-body">
<view class="table-row" v-for="item in tableData" :key="item.id">
<view class="td col-id"><text class="td-txt">{{ item.id }}</text></view>
<view class="td col-avatar">
<view class="avatar-box">
<text class="avatar-placeholder" v-if="!item.hasAvatar">🖼️</text>
<view class="avatar-img-mock" v-else></view>
</view>
</view>
<view class="td col-nickname"><text class="td-txt">{{ item.nickname }}</text></view>
<view class="td col-orderno"><text class="td-txt">{{ item.orderNo }}</text></view>
<view class="td col-amount"><text class="td-txt">{{ item.amount }}</text></view>
<view class="td col-paid"><text class="td-txt">{{ item.isPaid }}</text></view>
<view class="td col-type"><text class="td-txt">{{ item.type }}</text></view>
<view class="td col-time"><text class="td-txt">{{ item.time }}</text></view>
<view class="td col-ops">
<text class="op-link">删除</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
const stats = ref([
{ label: '充值总金额', value: '446747490.72', icon: '¥', colorClass: 'blue' },
{ label: '充值退款金额', value: '1.19', icon: '¥', colorClass: 'orange' },
{ label: '支付宝充值金额', value: '78812.24', icon: '支', colorClass: 'green' },
{ label: '微信充值金额', value: '8518075.11', icon: '✔', colorClass: 'pink' }
])
interface RechargeRecord {
id: number
hasAvatar: boolean
nickname: string
orderNo: string
amount: string
isPaid: string
type: string
time: string
}
const tableData = ref<RechargeRecord[]>([
{
id: 4522,
hasAvatar: true,
nickname: 'TTA NW',
orderNo: 'cz540603403592531968',
amount: '10.00',
isPaid: '未支付',
type: '微信充值',
time: '暂无'
},
{
id: 4521,
hasAvatar: true,
nickname: 'TTA NW',
orderNo: 'cz540592008763277312',
amount: '3343.00',
isPaid: '未支付',
type: '微信充值',
time: '暂无'
},
{
id: 4520,
hasAvatar: true,
nickname: '绯',
orderNo: 'cz538561368400330752',
amount: '500.00',
isPaid: '未支付',
type: '支付宝充值',
time: '暂无'
},
{
id: 4519,
hasAvatar: false,
nickname: '六六狗',
orderNo: 'cz538368229429477376',
amount: '50.00',
isPaid: '未支付',
type: '微信充值',
time: '暂无'
},
{
id: 4518,
hasAvatar: false,
nickname: 'aabbc',
orderNo: 'cz538165303901683712',
amount: '10.00',
isPaid: '未支付',
type: '其他充值',
time: '暂无'
}
])
</script>
<style scoped lang="scss">
.finance-recharge {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.border-shadow {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
/* 筛选卡片 */
.filter-card {
padding: 20px 24px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 28px;
}
.filter-label {
font-size: 14px;
color: #333;
margin-right: 10px;
white-space: nowrap;
}
.date-picker-wrap {
width: 220px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
}
.calendar-icon {
font-size: 12px;
margin-right: 8px;
}
.date-placeholder {
font-size: 13px;
color: #c0c4cc;
}
.select-box {
width: 160px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0 12px;
}
.select-txt {
font-size: 13px;
color: #606266;
}
.arrow-down {
font-size: 8px;
color: #c0c4cc;
}
.search-wrap {
flex: 1;
}
.search-input {
flex: 1;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
font-size: 13px;
}
.btn-query {
background-color: #1890ff;
border-radius: 4px;
height: 32px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 10px;
}
.btn-txt {
color: #fff;
font-size: 14px;
}
/* 统计网格 */
.stats-grid {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 20px;
}
.stat-card {
width: 24%;
padding: 24px 20px;
display: flex;
flex-direction: row;
align-items: center;
}
.icon-circle {
width: 52px;
height: 52px;
border-radius: 26px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
}
.blue { background-color: #e6f7ff; color: #1890ff; }
.orange { background-color: #fff7e1; color: #fa8c16; }
.green { background-color: #f6ffed; color: #52c41a; }
.pink { background-color: #fff0f6; color: #eb2f96; }
.stat-icon { font-size: 22px; font-weight: bold; }
.stat-info {
display: flex;
flex-direction: column;
}
.stat-value {
font-size: 22px;
font-weight: 700;
color: #303133;
line-height: 1.1;
}
.stat-label {
font-size: 12px;
color: #909399;
margin-top: 6px;
}
/* 操作区 */
.action-section {
margin-bottom: 15px;
}
.btn-export {
width: 60px;
height: 30px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.btn-export-txt {
font-size: 13px;
color: #606266;
}
/* 表格 */
.table-container {
display: flex;
flex-direction: column;
}
.table-header {
background-color: #f8f9fb;
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.th {
padding: 12px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 14px;
font-weight: 600;
color: #909399;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.td {
padding: 12px 10px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 13px;
color: #606266;
}
.col-id { width: 80px; }
.col-avatar { width: 80px; }
.col-nickname { width: 150px; }
.col-orderno { width: 220px; }
.col-amount { width: 120px; }
.col-paid { width: 120px; }
.col-type { width: 150px; }
.col-time { width: 150px; }
.col-ops { flex: 1; min-width: 100px; }
.avatar-box {
width: 40px;
height: 40px;
background-color: #f0f2f5;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.avatar-img-mock {
width: 100%;
height: 100%;
background-color: #ccc;
}
.avatar-placeholder {
font-size: 16px;
}
.op-link {
font-size: 13px;
color: #1890ff;
}
</style>

View File

@@ -0,0 +1,836 @@
<template>
<view class="finance-transaction-stats">
<!-- 头部筛选 -->
<view class="header-filters">
<view class="date-tabs">
<text
v-for="(item, index) in dateOptions"
:key="index"
class="date-tab-item"
:class="{ active: activeDateTab === index }"
@click="activeDateTab = index"
>{{ item }}</text>
</view>
<view class="date-picker-wrap">
<text class="calendar-icon">D</text>
<text class="date-range-text">2026-02-03 - 2026-02-03</text>
</view>
</view>
<!-- 交易概况区块 (CRMEB 1:1 复刻) -->
<view class="overview-card">
<view class="overview-header">
<view class="header-left">
<text class="section-title">交易概况</text>
<text class="info-tag">?</text>
</view>
<view class="header-right">
<view class="date-picker-inline">
<text class="date-text">2026/01/05 - 2026/02/03</text>
</view>
<button class="btn-query">查询</button>
<button class="btn-export">导出</button>
</view>
</view>
<!-- 指标网格 -->
<view class="overview-grid">
<!-- 第一行 -->
<view class="grid-row">
<view class="overview-item">
<view class="icon-box blue"><text class="icon">🕒</text></view>
<view class="item-info">
<text class="item-label">营业额</text>
<text class="item-value">442753.70</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value up">44275370% ▲</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box green"><text class="icon">¥</text></view>
<view class="item-info">
<text class="item-label">商品支付金额</text>
<text class="item-value">434693.52</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value up">43469352% ▲</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box orange"><text class="icon">🔒</text></view>
<view class="item-info">
<text class="item-label">购买会员金额</text>
<text class="item-value">8059.18</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value up">805918% ▲</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box purple"><text class="icon">💰</text></view>
<view class="item-info">
<text class="item-label">充值金额</text>
<text class="item-value">0.00</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value">0% -</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box cyan"><text class="icon">🛒</text></view>
<view class="item-info">
<text class="item-label">线下收银金额</text>
<text class="item-value">1</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value up">100% ▲</text>
</view>
</view>
</view>
</view>
<!-- 第二行 -->
<view class="grid-row second">
<view class="overview-item">
<view class="icon-box light-green"><text class="icon">↘</text></view>
<view class="item-info">
<text class="item-label">支出金额</text>
<text class="item-value">442752.69</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value up">44275269% ▲</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box gold"><text class="icon">💳</text></view>
<view class="item-info">
<text class="item-label">余额支付金额</text>
<text class="item-value">442752.69</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value up">5293.00% ▲</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box red-purple"><text class="icon"></text></view>
<view class="item-info">
<text class="item-label">支付佣金金额</text>
<text class="item-value">0.00</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value">0% -</text>
</view>
</view>
</view>
<view class="overview-item">
<view class="icon-box blue-gray"><text class="icon">📦</text></view>
<view class="item-info">
<text class="item-label">商品退款金额</text>
<text class="item-value">0.00</text>
<view class="trend-row">
<text class="trend-label">环比增长:</text>
<text class="trend-value">0% -</text>
</view>
</view>
</view>
<!-- 占位使其对齐 -->
<view class="overview-item transparent"></view>
</view>
</view>
<!-- 概况图表区 -->
<view class="overview-chart-section">
<view class="overview-chart-legend">
<view class="legend-dot blue"><text class="legend-text">营业额</text></view>
<view class="legend-dot green"><text class="legend-text">商品支付金额</text></view>
<view class="legend-dot gray-blue"><text class="legend-text">购买会员金额</text></view>
<view class="legend-dot red"><text class="legend-text">充值金额</text></view>
<view class="legend-dot orange"><text class="legend-text">支出金额</text></view>
</view>
<view class="overview-chart-box">
<EChartsView v-if="overviewTrendOption != null" :option="overviewTrendOption" class="main-trend-chart" />
</view>
</view>
</view>
<!-- 之前的统计卡片区域 -->
<view class="stats-section">
<!-- 左侧:今日订单金额 -->
<view class="stats-card-main">
<view class="card-header">
<text class="card-title">今日订单金额</text>
</view>
<view class="card-content">
<view class="amount-wrap">
<text class="currency">¥</text>
<text class="amount-value">0</text>
</view>
<view class="chart-legend">
<view class="legend-item">
<view class="dot blue"></view>
<text>今天</text>
</view>
<view class="legend-item">
<view class="dot gray"></view>
<text>昨天</text>
</view>
</view>
<view class="chart-box">
<EChartsView v-if="orderAmountOption != null" :option="orderAmountOption" class="stats-chart" />
</view>
</view>
</view>
<!-- 侧边统计网格 -->
<view class="stats-side-grid">
<view class="side-column">
<!-- 今日订单数 -->
<view class="side-stat-card">
<view class="card-header">
<text class="card-title">今日订单数</text>
</view>
<view class="card-body">
<text class="main-val">0</text>
<view class="compare-row">
<text class="label">昨日:</text>
<text class="val">4</text>
</view>
<view class="compare-row">
<text class="label">日环比:</text>
<text class="val down">-100% ▼</text>
</view>
<view class="mini-chart-placeholder">
<view class="blue-line"></view>
</view>
</view>
</view>
<!-- 本月订单数 -->
<view class="side-stat-card">
<view class="card-header">
<text class="card-title">本月订单数</text>
</view>
<view class="card-body">
<text class="main-val">12</text>
<view class="compare-row">
<text class="label">上月:</text>
<text class="val">206</text>
</view>
<view class="compare-row">
<text class="label">月环比:</text>
<text class="val down">-94% ▼</text>
</view>
<view class="mini-chart-placeholder">
<view class="blue-line"></view>
</view>
</view>
</view>
</view>
<view class="side-column">
<!-- 今日支付人数 -->
<view class="side-stat-card">
<view class="card-header">
<text class="card-title">今日支付人数</text>
</view>
<view class="card-body">
<text class="main-val">0</text>
<view class="compare-row">
<text class="label">昨日:</text>
<text class="val">4</text>
</view>
<view class="compare-row">
<text class="label">日环比:</text>
<text class="val down">-100% ▼</text>
</view>
<view class="mini-chart-placeholder">
<view class="blue-line"></view>
</view>
</view>
</view>
<!-- 本月支付人数 -->
<view class="side-stat-card">
<view class="card-header">
<text class="card-title">本月支付人数</text>
</view>
<view class="card-body">
<text class="main-val">7</text>
<view class="compare-row">
<text class="label">上月:</text>
<text class="val">134</text>
</view>
<view class="compare-row">
<text class="label">月环比:</text>
<text class="val down">-94% ▼</text>
</view>
<view class="mini-chart-placeholder">
<view class="blue-line"></view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted } from 'vue'
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
const dateOptions = ['今天', '昨天', '最近7天', '最近30天', '本月', '本年']
const activeDateTab = ref(0)
const orderAmountOption = ref<any>(null)
const overviewTrendOption = ref<any>(null)
/**
* 工具函数:将 UTS 对象转换为纯 JavaScript 对象
* 确保 ECharts 在 renderjs 中能正确接收数据
*/
function toPlainObject(obj : any) : any {
if (obj == null) return null
if (typeof obj !== 'object') return obj
if (Array.isArray(obj)) {
return (obj as Array<any>).map((item : any) : any => toPlainObject(item))
}
const plain : Record<string, any> = {}
const keys = Object.keys(obj as Record<string, any>)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (key.startsWith('_') || key == 'toJSON') continue
const value = (obj as Record<string, any>)[key]
if (typeof value == 'function') continue
if (value != null && typeof value == 'object' && !Array.isArray(value)) {
plain[key] = toPlainObject(value)
} else {
plain[key] = value
}
}
return plain
}
onMounted(() => {
// 延迟初始化图表确保容器就位
setTimeout(() => {
initCharts()
}, 300)
})
function initCharts() {
// 模拟趋势数据
const todayData = [120, 132, 101, 134, 90, 230, 210]
const yesterdayData = [220, 182, 191, 234, 290, 330, 310]
const option = {
grid: { left: '3%', right: '4%', bottom: '3%', top: '5%', containLabel: true },
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: { color: '#1890ff', type: 'dashed' }
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '23:59'],
axisLine: { lineStyle: { color: '#f0f0f0' } },
axisLabel: { color: '#999' }
},
yAxis: {
type: 'value',
splitLine: { show: false },
axisLine: { show: false },
axisLabel: { color: '#999' }
},
series: [
{
name: '今天',
type: 'line',
smooth: true,
data: todayData,
lineStyle: { color: '#1890ff', width: 2 },
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(24, 144, 255, 0.2)' },
{ offset: 1, color: 'rgba(24, 144, 255, 0)' }
]
}
},
itemStyle: { color: '#1890ff' }
},
{
name: '昨天',
type: 'line',
smooth: true,
data: yesterdayData,
lineStyle: { color: '#d9d9d9', width: 2, type: 'dashed' },
itemStyle: { color: '#d9d9d9' }
}
]
}
// 核心修复:传递给 ECharts 的 Option 必须是 Plain Object
orderAmountOption.value = toPlainObject(option)
// 初始化交易概况趋势图 (多曲线)
const overviewOption = {
grid: { left: '3%', right: '4%', bottom: '10%', top: '5%', containLabel: true },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2026-01-05', '01-10', '01-15', '01-20', '01-25', '01-31', '02-03'],
axisLine: { lineStyle: { color: '#f0f0f0' } },
axisLabel: { color: '#999', fontSize: 10 }
},
yAxis: {
type: 'value',
axisLine: { show: false },
splitLine: { lineStyle: { color: '#f5f5f5' } },
axisLabel: { color: '#999' }
},
series: [
{
name: '营业额',
type: 'line',
smooth: true,
data: [1000, 5000, 20000, 15000, 80000, 20000, 5000],
itemStyle: { color: '#1890ff' }
},
{
name: '商品支付金额',
type: 'line',
smooth: true,
data: [800, 4000, 18000, 12000, 75000, 18000, 4000],
itemStyle: { color: '#52c41a' }
},
{
name: '支出金额',
type: 'line',
smooth: true,
data: [500, 3000, 15000, 10000, 90000, 15000, 3000],
itemStyle: { color: '#fa8c16' }
}
]
}
overviewTrendOption.value = toPlainObject(overviewOption)
}
</script>
<style scoped lang="scss">
.finance-transaction-stats {
padding: 16px;
background-color: #f0f2f5;
min-height: 100vh;
}
/* 头部筛选 */
.header-filters {
background: #fff;
padding: 12px 20px;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 20px;
}
.date-tabs {
display: flex;
flex-direction: row;
border: 1px solid #d9d9d9;
border-radius: 2px;
margin-right: 20px;
}
.date-tab-item {
padding: 4px 15px;
font-size: 14px;
color: #666;
border-right: 1px solid #d9d9d9;
cursor: pointer;
&:last-child {
border-right: none;
}
&.active {
background-color: #1890ff;
color: #fff;
border-color: #1890ff;
}
}
.date-picker-wrap {
display: flex;
flex-direction: row;
align-items: center;
padding: 4px 12px;
border: 1px solid #d9d9d9;
border-radius: 2px;
}
.calendar-icon {
margin-right: 8px;
font-size: 14px;
}
.date-range-text {
font-size: 14px;
color: #333;
}
/* 统计区域布局 */
.stats-section {
display: flex;
flex-direction: row;
gap: 16px;
}
.stats-card-main {
flex: 3;
background: #fff;
border-radius: 4px;
padding: 24px;
min-height: 380px;
}
.card-title {
font-size: 16px;
color: #333;
font-weight: 500;
margin-bottom: 20px;
display: block;
}
.amount-wrap {
margin-top: 10px;
}
.currency {
font-size: 24px;
color: #333;
margin-right: 8px;
}
.amount-value {
font-size: 40px;
color: #333;
font-weight: bold;
}
.chart-legend {
display: flex;
flex-direction: row;
margin-top: 16px;
}
.legend-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 20px;
font-size: 14px;
color: #666;
}
.dot {
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
&.blue { background-color: #1890ff; }
&.gray { background-color: #d9d9d9; }
}
.chart-box {
width: 100%;
height: 220px;
margin-top: 20px;
}
.stats-chart {
width: 100%;
height: 100%;
}
/* 侧边网格 */
.stats-side-grid {
flex: 2;
display: flex;
flex-direction: row;
gap: 16px;
}
.side-column {
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
}
.side-stat-card {
background: #fff;
border-radius: 4px;
padding: 24px;
display: flex;
flex-direction: column;
}
.main-val {
font-size: 32px;
font-weight: bold;
color: #333;
margin-bottom: 20px;
display: block;
}
.compare-row {
display: flex;
flex-direction: row;
margin-bottom: 8px;
font-size: 14px;
}
.compare-row .label {
color: #999;
margin-right: 8px;
}
.compare-row .val {
color: #333;
&.down { color: #52c41a; }
&.up { color: #f5222d; }
}
.mini-chart-placeholder {
margin-top: 20px;
height: 2px;
background-color: #f0f0f0;
position: relative;
}
.blue-line {
position: absolute;
left: 0;
top: 0;
width: 60%;
height: 100%;
background-color: #1890ff;
}
/* 交易概况复刻样式 */
.overview-card {
background: #fff;
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
}
.overview-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.overview-header .header-left {
display: flex;
flex-direction: row;
align-items: center;
}
.section-title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.info-tag {
width: 16px;
height: 16px;
border-radius: 50%;
background: #eee;
color: #999;
font-size: 11px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 8px;
}
.overview-header .header-right {
display: flex;
flex-direction: row;
gap: 12px;
}
.date-picker-inline {
border: 1px solid #dcdfe6;
padding: 5px 15px;
border-radius: 4px;
display: flex;
align-items: center;
}
.date-text {
font-size: 13px;
color: #606266;
}
.btn-query, .btn-export {
padding: 0 16px;
height: 32px;
line-height: 32px;
font-size: 13px;
border-radius: 4px;
cursor: pointer;
}
.btn-query {
background-color: #1890ff;
color: #fff;
border: none;
}
.btn-export {
background: #fff;
color: #1890ff;
border: 1px solid #1890ff;
}
/* 指标网格 */
.overview-grid {
display: flex;
flex-direction: column;
gap: 30px;
padding-bottom: 30px;
border-bottom: 1px dashed #f0f0f0;
}
.grid-row {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.overview-item {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
}
.overview-item.transparent {
visibility: hidden;
}
.icon-box {
width: 44px;
height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
}
.icon-box .icon {
font-size: 20px;
color: #fff;
}
.icon-box.blue { background-color: #2f54eb; }
.icon-box.green { background-color: #52c41a; }
.icon-box.orange { background-color: #fa8c16; }
.icon-box.purple { background-color: #722ed1; }
.icon-box.cyan { background-color: #13c2c2; }
.icon-box.light-green { background-color: #a0d911; }
.icon-box.gold { background-color: #faad14; }
.icon-box.red-purple { background-color: #eb2f96; }
.icon-box.blue-gray { background-color: #4096ff; }
.item-info {
display: flex;
flex-direction: column;
}
.item-label {
font-size: 13px;
color: #999;
margin-bottom: 4px;
}
.item-value {
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 4px;
}
.trend-row {
display: flex;
flex-direction: row;
font-size: 12px;
color: #999;
}
.trend-value.up {
color: #f5222d;
margin-left: 4px;
}
/* 图表区 */
.overview-chart-section {
padding-top: 24px;
}
.overview-chart-legend {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 16px;
margin-bottom: 20px;
}
.legend-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.legend-dot.blue { background: #1890ff; }
.legend-dot.green { background: #52c41a; }
.legend-dot.gray-blue { background: #607d8b; }
.legend-dot.red { background: #f44336; }
.legend-dot.orange { background: #fa8c16; }
.legend-text {
font-size: 12px;
color: #666;
}
.overview-chart-box {
width: 100%;
height: 400px;
}
.main-trend-chart {
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,469 @@
<template>
<view class="finance-withdrawal">
<!-- 头部筛选区 -->
<view class="filter-card">
<view class="filter-row">
<view class="filter-item">
<text class="filter-label">时间选择:</text>
<uni-datetime-picker v-model="timeRange" type="daterange" class="dt-picker" />
</view>
<view class="filter-item">
<text class="filter-label">提现状态:</text>
<uni-data-select v-model="statusValue" :localdata="statusOptions" class="data-select" />
</view>
<view class="filter-item">
<text class="filter-label">提现方式:</text>
<uni-data-select v-model="methodValue" :localdata="methodOptions" class="data-select" />
</view>
<view class="filter-item search-wrap">
<text class="filter-label">搜索:</text>
<uni-easyinput v-model="searchKeyword" placeholder="微信昵称/姓名/支付宝账号/银行卡号" class="search-input" />
</view>
<button class="btn-query" @click="handleQuery">查询</button>
</view>
</view>
<!-- 统计指标网格 -->
<view class="stats-grid">
<view class="stat-card" v-for="(item, index) in stats" :key="index">
<view class="icon-circle" :class="item.colorClass">
<text class="stat-icon">{{ item.icon }}</text>
</view>
<view class="stat-info">
<text class="stat-value">{{ item.value }}</text>
<text class="stat-label">{{ item.label }}</text>
</view>
</view>
</view>
<!-- 操作按钮区 -->
<view class="action-section">
<view class="btn-record">
<text class="btn-record-txt">佣金记录</text>
</view>
</view>
<!-- 数据表格 (使用 Flex 模拟以确保兼容性和精度) -->
<view class="table-container">
<view class="table-header">
<view class="th col-id"><text class="th-txt">ID</text></view>
<view class="th col-user"><text class="th-txt">用户信息</text></view>
<view class="th col-amount"><text class="th-txt">提现金额</text></view>
<view class="th col-fee"><text class="th-txt">提现手续费</text></view>
<view class="th col-net"><text class="th-txt">到账金额</text></view>
<view class="th col-method"><text class="th-txt">提现方式</text></view>
<view class="th col-qr"><text class="th-txt">收款码</text></view>
<view class="th col-time"><text class="th-txt">申请时间</text></view>
<view class="th col-remark"><text class="th-txt">备注</text></view>
<view class="th col-status"><text class="th-txt">审核状态</text></view>
<view class="th col-ops"><text class="th-txt">操作</text></view>
</view>
<view class="table-body">
<view class="table-row" v-for="(item, index) in tableData" :key="item.id">
<view class="td col-id"><text class="td-txt">{{ item.id }}</text></view>
<view class="td col-user">
<view class="user-info-box">
<view class="avatar-box">
<text class="avatar-placeholder">U</text>
</view>
<view class="user-detail">
<text class="user-nickname">{{ item.nickname }}</text>
<text class="user-id">用户id:{{ item.userId }}</text>
</view>
</view>
</view>
<view class="td col-amount"><text class="td-txt">{{ item.amount }}</text></view>
<view class="td col-fee"><text class="td-txt">{{ item.fee }}</text></view>
<view class="td col-net"><text class="td-txt green-txt">{{ item.netAmount }}</text></view>
<view class="td col-method">
<view class="method-box">
<text class="m-line">姓名:{{ item.name }}</text>
<text class="m-line">{{ item.type }}:{{ item.account }}</text>
<text v-if="item.bank" class="m-line">银行开户地址:{{ item.bank }}</text>
</view>
</view>
<view class="td col-qr">
<view class="qr-box" v-if="item.id === 57">
<text class="qr-icon-txt">■</text>
</view>
</view>
<view class="td col-time"><text class="td-txt">{{ item.time }}</text></view>
<view class="td col-remark"><text class="td-txt">{{ item.remark || '' }}</text></view>
<view class="td col-status"><text class="td-txt">申请中</text></view>
<view class="td col-ops">
<view class="ops-box">
<text class="op-btn blue">编辑</text>
<text class="op-sep">|</text>
<text class="op-btn blue">通过</text>
<text class="op-sep">|</text>
<text class="op-btn blue">驳回</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
const timeRange = ref([])
const statusValue = ref('all')
const methodValue = ref('all')
const searchKeyword = ref('')
const statusOptions = ref([
{ value: 'all', text: '全部' },
{ value: '0', text: '待审核' },
{ value: '1', text: '已通过' },
{ value: '-1', text: '已驳回' }
])
const methodOptions = ref([
{ value: 'all', text: '全部' },
{ value: 'alipay', text: '支付宝' },
{ value: 'bank', text: '银行卡' },
{ value: 'weixin', text: '微信' }
])
const stats = ref([
{ label: '佣金总金额', value: '676809.25', icon: '$', colorClass: 'blue' },
{ label: '待提现金额', value: '71', icon: '¥', colorClass: 'orange' },
{ label: '已提现金额', value: '68879.25', icon: '$', colorClass: 'green' },
{ label: '未提现金额', value: '607930.00', icon: '¥', colorClass: 'pink' }
])
const tableData = ref([
{
id: 57,
nickname: '用户昵称: 177****766',
userId: '58837',
amount: '20.00',
fee: '0.00',
netAmount: '20.00',
name: '接口',
type: '支付宝',
account: '1195953899',
time: '2025-10-24 16:04',
remark: ''
},
{
id: 56,
nickname: '用户昵称: 测试员的',
userId: '20695',
amount: '1.00',
fee: '0.00',
netAmount: '1.00',
name: '123',
type: '银行卡',
account: '4001231221',
bank: '中国银行',
time: '2025-07-04 15:11',
remark: ''
}
])
const handleQuery = () => {
console.log('Query with:', statusValue.value, methodValue.value, searchKeyword.value)
}
</script>
<style scoped lang="scss">
.finance-withdrawal {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 筛选样式更新 */
.filter-card {
background-color: #fff;
padding: 24px;
border-radius: 4px;
margin-bottom: 20px;
}
.filter-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 24px;
margin-bottom: 16px;
}
.filter-label {
font-size: 14px;
color: #606266;
margin-right: 12px;
white-space: nowrap;
}
.dt-picker {
width: 260px;
}
.data-select {
width: 140px;
}
.search-wrap {
flex: 1;
min-width: 320px;
}
.search-input {
flex: 1;
}
.btn-query {
background-color: #1890ff;
color: #fff;
font-size: 14px;
height: 36px;
line-height: 36px;
padding: 0 24px;
border-radius: 4px;
border: none;
margin-bottom: 16px;
}
/* 统计卡片样式 */
.stats-grid {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 20px;
}
.stat-card {
width: 24%;
background-color: #fff;
padding: 24px 20px;
border-radius: 4px;
display: flex;
flex-direction: row;
align-items: center;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.05);
}
.icon-circle {
width: 52px;
height: 52px;
border-radius: 26px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
}
.blue { background-color: #e6f7ff; color: #1890ff; }
.orange { background-color: #fff7e1; color: #fa8c16; }
.green { background-color: #f6ffed; color: #52c41a; }
.pink { background-color: #fff0f6; color: #eb2f96; }
.stat-icon { font-size: 24px; font-weight: bold; }
.stat-info {
display: flex;
flex-direction: column;
}
.stat-value {
font-size: 22px;
font-weight: 700;
color: #303133;
line-height: 1.1;
}
.stat-label {
font-size: 13px;
color: #909399;
margin-top: 6px;
}
/* 操作区域 */
.action-section {
margin-bottom: 12px;
display: flex;
flex-direction: row;
}
.btn-record {
background-color: #1890ff;
border-radius: 4px;
padding: 6px 16px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-record-txt {
color: #fff;
font-size: 13px;
}
/* 表格容器样式 (Flex 模拟) */
.table-container {
background-color: #fff;
border-radius: 4px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.table-header {
background-color: #f8f9fb;
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.th {
padding: 12px 8px;
display: flex;
align-items: center;
justify-content: center;
}
.th-txt {
font-size: 14px;
font-weight: 600;
color: #909399;
}
.table-body {
display: flex;
flex-direction: column;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #ebeef5;
}
.td {
padding: 12px 8px;
display: flex;
align-items: center;
justify-content: center;
}
.td-txt {
font-size: 13px;
color: #606266;
}
/* 列宽定义 (与截图匹配) */
.col-id { width: 60px; }
.col-user { width: 180px; justify-content: flex-start; }
.col-amount { width: 100px; }
.col-fee { width: 100px; }
.col-net { width: 100px; }
.col-method { flex: 1; min-width: 220px; justify-content: flex-start; }
.col-qr { width: 80px; }
.col-time { width: 150px; }
.col-remark { width: 80px; }
.col-status { width: 100px; }
.col-ops { width: 160px; }
/* 用户信息单元格 */
.user-info-box {
display: flex;
flex-direction: row;
align-items: center;
}
.avatar-box {
width: 32px;
height: 32px;
border-radius: 16px;
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
.avatar-placeholder {
font-size: 14px;
color: #999;
}
.user-detail {
display: flex;
flex-direction: column;
}
.user-nickname {
font-size: 13px;
color: #303133;
margin-bottom: 2px;
}
.user-id {
font-size: 11px;
color: #909399;
}
/* 提现方式单元格 */
.method-box {
display: flex;
flex-direction: column;
}
.m-line {
font-size: 12px;
color: #666;
margin-bottom: 2px;
}
.green-txt {
color: #52c41a;
font-weight: 600;
}
/* 收款码 */
.qr-box {
width: 40px;
height: 40px;
background-color: #1a1a1a;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.qr-icon-txt {
color: #fff;
font-size: 16px;
}
/* 操作项 */
.ops-box {
display: flex;
flex-direction: row;
align-items: center;
}
.op-btn {
font-size: 13px;
margin: 0 4px;
}
.blue { color: #1890ff; }
.op-sep {
color: #ebeef5;
font-size: 12px;
}
</style>