diff --git a/admin/dashboard/templates/contacts_management.html b/admin/dashboard/templates/contacts_management.html
index 64058b7..8adbd2c 100644
--- a/admin/dashboard/templates/contacts_management.html
+++ b/admin/dashboard/templates/contacts_management.html
@@ -430,6 +430,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {nickname}{wxid}{group_id}{now}{head_url}
+
+
+
+
+
文本:{% raw %}{{ previewGroupWelcomeText }}{% endraw %}
+
标题:{% raw %}{{ previewGroupWelcomeTitle }}{% endraw %}
+
描述:{% raw %}{{ previewGroupWelcomeDesc }}{% endraw %}
+
URL:{% raw %}{{ previewGroupWelcomeUrl }}{% endraw %}
+
+
+
+ 保存欢迎配置
+ 恢复默认
+
+
+
@@ -786,6 +833,16 @@
managedGroupMap: {},
groupPermissions: [],
groupPermissionsLoading: false,
+ groupWelcomeConfigLoading: false,
+ groupWelcomeConfig: {
+ 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}'
+ },
// 当前群基础资料:用于展示群主、群公告、管理员、成员数等信息。
currentGroupProfile: { owner_wxid: '', owner_name: '', announcement: '', member_count: 0, admin_count: 0, admins: [] },
// 群公告手动同步按钮的加载态,避免重复点击触发多次请求。
@@ -849,6 +906,18 @@
const keyword = (this.emojiKeyword || '').trim().toLowerCase();
if (!keyword) return this.emojiLibrary;
return this.emojiLibrary.filter(item => (item.md5 || '').toLowerCase().includes(keyword));
+ },
+ previewGroupWelcomeText() {
+ return this.renderWelcomeTemplate(this.groupWelcomeConfig.welcome_text_template);
+ },
+ previewGroupWelcomeTitle() {
+ return this.renderWelcomeTemplate(this.groupWelcomeConfig.card_title_template);
+ },
+ previewGroupWelcomeDesc() {
+ return this.renderWelcomeTemplate(this.groupWelcomeConfig.card_desc_template);
+ },
+ previewGroupWelcomeUrl() {
+ return this.renderWelcomeTemplate(this.groupWelcomeConfig.card_url);
}
},
mounted() {
@@ -910,10 +979,100 @@
this.loadGroupMembers(group.wxid);
this.loadGroupPermissions(group.wxid);
this.loadGroupInsights(group.wxid);
+ this.loadGroupWelcomeConfig(group.wxid);
},
viewUserDetails(user) { this.currentUser = user; this.userDetailDialogVisible = true; },
viewOfficialDetails(official) { this.currentOfficial = official; this.officialDetailDialogVisible = true; },
viewPublicDetails(publicFriend) { this.currentPublic = publicFriend; this.publicDetailDialogVisible = true; },
+ getDefaultWelcomeConfig() {
+ return {
+ 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}'
+ };
+ },
+ normalizeWelcomeConfig(raw) {
+ const base = this.getDefaultWelcomeConfig();
+ const cfg = raw && typeof raw === 'object' ? raw : {};
+ return {
+ welcome_text_enabled: cfg.welcome_text_enabled !== undefined ? !!cfg.welcome_text_enabled : base.welcome_text_enabled,
+ welcome_text_template: String(cfg.welcome_text_template || base.welcome_text_template),
+ welcome_card_enabled: cfg.welcome_card_enabled !== undefined ? !!cfg.welcome_card_enabled : base.welcome_card_enabled,
+ card_title_template: String(cfg.card_title_template || base.card_title_template),
+ card_desc_template: String(cfg.card_desc_template || base.card_desc_template),
+ card_url: String(cfg.card_url || base.card_url),
+ card_thumb_url: String(cfg.card_thumb_url || base.card_thumb_url)
+ };
+ },
+ renderWelcomeTemplate(template) {
+ const vars = {
+ nickname: '张三',
+ wxid: 'wxid_demo_123',
+ group_id: (this.currentGroup && this.currentGroup.wxid) || '123456@chatroom',
+ now: '2026-04-20 12:00:00',
+ head_url: 'https://example.com/avatar.png'
+ };
+ let text = String(template || '');
+ Object.entries(vars).forEach(([k, v]) => {
+ text = text.replace(new RegExp(`\\{${k}\\}`, 'g'), String(v));
+ });
+ return text;
+ },
+ loadGroupWelcomeConfig(groupId) {
+ if (!groupId) return;
+ this.groupWelcomeConfigLoading = true;
+ this.groupWelcomeConfig = this.getDefaultWelcomeConfig();
+ axios.get('/group_plugin_config/api/list', {
+ params: { group_id: groupId, plugin_name: '群成员变更监控' }
+ }).then(response => {
+ if (!response.data || !response.data.success) {
+ this.$message.warning('加载欢迎配置失败,已使用默认值');
+ return;
+ }
+ const rows = response.data.data || [];
+ const row = rows.find(item => String(item.config_key || '') === 'welcome');
+ if (row && row.config_json) {
+ this.groupWelcomeConfig = this.normalizeWelcomeConfig(row.config_json);
+ }
+ }).catch(error => {
+ console.error('加载群欢迎配置失败:', error);
+ this.$message.warning('加载欢迎配置失败,已使用默认值');
+ }).finally(() => { this.groupWelcomeConfigLoading = false; });
+ },
+ resetGroupWelcomeConfig() {
+ this.groupWelcomeConfig = this.getDefaultWelcomeConfig();
+ this.$message.success('已恢复默认欢迎配置');
+ },
+ saveGroupWelcomeConfig() {
+ if (!this.currentGroup || !this.currentGroup.wxid) return;
+ const renderedUrl = this.renderWelcomeTemplate(this.groupWelcomeConfig.card_url);
+ if (!/^https?:\/\//i.test(renderedUrl)) {
+ this.$message.error('卡片URL必须是 http 或 https 开头');
+ return;
+ }
+ this.groupWelcomeConfigLoading = true;
+ axios.post('/group_plugin_config/api/upsert', {
+ group_id: this.currentGroup.wxid,
+ plugin_name: '群成员变更监控',
+ config_key: 'welcome',
+ enabled: true,
+ config_json: this.groupWelcomeConfig,
+ updated_by: 'dashboard'
+ }).then(response => {
+ if (response.data && response.data.success) {
+ this.$message.success('群欢迎配置保存成功');
+ } else {
+ this.$message.error((response.data && response.data.message) || '群欢迎配置保存失败');
+ }
+ }).catch(error => {
+ console.error('保存群欢迎配置失败:', error);
+ this.$message.error('保存群欢迎配置失败');
+ }).finally(() => { this.groupWelcomeConfigLoading = false; });
+ },
loadGroupPermissions(groupId) {
this.groupPermissionsLoading = true;
this.groupPermissions = [];
@@ -1537,6 +1696,7 @@
.pagination-container { margin-top: 20px; text-align: right; }
.group-insight-section { margin-top: 20px; }
.group-permission-section { margin-top: 20px; }
+ .welcome-config-card { margin-top: 14px; }
.group-members-section { margin-top: 20px; }
.section-title {
margin: 20px 0 15px 0; border-bottom: 1px solid rgba(148,163,184,0.12); padding-bottom: 10px;
@@ -1677,6 +1837,16 @@
border: 1px solid rgba(148,163,184,0.16); border-radius: 12px; padding: 8px;
display: flex; flex-direction: column; gap: 8px; align-items: center; background: #fff;
}
+ .form-tip{
+ padding:10px 12px;border-radius:10px;background:#f8fbff;border:1px solid #d9e8f8;color:#4a6179
+ }
+ .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}
.emoji-thumb { width: 72px; height: 72px; object-fit: contain; border-radius: 8px; background: rgba(148,163,184,0.08); }
.emoji-md5 { font-size: 11px; color: #64748b; word-break: break-all; text-align: center; min-height: 30px; }
.emoji-actions { width: 100%; display: flex; justify-content: center; }