first commit

This commit is contained in:
2026-09-21 19:21:35 +08:00
commit 6c944c4ffd
2733 changed files with 296956 additions and 0 deletions
@@ -0,0 +1,178 @@
<template>
<div class="home">
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="用户ID" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户ID" clearable />
</el-form-item>
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable />
</el-form-item>
<el-form-item label="手机号码" prop="phoneNumber">
<el-input v-model="queryParams.phoneNumber" placeholder="请输入手机号码" clearable />
</el-form-item>
<el-form-item label="变动场景">
<el-select v-model="queryParams.source" placeholder="请选择变动场景" clearable style="width: 220px">
<el-option v-for="item in sourceOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="变动类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择变动类型" clearable>
<el-option label="支出" value="0" />
<el-option label="收入" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="tableData" style="width: 100%" v-loading="loading">
<el-table-column align="center" prop="id" label="金币流水记录ID"></el-table-column>
<el-table-column align="center" prop="userId" label="用户ID "></el-table-column>
<el-table-column align="center" prop="amount" label="变动金额 "></el-table-column>
<el-table-column align="center" prop="finalAmount" label="最终金额 "></el-table-column>
<el-table-column align="center" prop="type" label="变动类型">
<template slot-scope="scope">
<div v-if="scope.row.type==0" class="df">
<span class="ds" style="background-color:#00a65a;"></span>支出
</div>
<div v-if="scope.row.type==1" class="df">
<span class="ds" style="background-color:#f3c192;"></span>收入
</div>
</template>
</el-table-column>
<el-table-column align="center" label="变动来源">
<template slot-scope="scope">{{ formatSource(scope.row) }}</template>
</el-table-column>
<el-table-column align="center" prop="createTime" label="创建时间 "></el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.page"
:limit.sync="queryParams.size"
@pagination="getList"
/>
</div>
</template>
<script>
import { getUserBlendErcash } from "@/api/skins/ttUserBlendErcash/api";
import { formatAccountSource } from "@/utils/accountSource";
export default {
name: 'AmountRecords',
data() {
return {
real: 0,
sourceOptions: [
{ value: 1, label: '充值收入' },
{ value: 2, label: '经典开箱消费' },
{ value: 3, label: '经典开箱奖励' },
{ value: 4, label: '对战游戏消费' },
{ value: 5, label: '对战游戏奖励' },
{ value: 56, label: 'Roll房未发放退回主播' },
{ value: 59, label: '主播Roll房奖池扣款' },
{ value: 7, label: 'roll房奖励' },
{ value: 40, label: '幸运升级消费' },
{ value: 41, label: '幸运升级奖励' },
{ value: 38, label: '疯狂转盘消费' },
{ value: 39, label: '疯狂转盘奖励' },
{ value: 64, label: '疯狂转盘注单退款' },
{ value: 60, label: '玫瑰女郎消费' },
{ value: 61, label: '玫瑰女郎奖励' },
{ value: 10, label: '背包分解饰品收入' },
{ value: 12, label: '商城兑换消费' },
{ value: 17, label: '兑换CDKEY收入' },
{ value: 48, label: '推广CDKEY兑换收入' },
{ value: 19, label: '流水消费排行榜奖励' },
{ value: 27, label: '推广充值返利' },
{ value: 47, label: '特殊游戏返利' },
{ value: 49, label: '经典游戏返利' },
{ value: 62, label: '招商周结佣金' },
{ value: 29, label: '消费排行榜奖励' },
{ value: 44, label: 'VIP流水奖励' },
{ value: 63, label: '流水抽奖奖励' },
{ value: 65, label: '管理员调整余额' },
{ value: 66, label: '管理员调整积分' },
],
loading: false,
showSearch: true,
total: 1,
tableData: [],
queryParams: {
page: 1,
size: 10,
nickName: null,
phoneNumber: null,
source: null,
type: null,
userId: null,
moneyType: 1
}
};
},
mounted() {
this.getList();
},
methods: {
resetQuery() {
this.queryParams = {
page: 1,
size: 10,
nickName: null,
phoneNumber: null,
source: null,
type: null,
userId: null,
moneyType: 1
};
this.getList();
},
handleQuery() {
this.getList();
},
// 变动来源:优先按 source 显示中文名,缺失回退 remark
formatSource(row) {
return formatAccountSource(row);
},
getList() {
this.loading = true;
getUserBlendErcash(this.queryParams).then(res => {
this.loading = false;
this.tableData = res.data.records;
this.total = res.data.total;
});
}
}
};
</script>
<style lang="scss" scoped>
.home {
padding: 20px;
}
.ds {
width: 8px;
height: 8px;
margin-right: 10px;
border-radius: 50%;
display: inline-block;
}
.df {
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
</style>
@@ -0,0 +1,227 @@
<template>
<div class="home">
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="用户ID" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户ID" clearable />
</el-form-item>
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable />
</el-form-item>
<el-form-item label="手机号码" prop="phoneNumber">
<el-input v-model="queryParams.phoneNumber" placeholder="请输入手机号码" clearable />
</el-form-item>
<el-form-item label="变动场景">
<el-select v-model="queryParams.source" placeholder="请选择变动场景" clearable style="width: 220px">
<el-option v-for="item in sourceOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="变动类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择变动类型" clearable>
<el-option label="支出" value="0" />
<el-option label="收入" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="tableData" style="width: 100%" v-loading="loading">
<el-table-column align="center" prop="id" :label="moneyType === 2 ? '积分流水记录ID' : '金币流水记录ID'"></el-table-column>
<el-table-column align="center" prop="userId" label="用户ID "></el-table-column>
<el-table-column v-if="moneyType === 2" align="center" prop="credits" label="变动积分 "></el-table-column>
<el-table-column v-if="moneyType === 2" align="center" prop="finalCredits" label="最终积分 "></el-table-column>
<el-table-column v-if="moneyType !== 2" align="center" prop="amount" label="变动金额 "></el-table-column>
<el-table-column v-if="moneyType !== 2" align="center" prop="finalAmount" label="最终金额 "></el-table-column>
<el-table-column align="center" prop="type" label="变动类型">
<template slot-scope="scope">
<div v-if="scope.row.type==0" class="df">
<span class="ds" :style="{ backgroundColor: moneyType === 2 ? '#f3c192' : '#00a65a' }"></span>支出
</div>
<div v-if="scope.row.type==1" class="df">
<span class="ds" :style="{ backgroundColor: moneyType === 2 ? '#dd4b39' : '#f3c192' }"></span>收入
</div>
</template>
</el-table-column>
<el-table-column align="center" label="变动来源">
<template slot-scope="scope">{{ formatSource(scope.row) }}</template>
</el-table-column>
<el-table-column align="center" prop="createTime" label="创建时间 "></el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.page"
:limit.sync="queryParams.size"
@pagination="getList"
/>
</div>
</template>
<script>
import { getUserBlendErcashArchive } from "@/api/skins/ttUserBlendErcash/archiveApi";
import { formatAccountSource } from "@/utils/accountSource";
// 余额(金币)变动来源选项
const AMOUNT_SOURCE_OPTIONS = [
{ value: 1, label: '充值收入' },
{ value: 2, label: '经典开箱消费' },
{ value: 3, label: '经典开箱奖励' },
{ value: 4, label: '对战游戏消费' },
{ value: 5, label: '对战游戏奖励' },
{ value: 56, label: 'Roll房未发放退回主播' },
{ value: 59, label: '主播Roll房奖池扣款' },
{ value: 7, label: 'roll房奖励' },
{ value: 40, label: '幸运升级消费' },
{ value: 41, label: '幸运升级奖励' },
{ value: 38, label: '疯狂转盘消费' },
{ value: 39, label: '疯狂转盘奖励' },
{ value: 64, label: '疯狂转盘注单退款' },
{ value: 60, label: '玫瑰女郎消费' },
{ value: 61, label: '玫瑰女郎奖励' },
{ value: 10, label: '背包分解饰品收入' },
{ value: 12, label: '商城兑换消费' },
{ value: 17, label: '兑换CDKEY收入' },
{ value: 48, label: '推广CDKEY兑换收入' },
{ value: 19, label: '流水消费排行榜奖励' },
{ value: 27, label: '推广充值返利' },
{ value: 47, label: '特殊游戏返利' },
{ value: 49, label: '经典游戏返利' },
{ value: 62, label: '招商周结佣金' },
{ value: 29, label: '消费排行榜奖励' },
{ value: 44, label: 'VIP流水奖励' },
{ value: 63, label: '流水抽奖奖励' },
];
// 积分变动来源选项
const CREDITS_SOURCE_OPTIONS = [
{ value: 1, label: '充值收入' },
{ value: 2, label: '经典开箱消费' },
{ value: 3, label: '经典开箱奖励' },
{ value: 4, label: '对战游戏消费' },
{ value: 5, label: '对战游戏奖励' },
{ value: 56, label: 'Roll房未发放退回主播' },
{ value: 59, label: '主播Roll房奖池扣款' },
{ value: 7, label: 'roll房奖励' },
{ value: 40, label: '幸运升级消费' },
{ value: 41, label: '幸运升级奖励' },
{ value: 38, label: '疯狂转盘消费' },
{ value: 39, label: '疯狂转盘奖励' },
{ value: 64, label: '疯狂转盘注单退款' },
{ value: 60, label: '玫瑰女郎消费' },
{ value: 61, label: '玫瑰女郎奖励' },
{ value: 10, label: '背包分解饰品收入' },
{ value: 12, label: '商城兑换消费' },
{ value: 17, label: '兑换CDKEY收入' },
{ value: 48, label: '推广CDKEY兑换收入' },
{ value: 19, label: '流水消费排行榜奖励' },
{ value: 27, label: '推广充值返利' },
{ value: 47, label: '特殊游戏返利' },
{ value: 49, label: '经典游戏返利' },
{ value: 62, label: '招商周结佣金' },
{ value: 29, label: '消费排行榜奖励' },
{ value: 44, label: 'VIP流水奖励' },
{ value: 63, label: '流水抽奖奖励' },
];
export default {
name: 'BlendErcashArchive',
data() {
return {
// 1=余额(金币)变动,2=积分变动,进入时按路由判定
moneyType: 1,
loading: false,
showSearch: true,
total: 1,
tableData: [],
queryParams: {
page: 1,
size: 10,
nickName: null,
phoneNumber: null,
source: null,
type: null,
userId: null,
moneyType: 1
}
};
},
computed: {
// 按 moneyType 动态选用两套来源选项
sourceOptions() {
return this.moneyType === 2 ? CREDITS_SOURCE_OPTIONS : AMOUNT_SOURCE_OPTIONS;
}
},
created() {
this.moneyType = this.resolveMoneyType();
this.queryParams.moneyType = this.moneyType;
},
mounted() {
this.getList();
},
methods: {
// 路由 path 或 name 含 'Credits' 判为积分(2),否则为余额(1)
resolveMoneyType() {
const routeStr = `${this.$route.path || ''}${this.$route.name || ''}`;
return /credits/i.test(routeStr) ? 2 : 1;
},
resetQuery() {
this.queryParams = {
page: 1,
size: 10,
nickName: null,
phoneNumber: null,
source: null,
type: null,
userId: null,
moneyType: this.moneyType
};
this.getList();
},
handleQuery() {
this.getList();
},
// 变动来源:优先按 source 显示中文名,缺失回退 remark
formatSource(row) {
return formatAccountSource(row);
},
getList() {
this.loading = true;
getUserBlendErcashArchive(this.queryParams).then(res => {
this.loading = false;
this.tableData = res.data.records;
this.total = res.data.total;
});
}
}
};
</script>
<style lang="scss" scoped>
.home {
padding: 20px;
}
.ds {
width: 8px;
height: 8px;
margin-right: 10px;
border-radius: 50%;
display: inline-block;
}
.df {
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
</style>
@@ -0,0 +1,181 @@
<template>
<div class="home">
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="用户ID" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户ID" clearable />
</el-form-item>
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable />
</el-form-item>
<el-form-item label="手机号码" prop="phoneNumber">
<el-input v-model="queryParams.phoneNumber" placeholder="请输入手机号码" clearable />
</el-form-item>
<el-form-item label="变动场景">
<el-select v-model="queryParams.source" placeholder="请选择变动场景" clearable style="width: 220px">
<el-option v-for="item in sourceOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="变动类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择变动类型" clearable>
<el-option label="支出" value="0" />
<el-option label="收入" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="tableData" style="width: 100%" v-loading="loading">
<el-table-column align="center" prop="id" label="积分流水记录ID"></el-table-column>
<el-table-column align="center" prop="userId" label="用户ID "></el-table-column>
<el-table-column align="center" prop="credits" label="变动积分 "></el-table-column>
<el-table-column align="center" prop="finalCredits" label="最终积分 "></el-table-column>
<el-table-column align="center" prop="type" label="变动类型">
<template slot-scope="scope">
<div v-if="scope.row.type==0" class="df">
<span class="ds" style="background-color:#f3c192;"></span>支出
</div>
<div v-if="scope.row.type==1" class="df">
<span class="ds" style="background-color:#dd4b39;"></span>收入
</div>
</template>
</el-table-column>
<el-table-column align="center" label="变动来源">
<template slot-scope="scope">{{ formatSource(scope.row) }}</template>
</el-table-column>
<el-table-column align="center" prop="createTime" label="创建时间 "></el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.page"
:limit.sync="queryParams.size"
@pagination="getList"
/>
</div>
</template>
<script>
import { getUserBlendErcash } from "@/api/skins/ttUserBlendErcash/api";
import { formatAccountSource } from "@/utils/accountSource";
export default {
name: 'CreditsRecords',
data() {
return {
sourceOptions: [
{ value: 1, label: '充值收入' },
{ value: 2, label: '经典开箱消费' },
{ value: 3, label: '经典开箱奖励' },
{ value: 4, label: '对战游戏消费' },
{ value: 5, label: '对战游戏奖励' },
{ value: 56, label: 'Roll房未发放退回主播' },
{ value: 59, label: '主播Roll房奖池扣款' },
{ value: 7, label: 'roll房奖励' },
{ value: 40, label: '幸运升级消费' },
{ value: 41, label: '幸运升级奖励' },
{ value: 38, label: '疯狂转盘消费' },
{ value: 39, label: '疯狂转盘奖励' },
{ value: 64, label: '疯狂转盘注单退款' },
{ value: 60, label: '玫瑰女郎消费' },
{ value: 61, label: '玫瑰女郎奖励' },
{ value: 10, label: '背包分解饰品收入' },
{ value: 12, label: '商城兑换消费' },
{ value: 17, label: '兑换CDKEY收入' },
{ value: 48, label: '推广CDKEY兑换收入' },
{ value: 19, label: '流水消费排行榜奖励' },
{ value: 27, label: '推广充值返利' },
{ value: 47, label: '特殊游戏返利' },
{ value: 49, label: '经典游戏返利' },
{ value: 62, label: '招商周结佣金' },
{ value: 29, label: '消费排行榜奖励' },
{ value: 44, label: 'VIP流水奖励' },
{ value: 63, label: '流水抽奖奖励' },
{ value: 65, label: '管理员调整余额' },
{ value: 66, label: '管理员调整积分' },
],
loading: false,
showSearch: true,
total: 1,
tableData: [],
queryParams: {
page: 1,
size: 10,
nickName: null,
phoneNumber: null,
source: null,
type: null,
userId: null,
moneyType: 2
}
};
},
mounted() {
this.getList();
},
methods: {
resetQuery() {
this.queryParams = {
page: 1,
size: 10,
nickName: null,
phoneNumber: null,
source: null,
type: null,
userId: null,
moneyType: 2
};
this.getList();
},
handleQuery() {
this.getList();
},
// 变动来源:优先按 source 显示中文名,缺失回退 remark
formatSource(row) {
return formatAccountSource(row);
},
getList() {
this.loading = true;
// userCreditsRecords(this.queryParams).then(res => {
// this.loading = false;
// this.tableData = res.rows;
// this.total = res.total;
// });
getUserBlendErcash(this.queryParams).then(res => {
this.loading = false;
this.tableData = res.data.records;
this.total = res.data.total;
});
}
}
};
</script>
<style lang="scss" scoped>
.home {
padding: 20px;
}
.ds {
width: 8px;
height: 8px;
margin-right: 10px;
border-radius: 50%;
display: inline-block;
}
.df {
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
</style>
+976
View File
@@ -0,0 +1,976 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="用户ID" prop="userName">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="用户昵称" prop="nickName">
<el-input
v-model="queryParams.nickName"
placeholder="请输入用户昵称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="用户类型" prop="userType">
<el-select v-model="queryParams.userType" placeholder="请选择用户类型" clearable>
<el-option
v-for="dict in dict.type.user_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="手机号码" prop="phoneNumber">
<el-input
v-model="queryParams.phoneNumber"
placeholder="请输入手机号码"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="用户状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择用户状态" clearable>
<el-option
v-for="dict in dict.type.user_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="邀请码" prop="invitationCode">
<el-input
v-model="queryParams.invitationCode"
placeholder="请输入邀请码"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="上级ID" prop="parentId">
<el-input
v-model="queryParams.parentId"
placeholder="请输入上级ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
icon="el-icon-circle-plus-outline"
type="success"
size="mini"
@click="openBusinessDialog"
>生成招商账号</el-button>
</el-col>
<el-col :span="1.5">
<el-button
icon="el-icon-circle-plus-outline"
type="primary"
size="mini"
@click="addRobot = true"
>生成机器人</el-button>
</el-col>
<el-col :span="1.5">
<el-button
icon="el-icon-circle-plus-outline"
type="danger"
size="mini"
@click="openCardDialog"
>生成卡商账号</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="ID" align="center" prop="userId" />
<el-table-column label="用户昵称" align="center" prop="nickName" />
<el-table-column label="头像" align="center" prop="avatar">
<template slot-scope="scope">
<image-preview :src="scope.row.avatar" :width="50" :height="50" />
</template>
</el-table-column>
<el-table-column label="手机号码" align="center" prop="phoneNumber" />
<el-table-column label="上级" align="center" prop="parentId" />
<el-table-column label="邀请码" align="center" prop="invitationCode" />
<el-table-column label="用户类型" align="center" prop="userType">
<template slot-scope="scope">
<span v-for="dict in dict.type.user_type" v-if="dict.value === scope.row.userType" :key="dict.value">{{ dict.label }}</span>
</template>
</el-table-column>
<el-table-column label="账户金额" align="center" prop="accountAmount" />
<el-table-column label="账户积分" align="center" prop="accountCredits" />
<el-table-column label="帐号状态" align="center" prop="status" class="kg">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
:active-value="'1'"
:inactive-value="'0'"
active-color="#D9534F"
inactive-color="#5CB85C"
active-text="正常"
inactive-text="停用"
@change="updateUserStatus(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="提货状态" align="center" prop="deliveryStatus" class="kg">
<template slot-scope="scope">
<el-switch
v-model="scope.row.deliveryStatus"
:active-value="'1'"
:inactive-value="'0'"
active-color="#D9534F"
inactive-color="#5CB85C"
active-text="启用"
inactive-text="禁用"
@change="updateUserStatus(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="赠送状态" align="center" prop="giftStatus" class="kg">
<template slot-scope="scope">
<el-switch
v-model="scope.row.giftStatus"
:active-value="'1'"
:inactive-value="'0'"
active-color="#D9534F"
inactive-color="#5CB85C"
active-text="启用"
inactive-text="禁用"
@change="updateUserStatus(scope.row)"
></el-switch>
</template>
</el-table-column>
<!-- 推广等级已按要求隐藏(列表与详情都不再展示);最后登录时间移入详情 -->
<el-table-column label="VIP 等级" align="center" prop="vipLevel">
<template slot-scope="scope">VIP{{ scope.row.vipLevel }}</template>
</el-table-column>
<el-table-column label="总充值" align="center" prop="totalPrice" />
<el-table-column label="总提取" align="center" prop="totalDelivery" />
<el-table-column label="最后登录IP" align="center" prop="loginIp" />
<!-- <el-table-column label="备注" align="center" prop="remark" /> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="handleCount(scope.row)">统计</el-button>
<el-button size="mini" type="text" @click="handlePsack(scope.row)">背包</el-button>
<el-dropdown size="mini">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
@click.native="handleUpdate(scope.row)"
>修改</el-dropdown-item>
<el-dropdown-item
@click.native="handleView(scope.row)"
>详情</el-dropdown-item>
<el-dropdown-item
@click.native="handleResetBalance(scope.row)"
>重置余额积分</el-dropdown-item>
<el-dropdown-item
@click.native="handleDelete(scope.row)"
>删除</el-dropdown-item>
<el-dropdown-item
@click.native="handleForceDelete(scope.row)" style="color: #F56C6C;"
>真删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<!-- 生成招商账号 -->
<el-dialog title="新增招商用户" :visible.sync="addNewUser" width="600px">
<el-form label-width="90px">
<el-form-item label="请选择数量:" style="margin-bottom: 12px;">
<el-input-number size="mini" v-model="newNumber" :min="1" :max="10" @change="onBusinessNumberChange"></el-input-number>
<span style="font-size:12px;color:#909399;margin-left:10px;">
<i class="el-icon-info"></i> 可生成 1-10 个账号
</span>
</el-form-item>
<el-form-item
v-for="(item, index) in businessPhones"
:key="index"
:label="'手机号' + (index + 1)"
style="margin-bottom: 10px;"
>
<el-input
v-model="item.value"
maxlength="11"
clearable
placeholder="留空则自动生成随机手机号"
/>
</el-form-item>
<div style="font-size:12px;color:#909399;padding-left:90px;">
<i class="el-icon-info"></i> 手机号选填:填写后作为登录账号,留空则系统随机生成
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addNewUser = false">取 消</el-button>
<el-button type="primary" @click="generateAccount">确 定</el-button>
</div>
</el-dialog>
<!-- 生成机器人 -->
<el-dialog title="生成机器人" :visible.sync="addRobot" width="600px">
<el-form>
<el-form-item label="请选择数量:" style="margin-bottom: 2px;">
<el-input-number size="mini" v-model="newNumber" :min="1" :max="10" label="描述文字"></el-input-number>
</el-form-item>
<div style="font-size:14px;color:#797979;">
<i class="el-icon-info"></i> 要生成的账号数量
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addRobot = false">取 消</el-button>
<el-button type="primary" @click="generateRobot">确 定</el-button>
</div>
</el-dialog>
<!-- 生成卡商账号 -->
<el-dialog title="生成卡商账号" :visible.sync="addCardMerchant" width="600px">
<el-form label-width="90px">
<el-form-item label="请选择数量:" style="margin-bottom: 12px;">
<el-input-number size="mini" v-model="newNumber" :min="1" :max="10" @change="onCardNumberChange"></el-input-number>
<span style="font-size:12px;color:#909399;margin-left:10px;">
<i class="el-icon-info"></i> 可生成 1-10 个卡商账号
</span>
</el-form-item>
<el-form-item
v-for="(item, index) in cardPhones"
:key="index"
:label="'手机号' + (index + 1)"
style="margin-bottom: 10px;"
>
<el-input
v-model="item.value"
maxlength="11"
clearable
placeholder="留空则自动生成随机手机号"
/>
</el-form-item>
<div style="font-size:12px;color:#909399;padding-left:90px;">
<i class="el-icon-info"></i> 手机号选填:填写后作为登录账号,留空则系统随机生成
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addCardMerchant = false">取 消</el-button>
<el-button type="primary" @click="handleGenerateCardMerchant">确 定</el-button>
</div>
</el-dialog>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改注册用户对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" />
</el-form-item>
<el-form-item label="用户类型" prop="userType">
<el-select v-model="form.userType" placeholder="请选择用户类型" disabled>
<el-option
v-for="dict in dict.type.user_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="用户邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入用户邮箱" />
</el-form-item>
<el-form-item label="手机号码" prop="phoneNumber">
<el-input v-model="form.phoneNumber" placeholder="请输入手机号码" />
</el-form-item>
<el-form-item label="邀请码" prop="invitationCode">
<el-input v-model="form.invitationCode" placeholder="请输入邀请码" />
</el-form-item>
<el-form-item label="头像地址" prop="avatar">
<image-upload v-model="form.avatar" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="安全密码" prop="safePasswordPlain">
<el-input v-model="form.safePasswordPlain" placeholder="6位数字,留空则不修改" maxlength="6" />
</el-form-item>
<el-form-item label="账户金额" prop="accountAmount">
<el-input v-model="form.accountAmount" placeholder="请输入账户金额" />
</el-form-item>
<el-form-item label="账户积分" prop="accountCredits">
<el-input v-model="form.accountCredits" placeholder="请输入账户积分" />
</el-form-item>
<el-form-item label="上级ID" prop="parentId">
<el-input v-model="form.parentId" placeholder="请输入上级ID" />
</el-form-item>
<el-form-item label="steam交易链接" prop="transactionLink">
<el-input v-model="form.transactionLink" placeholder="请输入steam交易链接" />
</el-form-item>
<el-form-item label="实名认证状态" prop="isRealCheck">
<el-radio-group v-model="form.isRealCheck">
<el-radio :label="'1'">已实名</el-radio>
<el-radio :label="'0'">未实名</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="邀请新人充值比例" prop="commissionRate">
<el-input v-model="form.commissionRate" placeholder="请输入邀请新人充值比例(如 2 表示 2%)" />
</el-form-item>
<el-form-item v-if="form.userType === '04' || form.userType === '01'" label="新游戏消费返点比例" prop="newGameCommissionRate">
<el-input v-model="form.newGameCommissionRate" placeholder="新游戏消费返点比例(如 1 表示 1%)" />
</el-form-item>
<el-form-item v-if="form.userType === '04' || form.userType === '01'" label="经典玩法返点比例" prop="classicGameCommissionRate">
<el-input v-model="form.classicGameCommissionRate" placeholder="经典玩法返点比例(如 3.5 表示 3.5%)" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 用户详情 -->
<el-dialog title="用户详情" :visible.sync="openView" width="800px" append-to-body>
<el-form ref="form" :model="form" label-width="120px" size="mini">
<el-row>
<el-col :span="12">
<el-form-item label="用户ID:">{{ form.userId }}</el-form-item>
<el-form-item label="账号:">{{ form.userName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户昵称:">{{ form.nickName }}</el-form-item>
<el-form-item label="密码:">{{ form.remark }}</el-form-item>
<el-form-item label="安全密码:">{{ form.safePasswordPlain }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电话号码:">{{ form.phoneNumber }}</el-form-item>
<el-form-item label="用户邮箱:">{{ form.email }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户类型:" prop="userType">
<span v-if="form.userType === '00'">系统用户</span>
<span v-if="form.userType === '01'">主播</span>
<span v-if="form.userType === '02'">普通用户</span>
</el-form-item>
<el-form-item label="用户状态:">
<span v-if="form.status === '0'">正常</span>
<span v-if="form.status === '1'">停用</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="余额:">{{ form.accountAmount }}</el-form-item>
<el-form-item label="积分:">{{ form.accountCredits }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邀请码:">{{ form.invitationCode }}</el-form-item>
<el-form-item label="上级:">{{ form.parentId }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="steam交易链接:">{{ form.transactionLink }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="真实姓名:">{{ form.realName }}</el-form-item>
<el-form-item label="身份证号:">{{ form.idNum }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否实名:">
<span v-if="form.isRealCheck === '0'">未实名</span>
<span v-if="form.isRealCheck === '1'">已实名</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最后登录ip:">{{ form.loginIp }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最后登录时间:">{{ form.loginDate }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建自:">{{ form.createBy }}</el-form-item>
<el-form-item label="注册时间:">{{ form.createTime }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="更新自:">{{ form.updateBy }}</el-form-item>
<el-form-item label="更新时间:">{{ form.updateTime }}</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="openView = false">关 闭</el-button>
</div>
</el-dialog>
<!-- 统计 -->
<el-dialog title="用户利润统计" :visible.sync="countVisible" width="600px">
<el-row style="display: flex; justify-content: center;">
<div id="main"></div>
</el-row>
</el-dialog>
</div>
</template>
<script>
import {
listUser,
getUser,
delUser,
updateUser,
generateAccount,
generateRobot,
generateCardMerchant,
getUserProfitStatistics,
resetUserBalance,
forceDeleteUser
} from "@/api/skins/ttuser/api";
import * as echarts from "echarts";
export default {
name: 'TtUser',
dicts: ["user_type", "user_status"],
data() {
return {
countVisible: false,
openView: false,
newNumber: 1,
addNewUser: false,
addRobot: false,
addCardMerchant: false,
// 招商账号-自定义手机号输入列表(每项 { value },留空则后端随机生成)
businessPhones: [{ value: "" }],
// 卡商账号-自定义手机号输入列表
cardPhones: [{ value: "" }],
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 注册用户表格数据
userList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
nickName: null,
phoneNumber: null,
status: null,
certifyId: null,
userId: null,
userName: null,
userType: null
},
// 表单参数
form: {},
// 表单校验
rules: {
userName: [
{ required: true, message: "用户账号不能为空", trigger: "blur" }
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
userType: [
{ required: true, message: "用户类型不能为空", trigger: "change" }
],
accountAmount: [
{ required: true, message: "账户金额不能为空", trigger: "blur" }
],
accountCredits: [
{ required: true, message: "账户积分不能为空", trigger: "blur" }
],
invitationCode: [
{ required: true, message: "邀请码不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "帐号状态不能为空", trigger: "change" }
],
isRealCheck: [
{
required: true,
message: "实名认证状态不能为空",
trigger: "change"
}
],
delFlag: [
{ required: true, message: "删除标志不能为空", trigger: "change" }
],
safePasswordPlain: [
{
validator: (rule, value, callback) => {
if (!value || /^\d{6}$/.test(value)) return callback();
callback(new Error("安全密码必须为6位数字"));
},
trigger: "blur"
}
]
}
};
},
created() {
this.getList();
},
methods: {
initEcharts(res) {
var chartDom = document.getElementById("main");
var myChart = echarts.init(chartDom);
var option;
option = {
xAxis: {
type: "category",
data: []
},
legend: {
data: ["日出货总金额", "日开启次数", "日利润"]
},
tooltip: {
trigger: "axis"
},
yAxis: {
type: "value"
},
series: [
{
data: [res.totalRecharge],
type: "bar",
name: "总充值",
label: {
show: true,
position: "top",
formatter: "总充值:" + "{c}"
}
},
{
data: [res.totalDelivery],
type: "bar",
name: "总提货",
label: {
show: true,
position: "top",
formatter: "提货:" + "{c}"
}
},
{
data: [res.totalProfit],
type: "bar",
name: "总利润",
label: {
show: true,
position: "top",
formatter: "总利润:" + "{c}"
}
}
]
};
option && myChart.setOption(option);
},
handleCount(res) {
this.countVisible = true;
getUserProfitStatistics(res.userId).then(res => {
this.initEcharts(res.data);
});
},
handlePsack(res) {
this.$router.push({
path: "/user/userPack",
query: {
id: res.userId,
status: 0
}
});
},
handleView(res) {
this.form = [];
this.openView = true;
getUser(res.userId).then(response => {
this.form = response.data;
});
},
/* 打开生成招商账号弹窗 */
openBusinessDialog() {
this.newNumber = 1;
this.businessPhones = this.buildPhoneInputs(this.newNumber, []);
this.addNewUser = true;
},
/* 打开生成卡商账号弹窗 */
openCardDialog() {
this.newNumber = 1;
this.cardPhones = this.buildPhoneInputs(this.newNumber, []);
this.addCardMerchant = true;
},
/* 根据数量构建手机号输入框数组,保留已填写的值 */
buildPhoneInputs(count, existing) {
const list = [];
for (let i = 0; i < count; i++) {
list.push({ value: existing[i] ? existing[i].value : "" });
}
return list;
},
/* 招商账号数量变化时,重建手机号输入框 */
onBusinessNumberChange(val) {
this.businessPhones = this.buildPhoneInputs(val, this.businessPhones);
},
/* 卡商账号数量变化时,重建手机号输入框 */
onCardNumberChange(val) {
this.cardPhones = this.buildPhoneInputs(val, this.cardPhones);
},
/* 校验并提取自定义手机号:合法返回数组(留空占位为""),非法返回 null */
extractCustomPhones(phones) {
const result = [];
const seen = new Set();
const reg = /^1[3-9]\d{9}$/;
for (let i = 0; i < phones.length; i++) {
const v = (phones[i].value || "").trim();
if (v) {
if (!reg.test(v)) {
this.$modal.msgError(`第 ${i + 1} 个手机号格式不正确,请输入 11 位有效手机号`);
return null;
}
if (seen.has(v)) {
this.$modal.msgError(`第 ${i + 1} 个手机号重复:${v}`);
return null;
}
seen.add(v);
}
result.push(v);
}
return result;
},
/* 生成招商账号 */
generateAccount() {
const customPhoneNumbers = this.extractCustomPhones(this.businessPhones);
if (customPhoneNumbers === null) return;
generateAccount({ num: this.newNumber, customPhoneNumbers }).then(res => {
this.getList();
this.addNewUser = false;
const blob = new Blob([res], {
type: "text/plain;charset=utf-8"
});
const objectURL = URL.createObjectURL(blob);
const aTag = document.createElement("a");
aTag.href = objectURL;
aTag.download = `账号数据_${new Date().getTime()}.txt`;
aTag.click();
URL.revokeObjectURL(objectURL);
});
},
/* 生成机器人 */
generateRobot() {
generateRobot(this.newNumber).then(res => {
this.getList();
(this.newNumber = null), (this.addRobot = false);
const blob = new Blob([res], {
type: "text/plain;charset=utf-8"
});
const objectURL = URL.createObjectURL(blob);
const aTag = document.createElement("a");
aTag.href = objectURL;
aTag.download = `账号数据_${new Date().getTime()}.txt`;
aTag.click();
URL.revokeObjectURL(objectURL);
});
},
/* 生成卡商账号 */
handleGenerateCardMerchant() {
const customPhoneNumbers = this.extractCustomPhones(this.cardPhones);
if (customPhoneNumbers === null) return;
generateCardMerchant({ num: this.newNumber, customPhoneNumbers }).then(res => {
this.getList();
this.addCardMerchant = false;
const blob = new Blob([res], {
type: "text/plain;charset=utf-8"
});
const objectURL = URL.createObjectURL(blob);
const aTag = document.createElement("a");
aTag.href = objectURL;
aTag.download = `卡商账号_${new Date().getTime()}.txt`;
aTag.click();
URL.revokeObjectURL(objectURL);
});
},
/** 查询注册用户列表 */
getList() {
this.loading = true;
listUser(this.queryParams).then(response => {
this.userList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
userId: null,
userName: null,
nickName: null,
userType: null,
email: null,
phoneNumber: null,
avatar: null,
password: null,
safePasswordPlain: null,
accountAmount: null,
accountCredits: null,
invitationCode: null,
parentId: null,
status: null,
steamId: null,
transactionLink: null,
realName: null,
idNum: null,
certifyId: null,
isRealCheck: null,
loginIp: null,
loginDate: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null,
delFlag: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 修改用户状态操作 */
updateUserStatus(row) {
// row.avatar = "";
this.loading = true;
updateUser(row).then(res => {
this.$notify({
title: "成功",
message: "修改成功",
type: "success"
});
this.getList();
this.loading = false;
});
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const userId = row.userId || this.ids;
getUser(userId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改注册用户";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != null) {
updateUser(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids;
this.$modal
.confirm('是否确认删除注册用户编号为"' + userIds + '"的数据项?')
.then(function() {
return delUser(userIds);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download(
"admin/user/export",
{
...this.queryParams
},
`user_${new Date().getTime()}.xlsx`
);
},
handleResetBalance(row) {
this.$modal.confirm(`确认将用户【${row.nickName}】的余额和积分重置为 0 吗?`).then(() => {
resetUserBalance(row.userId).then(response => {
if (response.code !== 200) {
this.$modal.msgError(response.msg);
return;
}
this.$modal.msgSuccess("余额和积分已重置为 0");
this.getList();
});
}).catch(() => {});
},
handleForceDelete(row) {
this.$modal.confirm(
`⚠️ 确认彻底删除用户【${row.nickName}】?此操作不可恢复,数据将从数据库永久删除!`
).then(() => {
forceDeleteUser(row.userId).then(response => {
if (response.code !== 200) {
this.$modal.msgError(response.msg);
return;
}
this.$modal.msgSuccess("用户已彻底删除");
this.getList();
});
}).catch(() => {});
}
}
};
</script>
<style lang="scss" scoped>
::v-deep .el-switch {
border-radius: 0px !important;
height: 24px !important;
}
::v-deep .el-switch__core {
width: 70px !important;
height: 24px;
border-radius: 3px;
border: none;
}
::v-deep .el-switch__core::after {
width: 50%;
height: 24px;
border-radius: 0px;
top: 0px !important;
right: 0px !important;
left: 0px;
border: 1px solid #ccc;
border-radius: 3px;
}
::v-deep .el-switch.is-checked .el-switch__core::after {
margin-left: -35px;
box-sizing: border-box;
top: 0px !important;
right: 0px !important;
border: 1px solid #ccc;
border-radius: 3px;
text-align: center;
}
/*关闭时文字位置设置*/
::v-deep .el-switch__label--right {
text-align: center;
position: absolute;
width: 40%;
z-index: 1;
right: 6px;
margin-left: 0px;
color: rgba(255, 255, 255, 1);
span {
font-size: 13px;
box-sizing: border-box;
color: #fff;
}
}
/* 激活时另一个文字消失 */
::v-deep .el-switch__label.is-active {
text-align: center;
display: none;
}
/*开启时文字位置设置*/
::v-deep .el-switch__label--left {
text-align: center;
position: absolute;
width: 40%;
z-index: 1;
left: 5px;
margin-right: 0px;
color: rgba(255, 255, 255, 1);
span {
font-size: 13px;
box-sizing: border-box;
color: #fff;
}
}
#main {
width: 500px;
height: 400px;
}
</style>
+107
View File
@@ -0,0 +1,107 @@
<template>
<div class="app-container">
<el-form ref="queryForm" :inline="true" :model="queryParams" label-width="68px" size="small">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
clearable
placeholder="请输入登录地址"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
clearable
placeholder="请输入用户名称"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" size="mini" type="primary" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
:data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)"
style="width: 100%;"
>
<el-table-column align="center" label="序号" type="index">
<template slot-scope="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="会话编号" prop="token"/>
<el-table-column :show-overflow-tooltip="true" align="center" label="用户昵称" prop="nickName"/>
<el-table-column :show-overflow-tooltip="true" align="center" label="用户账号" prop="userName"/>
<el-table-column :show-overflow-tooltip="true" align="center" label="主机" prop="ipaddr"/>
<el-table-column
:show-overflow-tooltip="true"
align="center"
label="登录地点"
prop="loginLocation"
/>
<el-table-column align="center" label="浏览器" prop="browser"/>
<el-table-column align="center" label="操作系统" prop="os"/>
<el-table-column align="center" label="登录时间" prop="loginTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:limit.sync="queryParams.pageSize"
:page.sync="queryParams.pageNum"
:total="total"
/>
</div>
</template>
<script>
import {listUser_Online} from "@/api/skins/ttuser/api";
export default {
name: 'IpAddr',
data() {
return {
loading: true,
total: 0,
list: [],
pageNum: 1,
pageSize: 10,
queryParams: {
pageNum: 1,
pageSize: 10,
userName: null,
ipaddr: null
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listUser_Online(this.queryParams).then(response => {
this.list = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
}
}
};
</script>
<style lang="scss" scoped>
</style>
@@ -0,0 +1,474 @@
<template>
<div class="app-container">
<el-row>
<el-col :span="18">
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
>
<el-form-item label="用户ID" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="充值记录ID" prop="rechargeRecordId">
<el-input
v-model="queryParams.rechargeRecordId"
placeholder="请输入充值记录ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="下级用户ID" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择">
<el-option label="未结算" value="0"></el-option>
<el-option label="已结算" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="6">
<el-form
:model="ruleForm"
:rules="rules"
ref="ruleForm"
class="demo-ruleForm"
:inline="true"
size="small"
>
<el-form-item prop="value" label="推广统计">
<el-select v-model="ruleForm.value" placeholder="请选择" clearable>
<el-option
v-for="item in userList"
:key="item.userId"
:label="item.nickName"
:value="item.userId"
>
<span style="float: left">{{ item.nickName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.phoneNumber }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleOpen('ruleForm')">统计</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
<el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="推广记录ID" align="center" prop="id" />
<el-table-column label="用户ID" align="center" prop="userId" />
<el-table-column label="下级用户ID" align="center" prop="subordinateUserId" />
<el-table-column label="下级用户总消费" align="center" prop="totalConsumption" />
<el-table-column label="返佣金额" align="center" prop="rebate" />
<el-table-column label="充值记录ID" align="center" prop="rechargeRecordId" />
<!--<el-table-column label="结算状态" align="center" prop="status">-->
<!-- <template slot-scope="scope">-->
<!-- <div v-if="scope.row.status == '1'" class="df">-->
<!-- <span class="ds" style="background: #00a65a;"></span> 已结算-->
<!-- </div>-->
<!-- <div v-if="scope.row.status == '0'" class="df">-->
<!-- <span class="ds" style="background: #DD4B39;"></span>-->
<!-- 未结算-->
<!-- </div>-->
<!-- </template>-->
<!--</el-table-column>-->
<el-table-column label="创建时间" align="center" prop="createTime" />
<el-table-column label="更新时间" align="center" prop="updateTime" />
<!-- <el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button @click="handleOpen(scope.row)" type="text">统计</el-button>
</template>
</el-table-column>-->
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改推广记录数据对话框 -->
<el-dialog title="统计" :visible.sync="open" append-to-body width="50%">
<el-row>
<el-col :span="12" style="font-size:18px">
下级总充值金额:{{formRecoard.rechargeTotal}}
<span style="width: 50px; display: inline-block;"></span>
总返佣金额: {{formRecoard.rebateTotal}}
</el-col>
<el-col :span="12" style="text-align: right;">
<el-radio-group v-model="labelPosition" size="small" @input="handleChange()">
<el-radio-button label="month">月</el-radio-button>
<el-radio-button label="week">周</el-radio-button>
<el-radio-button label="day">日</el-radio-button>
</el-radio-group>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div id="tongji"></div>
</el-col>
<el-col :span="12">
<div id="jiesuan"></div>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script>
import {
getPromotionRecord,
statisticsPromotionData
} from "@/api/skins/ttuser/api";
import { listUser } from "@/api/skins/ttuser/api";
import * as echarts from "echarts";
export default {
name: 'PromotionRecord',
data() {
return {
op: null,
labelPosition: "week",
formRecoard: {},
value: null,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 推广记录数据表格数据
recordList: [],
userList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
userParams: {
pageNum: 1,
pageSize: 99
},
queryParams: {
pageNum: 1,
pageSize: 10,
userId: null,
subordinateUserId: null,
rechargePrice: null,
rebate: null,
rechargeRecordId: null,
status: null
},
// 表单参数
tableData: [],
ruleForm: {
value: null
},
form: {},
// 表单校验
rules: {
userId: [
{ required: true, message: "用户ID不能为空", trigger: "blur" }
],
value: [{ required: true, message: "请选择用户", trigger: "change" }],
subordinateUserId: [
{ required: true, message: "下级用户ID不能为空", trigger: "blur" }
],
rechargePrice: [
{
required: true,
message: "下级用户充值金额不能为空",
trigger: "blur"
}
],
rebate: [
{ required: true, message: "返佣金额不能为空", trigger: "blur" }
],
rechargeRecordId: [
{ required: true, message: "充值记录ID不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "结算状态不能为空", trigger: "change" }
],
createTime: [
{ required: true, message: "创建时间不能为空", trigger: "blur" }
]
}
};
},
created() {
this.getList();
},
methods: {
handleChange() {
if (this.labelPosition == "month") {
let value = [];
value[0] = this.formRecoard.thisMonthRebateTotal;
value[1] = this.formRecoard.thisMonthRechargeTotal;
let data = [];
data[0] = "本月返佣总金额";
data[1] = "本月下级充值总金额 ";
this.op = "月";
this.drawLine(data, value);
} else if (this.labelPosition == "week") {
let value = [];
value[0] = this.formRecoard.thisWeekRebateTotal;
value[1] = this.formRecoard.thisWeekRechargeTotal;
let data = [];
data[0] = "本周返佣总金额";
data[1] = "本周下级充值总金额";
this.op = "周";
this.drawLine(data, value);
} else if (this.labelPosition == "day") {
let value = [];
value[0] = this.formRecoard.todayRebateTotal;
value[1] = this.formRecoard.todayRechargeTota;
let data = [];
data[0] = "今日返佣总金额";
data[1] = "今日下级充值总金额";
this.op = "日";
this.drawLine(data, value);
}
},
drawLine(data, value) {
var chartDom = document.getElementById("tongji");
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: `本${this.op}下级充值/返佣统计`
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow"
}
},
xAxis: {
type: "category",
data: data
},
yAxis: {
type: "value"
},
series: [
{
data: value,
type: "bar"
}
]
};
option && myChart.setOption(option);
},
draw(data, value) {
var chartDom = document.getElementById("jiesuan");
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: "结算统计"
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow"
}
},
xAxis: {
type: "category",
data: data
},
yAxis: {
type: "value"
},
series: [
{
data: value,
type: "bar"
}
]
};
option && myChart.setOption(option);
},
handleOpen(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
this.open = true;
statisticsPromotionData(this.ruleForm.value).then(res => {
this.formRecoard = res.data;
// this.tableData[0] = res.data;
let data = [];
data[0] = "已结算返佣金额";
data[1] = "未结算返佣金额";
let value = [];
value[0] = res.data.balancedPrice;
value[1] = res.data.unbalancedPrice;
this.draw(data, value);
this.handleChange();
});
} else {
}
});
},
/** 查询推广记录数据列表 */
getList() {
this.loading = true;
getPromotionRecord(this.queryParams).then(response => {
this.recordList = response.rows;
this.total = response.total;
this.loading = false;
});
listUser(this.userParams).then(response => {
this.userList = response.rows;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: null,
userId: null,
subordinateUserId: null,
rechargePrice: null,
rebate: null,
rechargeRecordId: null,
status: null,
createTime: null,
updateTime: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加推广记录数据";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids;
getRecord(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改推广记录数据";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateRecord(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addRecord(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal
.confirm('是否确认删除推广记录数据编号为"' + ids + '"的数据项?')
.then(function() {
return delRecord(ids);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download(
"system/record/export",
{
...this.queryParams
},
`record_${new Date().getTime()}.xlsx`
);
}
}
};
</script>
<style scoped lang="scss">
.df {
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
.ds {
width: 8px;
height: 8px;
margin-right: 10px;
border-radius: 50%;
display: inline-block;
}
#jiesuan {
width: 450px;
height: 400px;
}
#tongji {
width: 450px;
height: 400px;
}
</style>
@@ -0,0 +1,70 @@
<template>
<div style="width: 98%; margin:0 auto; margin-top:50px;">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="id" label="Id" width="100"></el-table-column>
<el-table-column prop="nickName" label="称谓" width="100"></el-table-column>
<el-table-column prop="lv" label="等级" width="100"></el-table-column>
<el-table-column prop="Accumulated" label="下级累计充值" width="100"></el-table-column>
<el-table-column prop="Rebate" label="返佣比例(%)" width="100"></el-table-column>
<el-table-column prop="Registration" label="注册赠送" width="100"></el-table-column>
<el-table-column prop="desc" label="描述"></el-table-column>
<el-table-column prop="address" label="操作"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'SpreadLevel',
data() {
return {
tableData: [
{
id: 1,
nickName: "LV1",
lv: 1,
Accumulated: 200.0,
Rebate: 1.0,
Registration: 0.0,
desc: " 受邀用户累计充值200X币,玩家获得用户充值返佣1%"
},
{
id: 2,
nickName: "LV2",
lv: 2,
Accumulated: 1000.0,
Rebate: 1.5,
Registration: 0.0,
desc: " 受邀用户累计充值1000X币,玩家获得用户充值返佣1.5%"
},
{
id: 3,
nickName: "LV3",
lv: 3,
Accumulated: 5000.0,
Rebate: 2.0,
Registration: 0.0,
desc: " 受邀用户累计充值5000X币,玩家获得用户充值返佣2%"
},
{
id: 4,
nickName: "LV4",
lv: 4,
Accumulated: 10000.0,
Rebate: 2.5,
Registration: 0.0,
desc: " 受邀用户累计充值10000X币,玩家获得用户充值返佣2.5%"
},
{
id: 5,
nickName: "LV5",
lv: 5,
Accumulated: 20000.0,
Rebate: 3.0,
Registration: 0.0,
desc: " 受邀用户累计充值20000X币,玩家获得用户充值返佣3%"
}
]
};
}
};
</script>
@@ -0,0 +1,391 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="用户ID" prop="holderUserId">
<el-input
v-model="queryParams.holderUserId"
placeholder="请输入用户ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="对战ID" prop="fightId">
<el-input
v-model="queryParams.fightId"
placeholder="请输入用户昵称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="roll房ID" prop="rollId">
<el-input
v-model="queryParams.rollId"
placeholder="请输入邀请码"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phoneNumber">
<el-input
v-model="queryParams.phoneNumber"
placeholder="请输入手机号码"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="饰品来源" prop="source">
<el-select v-model="queryParams.source" placeholder="请选择来源" clearable>
<el-option label="经典开箱" value="1" />
<el-option label="对战" value="2" />
<el-option label="roll房" value="3" />
<el-option label="幸运升级" value="4" />
<el-option label="疯狂转盘" value="99" />
<el-option label="玫瑰女郎" value="13" />
<el-option label="转赠" value="9" />
<el-option label="系统发放" value="5" />
<el-option label="商城兑换" value="6" />
<el-option label="流水抽奖" value="14" />
</el-select>
</el-form-item>
<el-form-item label="饰品状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option
v-for="(label, value) in statusMap"
:key="value"
:label="label"
:value="String(value)"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
:disabled="multiple"
icon="el-icon-delete"
plain
size="mini"
type="danger"
@click="handleDel"
>删除</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column align="center" label="Id" prop="id" />
<el-table-column align="center" label="用户ID" prop="holderUserId" />
<el-table-column align="center" label="持有人" prop="nickName" />
<el-table-column align="center" label="饰品名称" prop="ornamentName" />
<el-table-column align="center" label="饰品图片" prop="avatar">
<template slot-scope="scope">
<image-preview :src="scope.row.imageUrl" :width="50" :height="50" />
</template>
</el-table-column>
<el-table-column align="center" label="饰品价格" prop="ornamentsPrice" />
<el-table-column align="center" label="来源" prop="source">
<template slot-scope="scope">
<span>{{ sourceLabel(scope.row.source) }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="状态" prop="status">
<template slot-scope="scope">
<span>{{ statusLabel(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="Roll房ID" prop="rollId" />
<el-table-column align="center" label="对战ID" prop="fightId" />
<el-table-column align="center" label="创建时间" prop="createTime" />
<el-table-column align="center" label="更新时间" prop="updateTime" />
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleDel(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script>
import { getPackSack, removeUserPackSackData } from "@/api/skins/ttuser/api";
export default {
name: 'UserPack',
dicts: ["user_type", "user_status", "user_pack_from"],
data() {
return {
sourceMap: {
1: '经典开箱',
2: '对战',
3: 'roll房',
4: '幸运升级',
99: '疯狂转盘',
5: '系统发放',
6: '商城兑换',
9: '转赠',
13: '玫瑰女郎',
14: '流水抽奖'
},
statusMap: {
0: '在背包显示',
1: '在背包不显示',
2: '申请提货',
3: '已经提货',
5: '分解',
10: '管理员删除',
20: '转赠审核中'
},
multiple: true,
ids: [],
openView: false,
newNumber: 1,
addNewUser: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 注册用户表格数据
userList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
userId: null,
holderUserId: this.$route.query.id,
phoneNumber: null,
status: '0',
source: null,
fightId: null,
rollId: null
},
// 表单参数
form: {},
// 表单校验
rules: {
userName: [
{ required: true, message: "用户账号不能为空", trigger: "blur" }
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
userType: [
{ required: true, message: "用户类型不能为空", trigger: "change" }
],
accountAmount: [
{ required: true, message: "账户金额不能为空", trigger: "blur" }
],
accountCredits: [
{ required: true, message: "账户积分不能为空", trigger: "blur" }
],
invitationCode: [
{ required: true, message: "邀请码不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "帐号状态不能为空", trigger: "change" }
],
isRealCheck: [
{
required: true,
message: "实名认证状态不能为空",
trigger: "change"
}
],
delFlag: [
{ required: true, message: "删除标志不能为空", trigger: "change" }
]
}
};
},
created() {
this.getList();
},
methods: {
sourceLabel(source) {
return this.sourceMap[source] || this.sourceMap[String(source)] || source;
},
statusLabel(row) {
// status=2 在库里只表示「待在提货背包」,不是「已提交提货申请」:
// 商城购买入库就是 2,用户点提货后状态仍是 2,靠 tt_delivery_record 区分。
// 有未取消的提货记录(后端返回 deliveryApply=1)才算「申请提货」,否则就是「在背包显示」。
if (String(row.status) === '2') {
return Number(row.deliveryApply) > 0 ? '申请提货' : '在背包显示';
}
return this.statusMap[row.status] || this.statusMap[String(row.status)] || row.status;
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleDel(row) {
const ids = row.id || this.ids;
this.$modal
.confirm('是否确认删除编号为"' + ids + '"的数据项?')
.then(function() {
return removeUserPackSackData(ids);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
},
getList() {
this.loading = true;
getPackSack(this.queryParams).then(response => {
this.userList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
userId: null,
userName: null,
nickName: null,
userType: null,
email: null,
phoneNumber: null,
avatar: null,
password: null,
accountAmount: null,
accountCredits: null,
invitationCode: null,
parentId: null,
status: null,
steamId: null,
transactionLink: null,
realName: null,
idNum: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
userId: null,
holderUserId: null,
phoneNumber: null,
status: '0',
source: null,
fightId: null,
rollId: null
};
this.handleQuery();
}
}
};
</script>
<style lang="scss" scoped>
::v-deep .el-switch {
border-radius: 0px !important;
height: 24px !important;
}
::v-deep .el-switch__core {
width: 70px !important;
height: 24px;
border-radius: 3px;
border: none;
}
::v-deep .el-switch__core::after {
width: 50%;
height: 24px;
border-radius: 0px;
top: 0px !important;
right: 0px !important;
left: 0px;
border: 1px solid #ccc;
border-radius: 3px;
}
::v-deep .el-switch.is-checked .el-switch__core::after {
margin-left: -35px;
box-sizing: border-box;
top: 0px !important;
right: 0px !important;
border: 1px solid #ccc;
border-radius: 3px;
text-align: center;
}
/*关闭时文字位置设置*/
::v-deep .el-switch__label--right {
text-align: center;
position: absolute;
width: 40%;
z-index: 1;
right: 6px;
margin-left: 0px;
color: rgba(255, 255, 255, 1);
span {
font-size: 13px;
box-sizing: border-box;
color: #fff;
}
}
/* 激活时另一个文字消失 */
::v-deep .el-switch__label.is-active {
text-align: center;
display: none;
}
/*开启时文字位置设置*/
::v-deep .el-switch__label--left {
text-align: center;
position: absolute;
width: 40%;
z-index: 1;
left: 5px;
margin-right: 0px;
color: rgba(255, 255, 255, 1);
span {
font-size: 13px;
box-sizing: border-box;
color: #fff;
}
}
</style>
@@ -0,0 +1,208 @@
<template>
<div class="app-container">
<!-- 搜索栏 -->
<el-row :gutter="10" style="margin-bottom:16px">
<el-input v-model="queryParams.userId" placeholder="用户ID" clearable @clear="handleSearch" @keyup.enter.native="handleSearch" style="width:130px" />
<el-input v-model="queryParams.nickName" placeholder="昵称" clearable @clear="handleSearch" @keyup.enter.native="handleSearch" style="width:130px" />
<el-input v-model="queryParams.phone" placeholder="手机号" clearable @clear="handleSearch" @keyup.enter.native="handleSearch" style="width:150px" />
<el-date-picker
v-model="dateRange"
type="datetimerange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
:picker-options="pickerOptions"
style="width:380px"
/>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
</el-row>
<!-- 排序提示 -->
<el-alert :closable="false" style="margin-bottom:12px" type="info">
当前排序:
<b>{{ sortLabels[queryParams.sortField] || '总流水' }}</b>
<span style="margin-left:4px">{{ queryParams.sortOrder === 'asc' ? '↑ 升序' : '↓ 降序' }}</span>
<span style="margin-left:12px;color:#909399">点击表头可切换排序字段和方向</span>
</el-alert>
<!-- 数据表格 -->
<div style="overflow-x:auto">
<el-table v-loading="loading" :data="tableData" border @sort-change="handleSortChange" style="width:100%">
<el-table-column prop="userId" label="用户ID" width="90" align="center" fixed sortable="custom" />
<el-table-column prop="nickName" label="昵称" width="120" show-overflow-tooltip fixed />
<el-table-column prop="phone" label="手机号" min-width="120" align="center" />
<el-table-column label="用户类型" min-width="80" align="center">
<template slot-scope="scope">
<el-tag size="mini" :type="userTypeTag(scope.row.userType)">{{ userTypeLabel(scope.row.userType) }}</el-tag>
</template>
</el-table-column>
<!-- 充值 -->
<el-table-column prop="totalRecharge" label="总充值" min-width="110" align="right" sortable="custom">
<template slot-scope="scope"><span style="color:#67c23a">{{ formatMoney(scope.row.totalRecharge) }}</span></template>
</el-table-column>
<!-- 消费流水 -->
<el-table-column prop="totalTurnover" label="总流水" min-width="110" align="right" sortable="custom">
<template slot-scope="scope"><span style="color:#f56c6c">{{ formatMoney(scope.row.totalTurnover) }}</span></template>
</el-table-column>
<!-- 游戏分类消费 -->
<el-table-column label="游戏分类消费" align="center">
<el-table-column prop="classicBox" label="经典开箱" min-width="100" align="right" sortable="custom">
<template slot-scope="scope">{{ formatMoney(scope.row.classicBox) }}</template>
</el-table-column>
<el-table-column prop="fightGame" label="对战" min-width="80" align="right" sortable="custom">
<template slot-scope="scope">{{ formatMoney(scope.row.fightGame) }}</template>
</el-table-column>
<el-table-column prop="luckyUpgrade" label="幸运升级" min-width="100" align="right" sortable="custom">
<template slot-scope="scope">{{ formatMoney(scope.row.luckyUpgrade) }}</template>
</el-table-column>
<el-table-column prop="wheelGame" label="疯狂转盘" min-width="100" align="right" sortable="custom">
<template slot-scope="scope">{{ formatMoney(scope.row.wheelGame) }}</template>
</el-table-column>
<el-table-column prop="olympusGame" label="玫瑰女郎" min-width="100" align="right" sortable="custom">
<template slot-scope="scope">{{ formatMoney(scope.row.olympusGame) }}</template>
</el-table-column>
<el-table-column prop="rollRoom" label="roll房" min-width="90" align="right" sortable="custom">
<template slot-scope="scope">{{ formatMoney(scope.row.rollRoom) }}</template>
</el-table-column>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<el-pagination
style="margin-top:16px;text-align:right"
background
layout="total, prev, pager, next, sizes"
:total="total"
:page-size.sync="queryParams.pageSize"
:current-page.sync="queryParams.pageNum"
:page-sizes="[5,10,20,50]"
@size-change="loadData"
@current-change="loadData"
/>
</div>
</template>
<script>
import { getUserTurnover } from '@/api/skins/userTurnover'
const sortLabels = {
totalRecharge: '充值', totalTurnover: '总流水',
classicBox: '经典开箱', fightGame: '对战', luckyUpgrade: '幸运升级',
wheelGame: '疯狂转盘', olympusGame: '玫瑰女郎', rollRoom: 'roll房',
userId: '用户ID'
}
/** 格式化日期为 yyyy-MM-dd HH:mm:ss */
function fmtDate(d) {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const h = String(d.getHours()).padStart(2, '0')
const min = String(d.getMinutes()).padStart(2, '0')
const s = String(d.getSeconds()).padStart(2, '0')
return `${y}-${m}-${day} ${h}:${min}:${s}`
}
/** 获取默认日期范围:昨天00:00:00 至 今天当前时间 */
function getDefaultDateRange() {
const now = new Date()
const yesterday = new Date(now)
yesterday.setDate(yesterday.getDate() - 1)
yesterday.setHours(0, 0, 0, 0)
return [fmtDate(yesterday), fmtDate(now)]
}
export default {
name: 'UserTurnover',
data() {
return {
loading: false,
tableData: [],
total: 0,
sortLabels,
// 日期范围,默认昨天00:00:00 至 今天当前时间
dateRange: getDefaultDateRange(),
pickerOptions: {
shortcuts: [
{ text: '今日', onClick(picker) {
const now = new Date(); const start = new Date(now); start.setHours(0, 0, 0, 0)
picker.$emit('pick', [start, now])
}},
{ text: '昨日', onClick(picker) {
const yd = new Date(); yd.setDate(yd.getDate() - 1); yd.setHours(0, 0, 0, 0)
const ydEnd = new Date(yd); ydEnd.setHours(23, 59, 59, 999)
picker.$emit('pick', [yd, ydEnd])
}},
{ text: '本周', onClick(picker) {
const now = new Date(); const day = now.getDay(); const diff = day === 0 ? 6 : day - 1
const monday = new Date(now); monday.setDate(monday.getDate() - diff); monday.setHours(0, 0, 0, 0)
picker.$emit('pick', [monday, now])
}},
{ text: '上周', onClick(picker) {
const now = new Date(); const day = now.getDay(); const diff = day === 0 ? 6 : day - 1
const lastMonday = new Date(now); lastMonday.setDate(lastMonday.getDate() - diff - 7); lastMonday.setHours(0, 0, 0, 0)
const lastSunday = new Date(lastMonday); lastSunday.setDate(lastSunday.getDate() + 6); lastSunday.setHours(23, 59, 59, 999)
picker.$emit('pick', [lastMonday, lastSunday])
}}
]
},
queryParams: {
userId: null,
nickName: null,
phone: null,
sortField: 'totalTurnover',
sortOrder: 'desc',
pageNum: 1,
pageSize: 10
}
}
},
created() { this.loadData() },
methods: {
loadData() {
this.loading = true
const params = { ...this.queryParams }
if (params.userId) params.userId = Number(params.userId)
// 日期范围(已是完整的 yyyy-MM-dd HH:mm:ss 格式)
if (this.dateRange && this.dateRange.length === 2) {
params.startTime = this.dateRange[0]
params.endTime = this.dateRange[1]
}
getUserTurnover(params).then(res => {
this.tableData = res.data.rows || []
this.total = res.data.total || 0
}).finally(() => { this.loading = false })
},
handleSearch() { this.queryParams.pageNum = 1; this.loadData() },
handleReset() {
this.dateRange = getDefaultDateRange()
this.queryParams = { userId: null, nickName: null, phone: null, sortField: 'totalTurnover', sortOrder: 'desc', pageNum: 1, pageSize: 10 }
this.loadData()
},
handleSortChange({ prop, order }) {
this.queryParams.sortField = prop || 'totalTurnover'
this.queryParams.sortOrder = order === 'ascending' ? 'asc' : 'desc'
this.loadData()
},
formatMoney(v) {
if (v == null) return '0.00'
return Number(v).toFixed(2)
},
userTypeLabel(type) {
const map = { '01': '主播', '02': '普通用户', '03': '机器人', '04': '招商', '05': '卡商', '99': '超级管理员' }
return map[type] || type || '-'
},
userTypeTag(type) {
const map = { '01': 'success', '02': '', '03': 'info', '04': 'warning', '05': 'danger', '99': 'danger' }
return map[type] || ''
}
}
}
</script>
+22
View File
@@ -0,0 +1,22 @@
<template>
<div>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="等级" width="180"></el-table-column>
<el-table-column prop="name" label="累充门槛" width="180"></el-table-column>
<el-table-column prop="name" label="充返比率(%)" width="180"></el-table-column>
<el-table-column prop="name" label="奖励红包" width="180"></el-table-column>
<el-table-column prop="name" label="描述" width="180"></el-table-column>
<el-table-column prop="name" label="创建时间" width="180"></el-table-column>
<el-table-column prop="name" label="更新时间" width="180"></el-table-column>
<el-table-column prop="address" label="操作"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'UserVips',
data() {
return {};
}
};
</script>