request->post(); $rule = new Validate([ 'journal_id' => 'require|number', 'scene' => 'require', 'language' => 'require', 'title' => 'require', 'subject' => 'require', ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $payload = [ 'journal_id' => intval($data['journal_id']), 'scene' => trim($data['scene']), 'language' => trim($data['language']), 'title' => trim($data['title']), 'subject' => trim($data['subject']), 'body_html' => $data['body_html'] ?? '', 'body_text' => $data['body_text'] ?? '', 'variables_json' => $data['variables_json'] ?? '', 'version' => intval($data['version'] ?? 1), 'is_active' => intval($data['is_active'] ?? 1), 'utime' => time(), ]; $templateId = intval($data['template_id'] ?? 0); if ($templateId) { $exists = Db::name('mail_template')->where('template_id', $templateId)->where('state', 0)->find(); if (!$exists) { return jsonError('Template not found'); } Db::name('mail_template')->where('template_id', $templateId)->update($payload); return jsonSuccess(['template_id' => $templateId]); } $payload['ctime'] = time(); $payload['state'] = 0; $newId = Db::name('mail_template')->insertGetId($payload); return jsonSuccess(['template_id' => $newId]); } /** * Soft delete a template * Params: template_id */ public function deleteTemplate() { $templateId = intval($this->request->param('template_id', 0)); if (!$templateId) { return jsonError('template_id is required'); } Db::name('mail_template')->where('template_id', $templateId)->update(['state' => 1, 'utime' => time()]); return jsonSuccess([]); } /** * Get template detail */ public function getTemplate() { $templateId = intval($this->request->param('template_id', 0)); if (!$templateId) { return jsonError('template_id is required'); } $tpl = Db::name('mail_template')->where('template_id', $templateId)->where('state', 0)->find(); if (!$tpl) { return jsonError('Template not found'); } return jsonSuccess(['template' => $tpl]); } /** * List templates * Params: journal_id, scene(optional), language(optional), is_active(optional) */ public function listTemplates() { $journalId = intval($this->request->param('journal_id', 0)); if (!$journalId) { return jsonError('journal_id is required'); } $scene = trim($this->request->param('scene', '')); $language = trim($this->request->param('language', '')); $isActive = $this->request->param('is_active', ''); $where = ['journal_id' => $journalId, 'state' => 0]; if ($scene !== '') $where['scene'] = $scene; if ($language !== '') $where['language'] = $language; if ($isActive !== '') $where['is_active'] = intval($isActive); $list = Db::name('mail_template') ->where($where) ->order('is_active desc, utime desc, template_id desc') ->select(); return jsonSuccess(['list' => $list]); } public function listTemplatesAll(){ $list = Db::name('mail_template') ->where('state', 0) ->order('is_active desc, utime desc, template_id desc') ->select(); return jsonSuccess(['list'=>$list]); } /** * Create or update a global mail style * 当前 style 表字段: * - style_id, name, description, header_html, footer_html, state, ctime */ public function saveStyle() { $data = $this->request->post(); $rule = new Validate([ 'name' => 'require', ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $payload = [ 'name' => trim($data['name']), 'description' => trim($data['description'] ?? ''), 'header_html' => $data['header_html'] ?? '', 'footer_html' => $data['footer_html'] ?? '', 'state' => 0, ]; $styleId = intval($data['style_id'] ?? 0); if ($styleId) { $exists = Db::name('mail_style')->where('style_id', $styleId)->where('state', 0)->find(); if (!$exists) { return jsonError('Style not found'); } Db::name('mail_style')->where('style_id', $styleId)->update($payload); return jsonSuccess(['style_id' => $styleId]); } $payload['ctime'] = time(); $newId = Db::name('mail_style')->insertGetId($payload); return jsonSuccess(['style_id' => $newId]); } /** * Delete a global mail style (soft delete) */ public function deleteStyle() { $styleId = intval($this->request->param('style_id', 0)); if (!$styleId) { return jsonError('style_id is required'); } Db::name('mail_style')->where('style_id', $styleId)->update(['state' => 1]); return jsonSuccess([]); } /** * Get style detail */ public function getStyle() { $styleId = intval($this->request->param('style_id', 0)); if (!$styleId) { return jsonError('style_id is required'); } $style = Db::name('mail_style')->where('style_id', $styleId)->where('state', 0)->find(); if (!$style) { return jsonError('Style not found'); } return jsonSuccess(['style' => $style]); } /** * List styles * 现在样式不再按 scene / language 区分,只返回全部正常状态的样式 */ public function listStyles() { $where = ['state' => 0]; $list = Db::name('mail_style') ->where($where) ->order('style_id desc') ->select(); return jsonSuccess(['list' => $list]); } /** * Render preview for a template预览效果,没啥用 * Params: template_id, vars (json string) */ public function preview() { $templateId = intval($this->request->param('template_id', 0)); $varsJson = $this->request->param('vars', ''); if (!$templateId) { return jsonError('template_id is required'); } $tpl = Db::name('mail_template')->where('template_id', $templateId)->where('state', 0)->find(); if (!$tpl) { return jsonError('Template not found'); } $vars = []; if ($varsJson) { $decoded = json_decode($varsJson, true); if (is_array($decoded)) $vars = $decoded; } $subject = $this->render($tpl['subject'], $vars); $body = $this->render($tpl['body_html'], $vars); // For preview we do not enforce a style; caller can combine with style if needed return jsonSuccess(['subject' => $subject, 'body' => $body]); } private function render($tpl, $vars) { if (!is_string($tpl) || empty($tpl)) return ''; if (!is_array($vars) || empty($vars)) return $tpl; $replace = []; foreach ($vars as $k => $v) { $key = trim((string)$k); if ($key === '') continue; $replace['{{' . $key . '}}'] = (string)$v; // backward compatible placeholders $replace['{' . $key . '}'] = (string)$v; } return str_replace(array_keys($replace), array_values($replace), $tpl); } }