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 %}