新增直营列表
This commit is contained in:
@@ -56,6 +56,11 @@
|
||||
<el-icon><Money /></el-icon>
|
||||
<template #title>转账管理</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="/direct-sale">
|
||||
<el-icon><Coin /></el-icon>
|
||||
<template #title>直营列表</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item v-if="userStore.isAdmin" index="/daily-transfer-stats">
|
||||
<el-icon><DataAnalysis /></el-icon>
|
||||
|
||||
@@ -48,6 +48,15 @@ const routes = [
|
||||
icon: 'Money'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'direct-sale',
|
||||
name: 'DirectSale',
|
||||
component: () => import('@/views/DirectSale.vue'),
|
||||
meta: {
|
||||
title: '直接销售 - 代理后台管理系统',
|
||||
icon: 'Coin'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'commissions',
|
||||
name: 'Commissions',
|
||||
|
||||
@@ -203,6 +203,14 @@ const api = {
|
||||
getTransferStats: () => request.get('/agents/transfers/stats')
|
||||
},
|
||||
|
||||
// 直营列表
|
||||
directSale: {
|
||||
getStats: () => request.get('/direct-sale/stats'),// 获取整体数据
|
||||
getDirectSales: (params) => request.get('/direct-sale', {params}),// 获取直营列表
|
||||
createDirectSale: (data) => request.post('/direct-sale', data),// 创建直营
|
||||
withdraw: (id) => request.post(`/direct-sale/${id}/withdraw`),// 提现
|
||||
},
|
||||
|
||||
// 文件上传
|
||||
upload: {
|
||||
uploadImage: (file) => {
|
||||
|
||||
450
src/views/DirectSale.vue
Normal file
450
src/views/DirectSale.vue
Normal file
@@ -0,0 +1,450 @@
|
||||
<template>
|
||||
<div class="direct-sale-container">
|
||||
<div class="page-header">
|
||||
<h1>直营列表</h1>
|
||||
<el-button type="primary" @click="createDirectSaler">
|
||||
<el-icon><Plus /></el-icon>
|
||||
创建直营
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索和筛选 -->
|
||||
<div class="search-section">
|
||||
<el-card>
|
||||
<el-form :model="searchForm" inline>
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="searchForm.search"
|
||||
placeholder="请输入姓名或手机号"
|
||||
clearable
|
||||
style="width: 250px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="等级">
|
||||
<el-select
|
||||
v-model="searchForm.level"
|
||||
placeholder="请选择等级"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option label="全部" value=""/>
|
||||
<el-option label="普通" value="normal"/>
|
||||
<el-option label="VIP" value="vip"/>
|
||||
<el-option label="SVIP" value="svip"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon>
|
||||
<Search/>
|
||||
</el-icon>
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon>
|
||||
<Refresh/>
|
||||
</el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<div class="stats-section">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-card class="stats-card">
|
||||
<div class="stats-content">
|
||||
<div class="stats-icon">
|
||||
<el-icon color="#409EFF">
|
||||
<User/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stats-info">
|
||||
<div class="stats-value">{{ directSaleStats.total_users || 0 }}</div>
|
||||
<div class="stats-label">总用户数</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="stats-card">
|
||||
<div class="stats-content">
|
||||
<div class="stats-icon">
|
||||
<el-icon color="#67C23A">
|
||||
<Coin/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stats-info">
|
||||
<div class="stats-value">{{ directSaleStats.total_beans || 0 }}</div>
|
||||
<div class="stats-label">总融豆数量</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="stats-card">
|
||||
<div class="stats-content">
|
||||
<div class="stats-icon">
|
||||
<el-icon color="#E6A23C">
|
||||
<Money/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stats-info">
|
||||
<div class="stats-value">{{ directSaleStats.today_withdrawals || 0 }}</div>
|
||||
<div class="stats-label">今日提现</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="stats-card">
|
||||
<div class="stats-content">
|
||||
<div class="stats-icon">
|
||||
<el-icon color="#F56C6C">
|
||||
<TrendCharts/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stats-info">
|
||||
<div class="stats-value">{{ directSaleStats.total_withdrawals || 0 }}</div>
|
||||
<div class="stats-label">总提现次数</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 直营列表表格 -->
|
||||
<div class="table-section">
|
||||
<el-card>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="directSaleList"
|
||||
stripe
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="id" label="ID" width="80"/>
|
||||
<el-table-column prop="name" label="姓名" width="120"/>
|
||||
<el-table-column label="手机号" width="150">
|
||||
<template #default="{ row }">
|
||||
{{ maskPhoneNumber(row.phone) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="beans_count" label="融豆数量" width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="beans-amount">{{ row.beans_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="level" label="等级" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getLevelType(row.level)">
|
||||
{{ getLevelText(row.level) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="created_at" label="注册时间" width="250">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleWithdraw(row)"
|
||||
>
|
||||
提现
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.size"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, reactive, onMounted} from 'vue'
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import {
|
||||
Search,
|
||||
Refresh,
|
||||
User,
|
||||
Coin,
|
||||
Money,
|
||||
TrendCharts
|
||||
} from '@element-plus/icons-vue'
|
||||
import api from '@/utils/api'
|
||||
import {maskPhoneNumber} from '@/utils/public_method'
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const directSaler = ref({})
|
||||
const directSaleList = ref([])
|
||||
const directSaleStats = ref({
|
||||
total_users: 0,
|
||||
total_beans: 0,
|
||||
today_withdrawals: 0,
|
||||
total_withdrawals: 0
|
||||
})
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
search: '',
|
||||
min_beans: null,
|
||||
max_beans: null,
|
||||
level: ''
|
||||
})
|
||||
|
||||
// 分页信息
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
size: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 创建直营
|
||||
const createDirectSaler = async () => {
|
||||
try {
|
||||
console.log("创建直营数据:",directSaler)
|
||||
await api.directSale.createDirectSale(directSaler.value)
|
||||
ElMessage.success('创建直营成功')
|
||||
getDirectSaleList()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error('创建直营失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 获取直营列表
|
||||
const getDirectSaleList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: searchForm.search,
|
||||
min_beans: searchForm.min_beans,
|
||||
max_beans: searchForm.max_beans,
|
||||
level: searchForm.level
|
||||
}
|
||||
|
||||
const response = await api.directSale.getDirectSales(params)
|
||||
directSaleList.value = response.data.data.direct_sales
|
||||
pagination.total = response.data.data.pagination.total
|
||||
} catch (error) {
|
||||
directSaleList.value = [{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
phone: '13800000000',
|
||||
beans_count: 1000,
|
||||
level: 'normal',
|
||||
created_at: '2023-01-01 00:00:00'
|
||||
},{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
phone: '13900000000',
|
||||
beans_count: 2000,
|
||||
level: 'vip',
|
||||
created_at: '2023-01-02 00:00:00'
|
||||
}]
|
||||
console.log(error)
|
||||
ElMessage.error('获取直营列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取统计数据
|
||||
const getDirectSaleStats = async () => {
|
||||
try {
|
||||
const response = await api.directSale.getStats()
|
||||
directSaleStats.value = response.data.data
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error('获取统计数据失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
getDirectSaleList()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchForm.search = ''
|
||||
searchForm.min_beans = null
|
||||
searchForm.max_beans = null
|
||||
searchForm.level = ''
|
||||
pagination.page = 1
|
||||
getDirectSaleList()
|
||||
}
|
||||
|
||||
// 分页大小改变
|
||||
const handleSizeChange = (size) => {
|
||||
pagination.size = size
|
||||
pagination.page = 1
|
||||
getDirectSaleList()
|
||||
}
|
||||
|
||||
// 当前页改变
|
||||
const handleCurrentChange = (page) => {
|
||||
pagination.page = page
|
||||
getDirectSaleList()
|
||||
}
|
||||
|
||||
// 处理提现
|
||||
const handleWithdraw = async (row) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要为用户 ${row.name} 进行提现操作吗?`,
|
||||
'提现确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
const response = await api.directSale.withdraw(row.id)
|
||||
ElMessage.success('提现操作成功')
|
||||
|
||||
// 刷新列表和统计数据
|
||||
getDirectSaleList()
|
||||
getDirectSaleStats()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.log(error)
|
||||
ElMessage.error('提现操作失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date) => {
|
||||
if (!date) return '-'
|
||||
return new Date(date).toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
// 获取等级类型
|
||||
const getLevelType = (level) => {
|
||||
const levelMap = {
|
||||
'normal': '',
|
||||
'vip': 'success',
|
||||
'svip': 'warning'
|
||||
}
|
||||
return levelMap[level] || ''
|
||||
}
|
||||
|
||||
// 获取等级文本
|
||||
const getLevelText = (level) => {
|
||||
const levelMap = {
|
||||
'normal': '普通',
|
||||
'vip': 'VIP',
|
||||
'svip': 'SVIP'
|
||||
}
|
||||
return levelMap[level] || '普通'
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
getDirectSaleList()
|
||||
getDirectSaleStats()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.direct-sale-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* .page-header {
|
||||
margin-bottom: 20px;
|
||||
} */
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stats-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.stats-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.stats-icon {
|
||||
font-size: 32px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.stats-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.beans-amount {
|
||||
color: #67C23A;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user