model = new \app\admin\model\SystemTimerConfig(); $this->assign('select_list_run_type', $this->model::SELECT_LIST_RUN_TYPE, true); $this->assign('select_list_status', $this->model::SELECT_LIST_STATUS, true); $this->assign('select_list_is_synced', $this->model::SELECT_LIST_IS_SYNCED, true); $this->assign('select_list_manual_trigger', $this->model::SELECT_LIST_MANUAL_TRIGGER, true); // 允许通过行内修改的字段 $this->allowModifyFields = [ 'status', 'run_type', 'concurrency', ]; } /** * @NodeAnotation(title="添加") */ public function add() { $this->error('定时任务配置由系统同步生成,不支持手动添加'); } /** * @NodeAnotation(title="删除") */ public function delete($id) { $this->error('定时任务配置由系统管理,不支持删除'); } /** * @NodeAnotation(title="编辑") */ public function edit($id) { $row = $this->model->find($id); empty($row) && $this->error('数据不存在'); if ($this->request->isPost()) { $post = $this->request->post(); // 只允许修改 run_type、status、concurrency $post = array_intersect_key($post, array_flip(['run_type', 'status', 'concurrency'])); if (array_key_exists('concurrency', $post)) { // 空/null=继承代码默认写 NULL;正整数=覆盖;0或负数=拒绝(M5 防静默吞任务) $post['concurrency'] = $this->normalizeConcurrency($post['concurrency']); } try { $save = $row->save($post); } catch (\Exception $e) { $this->error('保存失败:' . $e->getMessage()); } if ($save) { // D18:DB commit 后递增脏标记,触发 timer reload(edit 改 concurrency/run_type/status,与 trigger 一致) Cache::inc('timer_config_version'); $this->success('保存成功'); } $this->error('保存失败'); } $this->assign('row', $row); return $this->fetch(); } /** * @NodeAnotation(title="手动触发") */ public function trigger($id) { $this->checkPostRequest(); $row = $this->model->find($id); if (!$row) { $this->error('数据不存在'); } $trigger_node_id = $this->request->post('trigger_node_id'); if (empty($trigger_node_id)) { $this->error('请选择节点'); } try { // 手动触发跨 run_type、穿透 status(D19:调试工作流,关闭+手动触发+打开) $row->save([ 'manual_trigger' => 1, 'trigger_node_id' => $trigger_node_id, 'last_trigger_time' => time(), ]); // D18:DB commit 成功后才递增 version,防脏读(commit 前递增→节点 reload 读旧值→永不 reload) Cache::inc('timer_config_version'); } catch (\Exception $e) { $this->error('触发失败:' . $e->getMessage()); } $this->success('触发成功,等待定时器执行'); } /** * @NodeAnotation(title="节点列表") */ public function hostList() { $list = \app\admin\model\SystemHost::where('status', 1) ->field('node_id,is_master,ip_address,last_heartbeat_at') ->order('is_master desc, node_id asc') ->select(); $this->success('', $list); } /** * @NodeAnotation(title="属性修改") */ public function modify() { $this->checkPostRequest(); $post = $this->request->post(); $rule = [ 'id|ID' => 'require', 'field|字段' => 'require', 'value|值' => 'require', ]; $this->validate($post, $rule); if (!in_array($post['field'], $this->allowModifyFields)) { $this->error('该字段不允许修改:' . $post['field']); } // concurrency 行内修改必须为正整数(M5 防静默吞任务;继承默认请走 edit 表单传空值) if ($post['field'] === 'concurrency' && (!is_numeric($post['value']) || (int) $post['value'] < 1)) { $this->error('concurrency 必须是正整数'); } $row = $this->model->find($post['id']); empty($row) && $this->error('数据不存在'); $value = $post['field'] === 'concurrency' ? (int) $post['value'] : $post['value']; try { $save = $row->save([$post['field'] => $value]); } catch (\Exception $e) { $this->error($e->getMessage()); } if ($save) { // D18:DB commit 后递增脏标记,触发 timer reload(行内改 concurrency/status/run_type,同 edit) Cache::inc('timer_config_version'); } $this->success('保存成功'); } /** * 归一化 concurrency 入库值. * 空字符串/null → null(继承代码默认);正整数 → int;0或负数/非数字 → 拒绝. * * @param mixed $value 提交值 * @return int|null */ private function normalizeConcurrency($value) { if ($value === '' || $value === null) { return null; } if (!is_numeric($value) || (int) $value < 1) { $this->error('concurrency 必须是正整数或空(继承默认)'); } return (int) $value; } }