diff --git a/app/admin/controller/game/Channel.php b/app/admin/controller/Channel.php similarity index 78% rename from app/admin/controller/game/Channel.php rename to app/admin/controller/Channel.php index d191808..d4027f8 100644 --- a/app/admin/controller/game/Channel.php +++ b/app/admin/controller/Channel.php @@ -1,6 +1,6 @@ model = new \app\common\model\GameChannel(); + $this->model = new \app\common\model\Channel(); + $this->currentChannelIds = $this->getCurrentChannelIds(); return null; } @@ -40,11 +43,13 @@ class Channel extends Backend $response = $this->initializeBackend($request); if ($response !== null) return $response; - $channels = Db::name('game_channel') + $query = Db::name('channel') ->field(['id', 'name', 'admin_group_id']) - ->order('id', 'asc') - ->select() - ->toArray(); + ->order('id', 'asc'); + if (!$this->auth->isSuperAdmin()) { + $query = $query->where('id', 'in', $this->currentChannelIds ?: [0]); + } + $channels = $query->select()->toArray(); $groupChildrenCache = []; $getGroupChildren = function ($groupId) use (&$getGroupChildren, &$groupChildrenCache) { @@ -131,13 +136,14 @@ class Channel extends Backend $data = $this->applyInputFilter($data); $data = $this->excludeFields($data); + $data = $this->normalizeAgentModeFields($data); + unset($data['invite_code']); $adminId = $data['admin_id'] ?? null; if ($adminId === null || $adminId === '') { return $this->error(__('Parameter %s can not be empty', ['admin_id'])); } - // 不允许前端填写,统一后端根据管理员所属“顶级角色组(pid=0)”自动回填 if (array_key_exists('admin_group_id', $data)) { unset($data['admin_group_id']); } @@ -153,6 +159,10 @@ class Channel extends Backend return $this->error(__('Record not found')); } $data['admin_group_id'] = $topGroupId; + if (!$this->auth->isSuperAdmin()) { + $data['top_admin_id'] = $this->auth->id; + $data['admin_id'] = $this->auth->id; + } if ($this->dataLimit && $this->dataLimitFieldAutoFill) { $data[$this->dataLimitField] = $this->auth->id; @@ -198,6 +208,9 @@ class Channel extends Backend if (!$row) { return $this->error(__('Record not found')); } + if (!$this->auth->isSuperAdmin() && !in_array($row['id'], $this->currentChannelIds, true)) { + return $this->error(__('You have no permission')); + } $dataLimitAdminIds = $this->getDataLimitAdminIds(); if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { @@ -212,8 +225,9 @@ class Channel extends Backend $data = $this->applyInputFilter($data); $data = $this->excludeFields($data); + $data = $this->normalizeAgentModeFields($data); + unset($data['invite_code']); - // 不允许前端填写,统一后端根据管理员所属“顶级角色组(pid=0)”自动回填 if (array_key_exists('admin_group_id', $data)) { unset($data['admin_group_id']); } @@ -232,6 +246,10 @@ class Channel extends Backend } $data['admin_group_id'] = $topGroupId; } + if (!$this->auth->isSuperAdmin()) { + $data['top_admin_id'] = $this->auth->id; + $data['admin_id'] = $this->auth->id; + } $result = false; $this->model->startTrans(); @@ -270,17 +288,14 @@ class Channel extends Backend */ protected function _index(): Response { - // 如果是 select 则转发到 select 方法,若未重写该方法,其实还是继续执行 index if ($this->request && $this->request->get('select')) { return $this->select($this->request); } - /** - * 1. withJoin 不可使用 alias 方法设置表别名,别名将自动使用关联模型名称(小写下划线命名规则) - * 2. 以下的别名设置了主表别名,同时便于拼接查询参数等 - * 3. paginate 数据集可使用链式操作 each(function($item, $key) {}) 遍历处理 - */ list($where, $alias, $limit, $order) = $this->queryBuilder(); + if (!$this->auth->isSuperAdmin()) { + $where[] = [$alias['channel'] . '.id', 'in', $this->currentChannelIds ?: [0]]; + } $res = $this->model ->withJoin($this->withJoinTable, $this->withJoinType) ->with($this->withJoinTable) @@ -297,7 +312,36 @@ class Channel extends Backend ]); } - /** - * 若需重写查看、编辑、删除等方法,请复制 @see \app\admin\library\traits\Backend 中对应的方法至此进行重写 - */ -} \ No newline at end of file + private function getCurrentChannelIds(): array + { + if ($this->auth->isSuperAdmin()) { + return Db::name('channel')->column('id'); + } + $admin = Db::name('admin') + ->field(['id', 'channel_id']) + ->where('id', $this->auth->id) + ->find(); + $ids = []; + if ($admin && !empty($admin['channel_id'])) { + $ids[] = $admin['channel_id']; + } + $owned = Db::name('channel')->where('top_admin_id', $this->auth->id)->column('id'); + $created = Db::name('channel')->where('admin_id', $this->auth->id)->column('id'); + return array_values(array_unique(array_merge($ids, $owned, $created))); + } + + private function normalizeAgentModeFields(array $data): array + { + $mode = $data['agent_mode'] ?? null; + if ($mode === 'turnover') { + $data['affiliate_share_rate'] = null; + $data['affiliate_fee_rate'] = null; + $data['carryover_balance'] = 0; + return $data; + } + if ($mode === 'affiliate') { + $data['turnover_share_rate'] = null; + } + return $data; + } +} diff --git a/app/common/model/GameChannel.php b/app/common/model/Channel.php similarity index 89% rename from app/common/model/GameChannel.php rename to app/common/model/Channel.php index f7e8632..e656ce8 100644 --- a/app/common/model/GameChannel.php +++ b/app/common/model/Channel.php @@ -5,12 +5,12 @@ namespace app\common\model; use support\think\Model; /** - * GameChannel + * Channel */ -class GameChannel extends Model +class Channel extends Model { // 表名 - protected $name = 'game_channel'; + protected $name = 'channel'; // 自动写入时间戳字段 protected $autoWriteTimestamp = true; @@ -21,7 +21,6 @@ class GameChannel extends Model 'update_time' => 'integer', ]; - public function getprofitAmountAttr($value): ?float { return is_null($value) ? null : (float)$value; @@ -36,4 +35,4 @@ class GameChannel extends Model { return $this->belongsTo(\app\admin\model\Admin::class, 'admin_id', 'id'); } -} \ No newline at end of file +} diff --git a/app/common/validate/GameChannel.php b/app/common/validate/GameChannel.php deleted file mode 100644 index 2e14afb..0000000 --- a/app/common/validate/GameChannel.php +++ /dev/null @@ -1,31 +0,0 @@ - [], - 'edit' => [], - ]; - -} diff --git a/web/src/lang/backend/en/channel.ts b/web/src/lang/backend/en/channel.ts new file mode 100644 index 0000000..720d0d8 --- /dev/null +++ b/web/src/lang/backend/en/channel.ts @@ -0,0 +1,37 @@ +export default { + id: 'id', + code: 'code', + invite_code: 'invite_code', + name: 'name', + top_admin_id: 'top_admin_id', + agent_mode: 'agent_mode', + 'agent_mode turnover': 'turnover', + 'agent_mode affiliate': 'affiliate', + agent_mode_title_turnover: 'Turnover Agent Mode', + agent_mode_desc_turnover_1: 'Settlement: commissions apply only when platform-wide PnL is positive.', + agent_mode_desc_turnover_2: 'Formula: bucket base by turnover × turnover share rate.', + agent_mode_desc_turnover_3: 'Fields: fill turnover share rate only; affiliate fields are cleared automatically.', + agent_mode_title_affiliate: 'Affiliate Agent Mode', + agent_mode_desc_affiliate_1: 'Settlement: based on net player loss within this affiliate line.', + agent_mode_desc_affiliate_2: 'Formula: net loss after costs × affiliate share rate.', + agent_mode_desc_affiliate_3: 'Fields: supports fee deduction rate and carryover balance; turnover rate is cleared automatically.', + turnover_share_rate: 'turnover_share_rate', + affiliate_share_rate: 'affiliate_share_rate', + affiliate_fee_rate: 'affiliate_fee_rate', + carryover_balance: 'carryover_balance', + user_count: 'user_count', + profit_amount: 'profit_amount', + total_profit_amount: 'total_profit_amount', + commission_pool_amount: 'commission_pool_amount', + status: 'status', + 'status 0': 'status 0', + 'status 1': 'status 1', + remark: 'remark', + admin_group_id: 'admin_group_id', + admingroup__name: 'name', + admin_id: 'admin_id', + admin__username: 'username', + create_time: 'create_time', + update_time: 'update_time', + 'quick Search Fields': 'id,code,name', +} diff --git a/web/src/lang/backend/en/game/channel.ts b/web/src/lang/backend/en/game/channel.ts deleted file mode 100644 index 35bea2f..0000000 --- a/web/src/lang/backend/en/game/channel.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default { - id: 'id', - code: 'code', - name: 'name', - user_count: 'user_count', - profit_amount: 'profit_amount', - status: 'status', - 'status 0': 'status 0', - 'status 1': 'status 1', - remark: 'remark', - admin_group_id: 'admin_group_id', - admingroup__name: 'name', - admin_id: 'admin_id', - admin__username: 'username', - create_time: 'create_time', - update_time: 'update_time', - 'quick Search Fields': 'id,code,name', -} diff --git a/web/src/lang/backend/zh-cn/channel.ts b/web/src/lang/backend/zh-cn/channel.ts new file mode 100644 index 0000000..ec53d48 --- /dev/null +++ b/web/src/lang/backend/zh-cn/channel.ts @@ -0,0 +1,37 @@ +export default { + id: 'ID', + code: '渠道标识', + invite_code: '渠道邀请码', + name: '渠道名', + top_admin_id: '顶级代理', + agent_mode: '代理模式', + 'agent_mode turnover': '普通返水代理', + 'agent_mode affiliate': '联营代理', + agent_mode_title_turnover: '普通返水代理(按流水分桶)', + agent_mode_desc_turnover_1: '结算口径:仅在平台大盘盈利时参与分红;大盘亏损或持平时当期分红为0。', + agent_mode_desc_turnover_2: '计算方式:渠道分桶基数 × 返水分红比例(turnover_share_rate)。', + agent_mode_desc_turnover_3: '字段说明:仅需填写返水分红比例;切换到该模式会自动清空联营相关字段。', + agent_mode_title_affiliate: '联营代理(客损占成)', + agent_mode_desc_affiliate_1: '结算口径:按该渠道辖区净客损结算,支持联营占成分账。', + agent_mode_desc_affiliate_2: '计算方式:净客损扣除成本后 × 联营占成比例(affiliate_share_rate)。', + agent_mode_desc_affiliate_3: '字段说明:可配置联营成本扣除比例与负结转余额;切换到该模式会自动清空返水比例。', + turnover_share_rate: '返水分红比例', + affiliate_share_rate: '联营占成比例', + affiliate_fee_rate: '联营成本扣除比例', + carryover_balance: '联营负结转余额', + user_count: '用户数', + profit_amount: '当期利润', + total_profit_amount: '累计总利润', + commission_pool_amount: '可分红资金池', + status: '状态', + 'status 0': '禁用', + 'status 1': '启用', + remark: '备注', + admin_group_id: '管理角色组', + admingroup__name: '组名', + admin_id: '管理员', + admin__username: '用户名', + create_time: '创建时间', + update_time: '修改时间', + 'quick Search Fields': 'ID、渠道标识、渠道名', +} diff --git a/web/src/lang/backend/zh-cn/game/channel.ts b/web/src/lang/backend/zh-cn/game/channel.ts deleted file mode 100644 index f185326..0000000 --- a/web/src/lang/backend/zh-cn/game/channel.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default { - id: 'ID', - code: '渠道标识', - name: '渠道名', - user_count: '用户数', - profit_amount: '利润', - status: '状态', - 'status 0': '禁用', - 'status 1': '启用', - remark: '备注', - admin_group_id: '管理角色组', - admingroup__name: '组名', - admin_id: '管理员', - admin__username: '用户名', - create_time: '创建时间', - update_time: '修改时间', - 'quick Search Fields': 'ID、渠道标识、渠道名', -} diff --git a/web/src/views/backend/channel/index.vue b/web/src/views/backend/channel/index.vue new file mode 100644 index 0000000..6754409 --- /dev/null +++ b/web/src/views/backend/channel/index.vue @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + diff --git a/web/src/views/backend/channel/popupForm.vue b/web/src/views/backend/channel/popupForm.vue new file mode 100644 index 0000000..620a41a --- /dev/null +++ b/web/src/views/backend/channel/popupForm.vue @@ -0,0 +1,229 @@ + + + + + {{ baTable.form.operate ? t(baTable.form.operate) : '' }} + + + + + + + + + + + + {{ item }} + + + + + + + + + + + + + + + + + {{ t('Cancel') }} + + {{ baTable.form.operateIds && baTable.form.operateIds.length > 1 ? t('Save and edit next item') : t('Save') }} + + + + + + + + + diff --git a/web/src/views/backend/game/channel/index.vue b/web/src/views/backend/game/channel/index.vue deleted file mode 100644 index eeee7c7..0000000 --- a/web/src/views/backend/game/channel/index.vue +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/web/src/views/backend/game/channel/popupForm.vue b/web/src/views/backend/game/channel/popupForm.vue deleted file mode 100644 index bfa5ceb..0000000 --- a/web/src/views/backend/game/channel/popupForm.vue +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - {{ baTable.form.operate ? t(baTable.form.operate) : '' }} - - - - - - - - - - - - - - - - {{ t('Cancel') }} - - {{ baTable.form.operateIds && baTable.form.operateIds.length > 1 ? t('Save and edit next item') : t('Save') }} - - - - - - - - -