From d4732d79ee897da7b833e47966e57249f8d41729 Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 20 Apr 2026 10:48:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BE=A4=E7=BA=A7=E9=85=8D=E7=BD=AE):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BB=93=E6=9E=84=E5=8C=96=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E9=99=8D=E4=BD=8EJSON=E7=BB=B4=E6=8A=A4?= =?UTF-8?q?=E9=97=A8=E6=A7=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为群成员变更监控/welcome 配置新增标准表单编辑模式,覆盖欢迎文本与卡片关键字段 - 保留高级JSON模式,支持标准表单与JSON双模式切换 - 新增变量提示与实时预览,便于运营同学所见即所得配置文案 - 增加URL与必填项校验,保存前拦截常见配置错误 - 标准表单字段变更实时同步JSON文本,确保两种模式数据一致 --- .../templates/group_plugin_config.html | 180 +++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) diff --git a/admin/dashboard/templates/group_plugin_config.html b/admin/dashboard/templates/group_plugin_config.html index 6a23464..e0fe0af 100644 --- a/admin/dashboard/templates/group_plugin_config.html +++ b/admin/dashboard/templates/group_plugin_config.html @@ -77,7 +77,49 @@ - + + + 标准表单 + 高级JSON + + + + + + @@ -103,6 +145,17 @@ new Vue({ filters: { group_id: '', plugin_name: '' }, dialogVisible: false, editing: false, + editorMode: 'simple', + // 标准表单模型:用于“群成员变更监控 + welcome”的结构化配置编辑。 + simpleWelcome: { + welcome_text_enabled: true, + welcome_text_template: '👏欢迎 {nickname} 加入群聊!🎉', + welcome_card_enabled: true, + card_title_template: '👏欢迎 {nickname} 加入群聊!🎉', + card_desc_template: '⌚时间:{now}', + card_url: 'https://newsnow.busiyi.world/', + card_thumb_url: '{head_url}' + }, form: { group_id: '', plugin_name: '', @@ -117,7 +170,115 @@ new Vue({ this.loadPlugins() this.loadRows() }, + computed: { + // 仅当命中当前已接入模板时启用标准表单,其它插件继续使用JSON高级模式。 + isWelcomeTemplateForm() { + return this.form.plugin_name === '群成员变更监控' && this.form.config_key === 'welcome' + }, + previewVariables() { + return { + nickname: '张三', + wxid: 'wxid_demo_123', + group_id: this.form.group_id || '123456@chatroom', + now: '2026-04-20 12:00:00', + head_url: 'https://example.com/avatar.png' + } + }, + previewWelcomeText() { + return this.renderTemplate(this.simpleWelcome.welcome_text_template) + }, + previewCardTitle() { + return this.renderTemplate(this.simpleWelcome.card_title_template) + }, + previewCardDesc() { + return this.renderTemplate(this.simpleWelcome.card_desc_template) + }, + previewCardUrl() { + return this.renderTemplate(this.simpleWelcome.card_url) + } + }, + watch: { + // 当插件/配置键切换到结构化模板时,自动从JSON回填表单,减少手工搬运。 + 'form.plugin_name'() { + this.onTemplateTypeChanged() + }, + 'form.config_key'() { + this.onTemplateTypeChanged() + }, + // 在标准表单模式下,任何字段变化都实时同步到JSON文本,保证两种模式数据一致。 + simpleWelcome: { + handler() { + if (this.isWelcomeTemplateForm && this.editorMode === 'simple') { + this.form.config_json_text = JSON.stringify(this.simpleWelcome, null, 2) + } + }, + deep: true + } + }, methods: { + renderTemplate(template) { + let result = String(template || '') + Object.entries(this.previewVariables).forEach(([k, v]) => { + result = result.replace(new RegExp(`\\{${k}\\}`, 'g'), String(v || '')) + }) + return result + }, + applyWelcomeDefaults() { + this.simpleWelcome = { + welcome_text_enabled: true, + welcome_text_template: '👏欢迎 {nickname} 加入群聊!🎉', + welcome_card_enabled: true, + card_title_template: '👏欢迎 {nickname} 加入群聊!🎉', + card_desc_template: '⌚时间:{now}', + card_url: 'https://newsnow.busiyi.world/', + card_thumb_url: '{head_url}' + } + this.form.config_json_text = JSON.stringify(this.simpleWelcome, null, 2) + }, + onTemplateTypeChanged() { + if (!this.isWelcomeTemplateForm) { + this.editorMode = 'advanced' + return + } + this.editorMode = 'simple' + let parsed = {} + try { + parsed = JSON.parse(this.form.config_json_text || '{}') + } catch (e) { + parsed = {} + } + this.simpleWelcome = { + welcome_text_enabled: parsed.welcome_text_enabled !== undefined ? !!parsed.welcome_text_enabled : true, + welcome_text_template: String(parsed.welcome_text_template || '👏欢迎 {nickname} 加入群聊!🎉'), + welcome_card_enabled: parsed.welcome_card_enabled !== undefined ? !!parsed.welcome_card_enabled : true, + card_title_template: String(parsed.card_title_template || '👏欢迎 {nickname} 加入群聊!🎉'), + card_desc_template: String(parsed.card_desc_template || '⌚时间:{now}'), + card_url: String(parsed.card_url || 'https://newsnow.busiyi.world/'), + card_thumb_url: String(parsed.card_thumb_url || '{head_url}') + } + this.form.config_json_text = JSON.stringify(this.simpleWelcome, null, 2) + }, + validateSimpleWelcome() { + // 结构化模式下做强校验,避免无效URL或空模板入库。 + if (!this.simpleWelcome.welcome_text_template.trim()) { + this.$message.error('文本模板不能为空') + return false + } + if (!this.simpleWelcome.card_title_template.trim()) { + this.$message.error('卡片标题不能为空') + return false + } + if (!this.simpleWelcome.card_url.trim()) { + this.$message.error('卡片URL不能为空') + return false + } + const renderedUrl = this.renderTemplate(this.simpleWelcome.card_url) + if (!/^https?:\/\//i.test(renderedUrl)) { + this.$message.error('卡片URL必须是 http 或 https 开头') + return false + } + return true + }, async loadGroups() { const resp = await axios.get('/contacts/api/groups') const groups = (resp.data && resp.data.data && resp.data.data.groups) || {} @@ -149,6 +310,7 @@ new Vue({ enabled: true, config_json_text: '{}' } + this.applyWelcomeDefaults() this.dialogVisible = true }, openEdit(row) { @@ -160,12 +322,22 @@ new Vue({ enabled: !!row.enabled, config_json_text: JSON.stringify(row.config_json || {}, null, 2) } + this.onTemplateTypeChanged() this.dialogVisible = true }, async saveForm() { let parsed = {} + if (this.isWelcomeTemplateForm && this.editorMode === 'simple') { + if (!this.validateSimpleWelcome()) { + return + } + parsed = { ...this.simpleWelcome } + this.form.config_json_text = JSON.stringify(parsed, null, 2) + } try { - parsed = JSON.parse(this.form.config_json_text || '{}') + parsed = this.isWelcomeTemplateForm && this.editorMode === 'simple' + ? parsed + : JSON.parse(this.form.config_json_text || '{}') } catch (e) { this.$message.error('JSON 配置格式错误') return @@ -219,5 +391,9 @@ new Vue({ .page-hero-copy h1{font-size:30px;line-height:1.1;margin-bottom:10px;color:#0f172a} .page-hero-copy p{color:#64748b;font-size:14px} .detail-pre{white-space:pre-wrap;word-break:break-word;background:rgba(248,250,252,.85);border:1px solid rgba(148,163,184,.12);border-radius:14px;padding:10px;color:#334155;max-height:180px;overflow:auto} +.form-tip{padding:10px 12px;border-radius:10px;background:#f8fbff;border:1px solid #d9e8f8;color:#4a6179;margin:0 0 12px 0} +.form-tip code{display:inline-block;margin-right:6px;background:#eef6ff;border:1px solid #d2e6ff;color:#12539a;padding:1px 6px;border-radius:6px;font-size:12px} +.preview-box{padding:12px;border:1px dashed #c7d8ea;background:#f8fbff;border-radius:10px;color:#3f5c77;line-height:1.7} +.preview-box p{margin:0 0 4px 0} {% endblock %}