Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce37a269e1 | ||
|
|
aa78f3940c | ||
|
|
1c55900291 | ||
|
|
386e0dd6d3 | ||
|
|
9bec70319b | ||
|
|
bd33759b80 |
21
config.yaml
21
config.yaml
@@ -1,3 +1,20 @@
|
||||
system:
|
||||
# 添加新好友或群之后通知给指定的人
|
||||
newFriendNotify:
|
||||
enable: true
|
||||
toUser:
|
||||
- "wxid_xxx"
|
||||
# 默认AI等配置
|
||||
defaultRule:
|
||||
# 默认是否开启AI
|
||||
ai: true
|
||||
# 默认是否开启水群排行榜
|
||||
chatRank: true
|
||||
# 默认是否开启聊天记录总结
|
||||
summary: true
|
||||
# 默认是否开启新成员加群欢迎
|
||||
welcome: true
|
||||
|
||||
# 微信HOOK配置
|
||||
wechat:
|
||||
# 微信HOOK接口地址
|
||||
@@ -87,6 +104,10 @@ resource:
|
||||
welcome-new:
|
||||
type: emotion
|
||||
path: 58e4150be2bba8f7b71974b10391f9e9
|
||||
# 给新好友或者群的自我介绍,不配置就不发送
|
||||
introduce:
|
||||
type: text
|
||||
path: "大家好,我是一个AI机器人,可以直接@我询问你想问的问题。"
|
||||
# 水群排行榜词云,只能是图片,末尾的`\%s`也是必须的
|
||||
wordcloud:
|
||||
type: image
|
||||
|
||||
@@ -6,6 +6,7 @@ var Conf conf
|
||||
// Config
|
||||
// @description: 配置
|
||||
type conf struct {
|
||||
System system `json:"system" yaml:"system"` // 系统配置
|
||||
Task task `json:"task" yaml:"task"` // 定时任务配置
|
||||
MySQL mysql `json:"mysql" yaml:"mysql"` // MySQL 配置
|
||||
Wechat wechat `json:"wechat" yaml:"wechat"` // 微信助手
|
||||
|
||||
21
config/system.go
Normal file
21
config/system.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package config
|
||||
|
||||
// 系统配置
|
||||
type system struct {
|
||||
NewFriendNotify newFriendNotify `json:"newFriendNotify" yaml:"newFriendNotify"` // 新好友通知
|
||||
DefaultRule defaultRule `json:"defaultRule" yaml:"defaultRule"` // 默认规则
|
||||
}
|
||||
|
||||
// 添加新好友或群之后通知给指定的人
|
||||
type newFriendNotify struct {
|
||||
Enable bool `json:"enable" yaml:"enable"` // 是否启用
|
||||
ToUser []string `json:"toUser" yaml:"toUser"` // 通知给谁
|
||||
}
|
||||
|
||||
// 默认规则
|
||||
type defaultRule struct {
|
||||
Ai bool `json:"ai" yaml:"ai"` // 是否启用AI
|
||||
ChatRank bool `json:"chatRank" yaml:"chatRank"` // 是否启用聊天排行榜
|
||||
Summary bool `json:"summary" yaml:"summary"` // 是否启用聊天总结
|
||||
Welcome bool `json:"welcome" yaml:"welcome"` // 是否启用欢迎新成员
|
||||
}
|
||||
@@ -41,6 +41,9 @@ func Sync() {
|
||||
|
||||
nowIds := []string{}
|
||||
|
||||
// 新增的成员,用于通知给指定的人
|
||||
var newItmes = make(map[string]string)
|
||||
|
||||
for _, friend := range base.Data {
|
||||
if strings.Contains(friend.Wxid, "gh_") || strings.Contains(friend.Wxid, "@openim") {
|
||||
continue
|
||||
@@ -67,14 +70,31 @@ func Sync() {
|
||||
PinyinAll: friend.PinyinAll,
|
||||
Wxid: friend.Wxid,
|
||||
IsOk: true,
|
||||
EnableAi: config.Conf.System.DefaultRule.Ai,
|
||||
EnableChatRank: config.Conf.System.DefaultRule.ChatRank,
|
||||
EnableSummary: config.Conf.System.DefaultRule.Summary,
|
||||
EnableWelcome: config.Conf.System.DefaultRule.Welcome,
|
||||
LastActive: time.Now().Local(),
|
||||
}).Error
|
||||
if err != nil {
|
||||
log.Printf("新增好友失败: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
newItmes[friend.Wxid] = friend.Nickname
|
||||
if conf, ok := config.Conf.Resource["introduce"]; ok {
|
||||
// 发送一条新消息
|
||||
utils.SendMessage(friend.Wxid, "", "大家好,我是一个AI机器人,可以直接@我询问你想问的问题。该功能默认未启用,请群主艾特我并发送 /ai enable 指令启用", 0)
|
||||
switch conf.Type {
|
||||
case "text":
|
||||
// 文字类型
|
||||
utils.SendMessage(friend.Wxid, "", conf.Path, 0)
|
||||
case "image":
|
||||
// 图片类型
|
||||
utils.SendImage(friend.Wxid, conf.Path, 0)
|
||||
case "emotion":
|
||||
// 表情类型
|
||||
utils.SendEmotion(friend.Wxid, conf.Path, 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pm := map[string]any{
|
||||
"nickname": friend.Nickname,
|
||||
@@ -95,6 +115,21 @@ func Sync() {
|
||||
}
|
||||
}
|
||||
|
||||
// 通知有新成员
|
||||
if len(newItmes) > 0 && config.Conf.System.NewFriendNotify.Enable {
|
||||
// 组装成一句话
|
||||
msg := []string{"#新好友通知\n"}
|
||||
for wxId, nickname := range newItmes {
|
||||
msg = append(msg, "微信Id: "+wxId+" -> 昵称: "+nickname)
|
||||
}
|
||||
for _, user := range config.Conf.System.NewFriendNotify.ToUser {
|
||||
if user != "" {
|
||||
// 发送一条新消息
|
||||
utils.SendMessage(user, "", strings.Join(msg, "\n"), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清理不在列表中的好友
|
||||
err = tx.Model(&entity.Friend{}).Where("wxid NOT IN (?)", nowIds).Update("is_ok", false).Error
|
||||
|
||||
|
||||
@@ -136,3 +136,43 @@
|
||||
</span>
|
||||
</button>
|
||||
{{end}}
|
||||
|
||||
|
||||
<!-- 水群排行榜 -->
|
||||
{{define "groupRank"}}
|
||||
<button type="button"
|
||||
class="{{ if eq .EnableWelcome true }}bg-green-600{{ else }}bg-gray-200{{ end }} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-offset-2"
|
||||
role="switch" aria-checked="false" onclick="changeUserGroupRankSkipStatus({{.Wxid}})">
|
||||
<span
|
||||
class="{{ if eq .EnableWelcome true }}translate-x-5{{ else }}translate-x-0{{ end }} pointer-events-none relative inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out">
|
||||
<span
|
||||
class="{{ if eq .EnableWelcome true }}opacity-0 duration-100 ease-out{{ else }}opacity-100 duration-200 ease-in{{ end }} absolute inset-0 flex h-full w-full items-center justify-center transition-opacity"
|
||||
aria-hidden="true">
|
||||
<svg class="h-3 w-3 text-gray-400" fill="none" viewBox="0 0 12 12">
|
||||
<path d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="{{ if eq .EnableWelcome true }}opacity-100 duration-200 ease-in{{ else }}opacity-0 duration-100 ease-out{{ end }} absolute inset-0 flex h-full w-full items-center justify-center transition-opacity"
|
||||
aria-hidden="true">
|
||||
<svg class="h-3 w-3 text-green-600" fill="currentColor" viewBox="0 0 12 12">
|
||||
<path
|
||||
d="M3.707 5.293a1 1 0 00-1.414 1.414l1.414-1.414zM5 8l-.707.707a1 1 0 001.414 0L5 8zm4.707-3.293a1 1 0 00-1.414-1.414l1.414 1.414zm-7.414 2l2 2 1.414-1.414-2-2-1.414 1.414zm3.414 2l4-4-1.414-1.414-4 4 1.414 1.414z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{{end}}
|
||||
|
||||
|
||||
<!-- 是否tag -->
|
||||
{{define "flagTag"}}
|
||||
{{ if eq . true }}
|
||||
<span
|
||||
class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20">是</span>
|
||||
{{ else }}
|
||||
<span
|
||||
class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/20">否</span>
|
||||
{{ end }}
|
||||
{{end}}
|
||||
|
||||
@@ -28,11 +28,7 @@
|
||||
<img src="assets/img/status-{{ if eq .IsOk true }}ok{{else}}fail{{end}}.png" alt="Tuple" class="h-12 w-12 flex-none rounded-lg bg-white object-cover ring-1 ring-gray-900/10">
|
||||
<div class="flex-1">
|
||||
<div class="text-sm font-medium leading-6 text-gray-900">{{ .Nickname }}</div>
|
||||
{{ if eq .IsOk true }}
|
||||
<span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20">正常</span>
|
||||
{{ else }}
|
||||
<span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/20">已删除</span>
|
||||
{{ end }}
|
||||
{{ template "flagTag" .IsOk }}
|
||||
</div>
|
||||
</div>
|
||||
<dl class="-my-3 divide-y divide-gray-100 px-6 py-4 text-sm leading-6">
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
||||
是否启用指令
|
||||
</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
||||
操作
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 bg-white">
|
||||
@@ -64,13 +67,7 @@
|
||||
{{ end }}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
||||
{{ if eq .IsOk true }}
|
||||
<span
|
||||
class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20">是</span>
|
||||
{{ else }}
|
||||
<span
|
||||
class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/20">否</span>
|
||||
{{ end }}
|
||||
{{ template "flagTag" .IsOk }}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
||||
{{ template "ai" . }}
|
||||
@@ -104,6 +101,9 @@
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
||||
{{ template "command" . }}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
||||
<button class="btn btn-link" onclick="getGroupUsers({{.Wxid}}, {{.Nickname}})">成员</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
@@ -113,6 +113,8 @@
|
||||
</main>
|
||||
|
||||
{{ template "footer.html" }}
|
||||
|
||||
{{ template "groupuser.html" }}
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
21
views/groupuser.html
Normal file
21
views/groupuser.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<dialog id="groupUserModal" class="modal">
|
||||
<div class="modal-box w-11/12 max-w-7xl">
|
||||
<h3 class="font-bold text-lg" id="groupUserModalName">我是群名称</h3>
|
||||
<div class="divider divider-warning">成员列表</div>
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>微信Id</th>
|
||||
<th>昵称</th>
|
||||
<th>是否群成员</th>
|
||||
<th>是否群主</th>
|
||||
<th>加群时间</th>
|
||||
<th>最后活跃时间</th>
|
||||
<th>退群时间</th>
|
||||
<th>是否跳过水群排行榜</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="groupUsers"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</dialog>
|
||||
@@ -155,12 +155,13 @@ function getGroupUsers(groupId, groupName) {
|
||||
// Insert data into cells
|
||||
row.insertCell(0).innerHTML = wxid;
|
||||
row.insertCell(1).innerHTML = nickname;
|
||||
row.insertCell(2).innerHTML = `<div class="badge badge-${isMember ? 'info' : 'error'} gap-2">${isMember ? '是' : '否'}</div>`;
|
||||
row.insertCell(3).innerHTML = `<div class="badge badge-${isAdmin ? 'info' : 'error'} gap-2">${isAdmin ? '是' : '否'}</div>`;
|
||||
row.insertCell(2).innerHTML = `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset ${isMember ? 'bg-green-50 text-green-700 ring-green-600/20' : 'bg-red-50 text-red-700 ring-red-600/20'}">${isMember ? '是' : '否'}</span>`;
|
||||
row.insertCell(3).innerHTML = `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset ${isAdmin ? 'bg-green-50 text-green-700 ring-green-600/20' : 'bg-red-50 text-red-700 ring-red-600/20'}">${isAdmin ? '是' : '否'}</span>`;
|
||||
row.insertCell(4).innerHTML = joinTime;
|
||||
row.insertCell(5).innerHTML = lastActive;
|
||||
row.insertCell(6).innerHTML = leaveTime;
|
||||
row.insertCell(7).innerHTML = `<input type="checkbox" class="toggle toggle-error" ${skipChatRank ? 'checked' : ''} onclick="changeUserGroupRankSkipStatus('${groupId}', '${wxid}')" />`;
|
||||
// row.insertCell(7).innerHTML = `<input type="checkbox" class="toggle toggle-error" ${skipChatRank ? 'checked' : ''} onclick="changeUserGroupRankSkipStatus('${groupId}', '${wxid}')" />`;
|
||||
row.insertCell(7).innerHTML = `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset ${skipChatRank ? 'bg-green-50 text-green-700 ring-green-600/20' : 'bg-red-50 text-red-700 ring-red-600/20'}">${skipChatRank ? '是' : '否'}</span>`;
|
||||
});
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
|
||||
Reference in New Issue
Block a user