fix: 按旧页面修正商务入口和绑定可见条件

This commit is contained in:
Yvan
2026-11-03 18:48:22 +08:00
parent c0a3692068
commit 317c253ba9
6 changed files with 226 additions and 51 deletions
@@ -0,0 +1,44 @@
{
"method": "真实 Chrome 渲染;受控身份和业务数据,权限页签与状态操作核对",
"results": [
{
"level": 0,
"bindingTab": false,
"editButtons": 0,
"passed": true,
"bindingCalls": 0,
"pageErrors": []
},
{
"level": 1,
"bindingTab": false,
"editButtons": 0,
"passed": true,
"sdkDetailReadonly": true,
"bindingCalls": 0,
"pageErrors": []
},
{
"level": 2,
"bindingTab": false,
"editButtons": 0,
"passed": true,
"sdkDetailReadonly": true,
"bindingCalls": 0,
"pageErrors": []
},
{
"level": 3,
"bindingTab": true,
"editButtons": 0,
"passed": true,
"normalUnbind": 1,
"rejectedUnbind": 0,
"pendingUnbind": 0,
"rejectedDetail": 1,
"rejectDrawerInViewport": true,
"bindingCalls": 1,
"pageErrors": []
}
]
}
+2
View File
@@ -13,6 +13,8 @@
用户补充:允许直接优化旧接口、SQL 和逻辑。优化时记录行为差异并验证业务结果;各批实现必须实际请求 HTTP 接口,不能只以单元测试和构建作为完成依据。
用户再次指出页面偏差后,明确按旧前端实际页面核对入口,不能从后端接口推断 UI 功能。详见 `page-parity.md`。商务列表已移除错误增加的编辑入口,恢复“绑定列表”名称及仅三级显示规则,并对齐按审核状态显示行操作。
用户已有的 `configs/config.yaml` 修改与迁移 SQL 保留。未经最后阶段的数据库确认,不连接、复制或修改用户的旧数据库。
## 依赖顺序与完成标准
+37
View File
@@ -0,0 +1,37 @@
# 旧商务页面功能核对
以旧前端 `dev/dev1.0` 的实际模板、事件处理和接口调用为准,不因为后端存在某个接口就向页面增加入口。页面样式采用 Kra;名称、业务可见条件和交互沿用旧商务。只有完成页面、接口和实际验证后才标为整个菜单完成。
## 商务列表与绑定列表
来源:`sw/web/src/views/BusMgmt/BusinessList.vue`,以及该目录下实际引用的抽屉组件。前端基线 `ba284011c87fd3d5730e0e3dceffb14a7389730c`。
| 旧页面行为 | 新页面状态 |
| --- | --- |
| 商务列表没有编辑按钮;操作列为画像 | 已移除错误增加的编辑入口;画像待报表与画像用例迁移,不能视为完成 |
| 第二个页签名为“绑定列表”,仅 `level=3` 显示 | 已对齐;超管、一级、二级均隐藏且不会加载绑定列表 |
| 商务列表筛选:商务名称、商务账号、等级、状态 | 已实现 |
| 添加子商务:账号、密码、姓名、手机号、QQ;展示等级/所属商务 | 已实现主要字段,所属商务展示继续核对;已移除原页面没有的邮箱和编辑审核表单 |
| SDK商务数量可点击,零数量也能打开详情 | 已对齐 |
| SDK商务绑定详情是只读抽屉,上级可以查看;列为平台、ID、游戏商务账号、审核状态、绑定日期 | 已对齐基础列表与字段;平台点击进入画像待实现 |
| 商务列表列名“旗下渠道数” | 已对齐;点击进入旗下渠道抽屉待实现 |
| 注册日期、绑定日期显示年月日 | 已对齐 |
| 绑定状态正常:画像、解绑;驳回:查看驳回;待审核:无操作 | 解绑/查看驳回/待审核无操作已对齐;画像待实现 |
| 查看驳回打开审核详情,展示申请商务、平台、账号、状态、申请/审核时间、审核人和审核意见 | 已实现 |
| 添加绑定、解除绑定确认使用右侧抽屉 | 已对齐 |
| 绑定列表点击旗下渠道数时,仅正常状态可查看并携带平台/平台商务筛选 | 待实现 |
| 全局偏好变化刷新商务/绑定数据 | 已接入 Kra 页面刷新机制 |
“仅三级可见”是旧页面页签规则。旧 Java 绑定查询接口仍支持超管全量、一级/二级查询下级,SDK 详情接口允许上级查看下级;这些接口的数据范围不能因页签隐藏而一并误删。
目前 sw7 是系统数据演练库,缺少 `tab_promote`。有绑定但渠道表未接入的数量明确返回空值并展示“未接入”,不当作零;完整数据环境继续计算真实数量。
## 验证
- `business-page-parity-2026-11-03.json`:真实 Chrome 渲染、受控身份/业务数据,检查四个等级的页签和按钮,以及三种审核状态的行操作;无页面运行时错误。
- `http-business-bindings-2026-11-03.json`:真实运行实例及已有 sw7 测试数据的 HTTP 验证。
- 画像、旗下渠道抽屉等未完成项没有用占位响应或假数据冒充已迁移功能。
## 其他页面
渠道列表、渠道激活、渠道统计、充值明细、注册明细、游戏数据、区服分析、排行榜、预警列表和预警规则,均需在各自实现前逐项提取旧模板的筛选项、列、按钮、抽屉、权限和跳转。数据库菜单清单或后端接口清单只能用于交叉核对,不能替代页面核对。
+76
View File
@@ -0,0 +1,76 @@
// 使用受控身份和接口数据检查实际 Vue 页面,不修改业务库。
const fs = require('node:fs/promises');
const path = require('node:path');
const { chromium } = require(process.env.SW_PLAYWRIGHT_MODULE || 'playwright');
(async () => {
const token = (await fs.readFile(path.join(process.env.TEMP, 'sw-kra-http-test-token'), 'utf8')).trim();
const browser = await chromium.launch({channel:'chrome', headless:true});
const results = [];
try {
for (const level of [0,1,2,3]) {
const context = await browser.newContext({viewport:{width:1440,height:1000}});
await context.addInitScript(value => localStorage.setItem('token',value),token);
const page = await context.newPage();
const pageErrors=[];
page.on('pageerror',e=>pageErrors.push(e.message));
let bindingCalls=0;
await page.route('http://127.0.0.1:8080/api/**', async route => {
const request=route.request();
const uri=new URL(request.url());
const apiPath=uri.pathname.slice(4);
let body;
if(apiPath==='/sw/business/list') body={code:0,msg:'成功',data:{rows:[{userId:79999,userName:'展示测试商务',level:2,parentUserName:'上级商务',realName:'测试姓名',phoneNumber:'',bindCount:0,promoteCount:0,createTime:'2026-11-03 10:00:00',status:'0',authorityId:902}],total:1}};
else if(apiPath==='/sw/business/bindPlatform') {
bindingCalls++;
body={code:0,msg:'成功',data:{total:3,rows:['0','2','3'].map((status,i)=>({userId:70000+level,sourceDb:'lx',platformName:'龙翔',platformBusierId:10+i,platformBusierAccount:['正常账号','驳回账号','待审账号'][i],bindUserName:'测试商务',promoteCount:status==='0'?2:0,status,createTime:'2026-11-03 10:00:00',reviewTime:'2026-11-03 11:00:00',reviewAccount:'测试审核人',rejectReason:status==='2'?'测试驳回原因':null}))}};
} else if(/^\/sw\/business\/\d+\/bindPlatform$/.test(apiPath)) body={code:0,msg:'成功',data:[]};
if(body) {await route.fulfill({json:body});return;}
const response=await route.fetch({url:'http://127.0.0.1:18000'+apiPath+uri.search,headers:{...request.headers(),'x-token':token}});
if(apiPath==='/user/getUserInfo') {
body=await response.json();
const info=body.data.userInfo;
Object.assign(info,{ID:70000+level,level,nickName:'页面核对账号',phone:'',email:'',authorityId:level===0?888:900+level});
await route.fulfill({response,json:body});
} else await route.fulfill({response});
});
await page.goto('http://127.0.0.1:8080/#/layout/sw-BusMgmt/BusinessList');
try { await page.getByRole('tab',{name:'商务列表',exact:true}).waitFor({timeout:15000}); } catch (error) { console.log(JSON.stringify({url:page.url(),errors:pageErrors,text:(await page.locator('body').innerText()).slice(0,1800)})); await page.screenshot({path:path.join(process.env.TEMP,'sw-kra-browser-failure.png')}); throw error; }
await page.getByText('展示测试商务',{exact:true}).waitFor();
const tabs=await page.getByRole('tab',{name:'绑定列表',exact:true}).count();
const editButtons=await page.getByRole('button',{name:'编辑',exact:true}).count();
if(tabs!==(level===3?1:0)||editButtons!==0) throw new Error('页面权限或编辑入口不一致 level='+level);
const result={level,bindingTab:tabs===1,editButtons,passed:true};
if(level===1 || level===2) {
await page.getByRole('row').filter({hasText:'展示测试商务'}).getByRole('button',{name:'0',exact:true}).click();
await page.getByRole('dialog',{name:'SDK商务绑定详情'}).waitFor();
result.sdkDetailReadonly=(await page.getByRole('dialog',{name:'SDK商务绑定详情'}).getByRole('button',{name:'解绑',exact:true}).count())===0;
if(!result.sdkDetailReadonly)throw new Error('SDK 详情出现写操作');
await page.getByRole('dialog',{name:'SDK商务绑定详情'}).getByRole('button',{name:'关闭此对话框',exact:true}).click();
}
if(level===3) {
await page.getByRole('tab',{name:'绑定列表',exact:true}).click();
await page.getByText('正常账号',{exact:true}).waitFor();
const normal=page.getByRole('row').filter({hasText:'正常账号'});
const rejected=page.getByRole('row').filter({hasText:'驳回账号'});
const pending=page.getByRole('row').filter({hasText:'待审账号'});
result.normalUnbind=await normal.getByRole('button',{name:'解绑',exact:true}).count();
result.rejectedUnbind=await rejected.getByRole('button',{name:'解绑',exact:true}).count();
result.pendingUnbind=await pending.getByRole('button',{name:'解绑',exact:true}).count();
result.rejectedDetail=await rejected.getByRole('button',{name:'查看驳回',exact:true}).count();
if(result.normalUnbind!==1||result.rejectedUnbind||result.pendingUnbind||result.rejectedDetail!==1)throw new Error('绑定状态操作不一致');
await rejected.getByRole('button',{name:'查看驳回',exact:true}).click();
await page.getByText('测试驳回原因',{exact:true}).waitFor();
const panel=await page.getByRole('dialog',{name:'审核详情',exact:true}).elementHandle();
await page.waitForFunction(el=>{const box=el.getBoundingClientRect();return box.x>=0 && box.right<=innerWidth+1},panel,{timeout:5000});
result.rejectDrawerInViewport=true;
} else if(bindingCalls!==0) throw new Error('非三级加载了绑定列表');
result.bindingCalls=bindingCalls;
result.pageErrors=pageErrors;
await page.screenshot({path:path.join(process.env.TEMP,'sw-kra-business-level-'+level+'.png'),fullPage:true,animations:'disabled'});
results.push(result);
console.log(JSON.stringify(result));
await context.close();
}
await fs.writeFile('docs/sw6-to-kra/business-page-parity-2026-11-03.json',JSON.stringify({method:'真实 Chrome 渲染;受控身份和业务数据,权限页签与状态操作核对',results},null,2));
} finally {await browser.close();}
})().catch(error=>{console.error(error.message);process.exitCode=1});
+17 -32
View File
@@ -1,7 +1,7 @@
<template>
<div>
<el-tabs v-model="activeTab"><el-tab-pane label="商务列表" name="accounts" /><el-tab-pane label="游戏 SDK 绑定" name="bindings" /></el-tabs>
<business-bindings v-if="activeTab === 'bindings'" @changed="load" />
<el-tabs v-model="activeTab"><el-tab-pane label="商务列表" name="accounts" /><el-tab-pane v-if="isLevel3" label="绑定列表" name="bindings" /></el-tabs>
<business-bindings v-if="isLevel3 && activeTab === 'bindings'" @changed="load" />
<div v-show="activeTab === 'accounts'" class="kra-search-box">
<el-form :inline="true" :model="query" @submit.prevent="search">
<el-form-item label="商务账号"><el-input v-model="query.userName" clearable placeholder="请输入账号" /></el-form-item>
@@ -23,41 +23,35 @@
<div class="kra-btn-list">
<el-button v-if="canAdd" type="primary" icon="plus" @click="openCreate">添加子商务</el-button>
</div>
<el-table v-loading="loading" :data="rows" row-key="userId" @sort-change="sort">
<el-table v-loading="loading" :data="rows" row-key="userId">
<el-table-column prop="userName" label="商务账号" min-width="140" />
<el-table-column label="商务等级" width="110"><template #default="{ row }">{{ levels[row.level] || '系统账号' }}</template></el-table-column>
<el-table-column prop="parentUserName" label="上级商务" min-width="140" />
<el-table-column prop="realName" label="姓名" min-width="100" />
<el-table-column prop="phoneNumber" label="手机号" min-width="130" />
<el-table-column prop="bindCount" label="SDK 商务数" width="120"><template #default="{ row }"><el-button v-if="row.bindCount > 0" link type="primary" @click="showBindings(row)">{{ row.bindCount }}</el-button><span v-else>0</span></template></el-table-column>
<el-table-column prop="promoteCount" label="直属渠道数" width="120">
<el-table-column prop="bindCount" label="SDK商务" width="120"><template #default="{ row }"><el-button link type="primary" @click="showBindings(row)">{{ row.bindCount }}</el-button></template></el-table-column>
<el-table-column prop="promoteCount" label="旗下渠道数" width="120">
<template #default="{ row }">
<el-tooltip v-if="row.promoteCount === null" content="当前数据库尚未接入渠道数据,商务资料和绑定数仍可查看。"><span class="text-gray-400">未接入</span></el-tooltip>
<span v-else>{{ row.promoteCount }}</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="注册时间" sortable="custom" min-width="180" />
<el-table-column prop="createTime" label="注册时间" min-width="130"><template #default="{ row }">{{ row.createTime?.slice(0, 10) }}</template></el-table-column>
<el-table-column label="状态" width="110"><template #default="{ row }"><el-tag :type="statusType(row.status)">{{ statuses[row.status] || row.status }}</el-tag></template></el-table-column>
<el-table-column v-if="canEdit" label="操作" fixed="right" width="90"><template #default="{ row }"><el-button v-if="row.authorityId !== 888" type="primary" link @click="openEdit(row)">编辑</el-button></template></el-table-column>
</el-table>
<div class="kra-pagination">
<el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="total" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" @size-change="search" @current-change="load" />
</div>
</div>
<el-drawer v-model="bindingsDrawer" title="已通过的游戏 SDK 绑定" size="85%" destroy-on-close><business-bindings :user-id="bindingUserId" /></el-drawer>
<el-drawer v-model="drawer" :title="editing ? '编辑商务' : '添加子商务'" :size="480" destroy-on-close>
<el-drawer append-to-body v-model="bindingsDrawer" title="SDK商务绑定详情" size="85%" destroy-on-close><business-bindings :user-id="bindingUserId" /></el-drawer>
<el-drawer append-to-body v-model="drawer" title="添加子商务" :size="480" destroy-on-close>
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
<el-form-item label="商务账号" prop="userName"><el-input v-model="form.userName" maxlength="30" /></el-form-item>
<el-form-item v-if="!editing" label="登录密码" prop="password"><el-input v-model="form.password" type="password" show-password autocomplete="new-password" /></el-form-item>
<el-form-item label="登录密码" prop="password"><el-input v-model="form.password" type="password" show-password autocomplete="new-password" /></el-form-item>
<el-form-item label="姓名" prop="realName"><el-input v-model="form.realName" maxlength="30" /></el-form-item>
<el-form-item label="手机号"><el-input v-model="form.phoneNumber" maxlength="11" /></el-form-item>
<el-form-item label="QQ"><el-input v-model="form.qqNumber" maxlength="20" /></el-form-item>
<el-form-item label="邮箱"><el-input v-model="form.email" maxlength="50" /></el-form-item>
<el-form-item v-if="editing" label="状态">
<el-select v-model="form.status"><el-option v-for="(label, value) in statuses" :key="value" :label="label" :value="value" /></el-select>
</el-form-item>
<el-form-item v-if="form.status === '2'" label="驳回原因"><el-input v-model="form.rejectReason" type="textarea" maxlength="200" /></el-form-item>
<el-form-item v-if="!editing" label="商务等级"><span>{{ childLevel }}</span></el-form-item>
<el-form-item label="商务等级"><span>{{ childLevel }}</span></el-form-item>
</el-form>
<template #footer><el-button @click="drawer = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">确定</el-button></template>
</el-drawer>
@@ -65,11 +59,11 @@
</template>
<script setup>
import { computed, reactive, ref, onMounted } from 'vue'
import { computed, reactive, ref, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/pinia/modules/user'
import { useBtnAuth } from '@/utils/btnAuth'
import { listBusiness, getBusiness, createBusiness, updateBusiness } from '@/api/business'
import { listBusiness, createBusiness } from '@/api/business'
import BusinessBindings from './components/BusinessBindings.vue'
defineOptions({ name: 'SwBusinessList' })
@@ -83,14 +77,13 @@ const levels = { 1: '一级商务', 2: '二级商务', 3: '三级商务' }
const statuses = { 0: '正常', 1: '停用', 2: '已驳回', 3: '待审核' }
const isAdmin = computed(() => Number(user.userInfo.authorityId) === 888)
const canAdd = computed(() => (isAdmin.value || buttons['sw:business:add']) && (isAdmin.value || Number(user.userInfo.level) < 3))
const canEdit = computed(() => isAdmin.value || buttons['sw:business:edit'])
const isLevel3 = computed(() => Number(user.userInfo.level) === 3)
const childLevel = computed(() => levels[isAdmin.value ? 1 : Number(user.userInfo.level || 1) + 1])
const query = reactive({ pageNum: 1, pageSize: 10, userName: '', realName: '', level: undefined, status: undefined, orderByColumn: '', isAsc: '' })
const rows = ref([])
const total = ref(0)
const loading = ref(false)
const drawer = ref(false)
const editing = ref(false)
const saving = ref(false)
const formRef = ref()
const form = ref({})
@@ -109,26 +102,18 @@ const load = async () => {
}
const search = () => { query.pageNum = 1; return load() }
const reset = () => { Object.assign(query, { userName: '', realName: '', level: undefined, status: undefined }); return search() }
const sort = ({ prop, order }) => { query.orderByColumn = prop || ''; query.isAsc = order === 'descending' ? 'desc' : 'asc'; return search() }
const openCreate = () => {
editing.value = false
form.value = { userName: '', password: '', realName: '', phoneNumber: '', qqNumber: '', email: '', status: '0', rejectReason: '' }
drawer.value = true
}
const openEdit = async (row) => {
const res = await getBusiness(row.userId)
if (res.code !== 0) return
editing.value = true
form.value = { ...res.data }
form.value = { userName: '', password: '', realName: '', phoneNumber: '', qqNumber: '', status: '0' }
drawer.value = true
}
const save = async () => {
if (!await formRef.value.validate().catch(() => false)) return
saving.value = true
try {
const res = await (editing.value ? updateBusiness : createBusiness)({ ...form.value, nickName: form.value.realName })
if (res.code === 0) { ElMessage.success(editing.value ? '修改成功' : '添加成功'); drawer.value = false; await load() }
const res = await createBusiness({ ...form.value, nickName: form.value.realName })
if (res.code === 0) { ElMessage.success('添加成功'); drawer.value = false; await load() }
} finally { saving.value = false }
}
watch(isLevel3, (visible) => { if (!visible) activeTab.value = 'accounts' })
onMounted(load)
</script>
+50 -19
View File
@@ -4,27 +4,31 @@
<el-form :inline="true" :model="query" @submit.prevent="search">
<el-form-item label="所属平台"><el-select v-model="query.sourceDb" multiple clearable placeholder="全部平台" style="width: 220px"><el-option v-for="(label, value) in platforms" :key="value" :value="value" :label="label" /></el-select></el-form-item>
<el-form-item label="游戏商务账号"><el-input v-model="query.platformBusierAccount" clearable /></el-form-item>
<el-form-item label="状态"><el-select v-model="query.status" clearable style="width: 130px"><el-option v-for="(label, value) in statuses" :key="value" :value="value" :label="label" /></el-select></el-form-item>
<el-form-item label="审核状态"><el-select v-model="query.status" clearable style="width: 130px"><el-option v-for="(label, value) in statuses" :key="value" :value="value" :label="label" /></el-select></el-form-item>
<el-form-item><el-button type="primary" icon="search" native-type="submit">查询</el-button><el-button icon="refresh" @click="reset">重置</el-button></el-form-item>
</el-form>
</div>
<div class="kra-table-box">
<div v-if="!userId && canBind" class="kra-btn-list"><el-button type="primary" icon="plus" @click="openBind">绑定游戏商务</el-button></div>
<el-table v-loading="loading" :data="rows" :row-key="rowKey">
<el-table-column prop="platformName" label="平台" min-width="80" />
<el-table-column prop="platformName" label="所属平台" min-width="80" />
<el-table-column v-if="userId" prop="platformBusierId" label="ID" min-width="90" />
<el-table-column prop="platformBusierAccount" label="游戏商务账号" min-width="140" />
<el-table-column prop="bindUserName" label="绑定商务" min-width="140" />
<el-table-column label="直属渠道数" min-width="110"><template #default="{ row }"><span :class="{ 'text-gray-400': row.promoteCount === null }">{{ row.promoteCount === null ? '未接入' : row.promoteCount }}</span></template></el-table-column>
<el-table-column label="状态" width="110"><template #default="{ row }"><el-tag :type="row.status === '0' ? 'success' : row.status === '2' ? 'danger' : 'warning'">{{ statuses[row.status] || row.status }}</el-tag></template></el-table-column>
<el-table-column prop="createTime" label="提交时间" min-width="180" />
<el-table-column prop="reviewTime" label="审核时间" min-width="180" />
<el-table-column prop="reviewAccount" label="审核人" min-width="100" />
<el-table-column prop="rejectReason" label="驳回原因" min-width="150" show-overflow-tooltip />
<el-table-column v-if="canBind" label="操作" width="90" fixed="right"><template #default="{ row }"><el-button v-if="row.userId === user.userInfo.ID" link type="danger" @click="remove(row)">解绑</el-button></template></el-table-column>
<el-table-column v-if="!userId" prop="bindUserName" label="绑定商务" min-width="140" />
<el-table-column v-if="!userId" label="旗下渠道数" min-width="110"><template #default="{ row }"><span :class="{ 'text-gray-400': row.promoteCount === null }">{{ row.promoteCount === null ? '未接入' : row.promoteCount }}</span></template></el-table-column>
<el-table-column label="审核状态" width="110"><template #default="{ row }"><el-tag :type="row.status === '0' ? 'success' : row.status === '2' ? 'danger' : 'warning'">{{ statuses[row.status] || row.status }}</el-tag></template></el-table-column>
<el-table-column prop="createTime" label="绑定时间" min-width="130"><template #default="{ row }">{{ row.createTime?.slice(0, 10) }}</template></el-table-column>
<el-table-column v-if="!userId" label="操作" width="110" fixed="right">
<template #default="{ row }">
<el-button v-if="canBind && row.status === '0' && row.userId === user.userInfo.ID" link type="danger" @click="remove(row)">解绑</el-button>
<el-button v-else-if="row.status === '2'" link type="primary" @click="showReject(row)">查看驳回</el-button>
<span v-else>—</span>
</template>
</el-table-column>
</el-table>
<div v-if="!userId" class="kra-pagination"><el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="total" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" @size-change="search" @current-change="load" /></div>
</div>
<el-dialog v-model="dialog" title="绑定游戏商务" width="460px" destroy-on-close>
<el-drawer append-to-body v-model="dialog" title="绑定游戏商务" size="460px" destroy-on-close>
<el-alert title="验证成功后提交 OA 审核,审核通过后可查看对应渠道数据。" type="info" :closable="false" class="mb-4" />
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
<el-form-item label="所属平台" prop="sourceDb"><el-select v-model="form.sourceDb"><el-option v-for="(label, value) in platforms" :key="value" :value="value" :label="label" /></el-select></el-form-item>
@@ -32,13 +36,31 @@
<el-form-item label="游戏商务密码" prop="password"><el-input v-model="form.password" type="password" show-password autocomplete="new-password" /></el-form-item>
</el-form>
<template #footer><el-button @click="dialog = false">取消</el-button><el-button type="primary" :loading="saving" @click="submit">验证并提交</el-button></template>
</el-dialog>
</el-drawer>
<el-drawer append-to-body v-model="rejectDrawer" title="审核详情" size="420px" destroy-on-close>
<el-descriptions v-if="selectedRow" :column="1" border>
<el-descriptions-item label="申请商务">{{ selectedRow.bindUserName || '—' }}</el-descriptions-item>
<el-descriptions-item label="所属平台">{{ selectedRow.platformName }}</el-descriptions-item>
<el-descriptions-item label="游戏商务账号">{{ selectedRow.platformBusierAccount }}</el-descriptions-item>
<el-descriptions-item label="当前状态">{{ statuses[selectedRow.status] }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ selectedRow.createTime || '—' }}</el-descriptions-item>
<el-descriptions-item label="审核时间">{{ selectedRow.reviewTime || '—' }}</el-descriptions-item>
<el-descriptions-item label="审核人">{{ selectedRow.reviewAccount || '—' }}</el-descriptions-item>
<el-descriptions-item label="审核意见">{{ selectedRow.rejectReason || '—' }}</el-descriptions-item>
</el-descriptions>
<template #footer><el-button @click="rejectDrawer = false">关闭</el-button></template>
</el-drawer>
<el-drawer append-to-body v-model="unbindDrawer" title="解除绑定确认" size="420px" destroy-on-close>
<p>确认解除游戏SDK商务「{{ selectedRow?.platformBusierAccount }}」(平台:{{ selectedRow?.platformName }})的绑定吗?</p>
<p class="mt-4 text-gray-500">解除后该商务将从列表移除,其名下渠道数据将不再可查询。</p>
<template #footer><el-button @click="unbindDrawer = false">取消</el-button><el-button type="danger" :loading="saving" @click="confirmUnbind">确认解除</el-button></template>
</el-drawer>
</div>
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/pinia/modules/user'
import { useBtnAuth } from '@/utils/btnAuth'
import { listBusinessBindings, listUserBindings, bindPlatform, unbindPlatform } from '@/api/business'
@@ -48,14 +70,18 @@ const props = defineProps({ userId: { type: Number, default: 0 } })
const emit = defineEmits(['changed'])
const user = useUserStore()
const buttons = useBtnAuth()
const canBind = computed(() => Number(user.userInfo.level) === 3 && Boolean(buttons['sw:business:bind']))
const canBind = computed(() => !props.userId && Number(user.userInfo.level) === 3 && Boolean(buttons['sw:business:bind']))
const platforms = { lx: '龙翔', hw: '汇玩', yq: '游趣' }
const statuses = { 0: '已通过', 2: '已驳回', 3: '待审核' }
const statuses = { 0: '正常', 2: '已驳回', 3: '待审核' }
const query = reactive({ pageNum: 1, pageSize: 10, sourceDb: [], platformBusierAccount: '', status: '' })
const rows = ref([])
const total = ref(0)
const loading = ref(false)
const dialog = ref(false)
const rejectDrawer = ref(false)
const unbindDrawer = ref(false)
const selectedRow = ref(null)
const showReject = (row) => { selectedRow.value = row; rejectDrawer.value = true }
const saving = ref(false)
const formRef = ref()
const form = ref({})
@@ -82,10 +108,15 @@ const submit = async () => {
if (res.code === 0) { ElMessage.success('已提交,请等待 OA 审核'); dialog.value = false; form.value.password = ''; emit('changed'); await load() }
} finally { saving.value = false }
}
const remove = async (row) => {
if (!await ElMessageBox.confirm(`确认解绑 ${row.platformName} 的游戏商务 ${row.platformBusierAccount}?`, '解绑确认', { type: 'warning' }).then(() => true).catch(() => false)) return
const res = await unbindPlatform({ sourceDb: row.sourceDb, platformBusierId: row.platformBusierId })
if (res.code === 0) { ElMessage.success('解绑成功'); emit('changed'); await load() }
const remove = (row) => { selectedRow.value = row; unbindDrawer.value = true }
const confirmUnbind = async () => {
const row = selectedRow.value
if (!row || !canBind.value || row.status !== '0' || row.userId !== user.userInfo.ID) return
saving.value = true
try {
const res = await unbindPlatform({ sourceDb: row.sourceDb, platformBusierId: row.platformBusierId })
if (res.code === 0) { ElMessage.success('解绑成功'); unbindDrawer.value = false; emit('changed'); await load() }
} finally { saving.value = false }
}
watch(() => props.userId, load, { immediate: true })
</script>