diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..f190a6b1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false + +eclint_indent_style = unset + +[Dockerfile] +indent_size = 4 \ No newline at end of file diff --git a/app/index.go b/app/index.go deleted file mode 100644 index affe9b4b..00000000 --- a/app/index.go +++ /dev/null @@ -1,29 +0,0 @@ -package app - -import ( - "fmt" - "github.com/gin-gonic/gin" - "go-wechat/config" - "go-wechat/service" - "net/http" -) - -// Index -// @description: 首页 -// @param ctx -func Index(ctx *gin.Context) { - var result = gin.H{ - "msg": "success", - } - // 取出所有好友列表 - friends, groups, err := service.GetAllFriend() - if err != nil { - result["msg"] = fmt.Sprintf("数据获取失败: %s", err.Error()) - } - result["friends"] = friends - result["groups"] = groups - result["vnc"] = config.Conf.Wechat.VncUrl - result["aiModels"] = config.Conf.Ai.Models - // 渲染页面 - ctx.HTML(http.StatusOK, "index.html", result) -} diff --git a/app/pages.go b/app/pages.go new file mode 100644 index 00000000..c1ab8b71 --- /dev/null +++ b/app/pages.go @@ -0,0 +1,79 @@ +package app + +import ( + "fmt" + "github.com/gin-gonic/gin" + "go-wechat/config" + "go-wechat/service" + "net/http" +) + +// Index +// @description: 首页 +// @param ctx +func Index(ctx *gin.Context) { + var result = gin.H{ + "msg": "success", + } + // 取出所有好友列表 + friends, groups, err := service.GetAllFriend() + if err != nil { + result["msg"] = fmt.Sprintf("数据获取失败: %s", err.Error()) + } + result["friendCount"] = len(friends) + result["groupCount"] = len(groups) + result["vnc"] = config.Conf.Wechat.VncUrl + result["isVnc"] = config.Conf.Wechat.VncUrl != "" + result["aiModels"] = config.Conf.Ai.Models + + // 渲染页面 + ctx.HTML(http.StatusOK, "index.html", result) +} + +// Friend +// @description: 好友列表 +// @param ctx +func Friend(ctx *gin.Context) { + var result = gin.H{ + "msg": "success", + } + + // 取出所有好友列表 + friends, _, err := service.GetAllFriend() + if err != nil { + result["msg"] = fmt.Sprintf("数据获取失败: %s", err.Error()) + } + result["friends"] = friends + result["vnc"] = config.Conf.Wechat.VncUrl + result["aiModels"] = config.Conf.Ai.Models + // 渲染页面 + ctx.HTML(http.StatusOK, "friend.html", result) +} + +// Group +// @description: 群组列表 +// @param ctx +func Group(ctx *gin.Context) { + var result = gin.H{ + "msg": "success", + } + // 取出所有好友列表 + _, groups, err := service.GetAllFriend() + if err != nil { + result["msg"] = fmt.Sprintf("数据获取失败: %s", err.Error()) + } + result["groups"] = groups + result["vnc"] = config.Conf.Wechat.VncUrl + result["aiModels"] = config.Conf.Ai.Models + + // 渲染页面 + ctx.HTML(http.StatusOK, "group.html", result) +} + +// PageNotFound +// @description: 404页面 +// @param ctx +func PageNotFound(ctx *gin.Context) { + // 渲染页面 + ctx.HTML(http.StatusOK, "404.html", nil) +} diff --git a/config.yaml b/config.yaml index 044a6426..2153fd44 100644 --- a/config.yaml +++ b/config.yaml @@ -23,7 +23,7 @@ mysql: schema: public # postgres 专用 task: - enable: true + enable: false syncFriends: enable: false cron: '*/5 * * * *' # 五分钟一次 @@ -66,17 +66,19 @@ ai: personality: 你的名字叫张三,你是一个百科机器人,你的爱好是看电影,你的性格是开朗的,你的专长是讲故事,你的梦想是当一名童话故事作家。你对政治没有一点儿兴趣,也不会讨论任何与政治相关的话题,你甚至可以拒绝回答这一类话题。 models: - name: ChatGPT-4 - model: gpt-4-0613 - - name: 讯飞星火v3 - model: SparkDesk3 - - name: 讯飞星火随机 - model: SparkDesk + model: gpt-4 + - name: 讯飞星火v3.1 + model: SparkDesk-v3.1 + - name: 讯飞星火v3.5 + model: SparkDesk-v3.5 - name: 月之暗面-8k model: moonshot-v1-8k - name: 月之暗面-32k model: moonshot-v1-32k - name: 月之暗面-128k model: moonshot-v1-128k + - name: 跃问 + model: StepChat # 资源配置 # map[k]v结构,k 会变成全小写,所以这儿不能用大写字母 diff --git a/main.go b/main.go index fb9d3ecb..5eb07dd2 100644 --- a/main.go +++ b/main.go @@ -40,11 +40,23 @@ func main() { // 自定义模板引擎函数 app.SetFuncMap(template.FuncMap{ - "checkSwap": func(flag bool) string { - if flag { - return "swap-active" + "codeToChinese": func(code string) string { + switch code { + case "friend": + return "好友列表" + case "group": + return "群组列表" + case "index": + return "首页" + default: + return "其他页面" } - return "" + }, + "boolToChinese": func(flag bool) string { + if flag { + return "是" + } + return "否" }, }) @@ -58,7 +70,7 @@ func main() { return } // 404直接跳转到首页 - ctx.Redirect(302, "/index.html") + ctx.Redirect(302, "/404.html") }) app.NoMethod(func(ctx *gin.Context) { ctx.String(http.StatusMethodNotAllowed, "不支持的请求方式") diff --git a/router/router.go b/router/router.go index 33848daa..7df7ae50 100644 --- a/router/router.go +++ b/router/router.go @@ -14,10 +14,11 @@ func Init(g *gin.Engine) { ctx.Redirect(302, "/index.html") }) - g.GET("/index.html", app.Index) // 首页 - g.GET("/test.html", func(ctx *gin.Context) { - ctx.HTML(200, "test.html", nil) - }) + g.GET("/index.html", app.Index) // 首页 + g.GET("/friend.html", app.Friend) // 好友列表 + g.GET("/group.html", app.Group) // 群组列表 + + g.GET("/404.html", app.PageNotFound) // 群组列表 // 接口 api := g.Group("/api") diff --git a/views/404.html b/views/404.html new file mode 100644 index 00000000..0ede84ef --- /dev/null +++ b/views/404.html @@ -0,0 +1,78 @@ + + + + + + 看起来你好像迷路了~ + + + + + + + +
+

404

+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + diff --git a/views/components.html b/views/components.html new file mode 100644 index 00000000..0d4f5b79 --- /dev/null +++ b/views/components.html @@ -0,0 +1,138 @@ + + + +{{define "ai"}} + +{{end}} + + + +{{define "chatRank"}} + +{{end}} + + +{{define "summary"}} + +{{end}} + + +{{define "welcome"}} + +{{end}} + + + +{{define "command"}} + +{{end}} diff --git a/views/footer.html b/views/footer.html new file mode 100644 index 00000000..0061ae64 --- /dev/null +++ b/views/footer.html @@ -0,0 +1,10 @@ + diff --git a/views/friend.html b/views/friend.html new file mode 100644 index 00000000..979b7f91 --- /dev/null +++ b/views/friend.html @@ -0,0 +1,113 @@ + + + + + + 好友列表 + + + + + + + + + + + +
+ {{ template "head.html" "friend" }} + +
+
+
+ + + + + + + + + + + + + + {{ range .friends }} + + + + + + + + + + {{ end }} + +
+ 微信Id + + 微信号 + 昵称 + + 最后活跃时间 + + 是否在通讯录 + + 是否启用AI + + 是否启用指令 +
+ {{ .Wxid }} + {{ + .CustomAccount }} + {{ + .Nickname }} + + {{ if eq .LastActive.IsNil true }} + 无数据 + {{ else }} + {{ .LastActive }} + {{ end }} + + {{ if eq .IsOk true }} + + {{ else }} + + {{ end }} + + {{ template "ai" . }} + + {{ if eq .EnableAi true }} + + {{ end }} + + {{ template "command" . }} +
+
+
+
+ + {{ template "footer.html" }} +
+ + + diff --git a/views/group.html b/views/group.html new file mode 100644 index 00000000..4feccec5 --- /dev/null +++ b/views/group.html @@ -0,0 +1,118 @@ + + + + + + 水群助手 + + + + + + + + + + + +
+ {{ template "head.html" "group" }} + +
+
+
+ + + + + + + + + + + + + + + {{ range .groups }} + + + + + + + + + + + {{ end }} + +
群名称 + + 最后活跃时间 + + 是否在通讯录 + + 是否启用AI + + 是否启用水群排行榜 + + 是否启用聊天记录总结 + + 是否启用迎新 + + 是否启用指令 +
+
{{ .Nickname }}
+
{{ .Wxid }}
+
+ {{ if eq .LastActive.IsNil true }} + 无数据 + {{ else }} + {{ .LastActive }} + {{ end }} + + {{ if eq .IsOk true }} + + {{ else }} + + {{ end }} + + {{ template "ai" . }} + + {{ if eq .EnableAi true }} + + {{ end }} + + {{ template "chatRank" . }} + + {{ template "summary" . }} + + {{ template "welcome" . }} + + {{ template "command" . }} +
+
+
+
+ + {{ template "footer.html" }} +
+ + diff --git a/views/head.html b/views/head.html new file mode 100644 index 00000000..ce5dbe42 --- /dev/null +++ b/views/head.html @@ -0,0 +1,27 @@ +
+ +
+
+

{{ codeToChinese . }}

+
+
+
diff --git a/views/index.html b/views/index.html index 06fb6df3..53988cc4 100644 --- a/views/index.html +++ b/views/index.html @@ -1,247 +1,45 @@ - + + - - 水群助手 + + 水群助手 - - + + - - + + - + - -
- - {{ if ne .msg "success" }} - - {{ end }} - -
- -
- - - - - - - - - - - - - - - - {{ range .friends }} - - - - - - - - - - {{ end }} - -
微信Id微信号昵称最后活跃时间是否在通讯录是否启用AI是否启用指令
{{ .Wxid }}{{ .CustomAccount }}{{ .Nickname }} - {{ if eq .LastActive.IsNil true }} - 无数据 - {{ else }} - {{ .LastActive }} - {{ end }} - - {{ if eq .IsOk true }} -
- 是 -
- {{ else }} -
- 否 -
- {{ end }} -
- - {{ if .EnableAi }} -
- - {{ end }} -
- -
-
- - -
- - - - - - - - - - - - - - - - - - - {{ range .groups }} - - - - - - - - - - - - - {{ end }} - -
群Id昵称最后活跃时间是否在通讯录是否启用AI是否启用水群排行榜是否启用聊天记录总结是否启用迎新是否启用指令操作
{{ .Wxid }}{{ .Nickname }} - {{ if eq .LastActive.IsNil true }} - 无数据 - {{ else }} - {{ .LastActive }} - {{ end }} - - {{ if eq .IsOk true }} -
- 是 -
- {{ else }} -
- 否 -
- {{ end }} -
- - - {{ if .EnableAi }} -
- - {{ end }} -
- - - - - - - - - - - -
-
- - {{ if ne .vnc "" }} - -
-
- -
-
- {{ end }} -
+ +
+ {{ template "head.html" "index"}} +
+
+
+
+
+
好友数量
+
{{ .friendCount }}
+
+
+
群组数量
+
{{ .groupCount }}
+
+
+
是否配置VNC
+
{{ boolToChinese .isVnc }}
+
+
+
+
- - - -
成员列表
- - - - - - - - - - - - - - - - -
微信Id昵称是否群成员是否群主加群时间最后活跃时间退群时间是否跳过水群排行榜
- - -
- - \ No newline at end of file diff --git a/views/notifications.html b/views/notifications.html new file mode 100644 index 00000000..03662895 --- /dev/null +++ b/views/notifications.html @@ -0,0 +1,53 @@ + +
+
+ +
+
+
+
+ +
+
+

通知标题

+

+ 通知内容,通知内容,通知内容,通知内容,通知内容,通知内容,通知内容,通知内容

+
+
+ +
+
+
+
+
+
+ + + diff --git a/views/static/css/404.css b/views/static/css/404.css new file mode 100644 index 00000000..b920fdf0 --- /dev/null +++ b/views/static/css/404.css @@ -0,0 +1,429 @@ +body { + background-color: #FF7F2E; + font-family: "Concert One", cursive; + margin: 0; + overflow: hidden; + padding: 0; +} + +/*/////////////////// rules */ +/*/////////////////// scene */ +.text { + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + color: rgba(19, 36, 44, 0.1); + font-size: 30em; + text-align: center; + top: 40%; +} + +.container { + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + height: 300px; + width: 500px; +} +.container:after { + position: absolute; + content: ""; + background-color: rgba(19, 36, 44, 0.1); + border-radius: 12px; + bottom: 40px; + height: 12px; + left: 80px; + width: 350px; + z-index: -1; +} + +/*/////////////////// caveman */ +.caveman { + height: 300px; + position: absolute; + width: 250px; +} + +.caveman:nth-child(1) { + right: 20px; +} + +.caveman:nth-child(2) { + left: 20px; + transform: rotateY(180deg); +} + +.head { + position: absolute; + background-color: #13242C; + border-radius: 50px; + height: 140px; + left: 60px; + top: 25px; + width: 65px; +} +.head:after, .head:before { + content: ""; + position: absolute; + background-color: #13242C; + border-radius: 10px; + height: 20px; + width: 7px; +} +.head:after { + left: 35px; + top: -8px; + transform: rotate(20deg); +} +.head:before { + left: 30px; + top: -8px; + transform: rotate(-20deg); +} +.head .eye { + left: 50%; + position: absolute; + transform: translateX(-50%); + background-color: #EAB08C; + border-radius: 50px; + height: 16px; + left: 45%; + top: 40px; + width: 48px; +} +.head .eye:after, .head .eye:before { + content: ""; + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #13242C; + border-radius: 50%; + height: 5px; + width: 5px; +} +.head .eye:after { + left: 5px; +} +.head .eye:before { + right: 9px; +} +.head .eye .nose { + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + background-color: #D9766C; + border-left: 8px solid rgba(19, 36, 44, 0.1); + border-radius: 10px; + box-sizing: border-box; + height: 35px; + left: 45%; + top: 12px; + width: 15px; +} + +.shape { + left: 50%; + position: absolute; + transform: translateX(-50%); + border-radius: 50%; + height: 140px; + overflow: hidden; + top: 70px; + width: 140px; +} +.shape .circle { + position: absolute; + border-radius: 50%; + height: 60px; + width: 60px; +} +.shape .circle:after, .shape .circle:before { + content: ""; + position: absolute; + border-radius: 50%; + height: 20px; + width: 20px; +} +.shape .circle:after { + left: 50px; + top: 10px; +} +.shape .circle:before { + left: 60px; + top: 45px; +} +.shape .circle:nth-child(1) { + left: -12px; + top: 80px; +} +.shape .circle:nth-child(2) { + right: 10px; + top: 0px; + transform: rotate(90deg); +} +.shape .circle:nth-child(2):after { + left: 65px; + top: 10px; +} +.shape .circle:nth-child(2):before { + display: none; +} + +.caveman:nth-child(1) .shape { + background-color: #D13433; +} +.caveman:nth-child(1) .shape .circle { + background-color: #932422; +} +.caveman:nth-child(1) .shape .circle:after, .caveman:nth-child(1) .shape .circle:before { + background-color: #932422; +} + +.caveman:nth-child(2) .shape { + background-color: #932422; +} +.caveman:nth-child(2) .shape .circle { + background-color: #D13433; +} +.caveman:nth-child(2) .shape .circle:after, .caveman:nth-child(2) .shape .circle:before { + background-color: #D13433; +} + +.arm-right { + position: absolute; + background-color: #EAB08C; + border-left: 8px solid rgba(19, 36, 44, 0.1); + border-radius: 50px; + box-sizing: border-box; + height: 180px; + left: 135px; + top: 80px; + transform-origin: 30px 30px; + width: 60px; + z-index: 1; +} +.arm-right .club { + position: absolute; + border-bottom: 110px solid #601513; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + height: 0; + left: -60px; + top: 120px; + transform: rotate(70deg); + width: 20px; +} +.arm-right .club:after, .arm-right .club:before { + position: absolute; + content: ""; + background-color: #601513; + border-radius: 50%; + left: 0; +} +.arm-right .club:after { + height: 20px; + width: 20px; + top: -10px; +} +.arm-right .club:before { + height: 40px; + width: 40px; + left: -10px; + top: 90px; +} + +.leg { + position: absolute; + border-radius: 10px; + height: 55px; + top: 200px; + width: 10px; +} +.leg:after { + position: absolute; + content: ""; + border-radius: 50%; + height: 10px; + left: -5px; + top: 15px; + width: 10px; +} +.leg .foot { + position: absolute; + border-radius: 25px 25px 0 0; + height: 25px; + left: -38px; + top: 30px; + width: 50px; +} +.leg .foot:after, .leg .foot:before, .leg .foot .fingers, .leg .foot .fingers:after { + position: absolute; + background-color: #EAB08C; + border-radius: 50%; + bottom: 0px; + height: 15px; + transform-origin: bottom; + width: 15px; +} +.leg .foot:after { + left: -6px; + content: ""; +} +.leg .foot:before { + left: 8px; + transform: scale(0.6); + content: ""; +} +.leg .foot .fingers { + left: 15px; + transform: scale(0.6); +} +.leg .foot .fingers:after { + left: 11px; + content: ""; +} + +.leg:nth-child(1) { + background-color: #B2524D; + left: 95px; +} +.leg:nth-child(1):after { + background-color: #B2524D; +} +.leg:nth-child(1) .foot { + background-color: #B2524D; +} +.leg:nth-child(1) .foot:after { + background-color: #B2524D; +} +.leg:nth-child(1) .foot:before { + display: none; +} + +.leg:nth-child(2) { + background-color: #D9766C; + left: 115px; +} +.leg:nth-child(2):after { + background-color: #D9766C; +} +.leg:nth-child(2) .foot { + background-color: #D9766C; +} + +/*/////////////////// animation */ +.caveman:nth-child(1) .arm-right { + animation: arm-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); +} + +.caveman:nth-child(2) .arm-right { + animation: arm-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); + animation-delay: 0.6s; +} + +@keyframes arm-anima { + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(-360deg); + } +} +.caveman:nth-child(2) .head { + animation: head-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); +} + +.caveman:nth-child(1) .head { + animation: head-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); + animation-delay: 0.6s; +} + +@keyframes head-anima { + 0% { + top: 25px; + } + 42% { + top: 25px; + } + 45% { + top: 50px; + } + 100% { + top: 25px; + } +} +.caveman:nth-child(2) .eye:after, +.caveman:nth-child(2) .eye:before { + animation: eye-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); +} + +.caveman:nth-child(1) .eye:after, +.caveman:nth-child(1) .eye:before { + animation: eye-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); + animation-delay: 0.6s; +} + +@keyframes eye-anima { + 0% { + height: 5px; + } + 42% { + height: 5px; + } + 45% { + height: 1px; + } + 100% { + height: 5px; + } +} +.container:after { + animation: shadow-anima 1.2s infinite cubic-bezier(0.55, 0.01, 0.16, 1.34); + animation-delay: 0.1s; +} + +@keyframes shadow-anima { + 0% { + width: 350px; + left: 80px; + } + 25% { + width: 450px; + left: 80px; + } + 50% { + width: 350px; + left: 80px; + } + 75% { + width: 450px; + left: 0px; + } + 100% { + width: 350px; + left: 80px; + } +} +/*/////////////////////// credit ////*/ +#link { + bottom: 20px; + color: #000; + opacity: 0.2; + display: flex; + align-items: center; + position: absolute; + left: 50%; + transform: translateX(-50%); +} + +#link p { + margin: 0; + margin-left: 5px; +} + +#link:hover { + opacity: 1; +} \ No newline at end of file diff --git a/views/static/img/logo.png b/views/static/img/logo.png new file mode 100644 index 00000000..00ad1a0a Binary files /dev/null and b/views/static/img/logo.png differ diff --git a/views/static/js/404.js b/views/static/js/404.js new file mode 100644 index 00000000..3282c8d4 --- /dev/null +++ b/views/static/js/404.js @@ -0,0 +1 @@ +// no JS this time ! \ No newline at end of file diff --git a/views/static/js/index.js b/views/static/js/index.js index fd9ddaef..10e47783 100644 --- a/views/static/js/index.js +++ b/views/static/js/index.js @@ -16,6 +16,8 @@ function changeAiEnableStatus(wxId) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) } @@ -34,6 +36,8 @@ function changeGroupRankEnableStatus(wxId) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) } @@ -52,6 +56,8 @@ function changeSummaryEnableStatus(wxId) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) } @@ -69,6 +75,8 @@ function changeWelcomeEnableStatus(wxId) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) } @@ -86,6 +94,8 @@ function changeCommandEnableStatus(wxId) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) } @@ -105,6 +115,8 @@ function changeUserGroupRankSkipStatus(groupId, userId) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) } @@ -177,5 +189,7 @@ function aiModelChange(event, wxid) { }).catch(function (error) { console.log(`错误信息: ${error}`); alert("修改失败") + }).finally(function () { + window.location.reload(); }) }