|
@@ -0,0 +1,1298 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="new-app-container layout-vertical">
|
|
|
|
|
+ <YMTableSearch :loading="loading" :search-form="searchForm" @onValueChange="onValueChange" @submit="onSubmit">
|
|
|
|
|
+ <template #dateRange="{ form }">
|
|
|
|
|
+ <div style="margin-right: 20px">
|
|
|
|
|
+ <el-date-picker v-model="form.dateRange" type="daterange" align="right" unlink-panels 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: 260px">
|
|
|
|
|
+ </el-date-picker>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </YMTableSearch>
|
|
|
|
|
+
|
|
|
|
|
+ <div style="margin-bottom: 12px; padding-left: 16px">
|
|
|
|
|
+ <el-button type="primary" :disabled="selectedMemberIds.length === 0"
|
|
|
|
|
+ @click="handleBatchSetChannel">批量设置通道</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <YMTable ref="table" :table-key="1" :index="true" :selection="true" @selection-change="handleSelectionChange"
|
|
|
|
|
+ :table-options="tableOptions" :edit-form="editForm" :edit-config="editConfig" :columns="columns"
|
|
|
|
|
+ :rows-actions="rowsActions" :show-summary="false" :apis="apis" :actionsWidth="100" @headerClick="headerClick"
|
|
|
|
|
+ :custom-style="{ height: 'calc(100vh - 280px)' }">
|
|
|
|
|
+ <template #agent="scoped">
|
|
|
|
|
+ <div v-if="scoped.row.agent">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ {{ scoped.row.agent.first_name || "--" }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ ID: {{ scoped.row.agent.member_id }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ 邀请码: {{ scoped.row.agent.user_code }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span v-else style="color: #c0c4cc">--</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 注册来源 -->
|
|
|
|
|
+ <template #from="{ row }">
|
|
|
|
|
+ <span :style="{
|
|
|
|
|
+ color: Number(row.from) === 1 ? '#05A58F' : Number(row.from) === 2 ? '#F3061F' : '#606266'
|
|
|
|
|
+ }">
|
|
|
|
|
+ {{
|
|
|
|
|
+ Number(row.from) === 1 ? '真实用户' :
|
|
|
|
|
+ Number(row.from) === 2 ? '虚拟用户' :
|
|
|
|
|
+ Number(row.from) === -1 ? 'tg用户' :
|
|
|
|
|
+ Number(row.from) === 0 ? '后台客服账号' : '--'
|
|
|
|
|
+ }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 冻结金额 -->
|
|
|
|
|
+ <template #wallet="{ row }">
|
|
|
|
|
+ <span :style="{
|
|
|
|
|
+ color: (row.wallet && Number(row.wallet.frozen_balance) > 0) ? '#F3061F' : '#606266'
|
|
|
|
|
+ }">
|
|
|
|
|
+ {{ row.wallet ? Number(row.wallet.frozen_balance) : '--' }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 余额宝金额 -->
|
|
|
|
|
+ <template #yuebao="{ row }">
|
|
|
|
|
+ <span :style="{
|
|
|
|
|
+ color: (row.wallet && Number(row.wallet.yuebao) > 0) ? '#05A58F' : '#606266'
|
|
|
|
|
+ }">
|
|
|
|
|
+ {{ row.wallet ? Number(row.wallet.yuebao) : '--' }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 打码量 -->
|
|
|
|
|
+ <template #total_consume="{ row }">
|
|
|
|
|
+ <span :style="{
|
|
|
|
|
+ color: Number(row.total_consume) > 0 ? '#18C80A' : '#606266'
|
|
|
|
|
+ }">
|
|
|
|
|
+ {{ row.total_consume != null ? Number(row.total_consume) : '--' }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 是否封号 -->
|
|
|
|
|
+ <template #is_banned="{ row }">
|
|
|
|
|
+ <span :style="{
|
|
|
|
|
+ color: Number(row.is_banned) === 0 ? '#18C80A' : '#F3061F',
|
|
|
|
|
+ fontWeight: 'bold'
|
|
|
|
|
+ }">
|
|
|
|
|
+ {{ Number(row.is_banned) === 0 ? '正常' : '封号' }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 是否封号 -->
|
|
|
|
|
+ <template #is_banned="{ row }">
|
|
|
|
|
+ <span :style="{
|
|
|
|
|
+ color: Number(row.is_banned) === 0 ? '#18C80A' : '#F3061F'
|
|
|
|
|
+ }">
|
|
|
|
|
+ {{ Number(row.is_banned) === 0 ? '正常' : '封号' }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ </YMTable>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 用户详情弹窗 -->
|
|
|
|
|
+ <Dialog ref="dialogDetail" :dialog-actions="{
|
|
|
|
|
+ width: '800px',
|
|
|
|
|
+ title: '用户详情',
|
|
|
|
|
+ confirmButtom: false,
|
|
|
|
|
+ }">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <!-- 原有详情展示区 -->
|
|
|
|
|
+ <div style="display: flex; flex-wrap: wrap; gap: 12px; padding: 10px 0; max-height: 400px; overflow-y: auto;">
|
|
|
|
|
+ <div v-for="item in detailItems" :key="item.label"
|
|
|
|
|
+ style="flex: 0 0 calc(33.33% - 12px); background: #f5f7fa; border-radius: 6px; padding: 12px 16px; box-sizing: border-box; border: 1px solid #e4e7ed;">
|
|
|
|
|
+ <div style="font-size: 13px; color: #909399; margin-bottom: 4px;">{{ item.label }}</div>
|
|
|
|
|
+ <!-- 三方余额:显示数值 + 一键转出按钮 -->
|
|
|
|
|
+ <div v-if="item.label === '三方余额'" style="display: flex; align-items: center; gap: 8px;">
|
|
|
|
|
+ <span :style="{ color: item.color || '#303133', fontSize: '15px' }">{{ item.value }}</span>
|
|
|
|
|
+ <el-button type="primary" size="mini"
|
|
|
|
|
+ @click="sfBalanceTransferClick(detailData.member_id)">一键转出</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 其他字段 -->
|
|
|
|
|
+ <div v-else :style="{ color: item.color || '#303133', fontSize: '15px', wordBreak: 'break-all' }">
|
|
|
|
|
+ {{ item.value }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ========== 新增:操作按钮区域 ========== -->
|
|
|
|
|
+ <div style="margin-top: 16px; text-align: center; border-top: 1px solid #e4e7ed; padding-top: 16px;">
|
|
|
|
|
+ <!-- 充值 -->
|
|
|
|
|
+ <el-button type="primary" size="small"
|
|
|
|
|
+ @click="rowsActions.find(a => a.key === 'upWallet').method(detailData)">
|
|
|
|
|
+ 充值
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 扣款 -->
|
|
|
|
|
+ <el-button type="danger" size="small" @click="rowsActions.find(a => a.key === 'unWallet').method(detailData)">
|
|
|
|
|
+ 扣款
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 提现地址 -->
|
|
|
|
|
+ <el-button type="info" size="small" @click="rowsActions.find(a => a.key === 'address').method(detailData)">
|
|
|
|
|
+ 提现地址
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 设置通道 -->
|
|
|
|
|
+ <el-button type="warning" size="small"
|
|
|
|
|
+ @click="rowsActions.find(a => a.key === 'setChannel').method(detailData)">
|
|
|
|
|
+ 设置通道
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 修改密码 -->
|
|
|
|
|
+ <el-button type="primary" size="small"
|
|
|
|
|
+ @click="rowsActions.find(a => a.key === 'modifyPassword').method(detailData)">
|
|
|
|
|
+ 修改密码
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 合并用户 -->
|
|
|
|
|
+ <el-button type="danger" size="small"
|
|
|
|
|
+ @click="rowsActions.find(a => a.key === 'secret_key').method(detailData)">
|
|
|
|
|
+ 合并用户
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 备注 -->
|
|
|
|
|
+ <el-button type="info" size="small" @click="rowsActions.find(a => a.key === 'note').method(detailData)">
|
|
|
|
|
+ 备注
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 用户日志 -->
|
|
|
|
|
+ <el-button type="primary" size="small" @click="rowsActions.find(a => a.key === 'log').method(detailData)">
|
|
|
|
|
+ 用户日志
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 封号(仅当未封号) -->
|
|
|
|
|
+ <el-button v-if="detailData.is_banned === 0" type="danger" size="small"
|
|
|
|
|
+ @click="rowsActions.find(a => a.key === 'banned').method(detailData)">
|
|
|
|
|
+ 封号
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <!-- 解封(仅当已封号) -->
|
|
|
|
|
+ <el-button v-if="detailData.is_banned === 1" type="success" size="small"
|
|
|
|
|
+ @click="rowsActions.find(a => a.key === 'jiefeng').method(detailData)">
|
|
|
|
|
+ 解封
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="sfLog" :dialog-actions="{
|
|
|
|
|
+ width: '800px',
|
|
|
|
|
+ title: '三方余额',
|
|
|
|
|
+ confirmButtom: false,
|
|
|
|
|
+ }">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <span style="padding-right: 10px">换算后总余额:{{ sfBalanceData.total_balance }}</span>
|
|
|
|
|
+ <span style="padding-right: 10px">原始游戏币总余额:{{ sfBalanceData.total_game_balance }}</span>
|
|
|
|
|
+ <span style="padding-right: 10px">当前换算比例:{{ sfBalanceData.rate }}</span>
|
|
|
|
|
+ <el-button type="primary" @click="sfBalanceTransferClick(sfBalanceData.member_id)">一键转出</el-button>
|
|
|
|
|
+ <!-- sfBalanceTransfer -->
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-table :data="sfBalanceData.list" border stripe height="400px" v-loading="logLoading">
|
|
|
|
|
+ <el-table-column prop="platform" label="平台名称" align="center" />
|
|
|
|
|
+ <el-table-column prop="balance" label="平台余额" align="center" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="dialog" :dialog-actions="{ width: '480px', title: '扣款金额' }" :loading="loading" @confirm="confirm">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <el-form ref="formDataref" :rules="rulesData" :model="formData" label-width="80px">
|
|
|
|
|
+ <el-form-item label="扣款金额 " prop="amount">
|
|
|
|
|
+ <el-input type="number" v-model="formData.amount" style="width: 300px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="说明" prop="remark">
|
|
|
|
|
+ <el-input v-model="formData.remark" style="width: 300px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="dialog1" :dialog-actions="{ width: '480px', title: '充值金额' }" :loading="loading" @confirm="confirm">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <el-form ref="formDataref" :rules="rulesData" :model="formData" label-width="80px">
|
|
|
|
|
+ <el-form-item label="充值类型" prop="change_type">
|
|
|
|
|
+ <el-select v-model="formData.change_type" placeholder="请选择" style="width: 300px">
|
|
|
|
|
+ <el-option v-for="item in listTypes" :key="item" :label="item" :value="item">
|
|
|
|
|
+ </el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="充值金额" prop="amount">
|
|
|
|
|
+ <el-input type="number" v-model="formData.amount" style="width: 300px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="说明" prop="remark">
|
|
|
|
|
+ <el-input v-model="formData.remark" style="width: 300px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="dialogAddress" :dialog-actions="{
|
|
|
|
|
+ width: '720px',
|
|
|
|
|
+ title: '提现地址',
|
|
|
|
|
+ confirmButtom: false,
|
|
|
|
|
+ }">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <div style="padding: 10px 0">
|
|
|
|
|
+ <div style="margin-bottom: 24px">
|
|
|
|
|
+ <h3 style="margin: 0 0 12px 0; color: #303133">
|
|
|
|
|
+ 银行卡 / 支付账户
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <el-table :data="listDataBank" border stripe height="260" empty-text="暂无银行卡/支付账户">
|
|
|
|
|
+ <el-table-column prop="bank_name" label="银行/渠道" width="140" />
|
|
|
|
|
+ <el-table-column prop="account" label="户名" width="120" />
|
|
|
|
|
+ <el-table-column prop="card_no" label="卡号/账号" />
|
|
|
|
|
+ <el-table-column prop="alias" label="别名" />
|
|
|
|
|
+ <el-table-column prop="channel" label="渠道码" width="100" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 style="margin: 0 0 12px 0; color: #303133">数字货币地址</h3>
|
|
|
|
|
+ <el-table :data="listDataAddress" border stripe height="260" empty-text="暂无数字货币地址">
|
|
|
|
|
+ <el-table-column prop="address" label="提现地址" />
|
|
|
|
|
+ <el-table-column prop="alias" label="别名" width="180" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="dialogLog" :dialog-actions="{
|
|
|
|
|
+ width: '800px',
|
|
|
|
|
+ title: '用户日志',
|
|
|
|
|
+ confirmButtom: false,
|
|
|
|
|
+ }">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <el-form :model="logFormData" inline label-width="80px">
|
|
|
|
|
+ <el-form-item label="日期范围">
|
|
|
|
|
+ <el-date-picker v-model="logFormData.dateRange" type="daterange" value-format="yyyy-MM-dd"
|
|
|
|
|
+ range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" @click="getLogList">查询</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <el-table :data="logTableData" border stripe height="400px" v-loading="logLoading">
|
|
|
|
|
+ <el-table-column prop="login_ip" label="IP" align="center" />
|
|
|
|
|
+ <el-table-column prop="created_at" label="时间" align="center" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="dialogChannel" :dialog-actions="{ width: '480px', title: '设置通道组合' }" :loading="loading"
|
|
|
|
|
+ @confirm="confirmChannel">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <el-form ref="channelFormRef" :rules="channelRules" :model="channelFormData" label-width="120px">
|
|
|
|
|
+ <el-form-item label="通道组合" prop="recharge_channel_group_id">
|
|
|
|
|
+ <el-select v-model="channelFormData.recharge_channel_group_id" placeholder="请选择通道组合" style="width: 280px">
|
|
|
|
|
+ <el-option v-for="item in channelGroupList" :key="item.id" :label="item.name"
|
|
|
|
|
+ :value="item.id"></el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <Dialog ref="dialogPassword" :dialog-actions="{ width: '480px', title: '修改密码' }" :loading="loading"
|
|
|
|
|
+ @confirm="confirmPassword">
|
|
|
|
|
+ <template slot="content">
|
|
|
|
|
+ <el-form ref="pwdFormRef" :rules="pwdRules" :model="pwdFormData" label-width="100px">
|
|
|
|
|
+ <el-form-item label="密码类型">
|
|
|
|
|
+ <el-radio-group v-model="pwdFormData.pwdType">
|
|
|
|
|
+ <el-radio label="login">登录密码</el-radio>
|
|
|
|
|
+ <el-radio label="payment">资金密码</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="新密码" prop="newPassword">
|
|
|
|
|
+ <el-input v-model="pwdFormData.newPassword" placeholder="请输入新密码" style="width: 280px" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import Dialog from "@/components/Dialog/index.vue";
|
|
|
|
|
+import {
|
|
|
|
|
+ getChangeTypes,
|
|
|
|
|
+ menucheck,
|
|
|
|
|
+ sfBalance,
|
|
|
|
|
+ sfBalanceTransfer,
|
|
|
|
|
+ useraddress,
|
|
|
|
|
+ userbanned,
|
|
|
|
|
+ usermerge,
|
|
|
|
|
+ usersetNote,
|
|
|
|
|
+ walletdebiting,
|
|
|
|
|
+ withdraw,
|
|
|
|
|
+ userLoginLog,
|
|
|
|
|
+ walletAddress,
|
|
|
|
|
+ walletBankList,
|
|
|
|
|
+ setUserRechargeChannelGroup,
|
|
|
|
|
+ getRechargeChannelGroupList,
|
|
|
|
|
+ setUserPassword,
|
|
|
|
|
+} from "@/api/data";
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ components: {
|
|
|
|
|
+ Dialog,
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ searchForm() {
|
|
|
|
|
+ return [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "用户名称",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "username",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "用户昵称",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "like_first_name",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "会员ID",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "member_id",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "用户等级",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "level",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "用户邀请码",
|
|
|
|
|
+ labelWidth: "110px",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "user_code",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "邀请人邀请码",
|
|
|
|
|
+ labelWidth: "110px",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "agent_user_code",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "充值通道",
|
|
|
|
|
+ type: "select",
|
|
|
|
|
+ prop: "recharge_channel_group_id",
|
|
|
|
|
+ options: this.channelGroupList.map((group) => ({
|
|
|
|
|
+ label: group.name,
|
|
|
|
|
+ value: group.id,
|
|
|
|
|
+ })),
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "注册来源",
|
|
|
|
|
+ type: "select",
|
|
|
|
|
+ prop: "from",
|
|
|
|
|
+ default: "2",
|
|
|
|
|
+ isHide: true,
|
|
|
|
|
+ options: [
|
|
|
|
|
+ { label: "tg用户", value: "-1" },
|
|
|
|
|
+ { label: "后台客服账号", value: "0" },
|
|
|
|
|
+ { label: "真实用户", value: "1" },
|
|
|
|
|
+ { label: "虚拟用户", value: "2" },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "新增用户",
|
|
|
|
|
+ type: "slot",
|
|
|
|
|
+ prop: "dateRange",
|
|
|
|
|
+ slotName: "dateRange",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "开始时间",
|
|
|
|
|
+ prop: "start_time",
|
|
|
|
|
+ isHide: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "结束时间",
|
|
|
|
|
+ prop: "end_time",
|
|
|
|
|
+ isHide: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "IP",
|
|
|
|
|
+ type: "input",
|
|
|
|
|
+ prop: "register_ip",
|
|
|
|
|
+ clearable: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ ];
|
|
|
|
|
+ },
|
|
|
|
|
+ detailItems() {
|
|
|
|
|
+ if (!this.detailData || !Object.keys(this.detailData).length) return [];
|
|
|
|
|
+ const row = this.detailData;
|
|
|
|
|
+ return [
|
|
|
|
|
+ { label: '会员ID', value: row.member_id },
|
|
|
|
|
+ { label: '邀请码', value: row.user_code },
|
|
|
|
|
+ { label: '会员昵称', value: row.first_name || '--' },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '注册来源',
|
|
|
|
|
+ value: this.getFromText(row.from),
|
|
|
|
|
+ color: Number(row.from) === 1 ? '#05A58F' : Number(row.from) === 2 ? '#F3061F' : '#606266'
|
|
|
|
|
+ },
|
|
|
|
|
+ { label: '飞机账号', value: row.username || '--' },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '上级邀请人',
|
|
|
|
|
+ value: row.agent ? `${row.agent.first_name} (ID:${row.agent.member_id}, 邀请码:${row.agent.user_code})` : '--'
|
|
|
|
|
+ },
|
|
|
|
|
+ { label: '会员等级', value: row.level?.level_name || '--' },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '钱包余额',
|
|
|
|
|
+ value: row.wallet ? Number(row.wallet.available_balance).toFixed(2) : '--',
|
|
|
|
|
+ color: '#409EFF' // 蓝色
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '三方余额',
|
|
|
|
|
+ value: row.third_game_total_balance != null ? Number(row.third_game_total_balance).toFixed(2) : '--',
|
|
|
|
|
+ color: '#409EFF' // 蓝色
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '冻结金额',
|
|
|
|
|
+ value: row.wallet ? Number(row.wallet.frozen_balance) : '--',
|
|
|
|
|
+ color: (row.wallet && Number(row.wallet.frozen_balance) > 0) ? '#F3061F' : '#606266'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '余额宝金额',
|
|
|
|
|
+ value: row.wallet ? row.wallet.yuebao : '--',
|
|
|
|
|
+ color: (row.wallet && Number(row.wallet.yuebao) > 0) ? '#05A58F' : '#606266'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '打码量',
|
|
|
|
|
+ value: row.total_consume != null ? Number(row.total_consume) : '--',
|
|
|
|
|
+ color: Number(row.total_consume) > 0 ? '#18C80A' : '#606266'
|
|
|
|
|
+ },
|
|
|
|
|
+ { label: '充值通道', value: this.getChannelName(row.recharge_channel_group_id) },
|
|
|
|
|
+ { label: '注册时间', value: row.created_at || '--' },
|
|
|
|
|
+ { label: '新增用户', value: this.getNewUserType(row.created_at) },
|
|
|
|
|
+ { label: '活跃时间', value: row.last_active_time || '--' },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '是否封号',
|
|
|
|
|
+ value: row.is_banned === 0 ? '正常' : '封号',
|
|
|
|
|
+ color: Number(row.is_banned) === 0 ? '#18C80A' : '#F3061F'
|
|
|
|
|
+ },
|
|
|
|
|
+ { label: '秘钥', value: row.secret_key || '--' },
|
|
|
|
|
+ { label: '访客ID', value: row.visitor_id || '--' },
|
|
|
|
|
+ { label: '备注', value: row.admin_note || '--' },
|
|
|
|
|
+ { label: '手机号', value: row.phone || '--' },
|
|
|
|
|
+ { label: 'IP', value: row.register_ip || '--' },
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ pwdFormData: {
|
|
|
|
|
+ member_id: "",
|
|
|
|
|
+ pwdType: "login",
|
|
|
|
|
+ newPassword: "",
|
|
|
|
|
+ },
|
|
|
|
|
+ sfBalanceData: [],
|
|
|
|
|
+ pwdRules: {
|
|
|
|
|
+ newPassword: [
|
|
|
|
|
+ { required: true, message: "请输入新密码", trigger: "blur" },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ pickerOptions: {
|
|
|
|
|
+ shortcuts: [
|
|
|
|
|
+ {
|
|
|
|
|
+ text: "今天",
|
|
|
|
|
+ onClick(picker) {
|
|
|
|
|
+ const start = new Date();
|
|
|
|
|
+ start.setHours(0, 0, 0, 0);
|
|
|
|
|
+ const end = new Date();
|
|
|
|
|
+ end.setHours(23, 59, 59, 999);
|
|
|
|
|
+ picker.$emit("pick", [start, end]);
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ text: "昨天",
|
|
|
|
|
+ onClick(picker) {
|
|
|
|
|
+ const start = new Date();
|
|
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
|
|
|
|
|
+ start.setHours(0, 0, 0, 0);
|
|
|
|
|
+ const end = new Date();
|
|
|
|
|
+ end.setTime(end.getTime() - 3600 * 1000 * 24 * 1);
|
|
|
|
|
+ end.setHours(23, 59, 59, 999);
|
|
|
|
|
+ picker.$emit("pick", [start, end]);
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ text: "7天内",
|
|
|
|
|
+ onClick(picker) {
|
|
|
|
|
+ const start = new Date();
|
|
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
|
|
|
|
+ start.setHours(0, 0, 0, 0);
|
|
|
|
|
+ const end = new Date();
|
|
|
|
|
+ end.setHours(23, 59, 59, 999);
|
|
|
|
|
+ picker.$emit("pick", [start, end]);
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ selectedMemberIds: [],
|
|
|
|
|
+ channelGroupList: [],
|
|
|
|
|
+ channelFormData: {
|
|
|
|
|
+ member_ids: [],
|
|
|
|
|
+ recharge_channel_group_id: "",
|
|
|
|
|
+ },
|
|
|
|
|
+ channelRules: {
|
|
|
|
|
+ recharge_channel_group_id: [
|
|
|
|
|
+ { required: true, message: "请选择充值通道组合", trigger: "change" },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ listDataBank: [],
|
|
|
|
|
+ listDataAddress: [],
|
|
|
|
|
+ listTypes: [],
|
|
|
|
|
+ positive: true,
|
|
|
|
|
+ SHOW: false,
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ queryData: {
|
|
|
|
|
+ order: "",
|
|
|
|
|
+ by: "",
|
|
|
|
|
+ },
|
|
|
|
|
+ visibleBasicDrawer: false,
|
|
|
|
|
+ renderContent: "",
|
|
|
|
|
+ rowsActions: [
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "view",
|
|
|
|
|
+ label: "查看",
|
|
|
|
|
+ method: (row) => this.showDetail(row)
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "upWallet",
|
|
|
|
|
+ label: "充值",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.positive = true;
|
|
|
|
|
+ this.formData.member_id = row.member_id;
|
|
|
|
|
+ this.$refs.dialog1.open();
|
|
|
|
|
+ getChangeTypes().then((res) => {
|
|
|
|
|
+ this.listTypes = res.data;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "unWallet",
|
|
|
|
|
+ label: "扣款",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.positive = false;
|
|
|
|
|
+ this.formData.member_id = row.member_id;
|
|
|
|
|
+ this.$refs.dialog.open();
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "address",
|
|
|
|
|
+ label: "提现地址",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => this.showWithdrawalAddress(row),
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "setChannel",
|
|
|
|
|
+ label: "设置通道",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) =>
|
|
|
|
|
+ this.openChannelDialog(
|
|
|
|
|
+ [row.member_id],
|
|
|
|
|
+ row.recharge_channel_group_id
|
|
|
|
|
+ ),
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "modifyPassword",
|
|
|
|
|
+ label: "修改密码",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.pwdFormData.member_id = row.member_id;
|
|
|
|
|
+ this.pwdFormData.pwdType = "login";
|
|
|
|
|
+ this.pwdFormData.newPassword = "";
|
|
|
|
|
+ this.$refs.dialogPassword.open();
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.$refs.pwdFormRef && this.$refs.pwdFormRef.clearValidate();
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "secret_key",
|
|
|
|
|
+ label: "合并用户",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.$prompt("请输入被合并的用户的秘钥", "提示", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ inputPattern: /^\S+$/,
|
|
|
|
|
+ inputErrorMessage: "请输入被合并的用户的秘钥",
|
|
|
|
|
+ }).then(({ value }) => {
|
|
|
|
|
+ usermerge({
|
|
|
|
|
+ secret_key: value,
|
|
|
|
|
+ member_id: row.member_id,
|
|
|
|
|
+ }).then((res) => {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ message: "合并成功!",
|
|
|
|
|
+ });
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "note",
|
|
|
|
|
+ label: "备注",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.$prompt("请输入备注", "备注", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ inputPattern: /^\S+$/,
|
|
|
|
|
+ inputValue: row.admin_note,
|
|
|
|
|
+ inputErrorMessage: "请输入备注",
|
|
|
|
|
+ }).then(({ value }) => {
|
|
|
|
|
+ usersetNote({
|
|
|
|
|
+ member_id: row.member_id,
|
|
|
|
|
+ admin_note: value,
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ message: "操作成功",
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "log",
|
|
|
|
|
+ label: "用户日志",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.logFormData.user_id = row.member_id;
|
|
|
|
|
+ this.logFormData.dateRange = [];
|
|
|
|
|
+ this.logTableData = [];
|
|
|
|
|
+ this.$refs.dialogLog.open();
|
|
|
|
|
+ this.getLogList();
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "banned",
|
|
|
|
|
+ label: "封号",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.$confirm(
|
|
|
|
|
+ "此操作将修改用户是否封号,保存封号修改?",
|
|
|
|
|
+ "是否封号",
|
|
|
|
|
+ {
|
|
|
|
|
+ distinguishCancelAndClose: true,
|
|
|
|
|
+ confirmButtonText: "封号",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ }
|
|
|
|
|
+ ).then(() => {
|
|
|
|
|
+ userbanned({
|
|
|
|
|
+ member_id: row.member_id,
|
|
|
|
|
+ is_banned: 1,
|
|
|
|
|
+ }).then((res) => {
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ type: "warning",
|
|
|
|
|
+ message: "保存修改为封号!",
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "jiefeng",
|
|
|
|
|
+ label: "解封",
|
|
|
|
|
+ // 隐藏该按钮(列表不显示,保留数组项供详情弹窗调用)
|
|
|
|
|
+ vIF: () => false,
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ this.$confirm(
|
|
|
|
|
+ "此操作将修改用户是否解封,保存解封修改?",
|
|
|
|
|
+ "是否解封",
|
|
|
|
|
+ {
|
|
|
|
|
+ distinguishCancelAndClose: true,
|
|
|
|
|
+ confirmButtonText: "正常",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ }
|
|
|
|
|
+ ).then(() => {
|
|
|
|
|
+ userbanned({
|
|
|
|
|
+ member_id: row.member_id,
|
|
|
|
|
+ is_banned: 0,
|
|
|
|
|
+ }).then((res) => {
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ message: "保存修改为正常!",
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ apis: {
|
|
|
|
|
+ list: {
|
|
|
|
|
+ url: "user",
|
|
|
|
|
+ dataParam: "data.data",
|
|
|
|
|
+ resultParam: "data",
|
|
|
|
|
+ init: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ tableOptions: {
|
|
|
|
|
+ add: {
|
|
|
|
|
+ show: false,
|
|
|
|
|
+ initData: () => {
|
|
|
|
|
+ return { test: "test" };
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ editForm: [
|
|
|
|
|
+ {
|
|
|
|
|
+ body: [],
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ editConfig: {},
|
|
|
|
|
+ formData: {
|
|
|
|
|
+ amount: "",
|
|
|
|
|
+ member_id: "",
|
|
|
|
|
+ remark: "",
|
|
|
|
|
+ change_type: "",
|
|
|
|
|
+ },
|
|
|
|
|
+ rulesData: {
|
|
|
|
|
+ change_type: [{ required: true, message: "请输入", trigger: "blur" }],
|
|
|
|
|
+ amount: [{ required: true, message: "请输入", trigger: "blur" }],
|
|
|
|
|
+ remark: [{ required: true, message: "请输入", trigger: "blur" }],
|
|
|
|
|
+ },
|
|
|
|
|
+ logFormData: {
|
|
|
|
|
+ user_id: "",
|
|
|
|
|
+ dateRange: [],
|
|
|
|
|
+ },
|
|
|
|
|
+ logTableData: [],
|
|
|
|
|
+ logLoading: false,
|
|
|
|
|
+ columns: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "会员ID",
|
|
|
|
|
+ prop: "member_id",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "邀请码",
|
|
|
|
|
+ prop: "user_code",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "会员昵称",
|
|
|
|
|
+ popover: true,
|
|
|
|
|
+ width: 140,
|
|
|
|
|
+ props: ["first_name"],
|
|
|
|
|
+ tagType: (row) => (row?.status === 1 ? "danger" : ""),
|
|
|
|
|
+ options: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "会员ID",
|
|
|
|
|
+ value: ["member_id"],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "用户名称",
|
|
|
|
|
+ value: ["username"],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "备注",
|
|
|
|
|
+ vShow: (row) => (row?.admin_note ? true : false),
|
|
|
|
|
+ value: ["admin_note"],
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "注册来源",
|
|
|
|
|
+ prop: "from",
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ const map = {
|
|
|
|
|
+ "-1": "tg用户",
|
|
|
|
|
+ 0: "后台客服账号",
|
|
|
|
|
+ 1: "真实用户",
|
|
|
|
|
+ 2: "虚拟用户",
|
|
|
|
|
+ };
|
|
|
|
|
+ return map[row.from] || "--";
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "飞机账号",
|
|
|
|
|
+ prop: "username",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "上级邀请人",
|
|
|
|
|
+ prop: "agent",
|
|
|
|
|
+ width: 240,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "会员等级",
|
|
|
|
|
+ prop: "level",
|
|
|
|
|
+ method: (row) => row.level?.level_name || "--",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "钱包余额",
|
|
|
|
|
+ link: true,
|
|
|
|
|
+ // sortable: "custom",
|
|
|
|
|
+ method: (row) =>
|
|
|
|
|
+ row.wallet
|
|
|
|
|
+ ? `${Number(row.wallet.available_balance).toFixed(2)}`
|
|
|
|
|
+ : "--",
|
|
|
|
|
+ click: (row) => {
|
|
|
|
|
+ this.$router.push({
|
|
|
|
|
+ name: "balance",
|
|
|
|
|
+ query: {
|
|
|
|
|
+ member_id: row.member_id,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "三方余额",
|
|
|
|
|
+ link: true,
|
|
|
|
|
+ // sortable: "custom",
|
|
|
|
|
+ method: (row) =>
|
|
|
|
|
+ row.wallet
|
|
|
|
|
+ ? `${Number(row.third_game_total_balance).toFixed(2)}`
|
|
|
|
|
+ : "--",
|
|
|
|
|
+ click: (row) => {
|
|
|
|
|
+ this.$refs.sfLog.open();
|
|
|
|
|
+ this.getSfList(row.member_id);
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "冻结金额",
|
|
|
|
|
+ prop: "wallet",
|
|
|
|
|
+ method: (row) =>
|
|
|
|
|
+ row.wallet ? Number(row.wallet.frozen_balance) : "--",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "余额宝金额",
|
|
|
|
|
+ prop: "yuebao",
|
|
|
|
|
+ method: (row) => (row.wallet ? row.wallet.yuebao : "--"),
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "打码量",
|
|
|
|
|
+ prop: "total_consume",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "充值通道",
|
|
|
|
|
+ prop: "recharge_channel",
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ this.channelGroupList.find(
|
|
|
|
|
+ (group) => group.id === row.recharge_channel_group_id
|
|
|
|
|
+ )?.name || "--"
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "注册时间",
|
|
|
|
|
+ prop: "created_at",
|
|
|
|
|
+ // sortable: "custom",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "新增用户",
|
|
|
|
|
+ prop: "created_at",
|
|
|
|
|
+ method: (row) => {
|
|
|
|
|
+ if (!row.created_at) return "--";
|
|
|
|
|
+ const targetDate = new Date(row.created_at.replace(/-/g, "/"));
|
|
|
|
|
+ const targetTime = targetDate.getTime();
|
|
|
|
|
+
|
|
|
|
|
+ const now = new Date();
|
|
|
|
|
+ const todayStart = new Date(
|
|
|
|
|
+ now.getFullYear(),
|
|
|
|
|
+ now.getMonth(),
|
|
|
|
|
+ now.getDate()
|
|
|
|
|
+ ).getTime();
|
|
|
|
|
+ const yesterdayStart = todayStart - 24 * 60 * 60 * 1000;
|
|
|
|
|
+ const sevenDaysAgoStart = todayStart - 7 * 24 * 60 * 60 * 1000;
|
|
|
|
|
+
|
|
|
|
|
+ if (targetTime >= todayStart) {
|
|
|
|
|
+ return "今天";
|
|
|
|
|
+ } else if (
|
|
|
|
|
+ targetTime >= yesterdayStart &&
|
|
|
|
|
+ targetTime < todayStart
|
|
|
|
|
+ ) {
|
|
|
|
|
+ return "昨天";
|
|
|
|
|
+ } else if (
|
|
|
|
|
+ targetTime >= sevenDaysAgoStart &&
|
|
|
|
|
+ targetTime < yesterdayStart
|
|
|
|
|
+ ) {
|
|
|
|
|
+ return "7天内";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return "7天前";
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "活跃时间",
|
|
|
|
|
+ // sortable: "custom",
|
|
|
|
|
+ prop: "last_active_time",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "是否封号",
|
|
|
|
|
+ prop: "is_banned",
|
|
|
|
|
+ method: (row) => (row.is_banned === 0 ? "正常" : "封号"),
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "秘钥",
|
|
|
|
|
+ popover: true,
|
|
|
|
|
+ default: "秘钥",
|
|
|
|
|
+ width: 70,
|
|
|
|
|
+ options: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "找回账号的秘钥",
|
|
|
|
|
+ value: ["secret_key"],
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "访客ID",
|
|
|
|
|
+ default: "访客ID",
|
|
|
|
|
+ width: 80,
|
|
|
|
|
+ popover: true,
|
|
|
|
|
+ options: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "访客ID",
|
|
|
|
|
+ value: ["visitor_id"],
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "备注",
|
|
|
|
|
+ prop: "admin_note",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "手机号",
|
|
|
|
|
+ prop: "phone",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "IP",
|
|
|
|
|
+ prop: "register_ip",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ detailData: {},
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ this.onSubmit();
|
|
|
|
|
+ menucheck("admin/wallet/topUp").then(({ code }) => {
|
|
|
|
|
+ this.rowsActions[0].vIF = () => code === 0;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ getRechargeChannelGroupList({ page: 1, limit: 1000 })
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.channelGroupList = res.data?.data || [];
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => console.log("获取通道组合失败", err));
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ getSfList(member_id) {
|
|
|
|
|
+ this.logLoading = true;
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ member_id: member_id,
|
|
|
|
|
+ };
|
|
|
|
|
+ sfBalance(params)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.sfBalanceData = res.data;
|
|
|
|
|
+ console.log(this.sfBalanceData);
|
|
|
|
|
+ this.logLoading = false;
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ this.logLoading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 转换注册来源文字
|
|
|
|
|
+ getFromText(from) {
|
|
|
|
|
+ const map = {
|
|
|
|
|
+ '-1': 'tg用户',
|
|
|
|
|
+ '0': '后台客服账号',
|
|
|
|
|
+ '1': '真实用户',
|
|
|
|
|
+ '2': '虚拟用户'
|
|
|
|
|
+ };
|
|
|
|
|
+ return map[from] || '--';
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 根据通道组合ID获取名称
|
|
|
|
|
+ getChannelName(id) {
|
|
|
|
|
+ const group = this.channelGroupList.find(g => g.id === id);
|
|
|
|
|
+ return group ? group.name : '--';
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 计算新增用户分类(与列表逻辑一致)
|
|
|
|
|
+ getNewUserType(created_at) {
|
|
|
|
|
+ if (!created_at) return '--';
|
|
|
|
|
+ const targetDate = new Date(created_at.replace(/-/g, '/'));
|
|
|
|
|
+ const targetTime = targetDate.getTime();
|
|
|
|
|
+ const now = new Date();
|
|
|
|
|
+ const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
|
|
|
|
|
+ const yesterdayStart = todayStart - 24 * 60 * 60 * 1000;
|
|
|
|
|
+ const sevenDaysAgoStart = todayStart - 7 * 24 * 60 * 60 * 1000;
|
|
|
|
|
+ if (targetTime >= todayStart) return '今天';
|
|
|
|
|
+ else if (targetTime >= yesterdayStart && targetTime < todayStart) return '昨天';
|
|
|
|
|
+ else if (targetTime >= sevenDaysAgoStart && targetTime < yesterdayStart) return '7天内';
|
|
|
|
|
+ else return '7天前';
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 打开详情弹窗
|
|
|
|
|
+ showDetail(row) {
|
|
|
|
|
+ this.detailData = { ...row };
|
|
|
|
|
+ this.$refs.dialogDetail.open();
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ sfBalanceTransferClick(member_id) {
|
|
|
|
|
+ this.logLoading = true;
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ member_id: member_id,
|
|
|
|
|
+ };
|
|
|
|
|
+ sfBalanceTransfer(params)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.logLoading = false;
|
|
|
|
|
+ this.$notify({
|
|
|
|
|
+ title: "成功",
|
|
|
|
|
+ message: "操作成功",
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ });
|
|
|
|
|
+ this.getSfList(member_id);
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ this.logLoading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ confirmPassword() {
|
|
|
|
|
+ this.$refs.pwdFormRef.validate((valid) => {
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ this.loading = true;
|
|
|
|
|
+ const payload = {
|
|
|
|
|
+ member_id: this.pwdFormData.member_id,
|
|
|
|
|
+ };
|
|
|
|
|
+ if (this.pwdFormData.pwdType === "login") {
|
|
|
|
|
+ payload.password = this.pwdFormData.newPassword;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ payload.payment_password = this.pwdFormData.newPassword;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ setUserPassword(payload)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ if (res.code === 0) {
|
|
|
|
|
+ this.$notify({
|
|
|
|
|
+ title: "成功",
|
|
|
|
|
+ message: "修改成功",
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ });
|
|
|
|
|
+ this.$refs.dialogPassword.close();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.$message.error(res.msg || "修改失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ handleSelectionChange(val) {
|
|
|
|
|
+ this.selectedMemberIds = val.map((item) => item.member_id);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ handleBatchSetChannel() {
|
|
|
|
|
+ this.openChannelDialog(this.selectedMemberIds, "");
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ openChannelDialog(ids, groupId) {
|
|
|
|
|
+ this.channelFormData.member_ids = ids;
|
|
|
|
|
+ this.channelFormData.recharge_channel_group_id = groupId || "";
|
|
|
|
|
+ this.$refs.dialogChannel.open();
|
|
|
|
|
+
|
|
|
|
|
+ if (this.channelGroupList.length === 0) {
|
|
|
|
|
+ getRechargeChannelGroupList({ page: 1, limit: 1000 })
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.channelGroupList = res.data?.data || [];
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => console.log("获取通道组合失败", err));
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ confirmChannel() {
|
|
|
|
|
+ this.$refs.channelFormRef.validate((valid) => {
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ this.loading = true;
|
|
|
|
|
+ setUserRechargeChannelGroup({
|
|
|
|
|
+ member_id: this.channelFormData.member_ids,
|
|
|
|
|
+ recharge_channel_group_id:
|
|
|
|
|
+ this.channelFormData.recharge_channel_group_id,
|
|
|
|
|
+ })
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ if (res.code === 0) {
|
|
|
|
|
+ this.$notify({
|
|
|
|
|
+ title: "成功",
|
|
|
|
|
+ message: "设置成功",
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ });
|
|
|
|
|
+ this.$refs.dialogChannel.close();
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.$message.error(res.msg || "设置失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ showWithdrawalAddress(row) {
|
|
|
|
|
+ this.listDataBank = [];
|
|
|
|
|
+ this.listDataAddress = [];
|
|
|
|
|
+
|
|
|
|
|
+ Promise.all([
|
|
|
|
|
+ walletBankList({ member_id: row.member_id }),
|
|
|
|
|
+ walletAddress({ member_id: row.member_id }),
|
|
|
|
|
+ ])
|
|
|
|
|
+ .then(([bankRes, addrRes]) => {
|
|
|
|
|
+ this.listDataBank = bankRes?.data?.list || [];
|
|
|
|
|
+ this.listDataAddress = addrRes?.data?.list || [];
|
|
|
|
|
+ this.$refs.dialogAddress.open();
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ this.$message.error("获取提现地址失败");
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ headerClick(column) {
|
|
|
|
|
+ const order =
|
|
|
|
|
+ column.order === "ascending"
|
|
|
|
|
+ ? "asc"
|
|
|
|
|
+ : column.order === "descending"
|
|
|
|
|
+ ? "desc"
|
|
|
|
|
+ : "";
|
|
|
|
|
+ let byValue = "";
|
|
|
|
|
+ if (column.label === "钱包余额") {
|
|
|
|
|
+ byValue = "available_balance";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (column.label === "注册时间") {
|
|
|
|
|
+ byValue = "created_at";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (column.label === "活跃时间") {
|
|
|
|
|
+ byValue = "last_active_time";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (order) {
|
|
|
|
|
+ this.$set(this.queryData, "by", byValue);
|
|
|
|
|
+ this.$set(this.queryData, "order", order);
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.$delete(this.queryData, "by");
|
|
|
|
|
+ this.$delete(this.queryData, "order");
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ confirm() {
|
|
|
|
|
+ console.log("提交数据:", this.formData);
|
|
|
|
|
+ this.$refs.formDataref.validate((valid) => {
|
|
|
|
|
+ let fn = withdraw;
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ this.loading = true;
|
|
|
|
|
+ if (!this.positive) {
|
|
|
|
|
+ fn = walletdebiting;
|
|
|
|
|
+ }
|
|
|
|
|
+ fn({
|
|
|
|
|
+ member_id: this.formData.member_id,
|
|
|
|
|
+ remark: this.formData.remark,
|
|
|
|
|
+ amount: this.formData.amount,
|
|
|
|
|
+ change_type: this.formData.change_type,
|
|
|
|
|
+ })
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ if (res.code === 0) {
|
|
|
|
|
+ this.$notify({
|
|
|
|
|
+ title: "成功",
|
|
|
|
|
+ message: "操作成功",
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ });
|
|
|
|
|
+ this.$refs.dialog.close();
|
|
|
|
|
+ this.$refs.dialog1.close();
|
|
|
|
|
+ this.onSubmit(this.queryData);
|
|
|
|
|
+ this.$refs.formDataref.resetFields();
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log("error submit!!");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ onValueChange(val) { },
|
|
|
|
|
+
|
|
|
|
|
+ onSubmit(params = {}) {
|
|
|
|
|
+ this.queryData = params;
|
|
|
|
|
+
|
|
|
|
|
+ const reqData = { ...params };
|
|
|
|
|
+
|
|
|
|
|
+ // 注册来源默认虚拟用户:仅当未通过表单指定(undefined)时兜底
|
|
|
|
|
+ if (reqData.from === undefined) {
|
|
|
|
|
+ reqData.from = "2";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (reqData.dateRange && reqData.dateRange.length === 2) {
|
|
|
|
|
+ reqData.start_time = reqData.dateRange[0].split(" ")[0];
|
|
|
|
|
+ reqData.end_time = reqData.dateRange[1].split(" ")[0];
|
|
|
|
|
+ } else if (
|
|
|
|
|
+ reqData.dateRange === null ||
|
|
|
|
|
+ reqData.dateRange === undefined ||
|
|
|
|
|
+ reqData.dateRange.length === 0
|
|
|
|
|
+ ) {
|
|
|
|
|
+ reqData.start_time = "";
|
|
|
|
|
+ reqData.end_time = "";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ delete reqData.dateRange;
|
|
|
|
|
+
|
|
|
|
|
+ this.$refs.table.getList(reqData);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getLogList() {
|
|
|
|
|
+ this.logLoading = true;
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ user_id: this.logFormData.user_id,
|
|
|
|
|
+ start_time: this.logFormData.dateRange
|
|
|
|
|
+ ? this.logFormData.dateRange[0]
|
|
|
|
|
+ : "",
|
|
|
|
|
+ end_time: this.logFormData.dateRange
|
|
|
|
|
+ ? this.logFormData.dateRange[1]
|
|
|
|
|
+ : "",
|
|
|
|
|
+ };
|
|
|
|
|
+ userLoginLog(params)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.logTableData = res.data?.data || [];
|
|
|
|
|
+ this.logLoading = false;
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ this.logLoading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|