model = new ScoreModel(); // 触发 score_rule / score_log 自愈 ScoreModel::ensureSchema(); } // ============ 积分规则 ============ public function index() { $page = $this->request->param('page/d', 1); $limit = $this->request->param('limit/d', 15); $title = $this->request->param('title', ''); $action = $this->request->param('action', ''); if ($this->request->isAjax()) { $query = $this->model->newQuery(); if ($title !== '') { $query->where('title', 'like', '%' . $title . '%'); } if ($action !== '') { $query->where('action', $action); } $list = $query->order('sort', 'desc') ->paginate(['page' => $page, 'list_rows' => $limit]); $typeList = ScoreModel::typeList(); $limitTypeList = ScoreService::limitTypeList(); $items = $list->items(); foreach ($items as &$item) { $item['type_text'] = $typeList[$item['type']] ?? '-'; $item['limit_text'] = self::limitText($item, $limitTypeList); $item['addon_text'] = empty($item['addon']) ? '核心' : $item['addon']; } $this->result->setCount($list->total())->success($items); } $this->assign('typeList', ScoreModel::typeList()); $this->assign('limitTypeList', ScoreService::limitTypeList()); $this->assign('uniqueTypeList', ScoreService::uniqueTypeList()); $this->assign('actionList', ScoreService::actions()); return $this->fetch(); } /** * 可用动作下拉数据(核心预置 + 插件注册 + 规则表已使用) */ public function actions() { $list = ScoreService::actions(); $data = []; foreach ($list as $key => $item) { $data[] = [ 'action' => $key, 'title' => $item['title'], 'addon' => $item['addon'], ]; } $this->result->success($data); } /** * 限次文案:不限 / 每日 N 次 ... */ protected static function limitText(array $item, array $limitTypeList): string { $type = (int) ($item['limit_type'] ?? 0); $times = (int) ($item['limit_times'] ?? 0); if ($type === 0 || $times <= 0) { return '不限'; } return ($limitTypeList[$type] ?? '-') . ' ' . $times . ' 次'; } public function save() { if (! $this->request->isPost()) { $this->result->error('请求方式错误', 405); } $params = $this->request->only( ['title', 'action', 'type', 'value', 'addon', 'limit_type', 'limit_times', 'unique_type', 'remark', 'sort', 'status'], 'post' ); try { validate(ScoreValidate::class)->check($params); $this->model->create($params); $this->result->success('', '添加成功'); } catch (ValidateException $e) { $this->result->error($e->getMessage()); } catch (DbException $e) { $this->result->error('添加失败: ' . $e->getMessage(), 2); } } public function edit($id = null) { $id = $id ?: $this->request->param('id'); $info = $this->model->find($id); if (! $info) { $this->result->error('记录不存在', 404); } $this->result->success(['info' => $info]); } public function update() { if (! ($this->request->isAjax() && $this->request->isPut())) { $this->result->error('请求方式错误', 405); } $params = $this->request->only( ['id', 'title', 'action', 'type', 'value', 'addon', 'limit_type', 'limit_times', 'unique_type', 'remark', 'sort', 'status'], 'param' ); $id = $params['id'] ?? null; $info = $this->model->find($id); if (! $info) { $this->result->error('记录不存在', 404); } $statusOnly = isset($params['status']) && count(array_diff(array_keys($params), ['id', 'status'])) === 0; if (! $statusOnly) { try { validate(ScoreValidate::class)->check($params); } catch (ValidateException $e) { $this->result->error($e->getMessage()); } } $info->save($params); $this->result->success($info, '更新成功'); } public function recyclebin() { $page = $this->request->param('page/d', 1); $limit = $this->request->param('limit/d', 15); if ($this->request->isAjax()) { $list = $this->model->onlyTrashed() ->order('sort', 'desc') ->paginate(['page' => $page, 'list_rows' => $limit]); $this->result->setCount($list->total())->success($list->items()); } return $this->fetch('score/index'); } public function delete() { if ($this->request->isAjax() && $this->request->isDelete()) { $ids = $this->request->param('ids', ''); $force = $this->request->param('force', false); if (empty($ids)) { $this->result->error('请选择要删除的数据'); } $idsArray = array_filter(explode(',', $ids), 'is_numeric'); if (empty($idsArray)) { $this->result->error('参数错误'); } try { Db::transaction(function () use ($idsArray, $force) { if ($force) { $this->model->onlyTrashed()->whereIn('id', $idsArray)->select() ->each(function ($item) { $item->force()->delete(); }); } else { $this->model->destroy($idsArray); } }); $this->result->success(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { $this->result->error('删除失败: ' . ($e->getMessage() ?: $e->__toString()), 500); } } } public function restore($ids = '') { if ($this->request->isAjax() && $this->request->isPost()) { $ids = $this->request->param('ids', ''); if (empty($ids)) { $this->result->error('请选择要恢复的数据'); } $idsArray = array_filter(explode(',', $ids), 'is_numeric'); Db::startTrans(); try { $this->model->withTrashed()->where('id', 'in', $idsArray)->select() ->each(function ($item) { $item->restore(); }); Db::commit(); $this->result->success('恢复成功'); } catch (DbException $e) { Db::rollback(); $this->result->error('恢复失败: ' . $e->getMessage()); } } } // ============ 积分流水 ============ public function log() { $page = $this->request->param('page/d', 1); $limit = $this->request->param('limit/d', 15); $uid = $this->request->param('uid/d', 0); $action = $this->request->param('action', ''); $source = $this->request->param('source', ''); if ($this->request->isAjax()) { $res = ScoreModel::logList($uid, $page, $limit, ['action' => $action, 'source' => $source]); $typeList = ScoreModel::typeList(); foreach ($res['list'] as &$item) { $item['type_text'] = $item['type'] == 2 ? '支出' : '收入'; } $this->result->setCount($res['count'])->success($res['list']); } return $this->fetch('score/log'); } }