Compare commits

...

2 Commits

Author SHA1 Message Date
5024fb4b05 Merge pull request '🔥 重构管理页面,长得更好看一些了' (#41) from hotfix into main
All checks were successful
BuildImage / build-image (push) Successful in 1m46s
Reviewed-on: #41
2024-04-23 10:45:38 +08:00
1fca021b38 🔥 重构管理页面,长得更好看一些了 2024-04-23 10:42:08 +08:00
18 changed files with 1144 additions and 279 deletions

21
.editorconfig Normal file
View File

@ -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

View File

@ -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)
}

79
app/pages.go Normal file
View File

@ -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)
}

View File

@ -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 会变成全小写,所以这儿不能用大写字母

22
main.go
View File

@ -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, "不支持的请求方式")

View File

@ -15,9 +15,10 @@ func Init(g *gin.Engine) {
})
g.GET("/index.html", app.Index) // 首页
g.GET("/test.html", func(ctx *gin.Context) {
ctx.HTML(200, "test.html", nil)
})
g.GET("/friend.html", app.Friend) // 好友列表
g.GET("/group.html", app.Group) // 群组列表
g.GET("/404.html", app.PageNotFound) // 群组列表
// 接口
api := g.Group("/api")

78
views/404.html Normal file
View File

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>看起来你好像迷路了~</title>
<link href="https://fonts.googleapis.com/css?family=Concert+One" rel="stylesheet">
<link rel="stylesheet" href="assets/css/404.css">
</head>
<body>
<!-- partial:index.partial.html -->
<div class="text">
<p>404</p>
</div>
<div class="container">
<!-- caveman left -->
<div class="caveman">
<div class="leg">
<div class="foot">
<div class="fingers"></div>
</div>
</div>
<div class="leg">
<div class="foot">
<div class="fingers"></div>
</div>
</div>
<div class="shape">
<div class="circle"></div>
<div class="circle"></div>
</div>
<div class="head">
<div class="eye">
<div class="nose"></div>
</div>
<div class="mouth"></div>
</div>
<div class="arm-right">
<div class="club"></div>
</div>
</div>
<!-- caveman right -->
<div class="caveman">
<div class="leg">
<div class="foot">
<div class="fingers"></div>
</div>
</div>
<div class="leg">
<div class="foot">
<div class="fingers"></div>
</div>
</div>
<div class="shape">
<div class="circle"></div>
<div class="circle"></div>
</div>
<div class="head">
<div class="eye">
<div class="nose"></div>
</div>
<div class="mouth"></div>
</div>
<div class="arm-right">
<div class="club"></div>
</div>
</div>
</div>
<!-- //////////////// CREDIT //////////////// -->
<!-- partial -->
<script src='https://use.fontawesome.com/releases/v5.0.7/js/all.js'></script>
<script src="assets/js/script.js"></script>
</body>
</html>

138
views/components.html Normal file
View File

@ -0,0 +1,138 @@
<!-- 公共模块 -->
<!-- AI设置 -->
{{define "ai"}}
<button type="button"
class="{{ if eq .EnableAi 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="changeAiEnableStatus({{.Wxid}})">
<span
class="{{ if eq .EnableAi 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 .EnableAi 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 .EnableAi 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}}
<!-- 水群排行榜 -->
{{define "chatRank"}}
<button type="button"
class="{{ if eq .EnableChatRank 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="changeGroupRankEnableStatus({{.Wxid}})">
<span
class="{{ if eq .EnableChatRank 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 .EnableChatRank 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 .EnableChatRank 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}}
<!-- 消息总结 -->
{{define "summary"}}
<button type="button"
class="{{ if eq .EnableSummary 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="changeSummaryEnableStatus({{.Wxid}})">
<span
class="{{ if eq .EnableSummary 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 .EnableSummary 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 .EnableSummary 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}}
<!-- 欢迎新成员 -->
{{define "welcome"}}
<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="changeWelcomeEnableStatus({{.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}}
<!-- 指令设置 -->
{{define "command"}}
<button type="button"
class="{{ if eq .EnableCommand 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="changeCommandEnableStatus({{.Wxid}})">
<span
class="{{ if eq .EnableCommand 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 .EnableCommand 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 .EnableCommand 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}}

10
views/footer.html Normal file
View File

@ -0,0 +1,10 @@
<footer>
<div class="mx-auto max-w-3xl px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<div class="border-t border-gray-200 py-8 text-center text-sm text-gray-500 sm:text-left">
<span class="block sm:inline">本项目完全开源,开源地址: </span>
<span class="block sm:inline text-red-500">
<a target="_blank" href="https://gitee.ltd/lxh/go-wxhelper">https://gitee.ltd</a>
</span>
</div>
</div>
</footer>

113
views/friend.html Normal file
View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en" class="h-full">
<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">
{{ template "head.html" "friend" }}
<main class="-mt-32">
<div class="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8">
<div class="rounded-lg bg-white px-5 py-6 shadow sm:px-6 text-2xl">
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
微信Id
</th>
<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>
<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>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
是否启用AI
</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">
{{ range .friends }}
<tr class="even:bg-gray-50">
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">
{{ .Wxid }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{
.CustomAccount }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{
.Nickname }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ if eq .LastActive.IsNil true }}
无数据
{{ else }}
{{ .LastActive }}
{{ 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 }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "ai" . }}
<!-- 使用的模型 -->
{{ if eq .EnableAi true }}
<select id="location" name="location"
class="mt-2 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, {{.Wxid}})">
<option value="" {{ if eq .AiModel
"" }}selected{{ end }}>默认(gpt-3.5-turbo-0613)
</option>
{{$useModel := .AiModel}}
{{ range $.aiModels }}
<option value="{{.Model}}" {{ if eq $useModel .Model}}selected{{ end }}>
{{.Name}}({{.Model}})
</option>
{{ end }}
</select>
{{ end }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "command" . }}
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</main>
{{ template "footer.html" }}
</div>
</body>
</html>

118
views/group.html Normal file
View File

@ -0,0 +1,118 @@
<!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">
{{ template "head.html" "group" }}
<main class="-mt-32">
<div class="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8">
<div class="rounded-lg bg-white px-5 py-6 shadow sm:px-6 text-2xl">
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<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>
<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">
是否启用AI
</th>
<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>
<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">
{{ range .groups }}
<tr class="even:bg-gray-50">
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
<div class="font-medium text-gray-900">{{ .Nickname }}</div>
<div class="mt-1 truncate text-gray-500">{{ .Wxid }}</div>
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ if eq .LastActive.IsNil true }}
无数据
{{ else }}
{{ .LastActive }}
{{ 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 }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "ai" . }}
<!-- 使用的模型 -->
{{ if eq .EnableAi true }}
<select id="location" name="location"
class="mt-2 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, {{.Wxid}})">
<option value="" {{ if eq .AiModel
"" }}selected{{ end }}>默认(gpt-3.5-turbo-0613)
</option>
{{$useModel := .AiModel}}
{{ range $.aiModels }}
<option value="{{.Model}}" {{ if eq $useModel .Model}}selected{{ end }}>
{{.Name}}({{.Model}})
</option>
{{ end }}
</select>
{{ end }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "chatRank" . }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "summary" . }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "welcome" . }}
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{{ template "command" . }}
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</main>
{{ template "footer.html" }}
</div>
</body>

27
views/head.html Normal file
View File

@ -0,0 +1,27 @@
<div class="bg-green-600 pb-32">
<nav class="border-b border-green-300 border-opacity-25 bg-green-600 lg:border-none">
<div class="mx-auto max-w-7xl px-2 sm:px-4 lg:px-8">
<div
class="relative flex h-16 items-center justify-between lg:border-b lg:border-green-400 lg:border-opacity-25">
<div class="flex items-center px-2 lg:px-0">
<div class="flex-shrink-0">
<img class="block h-8 w-8" src="assets/img/logo.png" alt="">
</div>
<div class="hidden lg:ml-10 lg:block">
<div class="flex space-x-4">
<a href="/index.html" class="{{ if eq . "index" }}bg-green-700{{ else }}hover:bg-green-500 hover:bg-opacity-75{{ end }} text-white rounded-md py-2 px-3 text-sm font-medium" aria-current="page">首页</a>
<a href="/friend.html" class="{{ if eq . "friend" }}bg-green-700{{ else }}hover:bg-green-500 hover:bg-opacity-75{{ end }} text-white rounded-md py-2 px-3 text-sm font-medium" aria-current="page">好友</a>
<a href="/group.html" class="{{ if eq . "group" }}bg-green-700{{ else }}hover:bg-green-500 hover:bg-opacity-75{{ end }} text-white rounded-md py-2 px-3 text-sm font-medium">群组</a>
<!-- <a href="/index.html" class="{{ if eq . "vnc" }}bg-green-700{{ else }}hover:bg-green-500 hover:bg-opacity-75{{ end }} text-white rounded-md py-2 px-3 text-sm font-medium">VNC</a>-->
</div>
</div>
</div>
</div>
</div>
</nav>
<header class="py-10">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold tracking-tight text-white">{{ codeToChinese . }}</h1>
</div>
</header>
</div>

View File

@ -1,247 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<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" />
<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"></script>
<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>
<div class="p-5 space-y-5">
<!-- 如果msg不等于success显示alert -->
{{ if ne .msg "success" }}
<div role="alert" class="alert alert-error">
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
<span>{{ .msg }}</span>
<body class="h-full">
<div class="min-h-full">
{{ template "head.html" "index"}}
<main class="-mt-32">
<div class="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8">
<div class="rounded-lg bg-white px-5 py-6 shadow sm:px-6 text-2xl">
<dl class="mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
<div class="overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6">
<dt class="truncate text-sm font-medium text-gray-500">好友数量</dt>
<dd class="mt-1 text-3xl font-semibold tracking-tight text-gray-900">{{ .friendCount }}</dd>
</div>
{{ end }}
<div role="tablist" class="tabs tabs-bordered">
<input type="radio" name="friend_tab" role="tab" class="tab" aria-label="好友列表" checked />
<div role="tabpanel" class="tab-content p-6">
<!-- 循环好友列表 -->
<table class="table table-zebra">
<!-- head -->
<thead>
<tr>
<th>微信Id</th>
<th>微信号</th>
<th>昵称</th>
<th>最后活跃时间</th>
<th>是否在通讯录</th>
<th>是否启用AI</th>
<th>是否启用指令</th>
</tr>
</thead>
<tbody>
{{ range .friends }}
<tr>
<td>{{ .Wxid }}</td>
<td>{{ .CustomAccount }}</td>
<td>{{ .Nickname }}</td>
<td>
{{ if eq .LastActive.IsNil true }}
无数据
{{ else }}
{{ .LastActive }}
{{ end }}
</td>
<td>
{{ if eq .IsOk true }}
<div class="badge badge-info gap-2">
<div class="overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6">
<dt class="truncate text-sm font-medium text-gray-500">群组数量</dt>
<dd class="mt-1 text-3xl font-semibold tracking-tight text-gray-900">{{ .groupCount }}</dd>
</div>
{{ else }}
<div class="badge badge-error gap-2">
<div class="overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6">
<dt class="truncate text-sm font-medium text-gray-500">是否配置VNC</dt>
<dd class="mt-1 text-3xl font-semibold tracking-tight text-gray-900">{{ boolToChinese .isVnc }}</dd>
</div>
{{ end }}
</td>
<td>
<label class="swap swap-flip {{ checkSwap .EnableAi }}">
<input type="checkbox" onclick="changeAiEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
{{ if .EnableAi }}
<br />
<select class="select select-success select-xs w-1/2 max-w-xs" onchange="aiModelChange(event, {{.Wxid}})">
<option value="" {{ if eq .AiModel ""}}selected{{ end }}>默认(gpt-3.5-turbo-0613)</option>
{{$useModel := .AiModel}}
{{ range $.aiModels }}
<option value="{{.Model}}" {{ if eq $useModel .Model}}selected{{ end }}>{{.Name}}({{.Model}})</option>
{{ end }}
</select>
{{ end }}
</td>
<td>
<label class="swap swap-flip {{ checkSwap .EnableCommand }}">
<input type="checkbox" onclick="changeCommandEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
<input type="radio" name="friend_tab" role="tab" class="tab" aria-label="群列表" />
<div role="tabpanel" class="tab-content p-6">
<!-- 循环群列表 -->
<table class="table table-zebra">
<!-- head -->
<thead>
<tr>
<th>群Id</th>
<th>昵称</th>
<th>最后活跃时间</th>
<th>是否在通讯录</th>
<th>是否启用AI</th>
<th>是否启用水群排行榜</th>
<th>是否启用聊天记录总结</th>
<th>是否启用迎新</th>
<th>是否启用指令</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{ range .groups }}
<tr>
<td>{{ .Wxid }}</td>
<td>{{ .Nickname }}</td>
<td>
{{ if eq .LastActive.IsNil true }}
无数据
{{ else }}
{{ .LastActive }}
{{ end }}
</td>
<td>
{{ if eq .IsOk true }}
<div class="badge badge-info gap-2">
</div>
{{ else }}
<div class="badge badge-error gap-2">
</div>
{{ end }}
</td>
<td>
<!-- EnableAi -->
<label class="swap swap-flip {{ checkSwap .EnableAi }}">
<input type="checkbox" onclick="changeAiEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
{{ if .EnableAi }}
<br />
<select class="select select-success select-xs w-1/2 max-w-xs" onchange="aiModelChange(event, {{.Wxid}})">
<option value="" {{ if eq .AiModel ""}}selected{{ end }}>默认(gpt-3.5-turbo-0613)</option>
{{$useModel := .AiModel}}
{{ range $.aiModels }}
<option value="{{.Model}}" {{ if eq $useModel .Model}}selected{{ end }}>{{.Name}}({{.Model}})</option>
{{ end }}
</select>
{{ end }}
</td>
<td>
<!-- EnableChatRank -->
<label class="swap swap-flip {{ checkSwap .EnableChatRank }}">
<input type="checkbox" onclick="changeGroupRankEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
</td>
<td>
<!-- EnableSummary -->
<label class="swap swap-flip {{ checkSwap .EnableSummary }}">
<input type="checkbox" onclick="changeSummaryEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
</td>
<td>
<label class="swap swap-flip {{ checkSwap .EnableWelcome }}">
<input type="checkbox" onclick="changeWelcomeEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
</td>
<td>
<label class="swap swap-flip {{ checkSwap .EnableCommand }}">
<input type="checkbox" onclick="changeCommandEnableStatus({{.Wxid}})"/>
<div class="swap-on">✔️已启用</div>
<div class="swap-off">❌已禁用</div>
</label>
</td>
<td>
<button class="btn btn-link" onclick="getGroupUsers({{.Wxid}}, {{.Nickname}})">查看群成员</button>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if ne .vnc "" }}
<input type="radio" name="friend_tab" role="tab" class="tab" aria-label="运行状态"/>
<div role="tabpanel" class="tab-content p-6">
<div style="height: 747px;width: 1280px;overflow: hidden !important;">
<iframe src="{{ .vnc }}" frameborder="0" style="width: 100%;height: 100%;pointer-events: none;"></iframe>
</dl>
</div>
</div>
{{ end }}
</div>
</main>
{{ template "footer.html" }}
</div>
</div>
<dialog id="groupUserModal" class="modal">
<div class="modal-box w-11/12 max-w-7xl">
<!-- <form method="dialog">-->
<!-- <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>-->
<!-- </form>-->
<h3 class="font-bold text-lg" id="groupUserModalName">我是群名称</h3>
<!-- 加载动画 -->
<div class="divider divider-warning">成员列表</div>
<!-- 好友列表 -->
<table class="table table-zebra">
<!-- head -->
<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>
</body>
</html>

53
views/notifications.html Normal file
View File

@ -0,0 +1,53 @@
<!-- Global notification live region, render this permanently at the end of the document -->
<div aria-live="assertive" class="pointer-events-none fixed inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6">
<div class="flex w-full flex-col items-center space-y-4 sm:items-end" id="notification">
<!--
Notification panel, dynamically insert this into the live region when it needs to be displayed
Entering: "transform ease-out duration-300 transition"
From: "translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2"
To: "translate-y-0 opacity-100 sm:translate-x-0"
Leaving: "transition ease-in duration-100"
From: "opacity-100"
To: "opacity-0"
-->
<div
class="pointer-events-auto w-full max-w-sm overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5">
<div class="p-4">
<div class="flex items-start">
<div class="flex-shrink-0">
<svg class="h-6 w-6 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm font-medium text-gray-900">通知标题</p>
<p class="mt-1 text-sm text-gray-500">
通知内容,通知内容,通知内容,通知内容,通知内容,通知内容,通知内容,通知内容</p>
</div>
<div class="ml-4 flex flex-shrink-0">
<button type="button"
class="inline-flex rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onclick="closeAlert()">
<span class="sr-only">关闭</span>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function closeAlert() {
const element = document.getElementById("notification");
element.parentNode.parentNode.removeChild(element.parentNode);
}
</script>

429
views/static/css/404.css Normal file
View File

@ -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;
}

BIN
views/static/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

1
views/static/js/404.js Normal file
View File

@ -0,0 +1 @@
// no JS this time !

View File

@ -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();
})
}