forked from lxh/go-wxhelper
Merge pull request '✨ 新增功能配置开放' (#81) from hotfix into main
Reviewed-on: lxh/go-wxhelper#81
This commit is contained in:
commit
0f578e6333
21
app/pages.go
21
app/pages.go
@ -107,6 +107,27 @@ func Assistant(ctx *gin.Context) {
|
|||||||
ctx.HTML(http.StatusOK, "assistant.html", result)
|
ctx.HTML(http.StatusOK, "assistant.html", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ManageWithGroupAdmin
|
||||||
|
// @description: 群组管理(管理员可用)
|
||||||
|
// @param ctx
|
||||||
|
func ManageWithGroupAdmin(ctx *gin.Context) {
|
||||||
|
// 取出id
|
||||||
|
id := ctx.Query("id")
|
||||||
|
if id == "" {
|
||||||
|
ctx.HTML(http.StatusOK, "404.html", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = gin.H{
|
||||||
|
"msg": "success",
|
||||||
|
}
|
||||||
|
result["info"], _ = service.GetFriendInfoById(id)
|
||||||
|
result["aiModels"] = config.Conf.Ai.Models
|
||||||
|
result["assistant"], _ = service.GetAllAiAssistant()
|
||||||
|
// 渲染页面
|
||||||
|
ctx.HTML(http.StatusOK, "manager-one.html", result)
|
||||||
|
}
|
||||||
|
|
||||||
// PageNotFound
|
// PageNotFound
|
||||||
// @description: 404页面
|
// @description: 404页面
|
||||||
// @param ctx
|
// @param ctx
|
||||||
|
@ -2,6 +2,8 @@ system:
|
|||||||
# 每日新闻接口 Token
|
# 每日新闻接口 Token
|
||||||
# 获取地址: https://admin.alapi.cn/api_manager/token_manager
|
# 获取地址: https://admin.alapi.cn/api_manager/token_manager
|
||||||
alApiToken: xxx
|
alApiToken: xxx
|
||||||
|
# 系统访问域名
|
||||||
|
domain: https://wechat.abc.com
|
||||||
# 添加新好友或群之后通知给指定的人
|
# 添加新好友或群之后通知给指定的人
|
||||||
newFriendNotify:
|
newFriendNotify:
|
||||||
enable: true
|
enable: true
|
||||||
@ -48,7 +50,7 @@ mysql:
|
|||||||
|
|
||||||
# 定时任务
|
# 定时任务
|
||||||
task:
|
task:
|
||||||
enable: true
|
enable: false
|
||||||
news:
|
news:
|
||||||
enable: false
|
enable: false
|
||||||
cron: '14 11 * * *' # 每天0:30
|
cron: '14 11 * * *' # 每天0:30
|
||||||
|
@ -2,6 +2,7 @@ package config
|
|||||||
|
|
||||||
// 系统配置
|
// 系统配置
|
||||||
type system struct {
|
type system struct {
|
||||||
|
Domain string `json:"domain" yaml:"domain"` // 域名
|
||||||
AlApiToken string `json:"alApiToken" yaml:"alApiToken"` // AL API Token
|
AlApiToken string `json:"alApiToken" yaml:"alApiToken"` // AL API Token
|
||||||
NewFriendNotify newFriendNotify `json:"newFriendNotify" yaml:"newFriendNotify"` // 新好友通知
|
NewFriendNotify newFriendNotify `json:"newFriendNotify" yaml:"newFriendNotify"` // 新好友通知
|
||||||
DefaultRule defaultRule `json:"defaultRule" yaml:"defaultRule"` // 默认规则
|
DefaultRule defaultRule `json:"defaultRule" yaml:"defaultRule"` // 默认规则
|
||||||
|
4
main.go
4
main.go
@ -60,6 +60,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
return "否"
|
return "否"
|
||||||
},
|
},
|
||||||
|
"checkIsGroup": func(str string) bool {
|
||||||
|
// 如果id包含@chatroom就是群组
|
||||||
|
return strings.HasSuffix(str, "@chatroom")
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
app.LoadHTMLGlob("views/*.html")
|
app.LoadHTMLGlob("views/*.html")
|
||||||
|
@ -1,29 +1,30 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"go-wechat/common/types"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Friend
|
// Friend
|
||||||
// @description: 好友列表
|
// @description: 好友列表
|
||||||
type Friend struct {
|
type Friend struct {
|
||||||
Wxid string `json:"wxid"` // 微信原始Id
|
Wxid string `json:"wxid"` // 微信原始Id
|
||||||
CustomAccount string `json:"customAccount"` // 微信号
|
CustomAccount string `json:"customAccount"` // 微信号
|
||||||
Nickname string `json:"nickname"` // 昵称
|
Nickname string `json:"nickname"` // 昵称
|
||||||
Pinyin string `json:"pinyin"` // 昵称拼音大写首字母
|
Pinyin string `json:"pinyin"` // 昵称拼音大写首字母
|
||||||
PinyinAll string `json:"pinyinAll"` // 昵称全拼
|
PinyinAll string `json:"pinyinAll"` // 昵称全拼
|
||||||
LastActive time.Time `json:"lastActive"` // 最后活跃时间
|
LastActive types.DateTime `json:"lastActive"` // 最后活跃时间
|
||||||
EnableAi bool `json:"enableAI" gorm:"type:tinyint(1) default 0 not null"` // 是否使用AI
|
EnableAi bool `json:"enableAI" gorm:"type:tinyint(1) default 0 not null"` // 是否使用AI
|
||||||
AiModel string `json:"aiModel"` // AI模型
|
AiModel string `json:"aiModel"` // AI模型
|
||||||
Prompt string `json:"prompt"` // 提示词
|
Prompt string `json:"prompt"` // 提示词
|
||||||
EnableChatRank bool `json:"enableChatRank" gorm:"type:tinyint(1) default 0 not null"` // 是否使用聊天排行
|
EnableChatRank bool `json:"enableChatRank" gorm:"type:tinyint(1) default 0 not null"` // 是否使用聊天排行
|
||||||
EnableWelcome bool `json:"enableWelcome" gorm:"type:tinyint(1) default 0 not null"` // 是否启用迎新
|
EnableWelcome bool `json:"enableWelcome" gorm:"type:tinyint(1) default 0 not null"` // 是否启用迎新
|
||||||
EnableSummary bool `json:"enableSummary" gorm:"type:tinyint(1) default 0 not null"` // 是否启用总结
|
EnableSummary bool `json:"enableSummary" gorm:"type:tinyint(1) default 0 not null"` // 是否启用总结
|
||||||
EnableNews bool `json:"enableNews" gorm:"type:tinyint(1) default 0 not null"` // 是否启用新闻
|
EnableNews bool `json:"enableNews" gorm:"type:tinyint(1) default 0 not null"` // 是否启用新闻
|
||||||
EnableHotTop bool `json:"enableHotTop" gorm:"type:tinyint(1) default 0 not null"` // 是否启用热榜新闻
|
EnableHotTop bool `json:"enableHotTop" gorm:"type:tinyint(1) default 0 not null"` // 是否启用热榜新闻
|
||||||
ClearMember int `json:"clearMember"` // 清理成员配置(多少天未活跃的)
|
ClearMember int `json:"clearMember"` // 清理成员配置(多少天未活跃的)
|
||||||
IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常
|
IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常
|
||||||
UsedTokens int `json:"usedTokens"` // 已使用的AI Token数量
|
UsedTokens int `json:"usedTokens"` // 已使用的AI Token数量
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Friend) TableName() string {
|
func (Friend) TableName() string {
|
||||||
|
@ -14,10 +14,11 @@ func Init(g *gin.Engine) {
|
|||||||
ctx.Redirect(302, "/index.html")
|
ctx.Redirect(302, "/index.html")
|
||||||
})
|
})
|
||||||
|
|
||||||
g.GET("/index.html", app.Index) // 首页
|
g.GET("/index.html", app.Index) // 首页
|
||||||
g.GET("/friend.html", app.Friend) // 好友列表
|
g.GET("/friend.html", app.Friend) // 好友列表
|
||||||
g.GET("/group.html", app.Group) // 群组列表
|
g.GET("/group.html", app.Group) // 群组列表
|
||||||
g.GET("/assistant.html", app.Assistant) // AI角色
|
g.GET("/assistant.html", app.Assistant) // AI角色
|
||||||
|
g.GET("/manager.html", app.ManageWithGroupAdmin) // 自己管理配置
|
||||||
|
|
||||||
g.GET("/404.html", app.PageNotFound) // 群组列表
|
g.GET("/404.html", app.PageNotFound) // 群组列表
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"go-wechat/client"
|
"go-wechat/client"
|
||||||
"go-wechat/common/constant"
|
"go-wechat/common/constant"
|
||||||
|
"go-wechat/common/types"
|
||||||
"go-wechat/config"
|
"go-wechat/config"
|
||||||
"go-wechat/model/dto"
|
"go-wechat/model/dto"
|
||||||
"go-wechat/model/entity"
|
"go-wechat/model/entity"
|
||||||
@ -77,7 +78,7 @@ func Sync() {
|
|||||||
EnableNews: config.Conf.System.DefaultRule.News,
|
EnableNews: config.Conf.System.DefaultRule.News,
|
||||||
EnableHotTop: config.Conf.System.DefaultRule.HotTop,
|
EnableHotTop: config.Conf.System.DefaultRule.HotTop,
|
||||||
ClearMember: 0,
|
ClearMember: 0,
|
||||||
LastActive: time.Now().Local(),
|
LastActive: types.DateTime(time.Now().Local()),
|
||||||
}).Error
|
}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("新增好友失败: %s", err.Error())
|
log.Printf("新增好友失败: %s", err.Error())
|
||||||
@ -98,6 +99,14 @@ func Sync() {
|
|||||||
utils.SendEmotion(friend.Wxid, conf.Path, 0)
|
utils.SendEmotion(friend.Wxid, conf.Path, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 发送配置网页
|
||||||
|
if config.Conf.System.Domain != "" {
|
||||||
|
title := "欢迎使用微信机器人"
|
||||||
|
desc := "点我可以配置功能喔,提示非微信官方网页,点击继续访问即可"
|
||||||
|
url := config.Conf.System.Domain + "/manager.html?id=" + friend.Wxid
|
||||||
|
utils.SendPublicMsg(friend.Wxid, title, desc, url, 0)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pm := map[string]any{
|
pm := map[string]any{
|
||||||
"nickname": friend.Nickname,
|
"nickname": friend.Nickname,
|
||||||
|
@ -188,3 +188,42 @@ func QuitChatroom(chatRoomId string, retryCount int) {
|
|||||||
}
|
}
|
||||||
log.Printf("退群结果: %s", resp.String())
|
log.Printf("退群结果: %s", resp.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendPublicMsg
|
||||||
|
// @description: 发送公众号消息
|
||||||
|
// @param wxId string 群或者好友Id
|
||||||
|
// @param title string 标题
|
||||||
|
// @param digest string 摘要
|
||||||
|
// @param url string 链接
|
||||||
|
// @param retryCount int 重试次数
|
||||||
|
func SendPublicMsg(wxId, title, digest, url string, retryCount int) {
|
||||||
|
if retryCount > 5 {
|
||||||
|
log.Printf("重试五次失败,停止发送")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装参数
|
||||||
|
param := map[string]any{
|
||||||
|
"appName": "公安部网安局", // 假装是公安部发的,看着都牛逼
|
||||||
|
"userName": "gh_e406f4bcdf34", // 这个是公安部网安局的公众号id
|
||||||
|
"title": title,
|
||||||
|
"digest": digest,
|
||||||
|
"url": url,
|
||||||
|
"thumbUrl": "https://gitee.ltd/assets/img/logo.png", // 这个logo写死了,懒得搞,要改的自己改一下
|
||||||
|
"wxid": wxId,
|
||||||
|
}
|
||||||
|
pbs, _ := json.Marshal(param)
|
||||||
|
|
||||||
|
res := resty.New()
|
||||||
|
resp, err := res.R().
|
||||||
|
SetHeader("Content-Type", "application/json;chartset=utf-8").
|
||||||
|
SetBody(string(pbs)).
|
||||||
|
Post(config.Conf.Wechat.GetURL("/api/forwardPublicMsg"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("发送公众号消息失败: %s", err.Error())
|
||||||
|
// 休眠五秒后重新发送
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
SendPublicMsg(wxId, title, digest, url, retryCount+1)
|
||||||
|
}
|
||||||
|
log.Printf("发送公众号消息结果: %s", resp.String())
|
||||||
|
}
|
||||||
|
@ -149,7 +149,8 @@
|
|||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
{{ end }}
|
</li>
|
||||||
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
151
views/manager-one.html
Normal file
151
views/manager-one.html
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="h-full bg-gray-100">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>水群助手</title>
|
||||||
|
|
||||||
|
<link href="assets/css/daisyui-4.4.14-full.min.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<link href="assets/css/index.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp"></script>
|
||||||
|
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.min.js"></script>
|
||||||
|
|
||||||
|
<script src="assets/js/index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="h-full">
|
||||||
|
<div class="min-h-full flex items-center justify-center">
|
||||||
|
|
||||||
|
<div class="overflow-hidden rounded-xl border border-gray-200">
|
||||||
|
<div class="flex items -center gap-x-4 border-b border-gray-900/5 bg-gray-50 p-6">
|
||||||
|
<img src="assets/img/status-{{ if eq .info.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="text-sm flex-1">
|
||||||
|
<div class="font-medium leading-6 text-gray-900">{{ .info.Nickname }}</div>
|
||||||
|
<div class="font-medium text-gray-500">{{ .info.Wxid }}</div>
|
||||||
|
{{ template "flagTag" .info.IsOk }}
|
||||||
|
<!-- <button type="button" class="btn-link float-end text-red-600" onclick="getGroupUsers({{.info.Wxid}}, {{.info.Nickname}})">群成员</button>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<dl class="-my-3 divide-y divide-gray-100 px-6 py-4 text-sm leading-6">
|
||||||
|
<!-- 最后活跃时间 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">最后活跃时间</dt>
|
||||||
|
<dd class="flex items-start gap-x-2">
|
||||||
|
{{ if eq .info.LastActive.IsNil true }}
|
||||||
|
无活跃数据
|
||||||
|
{{ else }}
|
||||||
|
<time datetime="{{ .LastActive }}">{{ .info.LastActive }}</time>
|
||||||
|
{{ end }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<!-- AI -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">AI(模型可选默认或者指定模型)</dt>
|
||||||
|
<dd class="flex items-start gap-x-2 items-center">
|
||||||
|
<div>
|
||||||
|
{{ template "ai" .info }}
|
||||||
|
</div>
|
||||||
|
{{ if eq .info.EnableAi true }}
|
||||||
|
<div class="float-end">
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
<select class="block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-green-600 sm:text-sm sm:leading-6" onchange="aiModelChange(event, {{.info.Wxid}})">
|
||||||
|
{{$useModel := .info.AiModel}}
|
||||||
|
{{ range $.aiModels }}
|
||||||
|
<option value="{{.Model}}" {{ if eq $useModel .Model}}selected{{ end }}>
|
||||||
|
{{.Name}}
|
||||||
|
</option>
|
||||||
|
{{ end }}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="float-end mt-1">
|
||||||
|
<label>
|
||||||
|
<select
|
||||||
|
class="block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-green-600 sm:text-sm sm:leading-6"
|
||||||
|
onchange="aiAssistantChange(event, {{.info.Wxid}})">
|
||||||
|
<option value="" {{ if eq .info.Prompt
|
||||||
|
"" }}selected{{ end }}>默认</option>
|
||||||
|
|
||||||
|
{{$usePrompt := .info.Prompt}}
|
||||||
|
{{ range $.assistant }}
|
||||||
|
<option value="{{.Id}}" {{ if eq $usePrompt .Id}}selected{{ end }}>
|
||||||
|
{{.Name}}
|
||||||
|
</option>
|
||||||
|
{{ end }}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{$isGroup := checkIsGroup .info.Wxid}}
|
||||||
|
{{ if eq $isGroup true }}
|
||||||
|
<!-- 水群排行榜 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">水群排行榜</dt>
|
||||||
|
<dd class="flex items-start gap-x-2">
|
||||||
|
{{ template "chatRank" .info }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<!-- 群聊总结 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">群聊总结</dt>
|
||||||
|
<dd class="flex items-start gap-x-2">
|
||||||
|
{{ template "summary" .info }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<!-- 迎新 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">迎新</dt>
|
||||||
|
<dd class="flex items-start gap-x-2">
|
||||||
|
{{ template "welcome" .info }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
<!-- 早报 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">早报</dt>
|
||||||
|
<dd class="flex items-start gap-x-2">
|
||||||
|
{{ template "news" .info }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<!-- 热榜 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">热榜</dt>
|
||||||
|
<dd class="flex items-start gap-x-2">
|
||||||
|
{{ template "hotTop" .info }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
{{ if eq $isGroup true }}
|
||||||
|
<!-- 自动清理不活跃成员 -->
|
||||||
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
|
<dt class="text-gray-500">
|
||||||
|
末位淘汰(需要机器人是<span class="text-red-500">管理员</span>)
|
||||||
|
<br/>
|
||||||
|
<span class="text-red-300">* 清理多少天不说话的成员,0表示不清理</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="flex items-start gap-x-2 items-center">
|
||||||
|
<div class="relative rounded-md">
|
||||||
|
<label>
|
||||||
|
<input type="number" id="auto-cm-{{ .Wxid }}" min="0" class="block w-1/2 float-end rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" placeholder="N天不活跃自动移除"
|
||||||
|
value="{{.info.ClearMember}}"
|
||||||
|
onblur="changeClearMember({{.info.Wxid}}, {{.info.ClearMember}}, this.value)"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
||||||
|
<span class="text-gray-500 sm:text-sm" id="price-currency">天</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user