| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298 |
- <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: "1",
- 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 = "1";
- }
- 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>
|