model = new \app\admin\model\CommissionRule; $catRows = Db::name('service_cat') ->field('id,name,status') ->order('weigh desc, id asc') ->select(); $catMap = [0 => '不限服务分类']; foreach ($catRows as $c) { $catMap[(int)$c['id']] = (string)$c['name'] . ($c['status'] === 'hidden' ? '(已隐藏)' : ''); } $this->view->assign([ 'orderModeList' => $this->model->getOrderModeList(), 'customerTypeList' => $this->model->getCustomerTypeList(), 'urgentModeList' => $this->model->getUrgentModeList(), 'calcModeList' => $this->model->getCalcModeList(), 'statusList' => $this->model->getStatusList(), 'catMap' => $catMap, ]); } /** * 配置中心首页(GET 渲染独立双页签配置界面;Ajax 返回按订单维度抽佣规则列表) */ public function index() { $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { $allCfg = FinanceConfigService::getAll(true); $withdrawCfg = FinanceConfigService::getWithdrawConfig(); $commDefaults = FinanceConfigService::getCommissionDefaults(); $this->view->assign([ 'cfg' => $allCfg, 'withdrawCfg' => $withdrawCfg, 'commDefaults' => $commDefaults, ]); return $this->view->fetch(); } [$where, $sort, $order, $offset, $limit] = $this->buildparams(); $orderExpr = $sort === 'weigh' ? "weigh {$order}, id desc" : "{$sort} {$order}"; $list = $this->model ->where($where) ->order($orderExpr) ->paginate($limit); $rows = $list->items(); if (!empty($rows)) { $cats = Db::name('service_cat')->column('name', 'id'); foreach ($rows as &$r) { $cid = (int)$r['cat_id']; $r['cat_name'] = $cid > 0 ? ($cats[$cid] ?? ('分类#' . $cid)) : ''; } unset($r); } return json([ 'total' => $list->total(), 'rows' => $rows, ]); } /** * 保存订单默认兜底抽佣设置 / 提现与微信转账规则配置 */ public function save() { if (false === $this->request->isPost()) { $this->error(__('Invalid parameters')); } $this->token(); $section = (string)$this->request->post('section', ''); $row = $this->request->post('row/a', []); if (!is_array($row) || empty($row)) { $this->error('提交的配置数据不能为空'); } // 处理多选框全部取消勾选时前端未上送对应键的情况 if ($section === 'withdraw') { if (!array_key_exists('withdraw_channels', $row)) { $this->error('请至少勾选一种开放提现渠道', null, ['token' => $this->request->token()]); } if (!array_key_exists('withdraw_allow_weekdays', $row)) { $this->error('请至少选择一天允许提现的周期', null, ['token' => $this->request->token()]); } } try { FinanceConfigService::saveConfigs($row); CommissionService::clearCache(); } catch (\InvalidArgumentException $e) { $this->error($e->getMessage(), null, ['token' => $this->request->token()]); } catch (\Throwable $e) { $this->error('保存配置失败:' . $e->getMessage(), null, ['token' => $this->request->token()]); } $msg = $section === 'commission_default' ? '抽佣默认设置已保存(仅影响新订单,已下单工单不受影响)' : '提现规则已保存生效'; $this->success($msg, null, ['token' => $this->request->token()]); } /** * 新增按订单维度抽佣规则 */ public function rule_add() { if (false === $this->request->isPost()) { $this->view->assign('row', [ 'name' => '', 'order_mode' => 'all', 'customer_type' => 'all', 'cat_id' => 0, 'urgent_mode' => 'all', 'min_amount' => '0.00', 'max_amount' => '0.00', 'calc_mode' => 'percent', 'commission_rate' => '10.00', 'fixed_fee' => '0.00', 'min_commission' => '0.00', 'max_commission' => '0.00', 'weigh' => 100, 'status' => 'normal', 'remark' => '', ]); return $this->view->fetch(); } $this->token(); $raw = $this->request->post('row/a', []); try { $clean = $this->validateAndCleanRuleInput($raw); $this->model->allowField(true)->save($clean); CommissionService::clearCache(); } catch (\InvalidArgumentException $e) { $this->error($e->getMessage()); } catch (PDOException|\Exception $e) { $this->error('新增规则失败:' . $e->getMessage()); } $this->success('抽佣规则已创建(仅对后续新订单生效)'); } /** * 编辑按订单维度抽佣规则 */ public function rule_edit($ids = null) { $row = $this->model->get($ids); if (!$row) { $this->error(__('No Results were found')); } if (false === $this->request->isPost()) { $this->view->assign('row', $row); return $this->view->fetch(); } $this->token(); $raw = $this->request->post('row/a', []); try { $clean = $this->validateAndCleanRuleInput($raw); $row->allowField(true)->save($clean); CommissionService::clearCache(); } catch (\InvalidArgumentException $e) { $this->error($e->getMessage()); } catch (PDOException|\Exception $e) { $this->error('更新规则失败:' . $e->getMessage()); } $this->success('抽佣规则已更新(历史已创订单不受影响)'); } /** * 删除抽佣规则 */ public function rule_del($ids = null) { if (false === $this->request->isPost()) { $this->error(__('Invalid parameters')); } $ids = $ids ?: $this->request->post('ids'); $idArr = array_values(array_filter(array_map('intval', explode(',', (string)$ids)))); if (empty($idArr)) { $this->error(__('Parameter %s can not be empty', 'ids')); } $count = 0; Db::startTrans(); try { $list = $this->model->where('id', 'in', $idArr)->select(); foreach ($list as $item) { $count += $item->delete(); } Db::commit(); CommissionService::clearCache(); } catch (PDOException|\Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success(); } $this->error(__('No rows were deleted')); } /** * 批量启用/停用抽佣规则 */ public function rule_multi($ids = null) { if (false === $this->request->isPost()) { $this->error(__('Invalid parameters')); } $ids = $ids ?: $this->request->post('ids'); $params = (string)$this->request->post('params', ''); parse_str($params, $values); if (empty($ids) || empty($values)) { $this->error(__('Parameter %s can not be empty', 'ids')); } $allowed = []; if (isset($values['status']) && in_array($values['status'], ['normal', 'hidden'], true)) { $allowed['status'] = $values['status']; } if (isset($values['weigh']) && is_numeric($values['weigh'])) { $allowed['weigh'] = (int)$values['weigh']; } if (empty($allowed)) { $this->error('仅允许批量修改启用状态或优先级权重'); } $idArr = array_values(array_filter(array_map('intval', explode(',', (string)$ids)))); $allowed['updatetime'] = time(); Db::name('commission_rule')->where('id', 'in', $idArr)->update($allowed); CommissionService::clearCache(); $this->success(); } /** * 抽佣规则入参强白名单与业务区间合法性校验 * * @param array $raw * @return array * @throws \InvalidArgumentException */ protected function validateAndCleanRuleInput(array $raw): array { $name = trim((string)($raw['name'] ?? '')); if ($name === '' || mb_strlen($name) > 80) { throw new \InvalidArgumentException('请填写规则名称(1 ~ 80 个字符)'); } $orderMode = (string)($raw['order_mode'] ?? 'all'); if (!array_key_exists($orderMode, $this->model->getOrderModeList())) { throw new \InvalidArgumentException('请选择有效的适用订单计价模式'); } $customerType = (string)($raw['customer_type'] ?? 'all'); if (!array_key_exists($customerType, $this->model->getCustomerTypeList())) { throw new \InvalidArgumentException('请选择有效的适用发单客群'); } $catId = max(0, (int)($raw['cat_id'] ?? 0)); if ($catId > 0 && !Db::name('service_cat')->where('id', $catId)->find()) { throw new \InvalidArgumentException('所选服务类目不存在'); } $urgentMode = (string)($raw['urgent_mode'] ?? 'all'); if (!array_key_exists($urgentMode, $this->model->getUrgentModeList())) { throw new \InvalidArgumentException('请选择有效的加急属性条件'); } $minAmount = round((float)($raw['min_amount'] ?? 0), 2); $maxAmount = round((float)($raw['max_amount'] ?? 0), 2); if ($minAmount < 0 || $maxAmount < 0) { throw new \InvalidArgumentException('订单金额区间不能为负数'); } if ($maxAmount > 0 && $minAmount > $maxAmount) { throw new \InvalidArgumentException('订单起始金额不能大于订单上限金额(0 表示不限上限)'); } $calcMode = (string)($raw['calc_mode'] ?? 'percent'); if (!array_key_exists($calcMode, $this->model->getCalcModeList())) { throw new \InvalidArgumentException('请选择有效的计佣方式'); } $rate = 0.00; if (in_array($calcMode, ['percent', 'mixed'], true)) { $rate = CommissionService::validateRateInput($raw['commission_rate'] ?? ''); } $fixedFee = 0.00; if (in_array($calcMode, ['fixed', 'mixed'], true)) { if (!isset($raw['fixed_fee']) || !is_numeric($raw['fixed_fee']) || (float)$raw['fixed_fee'] < 0) { throw new \InvalidArgumentException('请填写有效的每单固定抽佣金额(≥ 0 元)'); } $fixedFee = round((float)$raw['fixed_fee'], 2); } $minComm = round(max(0.00, (float)($raw['min_commission'] ?? 0)), 2); $maxComm = round(max(0.00, (float)($raw['max_commission'] ?? 0)), 2); if ($minComm > 0 && $maxComm > 0 && $minComm > $maxComm) { throw new \InvalidArgumentException('单笔保底抽佣金额不能大于单笔封顶抽佣金额'); } $weigh = isset($raw['weigh']) && is_numeric($raw['weigh']) ? (int)$raw['weigh'] : 100; $status = in_array($raw['status'] ?? 'normal', ['normal', 'hidden'], true) ? $raw['status'] : 'normal'; $remark = mb_substr(trim((string)($raw['remark'] ?? '')), 0, 255); return [ 'name' => $name, 'order_mode' => $orderMode, 'customer_type' => $customerType, 'cat_id' => $catId, 'urgent_mode' => $urgentMode, 'min_amount' => number_format($minAmount, 2, '.', ''), 'max_amount' => number_format($maxAmount, 2, '.', ''), 'calc_mode' => $calcMode, 'commission_rate' => number_format($rate, 2, '.', ''), 'fixed_fee' => number_format($fixedFee, 2, '.', ''), 'min_commission' => number_format($minComm, 2, '.', ''), 'max_commission' => number_format($maxComm, 2, '.', ''), 'weigh' => $weigh, 'status' => $status, 'remark' => $remark, ]; } }