Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba837f4cae | ||
|
|
0553424ef9 | ||
|
|
64037863ef | ||
|
|
db2eb62277 | ||
|
|
a3527a6d22 | ||
|
|
8d6618dac1 | ||
|
|
2c5995073f | ||
|
|
315d97895b | ||
|
|
3834af70b5 | ||
|
|
667e62e97e | ||
|
|
55ae8b2acd | ||
|
|
5a7d8407bc | ||
|
|
837a03a87e | ||
|
|
0edbc63bc1 | ||
|
|
9e01f95a61 | ||
|
|
fce8dbbe32 | ||
|
|
43f3581b1c | ||
|
|
9924c1e522 | ||
|
|
e87ac92cd1 | ||
|
|
e24a04a920 | ||
|
|
32017a2fbf | ||
|
|
369898bd7c | ||
|
|
e002e45f82 | ||
|
|
abadcceb19 | ||
|
|
5a07f63716 | ||
|
|
6c338626d6 | ||
|
|
22adc13acf | ||
|
|
432e7ac51a | ||
|
|
dd12dbfe07 | ||
|
|
4fbc896d75 | ||
|
|
603e89e204 | ||
|
|
abd5eb162a | ||
|
|
935bfe17a0 | ||
|
|
671ac2e1f7 | ||
|
|
dc3c45cd53 | ||
|
|
9a9e30f94e | ||
|
|
85b564e2ac | ||
|
|
851eca97ed | ||
|
|
0596599db9 | ||
|
|
40ac52923e | ||
|
|
c9673ca871 | ||
|
|
197c6c86f4 | ||
|
|
a2f328f97e | ||
|
|
c4ab970fb7 | ||
|
|
8fad32e396 | ||
|
|
6f331a07fc | ||
|
|
b4174a6412 | ||
|
|
0381984939 | ||
|
|
6348ace38e | ||
|
|
e8dd1eaa7d | ||
|
|
42cfe232fe | ||
|
|
4ae69706a5 | ||
|
|
3ef328a5a3 | ||
|
|
2b93d27a4e | ||
|
|
97990785cb | ||
|
|
b68c048383 | ||
|
|
f154b9e3c3 | ||
|
|
e2ca0607af | ||
|
|
6afeb65b91 | ||
|
|
e5ab79c40d | ||
|
|
8675fe333d | ||
|
|
fd4ff85191 | ||
|
|
6bf364ec0b | ||
|
|
47ed097923 | ||
|
|
e5cfc80916 | ||
|
|
c7265252d8 | ||
|
|
f6766d3dbd | ||
|
|
7c8b4d9b7c | ||
|
|
348cbcaf96 | ||
|
|
2a35cb4358 | ||
|
|
be6c5b525c | ||
|
|
9ed8aaf142 | ||
|
|
4ed54ca392 | ||
|
|
5173bc0aad | ||
|
|
fec2a43b9c | ||
|
|
32491e9cdd | ||
|
|
fe5c7af7e2 | ||
|
|
156e8b9c9f | ||
|
|
f8aaae42ff | ||
|
|
82379b8823 | ||
|
|
3e40554229 | ||
|
|
e159f9a88e | ||
|
|
c258e0473b | ||
|
|
5dbbf39cce | ||
|
|
50a2781b23 | ||
|
|
a6f7ac41b0 | ||
|
|
c1a6a41575 | ||
|
|
f44e8adb72 | ||
|
|
bd19a594ae | ||
|
|
7aee265721 | ||
|
|
8b30b8241c | ||
|
|
6e65935e3c | ||
|
|
2fb5102add | ||
|
|
68d9bafbdd | ||
|
|
d3d2235ca3 | ||
|
|
26e511113b | ||
|
|
047df08f84 | ||
|
|
27a368b386 | ||
|
|
da60b52be2 | ||
|
|
964746c19b | ||
|
|
99307f1c98 | ||
|
|
7d54bf785a | ||
|
|
5f3f6913b8 | ||
|
|
af2803ef1f | ||
|
|
fdc86ea6bf | ||
|
|
5fac9a0669 | ||
|
|
e5b8db41ea | ||
|
|
845f19fd1c | ||
|
|
ed9cc03514 | ||
|
|
7839dce0e6 | ||
|
|
37d708c5a1 | ||
|
|
16cc4567da | ||
|
|
bb87d01644 | ||
|
|
0a21d7289e | ||
|
|
f7f8cc0ef0 | ||
|
|
ab2b84c9fa | ||
|
|
25abba8eeb | ||
|
|
5a2ed4b2a4 | ||
|
|
82675c7500 | ||
|
|
1b86314c5f | ||
|
|
eff2f54641 | ||
|
|
ed4f186d8e | ||
|
|
a938c6cb23 | ||
|
|
cd354e9e1b | ||
|
|
6b5ef0a911 | ||
|
|
f98f3e146b | ||
|
|
cde4480b51 | ||
|
|
6e08013fd1 | ||
|
|
d7578efa2b | ||
|
|
da880bc6d6 | ||
|
|
673806ba2a | ||
|
|
1a515ef183 | ||
|
|
a04abb0cc8 | ||
|
|
296c9a22a8 | ||
|
|
f93b935ea5 | ||
|
|
e3751d9fa6 | ||
|
|
a6f6f23422 | ||
|
|
8c54914f9a | ||
|
|
33bf0f8625 | ||
|
|
4779214591 | ||
|
|
d53b0c1b62 | ||
|
|
5c3f6ae58d | ||
|
|
204f96e07a | ||
|
|
c89e35d0e0 | ||
|
|
77b19a8157 | ||
|
|
21a5b97ac8 | ||
|
|
543c7b624e | ||
|
|
a2abaef3a6 | ||
|
|
c3676f9744 | ||
|
|
89ba6bcff8 | ||
|
|
642b7ec5da | ||
|
|
5ac3a5b96c | ||
|
|
616d11202e | ||
|
|
b315d20197 | ||
|
|
f711fec00b | ||
|
|
331a55751d | ||
|
|
0397fe5f22 |
@@ -0,0 +1,68 @@
|
|||||||
|
name: Deploy im-manager production
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- pro
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: production-im-manager
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: git.olns.shop
|
||||||
|
IMAGE: git.olns.shop/pro/im_manager
|
||||||
|
SERVICE: im-manager
|
||||||
|
DEPLOY_HOST: 145.223.69.9
|
||||||
|
DEPLOY_USER: olns-deploy
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: deploy-host
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Log in to Gitea Container Registry
|
||||||
|
env:
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY" -u admin --password-stdin
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
env:
|
||||||
|
GITHUB_SHA: ${{ github.sha }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
SHORT_SHA="$(printf '%.12s' "$GITHUB_SHA")"
|
||||||
|
docker build -t "${IMAGE}:pro" -t "${IMAGE}:${SHORT_SHA}" .
|
||||||
|
docker push "$IMAGE:pro"
|
||||||
|
docker push "$IMAGE:$SHORT_SHA"
|
||||||
|
|
||||||
|
- name: Deploy Compose service
|
||||||
|
env:
|
||||||
|
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||||
|
DEPLOY_KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
install -d -m 700 "$HOME/.ssh"
|
||||||
|
KEY_FILE="$(mktemp "$HOME/.ssh/olns-deploy.XXXXXX")"
|
||||||
|
cleanup() {
|
||||||
|
shred -u "$KEY_FILE" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
printf '%s\n' "$DEPLOY_SSH_KEY" > "$KEY_FILE"
|
||||||
|
chmod 600 "$KEY_FILE"
|
||||||
|
printf '%s\n' "$DEPLOY_KNOWN_HOSTS" > "$HOME/.ssh/known_hosts"
|
||||||
|
chmod 600 "$HOME/.ssh/known_hosts"
|
||||||
|
SSH_ARGS=(-i "$KEY_FILE" -o BatchMode=yes -o StrictHostKeyChecking=yes)
|
||||||
|
printf '%s' "$REGISTRY_TOKEN" | ssh "${SSH_ARGS[@]}" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||||||
|
"docker login git.olns.shop -u admin --password-stdin"
|
||||||
|
ssh "${SSH_ARGS[@]}" "$DEPLOY_USER@$DEPLOY_HOST" \
|
||||||
|
"cd /opt/olns && docker compose pull im-manager && docker compose up -d --no-deps --wait im-manager"
|
||||||
@@ -163,3 +163,6 @@ dist
|
|||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
# Trae local debugging artifacts
|
||||||
|
.trae/
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/im_manager.iml" filepath="$PROJECT_DIR$/.idea/im_manager.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,960 @@
|
|||||||
|
# HotGo 项目开发规范
|
||||||
|
|
||||||
|
**生成或修改任何代码前,必须完整阅读本文档。**
|
||||||
|
本规范是项目唯一事实来源,所有新增代码必须严格对齐现有模块风格,不得自创新的代码模式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
| 层 | 技术 |
|
||||||
|
|----|----------------------------------------------------------------|
|
||||||
|
| 后端语言 | Go,module 名 `hotgo` |
|
||||||
|
| 后端框架 | GoFrame v2(gdb、ghttp、gcron、gerror、gctx、gerror、gjson、gvar) |
|
||||||
|
| 前端框架 | Vue 3 + Vite + TypeScript |
|
||||||
|
| UI 组件库 | **Naive UI**(优先使用,未经允许不得引入其他 UI 库) |
|
||||||
|
| 状态管理 | Pinia |
|
||||||
|
| HTTP 客户端 | 项目封装 `@/utils/http/axios`(`http.request`),禁止直接使用 axios |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后端目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
server/
|
||||||
|
├── addons/ # 插件模块(每个插件独立微架构,见"插件开发"章节)
|
||||||
|
│ ├── modules/ # 隐式注册文件(每个插件一个 .go,仅含 import)
|
||||||
|
│ └── <addonName>/ # 插件目录,与主模块结构镜像
|
||||||
|
├── api/admin/<module>/ # 主模块 HTTP 契约:Req/Res + g.Meta 路由声明
|
||||||
|
├── internal/
|
||||||
|
│ ├── consts/ # 全局常量与字典选项(枚举在此定义并注册)
|
||||||
|
│ ├── global/ # 全局公用变量(谨慎添加,尽量少用)
|
||||||
|
│ ├── controller/admin/sys/ # 薄控制器,只做参数透传,不含业务逻辑
|
||||||
|
│ ├── crons/ # 主模块定时任务注册与处理
|
||||||
|
│ ├── queues/ # 主模块消息队列消费者注册与处理
|
||||||
|
│ ├── logic/sys/ # 业务实现(sSysXxx),init() 注册到 service
|
||||||
|
│ ├── library/ # 内部基础库(addons、dict、hgorm、cache、queue、cron 等)
|
||||||
|
│ ├── service/ # 接口声明(ISysXxx)+ 注册函数
|
||||||
|
│ ├── dao/ # 对外 DAO;internal/dao/internal/ 为 CLI 生成,禁止手改
|
||||||
|
│ ├── model/
|
||||||
|
│ │ ├── entity/ # 表结构体(CLI 生成,禁止手改)
|
||||||
|
│ │ ├── do/ # ORM 写入结构(CLI 生成,禁止手改)
|
||||||
|
│ │ └── input/sysin/ # 业务入参、出参、过滤结构
|
||||||
|
│ └── router/
|
||||||
|
│ ├── admin.go # 主路由,末尾调用 genrouter.Register()
|
||||||
|
│ └── genrouter/ # 每个生成模块一个文件,init() 追加到 LoginRequiredRouter
|
||||||
|
├── resource/
|
||||||
|
│ ├── generate/default/curd/ # 主模块 CRUD 代码生成模板(参考,禁止直接修改)
|
||||||
|
│ └── generate/default/addon/ # 插件脚手架代码生成模板(参考,禁止直接修改)
|
||||||
|
└── utility/ # 通用工具:convert、excel、validate 等
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后端分层约定
|
||||||
|
|
||||||
|
### 分层职责(禁止跨层调用)
|
||||||
|
|
||||||
|
```
|
||||||
|
api(HTTP契约) → controller(参数透传) → service(接口) → logic(业务实现) → dao(数据访问)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **controller 层**:不写任何业务逻辑,只转调 service
|
||||||
|
- **logic 层**:不出现 HTTP 相关代码,所有校验通过 `Filter()` 或 `g.Validator()` 完成
|
||||||
|
- **dao 层**:`internal/dao/internal/` 由 CLI 自动生成,禁止手改
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. API 层 `api/admin/<module>/<module>.go`
|
||||||
|
|
||||||
|
- 每个接口一对 `XxxReq` / `XxxRes`,`g.Meta` 声明路由
|
||||||
|
- GET 接口用 `method:"get"`,写操作用 `method:"post"`
|
||||||
|
- 请求体嵌入 `sysin.XxxInp`,响应体嵌入对应 Model 或空 `struct{}`
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ListReq struct {
|
||||||
|
g.Meta `path:"/xxxModule/list" method:"get" tags:"XXX模块" summary:"获取XXX列表"`
|
||||||
|
sysin.XxxListInp
|
||||||
|
}
|
||||||
|
type ListRes struct {
|
||||||
|
form.PageRes
|
||||||
|
List []*sysin.XxxListModel `json:"list" dc:"数据列表"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Controller 层 `internal/controller/admin/sys/<module>.go`
|
||||||
|
|
||||||
|
- 变量:`var XxxModule = cXxxModule{}`,类型:`type cXxxModule struct{}`
|
||||||
|
- 只做参数转发和结果组装,禁止直接操作 dao 或写业务逻辑
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *cXxxModule) List(ctx context.Context, req *xxxmodule.ListReq) (res *xxxmodule.ListRes, err error) {
|
||||||
|
list, totalCount, err := service.SysXxxModule().List(ctx, &req.XxxListInp)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if list == nil {
|
||||||
|
list = []*sysin.XxxListModel{}
|
||||||
|
}
|
||||||
|
res = new(xxxmodule.ListRes)
|
||||||
|
res.List = list
|
||||||
|
res.PageRes.Pack(req, totalCount)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Service 层 `internal/service/sys.go`
|
||||||
|
|
||||||
|
- 在已有文件中**追加**接口声明和注册函数,禁止新建文件
|
||||||
|
- 声明 `ISysXxxModule` 接口,提供 `SysXxxModule()` 获取函数和 `RegisterSysXxxModule()` 注册函数
|
||||||
|
|
||||||
|
### 4. Logic 层 `internal/logic/sys/<module>.go`
|
||||||
|
|
||||||
|
- 结构体:`type sSysXxxModule struct{}`
|
||||||
|
- `init()` 里调用 `service.RegisterSysXxxModule(NewSysXxxModule())`
|
||||||
|
- `Model()` 方法:`return handler.Model(dao.XxxTable.Ctx(ctx), option...)`
|
||||||
|
- 列名引用必须用 `dao.XxxTable.Columns().FieldName`,禁止硬编码字符串字段名
|
||||||
|
- `Edit` 方法以 `in.Id > 0` 区分更新/新增,更新用 `XxxUpdateFields`,新增用 `XxxInsertFields`
|
||||||
|
- 字段校验在 `sysin` 的 `Filter(ctx)` 方法完成,logic 层不重复校验
|
||||||
|
|
||||||
|
### 5. Model 层 `internal/model/input/sysin/<module>.go`
|
||||||
|
|
||||||
|
| 类型 | 用途 |
|
||||||
|
|------|------|
|
||||||
|
| `XxxUpdateFields` | 更新时字段白名单 |
|
||||||
|
| `XxxInsertFields` | 新增时字段白名单 |
|
||||||
|
| `XxxEditInp` | 嵌入 `entity.XxxTable`,含 `Filter()` 校验方法 |
|
||||||
|
| `XxxListInp` | 列表查询入参,嵌入 `form.PageInp` |
|
||||||
|
| `XxxListModel` | 列表返回字段 |
|
||||||
|
| `XxxViewInp` / `XxxViewModel` | 详情入参/出参 |
|
||||||
|
| `XxxDeleteInp` | 删除入参(通常含 `Ids []int64`) |
|
||||||
|
| `XxxStatusInp`、`XxxMaxSortInp` 等 | 其他操作 |
|
||||||
|
|
||||||
|
### 6. 路由注册 `internal/router/genrouter/<module>.go`
|
||||||
|
|
||||||
|
```go
|
||||||
|
package genrouter
|
||||||
|
|
||||||
|
import "hotgo/internal/controller/admin/sys"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
LoginRequiredRouter = append(LoginRequiredRouter, sys.XxxModule) // XXX模块
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
新建此文件即可,`genrouter/init.go` 通过 `init()` 链自动加载,无需修改 `admin.go`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 字典与枚举规范
|
||||||
|
|
||||||
|
**字典由后端统一维护**,前端通过固定接口拉取,禁止在前端硬编码枚举值。
|
||||||
|
|
||||||
|
### 后端:定义与注册(`internal/consts/` 下对应文件)
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 1. 定义常量
|
||||||
|
const (
|
||||||
|
XxxStatusEnabled = 1 // 启用
|
||||||
|
XxxStatusDisable = 2 // 禁用
|
||||||
|
)
|
||||||
|
|
||||||
|
// 2. 定义选项(选择合适的样式函数)
|
||||||
|
var XxxStatusOptions = []*model.Option{
|
||||||
|
dict.GenSuccessOption(XxxStatusEnabled, "启用"),
|
||||||
|
dict.GenWarningOption(XxxStatusDisable, "禁用"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 在 init() 中注册(同文件)
|
||||||
|
func init() {
|
||||||
|
dict.RegisterEnums("XxxStatusOptions", "XXX状态选项", XxxStatusOptions)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**样式函数选择规则:**
|
||||||
|
|
||||||
|
| 函数 | 适用场景 |
|
||||||
|
|------|---------|
|
||||||
|
| `dict.GenSuccessOption` | 正常、启用、成功 |
|
||||||
|
| `dict.GenWarningOption` | 待处理、禁用、警告 |
|
||||||
|
| `dict.GenErrorOption` | 失败、封禁、危险 |
|
||||||
|
| `dict.GenInfoOption` | 信息类、中性状态 |
|
||||||
|
| `dict.GenPrimaryOption` | 主要操作、强调 |
|
||||||
|
| `dict.GenDefaultOption` | 默认、无特殊含义 |
|
||||||
|
| `dict.GenHashOption` | 不确定数量的动态枚举 |
|
||||||
|
|
||||||
|
### 后端:Logic 层中使用字典
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 获取标签文本
|
||||||
|
label := dict.GetOptionLabel(consts.XxxStatusOptions, in.Status)
|
||||||
|
|
||||||
|
// 校验是否为合法值
|
||||||
|
if !dict.HasOptionKey(consts.XxxStatusOptions, in.Status) {
|
||||||
|
return gerror.New("状态值不合法")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 前端:加载与使用字典
|
||||||
|
|
||||||
|
**加载**(在 `model.ts` 的 `loadOptions()` 中):
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export function loadOptions() {
|
||||||
|
dict.loadOptions(['XxxStatusOptions', 'sys_normal_disable']);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**在 `model.ts` 的 columns 中渲染字典标签:**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { useDictStore } from '@/store/modules/dict';
|
||||||
|
const dict = useDictStore();
|
||||||
|
|
||||||
|
// columns 中
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
render(row) {
|
||||||
|
return dict.getLabel('XxxStatusOptions', row.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**在搜索表单 schemas 中使用字典下拉:**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
component: 'NSelect',
|
||||||
|
label: '状态',
|
||||||
|
componentProps: {
|
||||||
|
options: computed(() => dict.getOptions('XxxStatusOptions')),
|
||||||
|
placeholder: '请选择状态',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 插件(Addon)开发规范
|
||||||
|
|
||||||
|
> 定位:独立、临时性、工具类型的功能推荐插件化开发,例如小游戏、广告管理、文章管理、小程序、微商城等。插件之间完全隔离,方便多项目复用。
|
||||||
|
|
||||||
|
### 插件目录结构
|
||||||
|
|
||||||
|
每个插件拥有完整的独立微架构,与主模块结构镜像,但 **包路径前缀为 `hotgo/addons/<addonName>/`**:
|
||||||
|
|
||||||
|
```
|
||||||
|
server/addons/<addonName>/
|
||||||
|
├── main.go # 插件入口:定义 module 结构体,实现 Module 接口,init() 注册
|
||||||
|
├── global/
|
||||||
|
│ ├── global.go # 插件级全局变量
|
||||||
|
│ └── init.go # Init(ctx, skeleton),GetSkeleton() 方法
|
||||||
|
├── api/
|
||||||
|
│ ├── admin/ # 后台接口契约(同主模块 api 写法)
|
||||||
|
│ ├── api/ # 前台 API 接口契约
|
||||||
|
│ └── home/ # 首页接口契约(如有)
|
||||||
|
├── controller/
|
||||||
|
│ ├── admin/sys/ # 后台薄控制器
|
||||||
|
│ ├── api/ # 前台控制器
|
||||||
|
│ └── home/ # 首页控制器(如有)
|
||||||
|
├── logic/
|
||||||
|
│ ├── logic.go # 匿名导入各 logic 子包触发 init()
|
||||||
|
│ └── sys/ # 业务实现(同主模块 logic 写法)
|
||||||
|
├── service/ # 插件内接口声明与注册(独立,不与主模块 service 混用)
|
||||||
|
├── model/
|
||||||
|
│ └── input/sysin/ # 插件内入参/出参(调用主模块服务时继承主模块 input 结构)
|
||||||
|
├── router/
|
||||||
|
│ ├── admin.go # 注册后台路由,使用 addons.RouterPrefix() 获取路由前缀
|
||||||
|
│ ├── api.go # 注册前台路由
|
||||||
|
│ ├── home.go # 注册首页路由(如有)
|
||||||
|
│ ├── websocket.go # 注册 WebSocket 路由(如有)
|
||||||
|
│ └── genrouter/
|
||||||
|
│ ├── init.go # 插件版 genrouter:Register() 使用插件前缀
|
||||||
|
│ └── *.go # 每个生成模块一个文件,追加到插件 LoginRequiredRouter
|
||||||
|
├── consts/ # 插件内常量与字典(同主模块 consts 写法)
|
||||||
|
├── crons/ # 插件定时任务(可选)
|
||||||
|
├── queues/ # 插件消息队列消费者(可选)
|
||||||
|
└── resource/ # 插件静态资源与模板(可选)
|
||||||
|
```
|
||||||
|
|
||||||
|
**对应前端目录:**
|
||||||
|
|
||||||
|
```
|
||||||
|
web/src/
|
||||||
|
├── api/addons/<addonName>/ # 插件前端 API 封装
|
||||||
|
└── views/addons/<addonName>/ # 插件前端页面
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件入口 `main.go`
|
||||||
|
|
||||||
|
```go
|
||||||
|
package <addonName>
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
|
_ "hotgo/addons/<addonName>/crons"
|
||||||
|
"hotgo/addons/<addonName>/global"
|
||||||
|
_ "hotgo/addons/<addonName>/logic"
|
||||||
|
_ "hotgo/addons/<addonName>/queues"
|
||||||
|
"hotgo/addons/<addonName>/router"
|
||||||
|
"hotgo/internal/library/addons"
|
||||||
|
"hotgo/internal/service"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type module struct {
|
||||||
|
skeleton *addons.Skeleton
|
||||||
|
ctx context.Context
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { newModule() }
|
||||||
|
|
||||||
|
func newModule() {
|
||||||
|
m := &module{
|
||||||
|
skeleton: &addons.Skeleton{
|
||||||
|
Label: "插件显示名",
|
||||||
|
Name: "<addonName>", // 与目录名一致
|
||||||
|
Group: 1,
|
||||||
|
Brief: "简介",
|
||||||
|
Description: "详细描述",
|
||||||
|
Author: "作者",
|
||||||
|
Version: "v1.0.0",
|
||||||
|
},
|
||||||
|
ctx: gctx.New(),
|
||||||
|
}
|
||||||
|
addons.RegisterModule(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *module) Start(option *addons.Option) (err error) {
|
||||||
|
global.Init(m.ctx, m.skeleton)
|
||||||
|
option.Server.Group("/", func(group *ghttp.RouterGroup) {
|
||||||
|
group.Middleware(service.Middleware().Addon)
|
||||||
|
router.Admin(m.ctx, group)
|
||||||
|
router.Api(m.ctx, group)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 其余方法:Stop、Ctx、GetSkeleton、Install、Upgrade、UnInstall(默认留空)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件路由前缀规则
|
||||||
|
|
||||||
|
```
|
||||||
|
后台:/admin/<addonName>/接口路径 → 对应 controller/admin/sys/
|
||||||
|
前台:/api/<addonName>/接口路径 → 对应 controller/api/
|
||||||
|
首页:/home/<addonName>/接口路径 → 对应 controller/home/
|
||||||
|
WebSocket:/socket/<addonName>/接口路径
|
||||||
|
```
|
||||||
|
|
||||||
|
路由前缀通过 `addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)` 自动生成,**禁止在路由文件里硬编码路径前缀**。
|
||||||
|
|
||||||
|
### 插件 genrouter 与主模块的区别
|
||||||
|
|
||||||
|
插件 `genrouter/init.go` 的 `Register()` 函数需要传入 `ctx` 和 `group`,并使用插件路由前缀:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 插件 genrouter/init.go
|
||||||
|
func Register(ctx context.Context, group *ghttp.RouterGroup) {
|
||||||
|
prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
|
||||||
|
group.Group(prefix, func(group *ghttp.RouterGroup) {
|
||||||
|
group.Middleware(service.Middleware().AdminAuth)
|
||||||
|
if len(LoginRequiredRouter) > 0 {
|
||||||
|
group.Bind(LoginRequiredRouter...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插件 genrouter/<module>.go
|
||||||
|
func init() {
|
||||||
|
LoginRequiredRouter = append(LoginRequiredRouter, sys.XxxModule)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
参考实现:`server/addons/hgexample/router/genrouter/`
|
||||||
|
|
||||||
|
### 插件调用主模块服务
|
||||||
|
|
||||||
|
**在插件 input 层继承主模块 input 结构,解耦参数依赖**,避免 import cycle:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 插件 model/input/sysin/config.go
|
||||||
|
package sysin
|
||||||
|
|
||||||
|
import "hotgo/internal/model/input/sysin"
|
||||||
|
|
||||||
|
type UpdateConfigInp struct {
|
||||||
|
sysin.UpdateAddonsConfigInp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 插件 logic 中调用主模块服务
|
||||||
|
import isc "hotgo/internal/service"
|
||||||
|
|
||||||
|
func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error {
|
||||||
|
in.UpdateAddonsConfigInp.AddonName = global.GetSkeleton().Name
|
||||||
|
return isc.SysAddonsConfig().UpdateConfigByGroup(ctx, in.UpdateAddonsConfigInp)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件获取自身信息
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 插件内部
|
||||||
|
global.GetSkeleton()
|
||||||
|
|
||||||
|
// 任意位置判断当前请求是否为插件请求
|
||||||
|
contexts.IsAddonRequest(ctx)
|
||||||
|
contexts.GetAddonName(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件隐式注册
|
||||||
|
|
||||||
|
在 `server/addons/modules/` 下新建 `<addonName>.go`,内容仅含一行匿名导入:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import _ "hotgo/addons/<addonName>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 新增插件检查清单
|
||||||
|
|
||||||
|
**后端:**
|
||||||
|
- [ ] `addons/<addonName>/main.go` — 插件入口,实现 Module 接口
|
||||||
|
- [ ] `addons/<addonName>/global/` — global.go + init.go
|
||||||
|
- [ ] `addons/modules/<addonName>.go` — 隐式注册
|
||||||
|
- [ ] `addons/<addonName>/service/` — 插件内接口声明(独立包)
|
||||||
|
- [ ] `addons/<addonName>/logic/logic.go` — 匿名导入触发 init()
|
||||||
|
- [ ] `addons/<addonName>/logic/sys/<module>.go` — 业务实现
|
||||||
|
- [ ] `addons/<addonName>/model/input/sysin/<module>.go` — 入参/出参
|
||||||
|
- [ ] `addons/<addonName>/api/admin/<module>/<module>.go` — API 契约
|
||||||
|
- [ ] `addons/<addonName>/controller/admin/sys/<module>.go` — 薄控制器
|
||||||
|
- [ ] `addons/<addonName>/router/admin.go` — 路由注册
|
||||||
|
- [ ] `addons/<addonName>/router/genrouter/init.go` — 插件 genrouter
|
||||||
|
- [ ] `addons/<addonName>/router/genrouter/<module>.go` — 模块路由追加
|
||||||
|
|
||||||
|
**前端:**
|
||||||
|
- [ ] `web/src/api/addons/<addonName>/index.ts` — API 封装
|
||||||
|
- [ ] `web/src/views/addons/<addonName>/model.ts` — State、schemas、columns
|
||||||
|
- [ ] `web/src/views/addons/<addonName>/index.vue` — 列表页
|
||||||
|
- [ ] `web/src/views/addons/<addonName>/edit.vue` — 编辑页
|
||||||
|
|
||||||
|
参考实现:`server/addons/hgexample/`(完整插件示例)、`server/resource/generate/default/addon/`(生成模板)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 标准 CRUD 接口清单
|
||||||
|
|
||||||
|
| 接口 | method | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| `/xxx/list` | GET | 分页列表 |
|
||||||
|
| `/xxx/view` | GET | 详情 |
|
||||||
|
| `/xxx/edit` | POST | 新增/编辑(id>0 为编辑) |
|
||||||
|
| `/xxx/delete` | POST | 删除(支持批量,传 ids) |
|
||||||
|
| `/xxx/status` | POST | 启用/禁用状态切换 |
|
||||||
|
| `/xxx/switch` | POST | 开关字段切换 |
|
||||||
|
| `/xxx/maxSort` | GET | 获取最大排序值 |
|
||||||
|
| `/xxx/export` | GET | 导出列表 |
|
||||||
|
|
||||||
|
按实际需求裁剪,不强制全部实现。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 前端目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
web/src/
|
||||||
|
├── api/<module>/index.ts # HTTP 请求封装
|
||||||
|
├── views/<module>/
|
||||||
|
│ ├── index.vue # 列表页
|
||||||
|
│ ├── edit.vue # 新增/编辑弹窗
|
||||||
|
│ └── model.ts # State 类、rules、schemas、columns、loadOptions
|
||||||
|
├── components/ # 通用组件(BasicTable、BasicForm、BasicModal 等)
|
||||||
|
├── store/modules/dict.ts # 字典 store(loadOptions、getLabel、getOptions)
|
||||||
|
└── utils/
|
||||||
|
├── http/axios.ts # HTTP 封装(http.request / jumpExport)
|
||||||
|
└── dateUtil.ts # 日期工具(defRangeShortcuts 等)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 前端编码约定
|
||||||
|
|
||||||
|
### API 文件 `api/<module>/index.ts`
|
||||||
|
|
||||||
|
- 使用 `http.request`,禁止直接使用 axios
|
||||||
|
- 函数名与接口语义一致:`List`、`Edit`、`Delete`、`View`、`Status`、`Switch`、`Export`、`MaxSort`
|
||||||
|
- 导出接口用 `jumpExport('/xxx/export', params)`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { http, jumpExport } from '@/utils/http/axios';
|
||||||
|
|
||||||
|
export function List(params) {
|
||||||
|
return http.request({ url: '/xxxModule/list', method: 'get', params });
|
||||||
|
}
|
||||||
|
export function Edit(params) {
|
||||||
|
return http.request({ url: '/xxxModule/edit', method: 'POST', params });
|
||||||
|
}
|
||||||
|
export function Export(params) {
|
||||||
|
jumpExport('/xxxModule/export', params);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### model.ts 结构
|
||||||
|
|
||||||
|
- `class State`:属性与后端 entity 字段对应,提供合理默认值
|
||||||
|
- `newState()`:工厂函数,支持深拷贝(`cloneDeep`)
|
||||||
|
- `rules`:Naive UI 表单校验规则
|
||||||
|
- `schemas`:搜索栏 `FormSchema[]`(`ref` 包装)
|
||||||
|
- `columns`:表格列定义,含权限守卫的操作用 `hasPermission(['/xxx/edit'])`
|
||||||
|
- `loadOptions()`:调用 `dict.loadOptions([...])`,预加载字典数据
|
||||||
|
|
||||||
|
### 组件使用规范
|
||||||
|
|
||||||
|
**必须优先使用 Naive UI 原生组件**,能用 Naive UI 实现的禁止自行封装替代组件:
|
||||||
|
|
||||||
|
| 场景 | 必须使用的组件 |
|
||||||
|
|------|--------------|
|
||||||
|
| 表格 | 项目封装 `BasicTable`(基于 Naive UI) |
|
||||||
|
| 表单 | 项目封装 `BasicForm`(基于 Naive UI) |
|
||||||
|
| 弹窗 | `n-modal` 或项目封装 `BasicModal` |
|
||||||
|
| 按钮 | `n-button`,类型用 `primary`/`default`/`error` 等语义值 |
|
||||||
|
| 选择器 | `n-select`(字典下拉)、`n-tree-select`(树形) |
|
||||||
|
| 开关 | `n-switch`,配合 Switch 接口 |
|
||||||
|
| 输入框 | `n-input` |
|
||||||
|
| 日期选择 | `n-date-picker`,范围选择配合 `defRangeShortcuts()` |
|
||||||
|
| 图片渲染 | `renderImage(url)` |
|
||||||
|
| 文件渲染 | `renderFile(url)` |
|
||||||
|
| 成员信息 | `renderPopoverMemberSumma(summa)` |
|
||||||
|
|
||||||
|
**禁止行为:**
|
||||||
|
- 禁止引入 Element Plus、Ant Design Vue 等其他 UI 库
|
||||||
|
- 禁止使用内联 style(使用 Naive UI 的 props 或 class)
|
||||||
|
- 禁止在模板里硬编码字典值文本,必须通过 `dict.getLabel()` 渲染
|
||||||
|
|
||||||
|
### 权限控制
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { usePermission } from '@/hooks/web/usePermission';
|
||||||
|
const { hasPermission } = usePermission();
|
||||||
|
|
||||||
|
// 模板中
|
||||||
|
v-if="hasPermission(['/xxxModule/edit'])"
|
||||||
|
|
||||||
|
// columns 中开关操作
|
||||||
|
disabled: !hasPermission(['/xxxModule/switch'])
|
||||||
|
```
|
||||||
|
|
||||||
|
权限标识与后端路由路径保持一致,**路由由后端菜单数据驱动,禁止在源码里硬编码路由路径**。
|
||||||
|
|
||||||
|
### Vue 3 代码规范
|
||||||
|
|
||||||
|
- 使用 Composition API(`<script setup>`)
|
||||||
|
- 响应式数据用 `ref` / `reactive`,计算属性用 `computed`
|
||||||
|
- 字典选项传给组件时用 `computed(() => dict.getOptions('XxxOptions'))`,保持响应式
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 新增 CRUD 模块检查清单
|
||||||
|
|
||||||
|
**后端(必须全部完成,顺序建议从下往上):**
|
||||||
|
|
||||||
|
- [ ] `internal/consts/<module>.go` — 常量定义、选项变量、`init()` 注册字典
|
||||||
|
- [ ] 使用 goframe CLI 生成:`entity`、`do`、`dao/internal`、`dao`(禁止手写)
|
||||||
|
- [ ] `internal/model/input/sysin/<module>.go` — 入参/出参/过滤模型
|
||||||
|
- [ ] `internal/service/sys.go` — 追加接口声明与注册函数
|
||||||
|
- [ ] `internal/logic/sys/<module>.go` — 业务实现
|
||||||
|
- [ ] `internal/controller/admin/sys/<module>.go` — 薄控制器
|
||||||
|
- [ ] `api/admin/<module>/<module>.go` — API 契约
|
||||||
|
- [ ] `internal/router/genrouter/<module>.go` — 路由注册(`LoginRequiredRouter` 追加)
|
||||||
|
|
||||||
|
**前端(必须全部完成):**
|
||||||
|
|
||||||
|
- [ ] `web/src/api/<module>/index.ts` — HTTP 封装
|
||||||
|
- [ ] `web/src/views/<module>/model.ts` — State、schemas、columns、rules、loadOptions
|
||||||
|
- [ ] `web/src/views/<module>/index.vue` — 列表页
|
||||||
|
- [ ] `web/src/views/<module>/edit.vue` — 编辑页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考实现
|
||||||
|
|
||||||
|
**所有新模块必须严格对齐以下文件的风格,生成前请逐一阅读:**
|
||||||
|
|
||||||
|
**主模块 CRUD 参考:**
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `server/internal/consts/status.go` | 字典常量定义与注册标准写法 |
|
||||||
|
| `server/api/admin/curddemo/curddemo.go` | API 契约标准写法 |
|
||||||
|
| `server/internal/controller/admin/sys/curd_demo.go` | 薄控制器标准写法 |
|
||||||
|
| `server/internal/logic/sys/curd_demo.go` | Logic 标准写法(含关联查询、导出、字段过滤) |
|
||||||
|
| `server/internal/model/input/sysin/curd_demo.go` | 入参/出参模型标准写法 |
|
||||||
|
| `server/internal/router/genrouter/curd_demo.go` | 主模块路由注册标准写法 |
|
||||||
|
| `web/src/api/curdDemo/index.ts` | 前端 API 封装标准写法 |
|
||||||
|
| `web/src/views/curdDemo/model.ts` | 前端 model 标准写法(含字典加载) |
|
||||||
|
| `web/src/views/curdDemo/index.vue` | 列表页标准写法 |
|
||||||
|
| `web/src/views/curdDemo/edit.vue` | 编辑页标准写法 |
|
||||||
|
|
||||||
|
**插件参考(以 hgexample 为标准):**
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `server/addons/hgexample/main.go` | 插件入口标准写法 |
|
||||||
|
| `server/addons/hgexample/global/init.go` | 插件 global 标准写法 |
|
||||||
|
| `server/addons/hgexample/router/admin.go` | 插件路由注册标准写法 |
|
||||||
|
| `server/addons/hgexample/router/genrouter/init.go` | 插件 genrouter 标准写法 |
|
||||||
|
| `server/addons/hgexample/router/genrouter/tenant_order.go` | 插件模块路由追加标准写法 |
|
||||||
|
| `server/addons/hgexample/logic/sys/tenant_order.go` | 插件业务逻辑标准写法 |
|
||||||
|
| `server/addons/hgexample/logic/sys/config.go` | 插件调用主模块服务标准写法 |
|
||||||
|
|
||||||
|
代码生成模板:
|
||||||
|
- 主模块 CRUD:`server/resource/generate/default/curd/`
|
||||||
|
- 插件脚手架:`server/resource/generate/default/addon/`
|
||||||
|
|
||||||
|
以上模板可参考逻辑,**禁止直接修改模板文件**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 错误处理规范
|
||||||
|
|
||||||
|
### 基本原则
|
||||||
|
|
||||||
|
- 业务错误直接用 `gerror.New("描述清晰的中文信息")` 返回,GoFrame 框架会统一处理响应码
|
||||||
|
- 错误信息要面向用户,清晰说明**发生了什么**,而不是堆栈路径
|
||||||
|
|
||||||
|
### 错误创建方式
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/gogf/gf/v2/errors/gerror"
|
||||||
|
|
||||||
|
// 普通业务错误(最常用)
|
||||||
|
return gerror.New("用户名已存在")
|
||||||
|
|
||||||
|
// 包装底层错误,追加上下文(调用第三方/dao 层出错时使用)
|
||||||
|
if err := dao.User.Ctx(ctx).Data(data).Insert(); err != nil {
|
||||||
|
return gerror.Wrap(err, "创建用户失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 带格式化参数
|
||||||
|
return gerror.Newf("订单 %d 状态不合法,当前状态:%d", in.Id, order.Status)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误传递原则
|
||||||
|
|
||||||
|
- **logic 层**:遇到底层错误用 `gerror.Wrap` 追加上下文后返回;纯业务校验失败用 `gerror.New` 直接返回
|
||||||
|
- **controller 层**:直接 `return` 透传 logic 的 error,**不再包装**,不打印日志(框架统一处理)
|
||||||
|
- **禁止**在 controller 层 `fmt.Println(err)` 或 `g.Log().Error` 打印已经会被框架记录的错误
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 缓存使用规范
|
||||||
|
|
||||||
|
### 统一使用 `cache.Instance()`
|
||||||
|
|
||||||
|
**禁止直接调用 `g.Redis().Do()`**,项目统一通过 `cache.Instance()` 操作缓存,底层适配器(Memory / Redis / File)由配置决定,业务层无需关心。
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"hotgo/internal/library/cache"
|
||||||
|
"github.com/gogf/gf/v2/os/gcache"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 设置缓存(带过期时间)
|
||||||
|
err := cache.Instance().Set(ctx, "user:info:1", userInfo, 30*time.Minute)
|
||||||
|
|
||||||
|
// 获取缓存
|
||||||
|
val, err := cache.Instance().Get(ctx, "user:info:1")
|
||||||
|
if err != nil || val.IsNil() {
|
||||||
|
// 缓存未命中,查数据库
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除缓存
|
||||||
|
_, err = cache.Instance().Remove(ctx, "user:info:1")
|
||||||
|
|
||||||
|
// GetOrSet:缓存不存在时自动执行函数并写入(推荐用于只读类缓存)
|
||||||
|
val, err := cache.Instance().GetOrSet(ctx, "user:info:1", func(ctx context.Context) (interface{}, error) {
|
||||||
|
return dao.AdminMember.Ctx(ctx).Where(...).One()
|
||||||
|
}, 30*time.Minute)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 缓存 Key 命名规范
|
||||||
|
|
||||||
|
- 格式:`模块:实体:唯一标识`,例如:`user:info:1`、`config:site:basic`、`dict:options:XxxStatus`
|
||||||
|
- 同一模块的 Key 统一在 `internal/consts/cache.go`(或对应模块的 consts 文件)中定义为常量,禁止散落在 logic 里硬编码
|
||||||
|
- 插件缓存 Key 加插件名前缀:`hgexample:order:1`
|
||||||
|
|
||||||
|
### 缓存使用原则
|
||||||
|
|
||||||
|
- 更新或删除数据后,**主动清除**相关缓存,不依赖过期自动失效
|
||||||
|
- 缓存时间:频繁更新的数据(配置、状态)用较短时间(5~30 分钟);基本不变的数据(字典、枚举)可用更长时间
|
||||||
|
- 缓存穿透场景:查询结果为空时也写入短时缓存(如 1 分钟)防止击穿
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 日志规范
|
||||||
|
|
||||||
|
### 日志级别选择
|
||||||
|
|
||||||
|
| 级别 | 方法 | 适用场景 |
|
||||||
|
|------|------|---------|
|
||||||
|
| Info | `g.Log().Info` / `g.Log().Infof` | 正常业务流程的关键节点(登录成功、订单创建、支付回调等) |
|
||||||
|
| Warning | `g.Log().Warning` / `g.Log().Warningf` | **遇到错误但不影响主流程**(重试、降级、外部服务异常、非致命校验失败) |
|
||||||
|
| Panic | `g.Log().Panic` / `g.Log().Panicf` | 极其严重、必须立即终止的情况(配置缺失、核心依赖不可用) |
|
||||||
|
|
||||||
|
### 使用示例
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Info:记录正常流程关键事件
|
||||||
|
g.Log().Infof(ctx, "用户登录成功 uid:%d ip:%s", member.Id, ip)
|
||||||
|
|
||||||
|
// Info:记录外部调用结果
|
||||||
|
g.Log().Info(ctx, "支付回调处理完成", g.Map{"orderId": orderId, "status": status})
|
||||||
|
|
||||||
|
// Warning:外部接口失败但已降级处理
|
||||||
|
g.Log().Warningf(ctx, "短信发送失败,已跳过 mobile:%s err:%+v", mobile, err)
|
||||||
|
|
||||||
|
// Warning:业务异常但不中断流程
|
||||||
|
g.Log().Warning(ctx, "用户余额不足,跳过自动扣款", g.Map{"uid": uid, "balance": balance})
|
||||||
|
|
||||||
|
// Panic:启动时核心配置缺失
|
||||||
|
g.Log().Panicf(ctx, "缓存未初始化,无法启动: %+v", err)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 日志上下文原则
|
||||||
|
|
||||||
|
- 日志**必须传入 `ctx`**(第一个参数),便于链路追踪
|
||||||
|
- 关键日志需携带足够的业务字段(uid、orderId、requestId 等),用 `g.Map{}` 附加结构化信息
|
||||||
|
- **禁止**用 `fmt.Println` 替代日志,禁止在 logic/controller 层裸打印调试信息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据库建表约定
|
||||||
|
|
||||||
|
建表时遵循以下字段命名约定,代码生成器和 ORM hook 会自动识别并处理:
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `id` | bigint(20) NOT NULL AUTO_INCREMENT | 主键,必须 |
|
||||||
|
| `created_at` | datetime | 创建时间,**自动写入**,禁止手动赋值 |
|
||||||
|
| `updated_at` | datetime | 更新时间,**自动维护**,禁止手动赋值 |
|
||||||
|
| `deleted_at` | datetime | 软删除时间,存在时查询自动加 `IS NULL`,删除只更新此字段 |
|
||||||
|
| `created_by` | bigint(20) | 创建者 ID,**自动写入** |
|
||||||
|
| `updated_by` | bigint(20) | 更新者 ID,**自动维护** |
|
||||||
|
| `deleted_by` | bigint(20) | 删除者 ID,**自动写入** |
|
||||||
|
| `status` | tinyint | 状态字段,默认使用系统字典 `sys_normal_disable` |
|
||||||
|
| `sort` | int | 排序字段,存在时编辑表单自动获取最大值+1填充 |
|
||||||
|
| `pid` | bigint(20) | 树表上级ID(树表必须) |
|
||||||
|
| `level` | int | 树等级(树表必须,自动维护) |
|
||||||
|
| `tree` | varchar(512) | 关系树(树表必须,自动维护) |
|
||||||
|
| `tenant_id` | bigint(20) | 租户ID(多租户场景按需加) |
|
||||||
|
|
||||||
|
**特殊字段查询方式(代码生成器默认生成):**
|
||||||
|
- `string` 类型字段 → `LIKE` 模糊查询
|
||||||
|
- `int/uint/int64` → `=` 精确查询
|
||||||
|
- `created_by`/`updated_by`/`deleted_by` → 关键词查询(ID/用户名/手机号匹配),调用 `service.AdminMember().GetIdsByKeyword()`
|
||||||
|
|
||||||
|
**数据类型 → Go 类型映射(影响生成代码的字段类型):**
|
||||||
|
- `tinyint/int/smallint` → `int`;加 `unsigned` → `uint`
|
||||||
|
- `bigint` → `int64`;加 `unsigned` → `uint64`
|
||||||
|
- `varchar/text/char` → `string`
|
||||||
|
- `datetime/timestamp` → `*gtime.Time`
|
||||||
|
- `json/jsonb` → `*gjson.Json`
|
||||||
|
- `decimal/float/double` → `float64`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据权限(权限过滤)
|
||||||
|
|
||||||
|
业务查询中如需过滤数据权限(仅自己/所属部门/下级等),在 ORM 链式调用中加入 handler:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "hotgo/internal/library/hgorm/handler"
|
||||||
|
|
||||||
|
// 按登录用户的数据权限范围过滤(表需含 created_by 或 member_id 字段)
|
||||||
|
dao.XxxTable.Ctx(ctx).Handler(handler.FilterAuth).Scan(&res)
|
||||||
|
|
||||||
|
// 表中无标准字段时,指定自定义字段
|
||||||
|
dao.XxxTable.Ctx(ctx).Handler(handler.FilterAuthWithField("custom_field")).Scan(&res)
|
||||||
|
|
||||||
|
// 多租户数据权限过滤(表需含 tenant_id 字段)
|
||||||
|
// 在 Model() 方法中通过 handler.Option 开启
|
||||||
|
func (s *sSysXxx) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
|
||||||
|
if len(option) == 0 {
|
||||||
|
option = append(option, &handler.Option{FilterTenant: true})
|
||||||
|
}
|
||||||
|
return handler.Model(dao.XxxTable.Ctx(ctx), option...)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
多租户增改时自动维护租户关系,在 ORM 操作后加 `.Hook(hook.SaveTenant)`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "hotgo/internal/library/hgorm/hook"
|
||||||
|
|
||||||
|
// 新增时自动写入 tenant_id/merchant_id/user_id
|
||||||
|
dao.XxxTable.Ctx(ctx).Fields(sysin.XxxInsertFields{}).Hook(hook.SaveTenant).Data(in).Insert()
|
||||||
|
|
||||||
|
// 更新时自动维护
|
||||||
|
s.Model(ctx).Fields(sysin.XxxUpdateFields{}).WherePri(in.Id).Data(in).Hook(hook.SaveTenant).Update()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 定时任务(Crons)
|
||||||
|
|
||||||
|
定时任务通过实现接口 + `init()` 注册,在后台「系统设置 → 定时任务」中配置执行策略:
|
||||||
|
|
||||||
|
**主模块**:新建 `server/internal/crons/<name>.go`
|
||||||
|
**插件**:新建 `server/addons/<addonName>/crons/<name>.go`
|
||||||
|
|
||||||
|
```go
|
||||||
|
package crons
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"hotgo/internal/library/cron"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cron.Register(MyTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
var MyTask = &cMyTask{name: "myTask"} // name 与后台配置的任务名称一致
|
||||||
|
|
||||||
|
type cMyTask struct{ name string }
|
||||||
|
|
||||||
|
func (c *cMyTask) GetName() string { return c.name }
|
||||||
|
|
||||||
|
func (c *cMyTask) Execute(ctx context.Context, parser *cron.Parser) (err error) {
|
||||||
|
parser.Logger.Infof(ctx, "任务执行:%v", ...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 消息队列(Queues)
|
||||||
|
|
||||||
|
队列采用接口 + `init()` 注册,topic 统一定义在 `internal/consts/queue.go`(或对应模块 consts 文件)。
|
||||||
|
|
||||||
|
**主模块**:新建 `server/internal/queues/<name>.go`
|
||||||
|
**插件**:新建 `server/addons/<addonName>/queues/<name>.go`
|
||||||
|
|
||||||
|
```go
|
||||||
|
package queues
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"hotgo/internal/consts"
|
||||||
|
"hotgo/internal/library/queue"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
queue.RegisterConsumer(MyConsumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
var MyConsumer = &qMyConsumer{}
|
||||||
|
|
||||||
|
type qMyConsumer struct{}
|
||||||
|
|
||||||
|
func (q *qMyConsumer) GetTopic() string { return consts.QueueMyTopic }
|
||||||
|
|
||||||
|
func (q *qMyConsumer) Handle(ctx context.Context, mqMsg queue.MqMsg) (err error) {
|
||||||
|
var data MyData
|
||||||
|
if err = json.Unmarshal(mqMsg.Body, &data); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 处理消息...
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**发送消息:**
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 即时消息
|
||||||
|
queue.Push(consts.QueueMyTopic, data)
|
||||||
|
|
||||||
|
// 延迟消息(仅 redis/rocketmq 驱动支持)
|
||||||
|
queue.SendDelayMsg(consts.QueueMyTopic, data, 10) // redis: 延迟秒数;rocketmq: 延迟级别
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 工具库使用规范
|
||||||
|
|
||||||
|
**后端(`server/utility/`)优先使用已有工具,禁止重复造轮子:**
|
||||||
|
|
||||||
|
| 包 | 用途 |
|
||||||
|
|----|------|
|
||||||
|
| `utility/convert` | 数据类型转换 |
|
||||||
|
| `utility/encrypt` | 加密/解密 |
|
||||||
|
| `utility/excel` | 电子表格导出/导入(导出接口用此包) |
|
||||||
|
| `utility/validate` | 数据验证工具 |
|
||||||
|
| `utility/tree` | 树形结构处理 |
|
||||||
|
| `utility/simple` | 简捷函数集合 |
|
||||||
|
| `utility/format` | 数据格式化 |
|
||||||
|
|
||||||
|
**前端(`web/src/utils/`)优先使用已有工具:**
|
||||||
|
|
||||||
|
| 工具 | 用途 |
|
||||||
|
|------|------|
|
||||||
|
| `@/utils/http/axios`(`http.request`) | HTTP 请求,**唯一入口** |
|
||||||
|
| `@/utils/dateUtil`(`defRangeShortcuts`) | 日期范围快捷选项 |
|
||||||
|
| `@/utils`(`renderImage`、`renderFile`、`renderPopoverMemberSumma`) | 表格渲染工具函数 |
|
||||||
|
| `@/store/modules/dict`(`useDictStore`) | 字典数据加载与渲染 |
|
||||||
|
| `@/hooks/web/usePermission`(`hasPermission`) | 权限判断 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 树表(Tree CRUD)特殊约定
|
||||||
|
|
||||||
|
树表在普通 CRUD 基础上有以下差异:
|
||||||
|
|
||||||
|
- 表中必须含 `pid`、`level`、`tree` 字段(参见建表约定)
|
||||||
|
- `pid`/`level`/`tree` 字段**由系统自动维护**,禁止在编辑表单中手动设置这三个字段
|
||||||
|
- 前端列表页使用树形表格(`BasicTable` 的 `childrenKey` 或 `treeData` 模式),而非普通分页列表
|
||||||
|
- 参考实现:`server/internal/logic/sys/tree_demo.go`、`web/src/views/develop/curd/treeDemo/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 响应格式约定
|
||||||
|
|
||||||
|
所有接口统一响应格式(由框架中间件自动处理,**无需在 controller 手动包装**):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 0, "message": "操作成功", "timestamp": 1234567890, "traceID": "xxx", "data": {} }
|
||||||
|
```
|
||||||
|
|
||||||
|
- 成功状态码:`0`;失败状态码:`-1`(GoFrame 内置,无需手动设置)
|
||||||
|
- `gerror.Wrap(err, "用户友好的提示")` → 客户端只看到最外层提示,开发者日志可见完整堆栈
|
||||||
|
- 禁止在 controller 层手动 `Write`/`WriteJSON` 等直接写响应(破坏统一格式)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见错误禁止清单
|
||||||
|
|
||||||
|
**后端:**
|
||||||
|
- 禁止在 controller 层直接调用 dao
|
||||||
|
- 禁止硬编码字段名字符串(用 `dao.Table.Columns().Field`)
|
||||||
|
- 禁止手改 `entity/`、`do/`、`dao/internal/` 目录下的文件
|
||||||
|
- 禁止在 logic 层重复做 `Filter()` 已完成的校验
|
||||||
|
- 禁止在 `internal/service/sys.go` 之外新建主模块 service 文件(同文件追加)
|
||||||
|
- 禁止插件 import 另一个插件的包(插件间完全隔离,通过主模块 service 通信)
|
||||||
|
- 禁止在插件路由文件里硬编码路由前缀(用 `addons.RouterPrefix()` 生成)
|
||||||
|
- 禁止在 `internal/library/` 下修改基础库(如需扩展,提 issue 或在 utility/ 添加)
|
||||||
|
|
||||||
|
**前端:**
|
||||||
|
- 禁止直接使用 axios,必须用 `http.request`
|
||||||
|
- 禁止硬编码字典值文本,必须用 `dict.getLabel()` 渲染
|
||||||
|
- 禁止引入 Naive UI 以外的 UI 框架
|
||||||
|
- 禁止内联 style
|
||||||
|
- 禁止在源码里硬编码菜单路由路径
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# ---- Stage 1: build the Vue frontend ----
|
||||||
|
FROM node:22-alpine AS web-build
|
||||||
|
WORKDIR /web
|
||||||
|
ENV CI=true
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
COPY web/package.json web/pnpm-lock.yaml web/pnpm-workspace.yaml ./
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
COPY web/ .
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
|
# ---- Stage 2: build the Go backend, embedding the frontend build ----
|
||||||
|
FROM golang:1.24-alpine AS server-build
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
WORKDIR /src
|
||||||
|
COPY server/go.mod server/go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY server/ .
|
||||||
|
|
||||||
|
# Same layout the project's own Makefile produces: built frontend goes into
|
||||||
|
# resource/public/admin/ before packing/building the backend.
|
||||||
|
RUN rm -rf resource/public/admin && mkdir -p resource/public/admin
|
||||||
|
COPY --from=web-build /web/dist/ ./resource/public/admin/
|
||||||
|
|
||||||
|
# main.go imports internal/packed. Generate the packed resource file directly
|
||||||
|
# through GoFrame's library API instead of installing the full gf CLI in CI.
|
||||||
|
RUN printf '%s\n' \
|
||||||
|
'package main' \
|
||||||
|
'import "github.com/gogf/gf/v2/os/gres"' \
|
||||||
|
'func main() {' \
|
||||||
|
' if err := gres.PackToGoFileWithOption("resource", "internal/packed/packed.go", "packed", gres.Option{}); err != nil { panic(err) }' \
|
||||||
|
'}' > /tmp/pack.go \
|
||||||
|
&& go run /tmp/pack.go \
|
||||||
|
&& rm /tmp/pack.go
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 go build -o /out/hotgo main.go
|
||||||
|
|
||||||
|
# ---- Stage 3: runtime ----
|
||||||
|
FROM alpine:3.22
|
||||||
|
|
||||||
|
RUN apk add --no-cache ca-certificates gettext bash tzdata
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV QUEUE_DRIVER=kafka
|
||||||
|
ENV KAFKA_ADDRESS=kafka.118im.com:30835
|
||||||
|
ENV KAFKA_VERSION=2.4.0
|
||||||
|
ENV KAFKA_USERNAME=
|
||||||
|
ENV KAFKA_PASSWORD=
|
||||||
|
ENV KAFKA_SASL_MECHANISM=
|
||||||
|
ENV MYSQL_DSN=
|
||||||
|
ENV REDIS_ADDR=redis.118im.com:30637
|
||||||
|
ENV REDIS_DB=2
|
||||||
|
ENV REDIS_PASSWORD=
|
||||||
|
ENV TOKEN_SECRET_KEY=hotgo123
|
||||||
|
ENV IM_ADMIN_API_BASE_URL=https://api.118im.com
|
||||||
|
ENV IM_ADMIN_API_SERVICE_ID=hotgo-admin
|
||||||
|
ENV IM_ADMIN_API_SECRET=
|
||||||
|
ENV IM_INTERNAL_API_BASE_URL=https://api.118im.com
|
||||||
|
ENV IM_INTERNAL_API_SERVICE_NAME=hotgo-admin
|
||||||
|
ENV IM_INTERNAL_API_SECRET=
|
||||||
|
ENV IM_WORKBENCH_API_BASE_URL=http://im-workbench.workbench-system.svc.cluster.local:6061
|
||||||
|
ENV IM_WORKBENCH_API_SERVICE_NAME=hotgo-admin
|
||||||
|
ENV IM_WORKBENCH_API_SECRET=hotgo-workbench-internal
|
||||||
|
ENV IM_CONFIG_API_SERVICE_NAME=im-server
|
||||||
|
ENV IM_CONFIG_API_SECRET=
|
||||||
|
|
||||||
|
COPY --from=server-build /src/manifest ./manifest
|
||||||
|
COPY --from=server-build /src/hack ./hack
|
||||||
|
COPY --from=server-build /out/hotgo .
|
||||||
|
COPY server/manifest/docker/entrypoint.sh .
|
||||||
|
|
||||||
|
RUN mkdir -p storage/logs storage/data storage/cache storage/diskqueue \
|
||||||
|
&& chmod +x entrypoint.sh hotgo
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=1m --timeout=3s --start-period=20s \
|
||||||
|
CMD wget -q -O /dev/null http://localhost:8000/healthz || exit 1
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021-present HotGo
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,2 +1,167 @@
|
|||||||
# im_manager
|
# HotGo-V2
|
||||||
|
<div align="center">
|
||||||
|
<img width="140px" src="https://gmycos.facms.cn/hotgo/logo.sig.png">
|
||||||
|
<p>
|
||||||
|
<h1>HotGo V2</h1>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://goframe.org/pages/viewpage.action?pageId=1114119" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/goframe-2.10.0-green" alt="goframe">
|
||||||
|
</a>
|
||||||
|
<a href="https://v3.vuejs.org/" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/vue.js-vue3.4-green" alt="vue">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.naiveui.com" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/naiveui-%3E2.44.1-blue" alt="naiveui">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.tslang.cn/" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
|
||||||
|
</a>
|
||||||
|
<a href="https://vitejs.dev/" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/vite-%3E5.4.2-yellow" alt="vite">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/bufanyun/hotgo/blob/v2.0/LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/license-MIT-success" alt="license">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## 平台简介
|
||||||
|
* 基于 GoFrame2 + Vue3 + NaiveUI + uniapp 的企业级全栈框架,为二次开发而生。
|
||||||
|
* 前端采用 Naive-Ui-Admin、Vue、Naive UI、uniapp。
|
||||||
|
* 企业级 AI 赋能基础开发平台,内置 AI 开发规范,适配主流 AI 开发工具,实现人机协同开发,大幅提升开发效率。
|
||||||
|
|
||||||
|
## 演示地址
|
||||||
|
- [https://hotgo.facms.cn/admin](https://hotgo.facms.cn/admin)
|
||||||
|
> 账号:admin 密码:123456
|
||||||
|
|
||||||
|
### 使用文档
|
||||||
|
|
||||||
|
[安装文档](docs/guide-zh-CN/start-installation.md) · [本地文档](docs/guide-zh-CN/README.md) · [更新历史](docs/guide-zh-CN/start-update-log.md) · [常见问题](docs/guide-zh-CN/start-issue.md)
|
||||||
|
|
||||||
|
|
||||||
|
## 特征
|
||||||
|
* 高生产率:极强的可扩展性,应用化、模块化、插件化机制敏捷开发,几分钟即可搭建一个应用开发骨架。
|
||||||
|
* 多应用入口:多入口分为 Admin (后台)、Home (前台页面)、Api (对外通用接口)、WebSocket (即时通讯接口),不同的业务,进入不同的应用入口。
|
||||||
|
* 极致的插件化: 微核架构,功能隔离,高可定制性,可以渐进式开发,亦可以多人协同开发。支持一键创建插件模板、一键安装、更新、卸载插件、可以非常方便的将插件迁移到新项目中。
|
||||||
|
* 快速生成代码:无需编写代码,只需创建表进行简单配置就能生成一个完善的 CURD、树表等常用的开发代码,其中所需表单控件也是勾选即可直接生成。
|
||||||
|
* 认证机制:采用 JWT 的用户状态认证及 casbin 的权限认证
|
||||||
|
* 路由模式:得益于 GoFrame 提供了规范化的路由注册方式,无需注解自动生成api文档
|
||||||
|
* 模块化设计,面向接口开发
|
||||||
|
|
||||||
|
|
||||||
|
## 内置功能
|
||||||
|
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||||
|
2. 部门管理:配置系统组织机构(公司、部门、岗位),树结构展现支持数据权限。
|
||||||
|
3. 岗位管理:配置系统用户所属担任职务。
|
||||||
|
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
||||||
|
5. 角色管理:角色菜单权限分配、设置角色按机构或按上下级关系进行数据范围权限划分。
|
||||||
|
6. 字典管理:对系统中经常使用的一些特定数据进行维护,支持枚举字典和自定义方法字典。
|
||||||
|
7. 配置管理:对系统动态配置常用参数。
|
||||||
|
8. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||||
|
9. 登录日志:系统登录日志记录查询包含登录异常。
|
||||||
|
10. 服务日志:服务端运行所产生的警告、异常、崩溃日志的详细数据和堆栈信息。
|
||||||
|
11. 支付网关:集成支付宝、微信支付、QQ支付等多种支付方式,只需简单配置即可使用。
|
||||||
|
12. 资金管理:支持在线充值、订单申请/原路退款、资金提现、资金/积分变动明细等通用模块。
|
||||||
|
13. 在线用户:当前系统中活跃用户状态监控。
|
||||||
|
14. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
||||||
|
15. 代码生成:支持自动化生成前后端代码。CURD关联表、树表、消息队列、定时任务一键生成等。
|
||||||
|
16. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
|
||||||
|
17. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
|
||||||
|
18. 附件管理:文件图片上传,大文件分片上传、断点续传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储、minio等多种上传驱动,后台一键切换配置,并集成了文件选择器。
|
||||||
|
19. TCP服务:基于gtcp的服务应用,支持长连接、断线重连、服务认证、路由分发、RPC消息、拦截器和数据绑定等。简化和规范了服务器开发流程。
|
||||||
|
20. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
|
||||||
|
21. 通知公告:采用WebSocket实时推送在线用户最新通知、公告、私信消息。
|
||||||
|
22. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
|
||||||
|
23. 常用工具:集成常用的工具包和命令行工具,可以快速开发自定义命令行,多种启动入口。
|
||||||
|
|
||||||
|
|
||||||
|
> HotGo开源以来得到了大家的很多支持,本项目初衷只为互相学习交流,没有任何盈利性目的!欢迎为HotGo贡献代码或提供建议!
|
||||||
|
|
||||||
|
|
||||||
|
## 演示图
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/1.png"/></td>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/2.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/3.png"/></td>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/4.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/5.png"/></td>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/6.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/7.png"/></td>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/8.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/9.png"/></td>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/10.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/11.png"/></td>
|
||||||
|
<td><img src="./docs/guide-zh-CN/images/demo/12.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
## 感谢(排名不分先后)
|
||||||
|
> gf框架 [https://github.com/gogf/gf](https://github.com/gogf/gf)
|
||||||
|
>
|
||||||
|
> naive-ui [https://www.naiveui.com](https://www.naiveui.com)
|
||||||
|
>
|
||||||
|
> naive-ui-admin [https://github.com/jekip/naive-ui-admin](https://github.com/jekip/naive-ui-admin)
|
||||||
|
>
|
||||||
|
> websocket [https://github.com/gorilla/websocket](github.com/gorilla/websocket)
|
||||||
|
>
|
||||||
|
> casbin [https://github.com/casbin/casbin](https://github.com/casbin/casbin)
|
||||||
|
>
|
||||||
|
> gopay [https://github.com/go-pay/gopay](https://github.com/go-pay/gopay)
|
||||||
|
|
||||||
|
|
||||||
|
## 交流QQ群
|
||||||
|
交流群①:190966648 <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=mJafkvme3VNyiQlCFIFNRtY8Xlr7pj9U&jump_from=webapi&authKey=jL10vIESr+vO8wpxwyd6DlChzkrbHpzN9uhAsIHgAinL/Vvd+nvuRyilf2UqUlCy"><img border="0" src="https://gmycos.facms.cn/hotgo/group.png" alt="HotGo框架交流1群" title="HotGo框架交流1群"></a>
|
||||||
|
> <img src="https://gmycos.facms.cn/hotgo/hotgo1qun.png" width="400px"/>
|
||||||
|
|
||||||
|
|
||||||
|
## 商用说明
|
||||||
|
|
||||||
|
> HotGo 是开源免费的,遵循 MIT 开源协议,意味着您无需支付任何费用,也无需授权,即可将它应用到您的产品中。
|
||||||
|
|
||||||
|
* 使用本项目必须保留所有版权信息。
|
||||||
|
|
||||||
|
* 本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||||
|
|
||||||
|
* 版权所有Copyright © 2020-2026 by Ms (https://github.com/bufanyun/hotgo)
|
||||||
|
|
||||||
|
* All rights reserved。
|
||||||
|
|
||||||
|
|
||||||
|
## 免责声明:
|
||||||
|
* HotGo为开源学习项目,一切商业行为与HotGo无关。
|
||||||
|
|
||||||
|
* 用户不得利用HotGo从事非法行为,用户应当合法合规的使用,发现用户在使用产品时有任何的非法行为,HotGo有权配合有关机关进行调查或向政府部门举报,HotGo不承担用户因非法行为造成的任何法律责任,一切法律责任由用户自行承担,如因用户使用造成第三方损害的,用户应当依法予以赔偿。
|
||||||
|
|
||||||
|
* 所有与使用HotGo相关的资源直接风险均由用户承担。
|
||||||
|
|
||||||
|
|
||||||
|
#### 如果对您有帮助,您可以点右上角 💘Star💘支持
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [感谢JetBrains提供的免费GoLand](https://jb.gg/OpenSource)
|
||||||
|
[](https://jb.gg/OpenSource)
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
[MIT © HotGo-2026](./LICENSE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"label": "数据概览",
|
||||||
|
"slug": "01-dashboard",
|
||||||
|
"route": "/dashboard",
|
||||||
|
"url": "https://admin.adfahi.cn/dashboard",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/01-dashboard.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n总用户数\n16\n活跃用户\n0\n总群组数\n6\n总会话数\n11\n总消息数\n220\n今日消息\n0\n用户增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0\n消息增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"日期",
|
||||||
|
"数量"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
"2026-08-28",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-29",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-30",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"日期",
|
||||||
|
"数量"
|
||||||
|
],
|
||||||
|
"idx": 1,
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
"2026-08-28",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-29",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-30",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"label": "数据概览",
|
||||||
|
"slug": "01-dashboard",
|
||||||
|
"route": "/dashboard",
|
||||||
|
"url": "https://admin.adfahi.cn/dashboard",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/01-dashboard.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n总用户数\n16\n活跃用户\n0\n总群组数\n6\n总会话数\n11\n总消息数\n220\n今日消息\n0\n用户增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0\n消息增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"日期",
|
||||||
|
"数量"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
"2026-08-28",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-29",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-30",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-31",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-09-01",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"日期",
|
||||||
|
"数量"
|
||||||
|
],
|
||||||
|
"idx": 1,
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
"2026-08-28",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-29",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-30",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-08-31",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2026-09-01",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,866 @@
|
|||||||
|
{
|
||||||
|
"label": "用户管理",
|
||||||
|
"slug": "02-user-management",
|
||||||
|
"route": "/users",
|
||||||
|
"url": "https://admin.adfahi.cn/users",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/02-user-management.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户管理\n编号\n用户分组\n全部\n状态\n全部\n关键词\n查 询\n重 置\n创建用户\n批量创建\n导入Excel\n下载模板\n编号\t头像\t用户名\t昵称\t手机号\t注册方式\t状态\t用户分组\t最近登录\t创建时间\t操作\n\n编号\n\t\n头像\n\t\n用户名\n\t\n昵称\n\t\n手机号\n\t\n注册方式\n\t\n状态\n\t\n用户分组\n\t\n最近登录\n\t\n创建时间\n\t\n操作\n\n16\t\n点击查看\n\thy73074162\tpoter001\t\t后台创建\t正常\t默认用户组\t2026-08-01 00:05:30\t2026-08-01 00:04:25\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n15\t\n点击查看\n\thy17716319\t往事随风\t\t后台创建\t正常\t默认用户组\t2026-08-01 21:16:15\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n14\t\n点击查看\n\thy34899108\t坚守的山羊\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n13\t\n点击查看\n\thy45257043\t沉稳的松鼠\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n12\t\n点击查看\n\thy69598195\t专注的白兔\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n11\t\n点击查看\n\thy20144467\t沉稳的黑猫\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n10\t\n点击查看\n\thy70299474\t坚韧的河马\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n9\t\n点击查看\n\thy23799134\t求真的猫头\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n8\t\n点击查看\n\thy18959373\t进取的北狐\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n7\t\n点击查看\n\thy80424632\t温润的乌鸦\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n6\t\n点击查看\n\thy98400466\t乐观的野马\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n5\t\n点击查看\n\thy99111080\tF\t13800001115\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:43:53\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n4\t\n点击查看\n\thy92120233\tF\t13800001114\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:43:37\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n3\t\n点击查看\n\thy69089908\tF\t13800001113\t后台创建\t正常\t默认用户组\t2026-07-31 23:26:17\t2026-07-31 22:43:12\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n2\t\n点击查看\n\thy91144536\t冯仁飞\t13800001112\t后台创建\t正常\t默认用户组\t2026-08-02 22:27:59\t2026-07-31 22:43:02\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n1\t\n点击查看\n\thy50703413\t冯宇昂\t13800001111\t后台创建\t正常\t默认用户组\t2026-07-31 23:37:42\t2026-07-31 22:42:45\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"编号",
|
||||||
|
"头像",
|
||||||
|
"用户名",
|
||||||
|
"昵称",
|
||||||
|
"手机号",
|
||||||
|
"注册方式",
|
||||||
|
"状态",
|
||||||
|
"用户分组",
|
||||||
|
"最近登录",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"编号",
|
||||||
|
"头像",
|
||||||
|
"用户名",
|
||||||
|
"昵称",
|
||||||
|
"手机号",
|
||||||
|
"注册方式",
|
||||||
|
"状态",
|
||||||
|
"用户分组",
|
||||||
|
"最近登录",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"16",
|
||||||
|
"点击查看",
|
||||||
|
"hy73074162",
|
||||||
|
"poter001",
|
||||||
|
"后台创建",
|
||||||
|
"正常",
|
||||||
|
"默认用户组",
|
||||||
|
"2026-08-01 00:05:30",
|
||||||
|
"2026-08-01 00:04:25",
|
||||||
|
"详 情重置密码IP白名单调整分组封 禁强制下线强制注销"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"15",
|
||||||
|
"点击查看",
|
||||||
|
"hy17716319",
|
||||||
|
"往事随风",
|
||||||
|
"后台创建",
|
||||||
|
"正常",
|
||||||
|
"默认用户组",
|
||||||
|
"2026-08-01 21:16:15",
|
||||||
|
"2026-07-31 22:44:06",
|
||||||
|
"详 情重置密码IP白名单调整分组封 禁强制下线强制注销"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户编号",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名/昵称/手机号",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "创建用户"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量创建"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "导入Excel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载模板"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重置密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "调整分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制下线"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "强制注销"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
{
|
||||||
|
"label": "用户分组",
|
||||||
|
"slug": "03-user-groups",
|
||||||
|
"route": "/user-policy-groups",
|
||||||
|
"url": "https://admin.adfahi.cn/user-policy-groups",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/03-user-groups.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户分组\n添加分组\nIP 白名单\n租户渠道 IP 白名单\nAPP:未配置\nWeb:未配置\n分组名称\t用户数\t允许加好友\t允许建群\t直接加好友\t好友上限\tAPP 登录\tWeb 登录\tIP 白名单\t状态\t权重\t操作\n\n分组名称\n\t\n用户数\n\t\n允许加好友\n\t\n允许建群\n\t\n直接加好友\n\t\n好友上限\n\t\nAPP 登录\n\t\nWeb 登录\n\t\nIP 白名单\n\t\n状态\n\t\n权重\n\t\n操作\n\n\n默认用户组\n默认\n\t16\t允许\t允许\t--\t不限\t允许\t允许\t未启用\t启用\t0\t\n编辑\n删除",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"分组名称",
|
||||||
|
"用户数",
|
||||||
|
"允许加好友",
|
||||||
|
"允许建群",
|
||||||
|
"直接加好友",
|
||||||
|
"好友上限",
|
||||||
|
"APP 登录",
|
||||||
|
"Web 登录",
|
||||||
|
"IP 白名单",
|
||||||
|
"状态",
|
||||||
|
"权重",
|
||||||
|
"操作",
|
||||||
|
"分组名称",
|
||||||
|
"用户数",
|
||||||
|
"允许加好友",
|
||||||
|
"允许建群",
|
||||||
|
"直接加好友",
|
||||||
|
"好友上限",
|
||||||
|
"APP 登录",
|
||||||
|
"Web 登录",
|
||||||
|
"IP 白名单",
|
||||||
|
"状态",
|
||||||
|
"权重",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"默认用户组默认",
|
||||||
|
"16",
|
||||||
|
"允许",
|
||||||
|
"允许",
|
||||||
|
"--",
|
||||||
|
"不限",
|
||||||
|
"允许",
|
||||||
|
"允许",
|
||||||
|
"未启用",
|
||||||
|
"启用",
|
||||||
|
"0",
|
||||||
|
"编辑删除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "添加分组"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP 白名单"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "编辑"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删除"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"label": "用户分组",
|
||||||
|
"slug": "03-user-groups",
|
||||||
|
"route": "/user-policy-groups",
|
||||||
|
"url": "https://admin.adfahi.cn/user-policy-groups",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/03-user-groups.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户分组\n添加分组\nIP 白名单\n租户渠道 IP 白名单\nAPP:未配置\nWeb:未配置\n分组名称\t用户数\t允许加好友\t允许建群\t直接加好友\t好友上限\tAPP 登录\tWeb 登录\tIP 白名单\t状态\t权重\t操作\n\n分组名称\n\t\n用户数\n\t\n允许加好友\n\t\n允许建群\n\t\n直接加好友\n\t\n好友上限\n\t\nAPP 登录\n\t\nWeb 登录\n\t\nIP 白名单\n\t\n状态\n\t\n权重\n\t\n操作\n\n\n默认用户组\n默认\n\t16\t允许\t允许\t--\t不限\t允许\t允许\t未启用\t启用\t0\t\n编辑\n删除",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"分组名称",
|
||||||
|
"用户数",
|
||||||
|
"允许加好友",
|
||||||
|
"允许建群",
|
||||||
|
"直接加好友",
|
||||||
|
"好友上限",
|
||||||
|
"APP 登录",
|
||||||
|
"Web 登录",
|
||||||
|
"IP 白名单",
|
||||||
|
"状态",
|
||||||
|
"权重",
|
||||||
|
"操作",
|
||||||
|
"分组名称",
|
||||||
|
"用户数",
|
||||||
|
"允许加好友",
|
||||||
|
"允许建群",
|
||||||
|
"直接加好友",
|
||||||
|
"好友上限",
|
||||||
|
"APP 登录",
|
||||||
|
"Web 登录",
|
||||||
|
"IP 白名单",
|
||||||
|
"状态",
|
||||||
|
"权重",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"默认用户组默认",
|
||||||
|
"16",
|
||||||
|
"允许",
|
||||||
|
"允许",
|
||||||
|
"--",
|
||||||
|
"不限",
|
||||||
|
"允许",
|
||||||
|
"允许",
|
||||||
|
"未启用",
|
||||||
|
"启用",
|
||||||
|
"0",
|
||||||
|
"编辑删除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "添加分组",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "IP 白名单",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "编辑",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删除",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
{
|
||||||
|
"label": "群组管理",
|
||||||
|
"slug": "04-group-management",
|
||||||
|
"route": "/groups",
|
||||||
|
"url": "https://admin.adfahi.cn/groups",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/04-group-management.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群组管理\n群号\n关键词\n状态\n全部\n查 询\n重 置\n群组编号\t群号\t群组名称\t成员数\t群主昵称\t群主用户名\t状态\t创建时间\t操作\n\n群组编号\n\t\n群号\n\t\n群组名称\n\t\n成员数\n\t\n群主昵称\n\t\n群主用户名\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n6\t68127154\t\n冯\n\t1\tF\thy69089908\t正常\t2026-07-31 22:50:52\t\n详 情\n群文件\n封 禁\n解 散\n\n5\t62262588\t\n冯\n\t3\tF\thy69089908\t正常\t2026-07-31 22:50:38\t\n详 情\n群文件\n封 禁\n解 散\n\n4\t75874312\t\n346亿916\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:57\t\n详 情\n群文件\n封 禁\n解 散\n\n3\t92851806\t\n64919\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:49\t\n详 情\n群文件\n封 禁\n解 散\n\n2\t89233971\t\n冯氏家族\n\t3\t冯仁飞\thy91144536\t正常\t2026-07-31 22:46:59\t\n详 情\n群文件\n封 禁\n解 散\n\n1\t17776111\t\n冯氏家族\n\t3\t冯宇昂\thy50703413\t正常\t2026-07-31 22:45:28\t\n详 情\n群文件\n封 禁\n解 散\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"群组编号",
|
||||||
|
"群号",
|
||||||
|
"群组名称",
|
||||||
|
"成员数",
|
||||||
|
"群主昵称",
|
||||||
|
"群主用户名",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"群组编号",
|
||||||
|
"群号",
|
||||||
|
"群组名称",
|
||||||
|
"成员数",
|
||||||
|
"群主昵称",
|
||||||
|
"群主用户名",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"6",
|
||||||
|
"68127154",
|
||||||
|
"冯",
|
||||||
|
"1",
|
||||||
|
"F",
|
||||||
|
"hy69089908",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:52",
|
||||||
|
"详 情群文件封 禁解 散"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"5",
|
||||||
|
"62262588",
|
||||||
|
"冯",
|
||||||
|
"3",
|
||||||
|
"F",
|
||||||
|
"hy69089908",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:38",
|
||||||
|
"详 情群文件封 禁解 散"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "群号",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "群名称",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,356 @@
|
|||||||
|
{
|
||||||
|
"label": "群组管理",
|
||||||
|
"slug": "04-group-management",
|
||||||
|
"route": "/groups",
|
||||||
|
"url": "https://admin.adfahi.cn/groups",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/04-group-management.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群组管理\n群号\n关键词\n状态\n全部\n查 询\n重 置\n群组编号\t群号\t群组名称\t成员数\t群主昵称\t群主用户名\t状态\t创建时间\t操作\n\n群组编号\n\t\n群号\n\t\n群组名称\n\t\n成员数\n\t\n群主昵称\n\t\n群主用户名\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n6\t68127154\t\n冯\n\t1\tF\thy69089908\t正常\t2026-07-31 22:50:52\t\n详 情\n群文件\n封 禁\n解 散\n\n5\t62262588\t\n冯\n\t3\tF\thy69089908\t正常\t2026-07-31 22:50:38\t\n详 情\n群文件\n封 禁\n解 散\n\n4\t75874312\t\n346亿916\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:57\t\n详 情\n群文件\n封 禁\n解 散\n\n3\t92851806\t\n64919\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:49\t\n详 情\n群文件\n封 禁\n解 散\n\n2\t89233971\t\n冯氏家族\n\t3\t冯仁飞\thy91144536\t正常\t2026-07-31 22:46:59\t\n详 情\n群文件\n封 禁\n解 散\n\n1\t17776111\t\n冯氏家族\n\t3\t冯宇昂\thy50703413\t正常\t2026-07-31 22:45:28\t\n详 情\n群文件\n封 禁\n解 散\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"群组编号",
|
||||||
|
"群号",
|
||||||
|
"群组名称",
|
||||||
|
"成员数",
|
||||||
|
"群主昵称",
|
||||||
|
"群主用户名",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"群组编号",
|
||||||
|
"群号",
|
||||||
|
"群组名称",
|
||||||
|
"成员数",
|
||||||
|
"群主昵称",
|
||||||
|
"群主用户名",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"6",
|
||||||
|
"68127154",
|
||||||
|
"冯",
|
||||||
|
"1",
|
||||||
|
"F",
|
||||||
|
"hy69089908",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:52",
|
||||||
|
"详 情群文件封 禁解 散"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"5",
|
||||||
|
"62262588",
|
||||||
|
"冯",
|
||||||
|
"3",
|
||||||
|
"F",
|
||||||
|
"hy69089908",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:38",
|
||||||
|
"详 情群文件封 禁解 散"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"4",
|
||||||
|
"75874312",
|
||||||
|
"346亿916",
|
||||||
|
"1",
|
||||||
|
"冯宇昂",
|
||||||
|
"hy50703413",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:47:57",
|
||||||
|
"详 情群文件封 禁解 散"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"92851806",
|
||||||
|
"64919",
|
||||||
|
"1",
|
||||||
|
"冯宇昂",
|
||||||
|
"hy50703413",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:47:49",
|
||||||
|
"详 情群文件封 禁解 散"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "群号",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "群名称",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详 情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "群文件",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "封 禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解 散",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"label": "群成员管理",
|
||||||
|
"slug": "05-group-members",
|
||||||
|
"route": "/group-members",
|
||||||
|
"url": "https://admin.adfahi.cn/group-members",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/05-group-members.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群成员管理\n群号\n角色\n全部\n关键词\n查 询\n重 置\n刷 新\n编号\t用户名\t昵称\t群昵称\t角色\t禁言状态\t加入时间\t操作\n\n编号\n\t\n用户名\n\t\n昵称\n\t\n群昵称\n\t\n角色\n\t\n禁言状态\n\t\n加入时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"编号",
|
||||||
|
"用户名",
|
||||||
|
"昵称",
|
||||||
|
"群昵称",
|
||||||
|
"角色",
|
||||||
|
"禁言状态",
|
||||||
|
"加入时间",
|
||||||
|
"操作",
|
||||||
|
"编号",
|
||||||
|
"用户名",
|
||||||
|
"昵称",
|
||||||
|
"群昵称",
|
||||||
|
"角色",
|
||||||
|
"禁言状态",
|
||||||
|
"加入时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "必填",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名/昵称",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
{
|
||||||
|
"label": "群成员管理",
|
||||||
|
"slug": "05-group-members",
|
||||||
|
"route": "/group-members",
|
||||||
|
"url": "https://admin.adfahi.cn/group-members",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/05-group-members.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群成员管理\n群号\n角色\n全部\n关键词\n查 询\n重 置\n刷 新\n编号\t用户名\t昵称\t群昵称\t角色\t禁言状态\t加入时间\t操作\n\n编号\n\t\n用户名\n\t\n昵称\n\t\n群昵称\n\t\n角色\n\t\n禁言状态\n\t\n加入时间\n\t\n操作\n\n3\thy69089908\tF\t--\t群主\t正常\t2026-07-31 22:50:52\t\n禁 言\n踢 出\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"编号",
|
||||||
|
"用户名",
|
||||||
|
"昵称",
|
||||||
|
"群昵称",
|
||||||
|
"角色",
|
||||||
|
"禁言状态",
|
||||||
|
"加入时间",
|
||||||
|
"操作",
|
||||||
|
"编号",
|
||||||
|
"用户名",
|
||||||
|
"昵称",
|
||||||
|
"群昵称",
|
||||||
|
"角色",
|
||||||
|
"禁言状态",
|
||||||
|
"加入时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"hy69089908",
|
||||||
|
"F",
|
||||||
|
"--",
|
||||||
|
"群主",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:52",
|
||||||
|
"禁 言踢 出"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "必填",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "68127154"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名/昵称",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "禁 言",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "踢 出",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"label": "邀请码管理",
|
||||||
|
"slug": "06-invite-codes",
|
||||||
|
"route": "/invite-codes",
|
||||||
|
"url": "https://admin.adfahi.cn/invite-codes",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/06-invite-codes.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n邀请码管理\n状态\n全部\n邀请码\n查 询\n重 置\n生成邀请码\n每次生成 1 个邀请码,可多次使用。可指定企业与用户;勾选「不限制时间」则永久有效;开启「自动加好友」后,使用该码注册的用户将直接成为指定用户的好友。点击「查看」可查看使用该邀请码注册的用户列表。\n邀请码\t指定用户\t自动加好友\t使用人数\t创建人\t状态\t过期时间\t创建时间\t操作\n\n邀请码\n\t\n指定用户\n\t\n自动加好友\n\t\n使用人数\n\t\n创建人\n\t\n状态\n\t\n过期时间\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"邀请码",
|
||||||
|
"指定用户",
|
||||||
|
"自动加好友",
|
||||||
|
"使用人数",
|
||||||
|
"创建人",
|
||||||
|
"状态",
|
||||||
|
"过期时间",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"邀请码",
|
||||||
|
"指定用户",
|
||||||
|
"自动加好友",
|
||||||
|
"使用人数",
|
||||||
|
"创建人",
|
||||||
|
"状态",
|
||||||
|
"过期时间",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "6 位数字",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "生成邀请码"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
{
|
||||||
|
"label": "邀请码管理",
|
||||||
|
"slug": "06-invite-codes",
|
||||||
|
"route": "/invite-codes",
|
||||||
|
"url": "https://admin.adfahi.cn/invite-codes",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/06-invite-codes.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n邀请码管理\n状态\n全部\n邀请码\n查 询\n重 置\n生成邀请码\n每次生成 1 个邀请码,可多次使用。可指定企业与用户;勾选「不限制时间」则永久有效;开启「自动加好友」后,使用该码注册的用户将直接成为指定用户的好友。点击「查看」可查看使用该邀请码注册的用户列表。\n邀请码\t指定用户\t自动加好友\t使用人数\t创建人\t状态\t过期时间\t创建时间\t操作\n\n邀请码\n\t\n指定用户\n\t\n自动加好友\n\t\n使用人数\n\t\n创建人\n\t\n状态\n\t\n过期时间\n\t\n创建时间\n\t\n操作\n\n323441\t往事随风 (#2271)\t否\t0\t16\t启用\t2026-09-05 00:34:55\t2026-09-04 00:34:55\t\n查 看\n删 除\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"邀请码",
|
||||||
|
"指定用户",
|
||||||
|
"自动加好友",
|
||||||
|
"使用人数",
|
||||||
|
"创建人",
|
||||||
|
"状态",
|
||||||
|
"过期时间",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"邀请码",
|
||||||
|
"指定用户",
|
||||||
|
"自动加好友",
|
||||||
|
"使用人数",
|
||||||
|
"创建人",
|
||||||
|
"状态",
|
||||||
|
"过期时间",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"323441",
|
||||||
|
"往事随风 (#2271)",
|
||||||
|
"否",
|
||||||
|
"0",
|
||||||
|
"16",
|
||||||
|
"启用",
|
||||||
|
"2026-09-05 00:34:55",
|
||||||
|
"2026-09-04 00:34:55",
|
||||||
|
"查 看删 除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "6 位数字",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "生成邀请码",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 看",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"label": "单聊消息",
|
||||||
|
"slug": "07-direct-messages",
|
||||||
|
"route": "/private-messages",
|
||||||
|
"url": "https://admin.adfahi.cn/private-messages",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/07-direct-messages.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n单聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n接收人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收人\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n接收人\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"发送人",
|
||||||
|
"接收人",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作",
|
||||||
|
"发送人",
|
||||||
|
"接收人",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "关键字",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "开始时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "结束时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,393 @@
|
|||||||
|
{
|
||||||
|
"label": "单聊消息",
|
||||||
|
"slug": "07-direct-messages",
|
||||||
|
"route": "/private-messages",
|
||||||
|
"url": "https://admin.adfahi.cn/private-messages",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/07-direct-messages.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n单聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n接收人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收人\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n接收人\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t系统\t\n语音通话 00:13\n\t正常\t2026-07-31 23:02:22\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t系统\t\n语音通话 00:01\n\t正常\t2026-07-31 23:01:45\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t系统\t\n语音通话 已取消\n\t正常\t2026-07-31 23:01:36\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t系统\t\n语音通话 已拒绝\n\t正常\t2026-07-31 23:01:19\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 已取消\n\t正常\t2026-07-31 23:00:20\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 00:19\n\t正常\t2026-07-31 22:59:59\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n语音通话 00:07\n\t正常\t2026-07-31 22:59:32\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t系统\t\n语音通话 已取消\n\t正常\t2026-07-31 22:59:05\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n语音通话 00:15\n\t正常\t2026-07-31 22:58:42\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 00:07\n\t正常\t2026-07-31 22:58:20\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 已取消\n\t正常\t2026-07-31 22:58:07\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t文本\t\n红心\n\t正常\t2026-07-31 22:51:35\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t文本\t\n1\n\t正常\t2026-07-31 22:51:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t文本\t\n你想让我\n\t正常\t2026-07-31 22:51:32\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t文本\t\n1\n\t正常\t2026-07-31 22:51:32\t\n删 除\n1\n2\n3\n4\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"发送人",
|
||||||
|
"接收人",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作",
|
||||||
|
"发送人",
|
||||||
|
"接收人",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯仁飞hy91144536",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:06:05",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:06:05",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:05:19",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯仁飞hy91144536",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:04:12",
|
||||||
|
"删 除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "关键字",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "开始时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "结束时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
{
|
||||||
|
"label": "群聊消息",
|
||||||
|
"slug": "08-group-messages",
|
||||||
|
"route": "/group-messages",
|
||||||
|
"url": "https://admin.adfahi.cn/group-messages",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/08-group-messages.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t群名称\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n群名称\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"发送人",
|
||||||
|
"群名称",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作",
|
||||||
|
"发送人",
|
||||||
|
"群名称",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "关键字",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "开始时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "结束时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,379 @@
|
|||||||
|
{
|
||||||
|
"label": "群聊消息",
|
||||||
|
"slug": "08-group-messages",
|
||||||
|
"route": "/group-messages",
|
||||||
|
"url": "https://admin.adfahi.cn/group-messages",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/08-group-messages.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t群名称\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n群名称\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\nF\nhy69089908\n\t\n冯\n68127154\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n89233971\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n62262588\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n89233971\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n68127154\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n68127154\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n89233971\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n62262588\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:03:50\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n😊😊😊😊\n\t正常\t2026-07-31 22:53:42\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nkddkkffjc\n\t正常\t2026-07-31 22:53:18\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nkdododdk\n\t正常\t2026-07-31 22:53:17\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkdkkddoso\n\t正常\t2026-07-31 22:53:16\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkkfkfkd\n\t正常\t2026-07-31 22:53:15\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkfkkdod\n\t正常\t2026-07-31 22:53:14\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t文本\t\n敏敏\n\t正常\t2026-07-31 22:53:13\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkfkfkdo\n\t正常\t2026-07-31 22:53:13\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t文本\t\n您提着\n\t正常\t2026-07-31 22:53:12\t\n删 除\n1\n2\n3\n4\n5\n•••\n8\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"发送人",
|
||||||
|
"群名称",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作",
|
||||||
|
"发送人",
|
||||||
|
"群名称",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯68127154",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:06:05",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯氏家族89233971",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:06:05",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯氏家族17776111",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:06:05",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯62262588",
|
||||||
|
"文本",
|
||||||
|
"哈哈哈哈",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 23:05:19",
|
||||||
|
"删 除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "关键字",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "开始时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "结束时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"label": "敏感词库",
|
||||||
|
"slug": "09-sensitive-words",
|
||||||
|
"route": "/sensitive-words",
|
||||||
|
"url": "https://admin.adfahi.cn/sensitive-words",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/09-sensitive-words.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n敏感词库\n状态\n全部\n等级\n全部\n关键词\n查 询\n重 置\n新增敏感词\n批量导入\n文件导入\n批量导出\nID\t敏感词\t等级\t替换词\t状态\t创建时间\t操作\n\nID\n\t\n敏感词\n\t\n等级\n\t\n替换词\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"ID",
|
||||||
|
"敏感词",
|
||||||
|
"等级",
|
||||||
|
"替换词",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"ID",
|
||||||
|
"敏感词",
|
||||||
|
"等级",
|
||||||
|
"替换词",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "敏感词",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "新增敏感词"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量导入"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "文件导入"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量导出"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
{
|
||||||
|
"label": "敏感词库",
|
||||||
|
"slug": "09-sensitive-words",
|
||||||
|
"route": "/sensitive-words",
|
||||||
|
"url": "https://admin.adfahi.cn/sensitive-words",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/09-sensitive-words.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n敏感词库\n状态\n全部\n等级\n全部\n关键词\n查 询\n重 置\n新增敏感词\n批量导入\n文件导入\n批量导出\nID\t敏感词\t等级\t替换词\t状态\t创建时间\t操作\n\nID\n\t\n敏感词\n\t\n等级\n\t\n替换词\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"ID",
|
||||||
|
"敏感词",
|
||||||
|
"等级",
|
||||||
|
"替换词",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"ID",
|
||||||
|
"敏感词",
|
||||||
|
"等级",
|
||||||
|
"替换词",
|
||||||
|
"状态",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "敏感词",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "新增敏感词",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量导入",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "文件导入",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量导出",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
{
|
||||||
|
"label": "文件管理",
|
||||||
|
"slug": "10-files",
|
||||||
|
"route": "/file-records",
|
||||||
|
"url": "https://admin.adfahi.cn/file-records",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/10-files.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n文件管理\n全部\n图片\n视频\n音频\n文档\n其他\n发送人用户名\n文件名\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收方\t类型\t内容\t文件名\t文件大小\tURL\t状态\t发送时间\t操作\n\n发送人\n\t\n接收方\n\t\n类型\n\t\n内容\n\t\n文件名\n\t\n文件大小\n\t\nURL\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n64919\n92851806\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n346亿916\n75874312\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:46:46\t\n删 除\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"发送人",
|
||||||
|
"接收方",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"文件名",
|
||||||
|
"文件大小",
|
||||||
|
"URL",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作",
|
||||||
|
"发送人",
|
||||||
|
"接收方",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"文件名",
|
||||||
|
"文件大小",
|
||||||
|
"URL",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"Fhy69089908",
|
||||||
|
"图片",
|
||||||
|
"预览下载",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"https://gdd-chat-fls.oss-a...",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:48:33",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"冯氏家族17776111",
|
||||||
|
"图片",
|
||||||
|
"预览下载",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"https://gdd-chat-fls.oss-a...",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:48:33",
|
||||||
|
"删 除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "搜索文件名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "开始时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "结束时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
{
|
||||||
|
"label": "文件管理",
|
||||||
|
"slug": "10-files",
|
||||||
|
"route": "/file-records",
|
||||||
|
"url": "https://admin.adfahi.cn/file-records",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/10-files.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n文件管理\n全部\n图片\n视频\n音频\n文档\n其他\n发送人用户名\n文件名\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收方\t类型\t内容\t文件名\t文件大小\tURL\t状态\t发送时间\t操作\n\n发送人\n\t\n接收方\n\t\n类型\n\t\n内容\n\t\n文件名\n\t\n文件大小\n\t\nURL\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n64919\n92851806\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n346亿916\n75874312\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:46:46\t\n删 除\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"发送人",
|
||||||
|
"接收方",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"文件名",
|
||||||
|
"文件大小",
|
||||||
|
"URL",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作",
|
||||||
|
"发送人",
|
||||||
|
"接收方",
|
||||||
|
"类型",
|
||||||
|
"内容",
|
||||||
|
"文件名",
|
||||||
|
"文件大小",
|
||||||
|
"URL",
|
||||||
|
"状态",
|
||||||
|
"发送时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"Fhy69089908",
|
||||||
|
"图片",
|
||||||
|
"预览下载",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"https://gdd-chat-fls.oss-a...",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:48:33",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"冯氏家族17776111",
|
||||||
|
"图片",
|
||||||
|
"预览下载",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"https://gdd-chat-fls.oss-a...",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:48:33",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"6491992851806",
|
||||||
|
"图片",
|
||||||
|
"预览下载",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"https://gdd-chat-fls.oss-a...",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:48:33",
|
||||||
|
"删 除"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"346亿91675874312",
|
||||||
|
"图片",
|
||||||
|
"预览下载",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"https://gdd-chat-fls.oss-a...",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:48:33",
|
||||||
|
"删 除"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "搜索文件名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "开始时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "结束时间",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "刷 新",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "下载",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "删 除",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
{
|
||||||
|
"label": "用户反馈",
|
||||||
|
"slug": "11-feedback",
|
||||||
|
"route": "/feedbacks",
|
||||||
|
"url": "https://admin.adfahi.cn/feedbacks",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/11-feedback.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户反馈\n用户ID\n状态\n全部\n优先级\n全部\n关键词\n查 询\n重 置\n批量处理\n导出 CSV\n\t用户\t优先级\t内容\t状态\t处理人\t创建时间\t操作\n\n\t\n用户\n\t\n优先级\n\t\n内容\n\t\n状态\n\t\n处理人\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"用户",
|
||||||
|
"优先级",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"处理人",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"用户",
|
||||||
|
"优先级",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"处理人",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户ID",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "内容/联系方式",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量处理"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "导出 CSV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
{
|
||||||
|
"label": "用户反馈",
|
||||||
|
"slug": "11-feedback",
|
||||||
|
"route": "/feedbacks",
|
||||||
|
"url": "https://admin.adfahi.cn/feedbacks",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/11-feedback.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户反馈\n用户ID\n状态\n全部\n优先级\n全部\n关键词\n查 询\n重 置\n批量处理\n导出 CSV\n\t用户\t优先级\t内容\t状态\t处理人\t创建时间\t操作\n\n\t\n用户\n\t\n优先级\n\t\n内容\n\t\n状态\n\t\n处理人\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"用户",
|
||||||
|
"优先级",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"处理人",
|
||||||
|
"创建时间",
|
||||||
|
"操作",
|
||||||
|
"用户",
|
||||||
|
"优先级",
|
||||||
|
"内容",
|
||||||
|
"状态",
|
||||||
|
"处理人",
|
||||||
|
"创建时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"暂无数据暂无数据"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户ID",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "内容/联系方式",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查 询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "批量处理",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "导出 CSV",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "on"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
"label": "操作日志",
|
||||||
|
"slug": "12-operation-logs",
|
||||||
|
"route": "/audit-logs",
|
||||||
|
"url": "https://admin.adfahi.cn/audit-logs",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/12-operation-logs.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n操作日志\n动作\n全部\n目标类型\n全部\n目标用户\n目标群\n开始时间\n结束时间\n查询\n重 置\n导出 CSV\n管理员\t动作\t目标类型\t目标\t查询条件\tIP\t时间\n\n管理员\n\t\n动作\n\t\n目标类型\n\t\n目标\n\t\n查询条件\n\t\nIP\n\t\n时间\n\nheiyue\t创建用户\t用户\t\npoter001\nhy73074162\n\t\n--\n\t104.30.173.163\t2026-08-01 00:04:25\nheiyue\t重置密码\t用户\t\n往事随风\nhy17716319\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:23\nheiyue\t重置密码\t用户\t\n坚守的山羊\nhy34899108\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:19\nheiyue\t重置密码\t用户\t\n沉稳的松鼠\nhy45257043\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:16\nheiyue\t重置密码\t用户\t\n专注的白兔\nhy69598195\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:12\nheiyue\t重置密码\t用户\t\n沉稳的黑猫\nhy20144467\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:09\nheiyue\t重置密码\t用户\t\n坚韧的河马\nhy70299474\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:05\nheiyue\t重置密码\t用户\t\n求真的猫头\nhy23799134\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:00\nheiyue\t重置密码\t用户\t\n进取的北狐\nhy18959373\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:55\nheiyue\t重置密码\t用户\t\n温润的乌鸦\nhy80424632\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:51\nheiyue\t重置密码\t用户\t\n乐观的野马\nhy98400466\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:48\nheiyue\t批量创建用户\t用户\t--\t\n详情\n\t141.164.107.33\t2026-07-31 22:44:06\nheiyue\t创建用户\t用户\t\nF\nhy99111080\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:53\nheiyue\t创建用户\t用户\t\nF\nhy92120233\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:37\nheiyue\t创建用户\t用户\t\nF\nhy69089908\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:12\nheiyue\t创建用户\t用户\t\n冯仁飞\nhy91144536\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:02\nheiyue\t创建用户\t用户\t\n冯宇昂\nhy50703413\n\t\n--\n\t141.164.107.33\t2026-07-31 22:42:45\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"管理员",
|
||||||
|
"动作",
|
||||||
|
"目标类型",
|
||||||
|
"目标",
|
||||||
|
"查询条件",
|
||||||
|
"IP",
|
||||||
|
"时间",
|
||||||
|
"管理员",
|
||||||
|
"动作",
|
||||||
|
"目标类型",
|
||||||
|
"目标",
|
||||||
|
"查询条件",
|
||||||
|
"IP",
|
||||||
|
"时间"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"创建用户",
|
||||||
|
"用户",
|
||||||
|
"poter001hy73074162",
|
||||||
|
"--",
|
||||||
|
"104.30.173.163",
|
||||||
|
"2026-08-01 00:04:25"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"重置密码",
|
||||||
|
"用户",
|
||||||
|
"往事随风hy17716319",
|
||||||
|
"--",
|
||||||
|
"141.164.107.33",
|
||||||
|
"2026-07-31 22:45:23"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "群号",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "导出 CSV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详情"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
{
|
||||||
|
"label": "操作日志",
|
||||||
|
"slug": "12-operation-logs",
|
||||||
|
"route": "/audit-logs",
|
||||||
|
"url": "https://admin.adfahi.cn/audit-logs",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/12-operation-logs.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n操作日志\n动作\n全部\n目标类型\n全部\n目标用户\n目标群\n开始时间\n结束时间\n查询\n重 置\n导出 CSV\n管理员\t动作\t目标类型\t目标\t查询条件\tIP\t时间\n\n管理员\n\t\n动作\n\t\n目标类型\n\t\n目标\n\t\n查询条件\n\t\nIP\n\t\n时间\n\nheiyue\t创建用户\t用户\t\npoter001\nhy73074162\n\t\n--\n\t104.30.173.163\t2026-08-01 00:04:25\nheiyue\t重置密码\t用户\t\n往事随风\nhy17716319\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:23\nheiyue\t重置密码\t用户\t\n坚守的山羊\nhy34899108\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:19\nheiyue\t重置密码\t用户\t\n沉稳的松鼠\nhy45257043\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:16\nheiyue\t重置密码\t用户\t\n专注的白兔\nhy69598195\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:12\nheiyue\t重置密码\t用户\t\n沉稳的黑猫\nhy20144467\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:09\nheiyue\t重置密码\t用户\t\n坚韧的河马\nhy70299474\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:05\nheiyue\t重置密码\t用户\t\n求真的猫头\nhy23799134\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:00\nheiyue\t重置密码\t用户\t\n进取的北狐\nhy18959373\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:55\nheiyue\t重置密码\t用户\t\n温润的乌鸦\nhy80424632\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:51\nheiyue\t重置密码\t用户\t\n乐观的野马\nhy98400466\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:48\nheiyue\t批量创建用户\t用户\t--\t\n详情\n\t141.164.107.33\t2026-07-31 22:44:06\nheiyue\t创建用户\t用户\t\nF\nhy99111080\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:53\nheiyue\t创建用户\t用户\t\nF\nhy92120233\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:37\nheiyue\t创建用户\t用户\t\nF\nhy69089908\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:12\nheiyue\t创建用户\t用户\t\n冯仁飞\nhy91144536\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:02\nheiyue\t创建用户\t用户\t\n冯宇昂\nhy50703413\n\t\n--\n\t141.164.107.33\t2026-07-31 22:42:45\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"管理员",
|
||||||
|
"动作",
|
||||||
|
"目标类型",
|
||||||
|
"目标",
|
||||||
|
"查询条件",
|
||||||
|
"IP",
|
||||||
|
"时间",
|
||||||
|
"管理员",
|
||||||
|
"动作",
|
||||||
|
"目标类型",
|
||||||
|
"目标",
|
||||||
|
"查询条件",
|
||||||
|
"IP",
|
||||||
|
"时间"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"创建用户",
|
||||||
|
"用户",
|
||||||
|
"poter001hy73074162",
|
||||||
|
"--",
|
||||||
|
"104.30.173.163",
|
||||||
|
"2026-08-01 00:04:25"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"重置密码",
|
||||||
|
"用户",
|
||||||
|
"往事随风hy17716319",
|
||||||
|
"--",
|
||||||
|
"141.164.107.33",
|
||||||
|
"2026-07-31 22:45:23"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"重置密码",
|
||||||
|
"用户",
|
||||||
|
"坚守的山羊hy34899108",
|
||||||
|
"--",
|
||||||
|
"141.164.107.33",
|
||||||
|
"2026-07-31 22:45:19"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"重置密码",
|
||||||
|
"用户",
|
||||||
|
"沉稳的松鼠hy45257043",
|
||||||
|
"--",
|
||||||
|
"141.164.107.33",
|
||||||
|
"2026-07-31 22:45:16"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "群号",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "导出 CSV",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "详情",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
{
|
||||||
|
"label": "群事件审计",
|
||||||
|
"slug": "14-group-event-audit",
|
||||||
|
"route": "/group-events",
|
||||||
|
"url": "https://admin.adfahi.cn/group-events",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/14-group-event-audit.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群事件审计\n群号\n操作人\n目标用户\n事件类型\n全部\n开始时间\n结束时间\n查询\n重 置\n群名称\t事件类型\t操作人\t目标用户\t可见范围\t旧值\t新值\t时间\n\n群名称\n\t\n事件类型\n\t\n操作人\n\t\n目标用户\n\t\n可见范围\n\t\n旧值\n\t\n新值\n\t\n时间\n\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n68127154\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:52\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯\n62262588\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:38\n\n冯氏家族\n17776111\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:34\n\n346亿916\n75874312\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:57\n\n64919\n92851806\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:50\n\n冯氏家族\n17776111\n\t成员加入\t\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 22:47:19\n\n冯氏家族\n89233971\n\t群创建\t\n冯仁飞\nhy91144536\n\t--\t全员可见\t--\t--\t2026-07-31 22:46:59\n\n冯氏家族\n17776111\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:45:28\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"群名称",
|
||||||
|
"事件类型",
|
||||||
|
"操作人",
|
||||||
|
"目标用户",
|
||||||
|
"可见范围",
|
||||||
|
"旧值",
|
||||||
|
"新值",
|
||||||
|
"时间",
|
||||||
|
"群名称",
|
||||||
|
"事件类型",
|
||||||
|
"操作人",
|
||||||
|
"目标用户",
|
||||||
|
"可见范围",
|
||||||
|
"旧值",
|
||||||
|
"新值",
|
||||||
|
"时间"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"冯62262588",
|
||||||
|
"成员加入",
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"全员可见",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"2026-07-31 23:03:42"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯62262588",
|
||||||
|
"成员加入",
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯仁飞hy91144536",
|
||||||
|
"全员可见",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"2026-07-31 23:03:42"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
{
|
||||||
|
"label": "群事件审计",
|
||||||
|
"slug": "14-group-event-audit",
|
||||||
|
"route": "/group-events",
|
||||||
|
"url": "https://admin.adfahi.cn/group-events",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/14-group-event-audit.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群事件审计\n群号\n操作人\n目标用户\n事件类型\n全部\n开始时间\n结束时间\n查询\n重 置\n群名称\t事件类型\t操作人\t目标用户\t可见范围\t旧值\t新值\t时间\n\n群名称\n\t\n事件类型\n\t\n操作人\n\t\n目标用户\n\t\n可见范围\n\t\n旧值\n\t\n新值\n\t\n时间\n\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n68127154\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:52\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯\n62262588\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:38\n\n冯氏家族\n17776111\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:34\n\n346亿916\n75874312\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:57\n\n64919\n92851806\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:50\n\n冯氏家族\n17776111\n\t成员加入\t\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 22:47:19\n\n冯氏家族\n89233971\n\t群创建\t\n冯仁飞\nhy91144536\n\t--\t全员可见\t--\t--\t2026-07-31 22:46:59\n\n冯氏家族\n17776111\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:45:28\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"群名称",
|
||||||
|
"事件类型",
|
||||||
|
"操作人",
|
||||||
|
"目标用户",
|
||||||
|
"可见范围",
|
||||||
|
"旧值",
|
||||||
|
"新值",
|
||||||
|
"时间",
|
||||||
|
"群名称",
|
||||||
|
"事件类型",
|
||||||
|
"操作人",
|
||||||
|
"目标用户",
|
||||||
|
"可见范围",
|
||||||
|
"旧值",
|
||||||
|
"新值",
|
||||||
|
"时间"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"冯62262588",
|
||||||
|
"成员加入",
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"全员可见",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"2026-07-31 23:03:42"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯62262588",
|
||||||
|
"成员加入",
|
||||||
|
"Fhy69089908",
|
||||||
|
"冯仁飞hy91144536",
|
||||||
|
"全员可见",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"2026-07-31 23:03:42"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯68127154",
|
||||||
|
"群创建",
|
||||||
|
"Fhy69089908",
|
||||||
|
"--",
|
||||||
|
"全员可见",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"2026-07-31 22:50:52"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"冯氏家族89233971",
|
||||||
|
"成员加入",
|
||||||
|
"冯仁飞hy91144536",
|
||||||
|
"冯宇昂hy50703413",
|
||||||
|
"全员可见",
|
||||||
|
"--",
|
||||||
|
"--",
|
||||||
|
"2026-07-31 22:50:43"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "用户名",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
{
|
||||||
|
"label": "管理员登录",
|
||||||
|
"slug": "15-admin-login",
|
||||||
|
"route": "/admin-login-history",
|
||||||
|
"url": "https://admin.adfahi.cn/admin-login-history",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/15-admin-login.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n管理员登录历史\n开始时间\n结束时间\n查询\n用户名\t登录时间\tUser-Agent\tIP 地址\n\n用户名\n\t\n登录时间\n\t\nUser-Agent\n\t\nIP 地址\n\nheiyue\t2026-09-04 00:10:57\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36\t103.136.251.99\nheiyue\t2026-08-01 00:03:52\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 22:47:31\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t141.164.107.235\nheiyue\t2026-07-31 22:42:09\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t141.164.107.33\nheiyue\t2026-07-31 21:32:28\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 00:45:59\tMozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1\t203.160.80.152\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"用户名",
|
||||||
|
"登录时间",
|
||||||
|
"User-Agent",
|
||||||
|
"IP 地址",
|
||||||
|
"用户名",
|
||||||
|
"登录时间",
|
||||||
|
"User-Agent",
|
||||||
|
"IP 地址"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"2026-09-04 00:10:57",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
|
||||||
|
"103.136.251.99"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"2026-08-01 00:03:52",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
|
||||||
|
"104.30.173.163"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
{
|
||||||
|
"label": "管理员登录",
|
||||||
|
"slug": "15-admin-login",
|
||||||
|
"route": "/admin-login-history",
|
||||||
|
"url": "https://admin.adfahi.cn/admin-login-history",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/15-admin-login.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n管理员登录历史\n开始时间\n结束时间\n查询\n用户名\t登录时间\tUser-Agent\tIP 地址\n\n用户名\n\t\n登录时间\n\t\nUser-Agent\n\t\nIP 地址\n\nheiyue\t2026-09-04 00:10:57\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36\t103.136.251.99\nheiyue\t2026-08-01 00:03:52\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 22:47:31\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t141.164.107.235\nheiyue\t2026-07-31 22:42:09\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t141.164.107.33\nheiyue\t2026-07-31 21:32:28\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 00:45:59\tMozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1\t203.160.80.152\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"用户名",
|
||||||
|
"登录时间",
|
||||||
|
"User-Agent",
|
||||||
|
"IP 地址",
|
||||||
|
"用户名",
|
||||||
|
"登录时间",
|
||||||
|
"User-Agent",
|
||||||
|
"IP 地址"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"2026-09-04 00:10:57",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
|
||||||
|
"103.136.251.99"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"2026-08-01 00:03:52",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
|
||||||
|
"104.30.173.163"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"2026-07-31 22:47:31",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
|
||||||
|
"141.164.107.235"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"heiyue",
|
||||||
|
"2026-07-31 22:42:09",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0",
|
||||||
|
"141.164.107.33"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
{
|
||||||
|
"label": "用户登录",
|
||||||
|
"slug": "16-user-login",
|
||||||
|
"route": "/user-login-history",
|
||||||
|
"url": "https://admin.adfahi.cn/user-login-history",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/16-user-login.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户登录历史\n用户编号\n用户名\n开始时间\n结束时间\nIP\n查询\n重 置\n用户编号\t用户名\t当前状态\t登录时间\t设备类型\t设备型号\t系统版本\tApp 版本\tIP 地址\t归属地\t操作\n\n用户编号\n\t\n用户名\n\t\n当前状态\n\t\n登录时间\n\t\n设备类型\n\t\n设备型号\n\t\n系统版本\n\t\nApp 版本\n\t\nIP 地址\n\t\n归属地\n\t\n操作\n\n16\thy73074162\t正常\t2026-08-01 00:04:47\tweb\tChrome Browser\tMac OS X 10.15.7\t-\t104.30.173.163\t美国 加利福尼亚州 罗斯维尔\t\n快速封禁\n\n15\thy17716319\t正常\t2026-07-31 22:50:19\tandroid\tOPPO PCHM10\tAndroid 11\t1.1.2\t141.164.107.33\t老挝 万象市 永珍\t\n快速封禁\n\n3\thy69089908\t正常\t2026-07-31 22:47:10\tandroid\tOPPO PKW110\tAndroid 16\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n2\thy91144536\t正常\t2026-07-31 22:45:28\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:45:10\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:44:44\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:43:38\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"用户编号",
|
||||||
|
"用户名",
|
||||||
|
"当前状态",
|
||||||
|
"登录时间",
|
||||||
|
"设备类型",
|
||||||
|
"设备型号",
|
||||||
|
"系统版本",
|
||||||
|
"App 版本",
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"操作",
|
||||||
|
"用户编号",
|
||||||
|
"用户名",
|
||||||
|
"当前状态",
|
||||||
|
"登录时间",
|
||||||
|
"设备类型",
|
||||||
|
"设备型号",
|
||||||
|
"系统版本",
|
||||||
|
"App 版本",
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"16",
|
||||||
|
"hy73074162",
|
||||||
|
"正常",
|
||||||
|
"2026-08-01 00:04:47",
|
||||||
|
"web",
|
||||||
|
"Chrome Browser",
|
||||||
|
"Mac OS X 10.15.7",
|
||||||
|
"-",
|
||||||
|
"104.30.173.163",
|
||||||
|
"美国 加利福尼亚州 罗斯维尔",
|
||||||
|
"快速封禁"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"15",
|
||||||
|
"hy17716319",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:19",
|
||||||
|
"android",
|
||||||
|
"OPPO PCHM10",
|
||||||
|
"Android 11",
|
||||||
|
"1.1.2",
|
||||||
|
"141.164.107.33",
|
||||||
|
"老挝 万象市 永珍",
|
||||||
|
"快速封禁"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "登录IP",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
{
|
||||||
|
"label": "用户登录",
|
||||||
|
"slug": "16-user-login",
|
||||||
|
"route": "/user-login-history",
|
||||||
|
"url": "https://admin.adfahi.cn/user-login-history",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/16-user-login.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户登录历史\n用户编号\n用户名\n开始时间\n结束时间\nIP\n查询\n重 置\n用户编号\t用户名\t当前状态\t登录时间\t设备类型\t设备型号\t系统版本\tApp 版本\tIP 地址\t归属地\t操作\n\n用户编号\n\t\n用户名\n\t\n当前状态\n\t\n登录时间\n\t\n设备类型\n\t\n设备型号\n\t\n系统版本\n\t\nApp 版本\n\t\nIP 地址\n\t\n归属地\n\t\n操作\n\n16\thy73074162\t正常\t2026-08-01 00:04:47\tweb\tChrome Browser\tMac OS X 10.15.7\t-\t104.30.173.163\t美国 加利福尼亚州 罗斯维尔\t\n快速封禁\n\n15\thy17716319\t正常\t2026-07-31 22:50:19\tandroid\tOPPO PCHM10\tAndroid 11\t1.1.2\t141.164.107.33\t老挝 万象市 永珍\t\n快速封禁\n\n3\thy69089908\t正常\t2026-07-31 22:47:10\tandroid\tOPPO PKW110\tAndroid 16\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n2\thy91144536\t正常\t2026-07-31 22:45:28\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:45:10\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:44:44\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:43:38\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"用户编号",
|
||||||
|
"用户名",
|
||||||
|
"当前状态",
|
||||||
|
"登录时间",
|
||||||
|
"设备类型",
|
||||||
|
"设备型号",
|
||||||
|
"系统版本",
|
||||||
|
"App 版本",
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"操作",
|
||||||
|
"用户编号",
|
||||||
|
"用户名",
|
||||||
|
"当前状态",
|
||||||
|
"登录时间",
|
||||||
|
"设备类型",
|
||||||
|
"设备型号",
|
||||||
|
"系统版本",
|
||||||
|
"App 版本",
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"16",
|
||||||
|
"hy73074162",
|
||||||
|
"正常",
|
||||||
|
"2026-08-01 00:04:47",
|
||||||
|
"web",
|
||||||
|
"Chrome Browser",
|
||||||
|
"Mac OS X 10.15.7",
|
||||||
|
"-",
|
||||||
|
"104.30.173.163",
|
||||||
|
"美国 加利福尼亚州 罗斯维尔",
|
||||||
|
"快速封禁"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"15",
|
||||||
|
"hy17716319",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:50:19",
|
||||||
|
"android",
|
||||||
|
"OPPO PCHM10",
|
||||||
|
"Android 11",
|
||||||
|
"1.1.2",
|
||||||
|
"141.164.107.33",
|
||||||
|
"老挝 万象市 永珍",
|
||||||
|
"快速封禁"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"hy69089908",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:47:10",
|
||||||
|
"android",
|
||||||
|
"OPPO PKW110",
|
||||||
|
"Android 16",
|
||||||
|
"1.1.2",
|
||||||
|
"61.153.184.95",
|
||||||
|
"浙江 绍兴",
|
||||||
|
"快速封禁"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"hy91144536",
|
||||||
|
"正常",
|
||||||
|
"2026-07-31 22:45:28",
|
||||||
|
"android",
|
||||||
|
"HONOR LOG-AN00",
|
||||||
|
"Android 15",
|
||||||
|
"1.1.2",
|
||||||
|
"61.153.184.95",
|
||||||
|
"浙江 绍兴",
|
||||||
|
"快速封禁"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "登录IP",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "快速封禁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
{
|
||||||
|
"label": "IP 账号统计",
|
||||||
|
"slug": "17-ip-account-stats",
|
||||||
|
"route": "/ip-user-stats",
|
||||||
|
"url": "https://admin.adfahi.cn/ip-user-stats",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/17-ip-account-stats.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\nIP 账号统计\nIP\n查询\n重 置\nIP 地址\t归属地\t关联用户\t注册用户\t登录用户\t正常\t已封禁\t最近活动\t操作\n\nIP 地址\n\t\n归属地\n\t\n关联用户\n\t\n注册用户\n\t\n登录用户\n\t\n正常\n\t\n已封禁\n\t\n最近活动\n\t\n操作\n\n61.153.184.95\t浙江 绍兴\t\n3\n多账号\n\t0\t3\t3\t0\t2026-08-02 22:27:59\t\n用户列表\n共 1 个 IP\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"关联用户",
|
||||||
|
"注册用户",
|
||||||
|
"登录用户",
|
||||||
|
"正常",
|
||||||
|
"已封禁",
|
||||||
|
"最近活动",
|
||||||
|
"操作",
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"关联用户",
|
||||||
|
"注册用户",
|
||||||
|
"登录用户",
|
||||||
|
"正常",
|
||||||
|
"已封禁",
|
||||||
|
"最近活动",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"61.153.184.95",
|
||||||
|
"浙江 绍兴",
|
||||||
|
"3多账号",
|
||||||
|
"0",
|
||||||
|
"3",
|
||||||
|
"3",
|
||||||
|
"0",
|
||||||
|
"2026-08-02 22:27:59",
|
||||||
|
"用户列表"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "IPv4 或 IPv6",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "用户列表"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"label": "IP 账号统计",
|
||||||
|
"slug": "17-ip-account-stats",
|
||||||
|
"route": "/ip-user-stats",
|
||||||
|
"url": "https://admin.adfahi.cn/ip-user-stats",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/17-ip-account-stats.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\nIP 账号统计\nIP\n查询\n重 置\nIP 地址\t归属地\t关联用户\t注册用户\t登录用户\t正常\t已封禁\t最近活动\t操作\n\nIP 地址\n\t\n归属地\n\t\n关联用户\n\t\n注册用户\n\t\n登录用户\n\t\n正常\n\t\n已封禁\n\t\n最近活动\n\t\n操作\n\n61.153.184.95\t浙江 绍兴\t\n3\n多账号\n\t0\t3\t3\t0\t2026-08-02 22:27:59\t\n用户列表\n共 1 个 IP\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"关联用户",
|
||||||
|
"注册用户",
|
||||||
|
"登录用户",
|
||||||
|
"正常",
|
||||||
|
"已封禁",
|
||||||
|
"最近活动",
|
||||||
|
"操作",
|
||||||
|
"IP 地址",
|
||||||
|
"归属地",
|
||||||
|
"关联用户",
|
||||||
|
"注册用户",
|
||||||
|
"登录用户",
|
||||||
|
"正常",
|
||||||
|
"已封禁",
|
||||||
|
"最近活动",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"61.153.184.95",
|
||||||
|
"浙江 绍兴",
|
||||||
|
"3多账号",
|
||||||
|
"0",
|
||||||
|
"3",
|
||||||
|
"3",
|
||||||
|
"0",
|
||||||
|
"2026-08-02 22:27:59",
|
||||||
|
"用户列表"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "IPv4 或 IPv6",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "用户列表",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
{
|
||||||
|
"label": "登录失败日志",
|
||||||
|
"slug": "18-login-failures",
|
||||||
|
"route": "/login-failure-logs",
|
||||||
|
"url": "https://admin.adfahi.cn/login-failure-logs",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/18-login-failures.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n登录失败日志\n类型\n全部\n登录账号\nIP\n开始时间\n结束时间\n查询\n重 置\n类型\t登录账号\t失败原因\tIP 地址\tUser-Agent\t时间\t操作\n\n类型\n\t\n登录账号\n\t\n失败原因\n\t\nIP 地址\n\t\nUser-Agent\n\t\n时间\n\t\n操作\n\n用户\t13800001111\t密码错误\t106.119.66.106\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t2026-08-01 01:31:20\t\n解锁\n\n用户\t13800001111\t密码错误\t61.153.184.95\tokhttp/4.12.0\t2026-07-31 22:44:36\t\n解锁\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"类型",
|
||||||
|
"登录账号",
|
||||||
|
"失败原因",
|
||||||
|
"IP 地址",
|
||||||
|
"User-Agent",
|
||||||
|
"时间",
|
||||||
|
"操作",
|
||||||
|
"类型",
|
||||||
|
"登录账号",
|
||||||
|
"失败原因",
|
||||||
|
"IP 地址",
|
||||||
|
"User-Agent",
|
||||||
|
"时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"用户",
|
||||||
|
"13800001111",
|
||||||
|
"密码错误",
|
||||||
|
"106.119.66.106",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0",
|
||||||
|
"2026-08-01 01:31:20",
|
||||||
|
"解锁"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"用户",
|
||||||
|
"13800001111",
|
||||||
|
"密码错误",
|
||||||
|
"61.153.184.95",
|
||||||
|
"okhttp/4.12.0",
|
||||||
|
"2026-07-31 22:44:36",
|
||||||
|
"解锁"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解锁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解锁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
{
|
||||||
|
"label": "登录失败日志",
|
||||||
|
"slug": "18-login-failures",
|
||||||
|
"route": "/login-failure-logs",
|
||||||
|
"url": "https://admin.adfahi.cn/login-failure-logs",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/18-login-failures.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n登录失败日志\n类型\n全部\n登录账号\nIP\n开始时间\n结束时间\n查询\n重 置\n类型\t登录账号\t失败原因\tIP 地址\tUser-Agent\t时间\t操作\n\n类型\n\t\n登录账号\n\t\n失败原因\n\t\nIP 地址\n\t\nUser-Agent\n\t\n时间\n\t\n操作\n\n用户\t13800001111\t密码错误\t106.119.66.106\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t2026-08-01 01:31:20\t\n解锁\n\n用户\t13800001111\t密码错误\t61.153.184.95\tokhttp/4.12.0\t2026-07-31 22:44:36\t\n解锁\n1\n20 条/页",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
"类型",
|
||||||
|
"登录账号",
|
||||||
|
"失败原因",
|
||||||
|
"IP 地址",
|
||||||
|
"User-Agent",
|
||||||
|
"时间",
|
||||||
|
"操作",
|
||||||
|
"类型",
|
||||||
|
"登录账号",
|
||||||
|
"失败原因",
|
||||||
|
"IP 地址",
|
||||||
|
"User-Agent",
|
||||||
|
"时间",
|
||||||
|
"操作"
|
||||||
|
],
|
||||||
|
"idx": 0,
|
||||||
|
"rows": [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
"用户",
|
||||||
|
"13800001111",
|
||||||
|
"密码错误",
|
||||||
|
"106.119.66.106",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0",
|
||||||
|
"2026-08-01 01:31:20",
|
||||||
|
"解锁"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"用户",
|
||||||
|
"13800001111",
|
||||||
|
"密码错误",
|
||||||
|
"61.153.184.95",
|
||||||
|
"okhttp/4.12.0",
|
||||||
|
"2026-07-31 22:44:36",
|
||||||
|
"解锁"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "全部",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "可选",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "查询",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "重 置",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解锁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "解锁",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": true,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "DIV",
|
||||||
|
"text": "20 条/页",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"label": "私域设置",
|
||||||
|
"slug": "19-private-domain-settings",
|
||||||
|
"route": "/tenant-settings",
|
||||||
|
"url": "https://admin.adfahi.cn/tenant-settings",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/19-private-domain-settings.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n私域设置\n私域设置 - 黑月测试\n消息字符上限\n范围 1~5000,仅允许调低\n图片大小上限(MB)\n范围 1~1000 MB\n文件大小上限(MB)\n范围 1~1000 MB,默认 50 MB\n最大撤回消息时间(分钟)\n群主/管理员撤回自己或他人消息的最长时限,范围 1~1440 分钟;普通用户撤回自己的消息固定为 2 分钟\n是否开启手机验证码\n开启\n关闭\n关闭后,注册仅支持邀请码,短信登录与忘记密码不可用\n保存设置",
|
||||||
|
"tables": [],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "开启关闭"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "保存设置"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"label": "私域设置",
|
||||||
|
"slug": "19-private-domain-settings",
|
||||||
|
"route": "/tenant-settings",
|
||||||
|
"url": "https://admin.adfahi.cn/tenant-settings",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/19-private-domain-settings.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n私域设置\n私域设置 - 黑月测试\n消息字符上限\n范围 1~5000,仅允许调低\n图片大小上限(MB)\n范围 1~1000 MB\n文件大小上限(MB)\n范围 1~1000 MB,默认 50 MB\n最大撤回消息时间(分钟)\n群主/管理员撤回自己或他人消息的最长时限,范围 1~1440 分钟;普通用户撤回自己的消息固定为 2 分钟\n是否开启手机验证码\n开启\n关闭\n关闭后,注册仅支持邀请码,短信登录与忘记密码不可用\n保存设置",
|
||||||
|
"tables": [],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "5000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "开启关闭",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "保存设置",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
{
|
||||||
|
"label": "安全策略",
|
||||||
|
"slug": "20-security-policy",
|
||||||
|
"route": "/security-settings",
|
||||||
|
"url": "https://admin.adfahi.cn/security-settings",
|
||||||
|
"title": "鸽达达管理后台",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/20-security-policy.png",
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n安全策略\n用户安全\n验证码触发次数\n连续密码错误该次数后要求验证码(1~10)\n密码最小位数\n用户密码最少字符数(6~32)\n强制包含字母\n开启后密码必须包含英文字母\n注册登录管控\n用户注册功能\n关闭后用户端将隐藏注册入口\n修改密码功能\n关闭后用户无法修改密码,不影响后台重置\n用户登录功能\n关闭后用户无法登录,不影响已登录用户\nWeb 端多端登录\n开启后同一账号可在多个浏览器标签页同时登录\n聊天消息管控\n全局好友功能\n关闭后无法搜索和添加好友\n全局群消息\n关闭后所有群无法发送消息\n全局私聊消息\n关闭后所有私聊无法发送消息\n群聊发言间隔(秒)\n0 表示不限制;1~1000 表示同一群内两次发言的最小间隔\n群组功能管控\n群号搜索功能\n关闭后用户端隐藏群号和群搜索入口\n群创建功能\n关闭后任何人无法新建群聊\n群解散功能\n关闭后任何人无法解散群聊,不影响后台管理员\n群管理员功能\n关闭后任何人无法设置群管理员\n是否显示群人数\n关闭后用户端查看群资料时不显示群总人数\n其他功能开关\n允许用户注销账号\n关闭后用户端将隐藏注销账号按钮\nIP 访问控制\n注册 IP 黑名单\n留空表示不限制;每行一个 IPv4、IPv6 或 CIDR。命中后无法注册及获取注册短信验证码。\n登录 IP 黑名单\n留空表示不限制;命中后无法密码登录、短信登录及刷新 Token。与用户分组登录白名单独立,黑名单优先。\n高级功能\n消息已读状态\n开启后显示消息已读/未读标记\n保存设置",
|
||||||
|
"tables": [],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "203.0.113.10\n10.0.0.0/8",
|
||||||
|
"tag": "TEXTAREA",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "198.51.100.0/24",
|
||||||
|
"tag": "TEXTAREA",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "保存设置"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
"label": "安全策略",
|
||||||
|
"slug": "20-security-policy",
|
||||||
|
"route": "/security-settings",
|
||||||
|
"url": "https://admin.adfahi.cn/security-settings",
|
||||||
|
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/20-security-policy.png",
|
||||||
|
"queried": true,
|
||||||
|
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n安全策略\n用户安全\n验证码触发次数\n连续密码错误该次数后要求验证码(1~10)\n密码最小位数\n用户密码最少字符数(6~32)\n强制包含字母\n开启后密码必须包含英文字母\n注册登录管控\n用户注册功能\n关闭后用户端将隐藏注册入口\n修改密码功能\n关闭后用户无法修改密码,不影响后台重置\n用户登录功能\n关闭后用户无法登录,不影响已登录用户\nWeb 端多端登录\n开启后同一账号可在多个浏览器标签页同时登录\n聊天消息管控\n全局好友功能\n关闭后无法搜索和添加好友\n全局群消息\n关闭后所有群无法发送消息\n全局私聊消息\n关闭后所有私聊无法发送消息\n群聊发言间隔(秒)\n0 表示不限制;1~1000 表示同一群内两次发言的最小间隔\n群组功能管控\n群号搜索功能\n关闭后用户端隐藏群号和群搜索入口\n群创建功能\n关闭后任何人无法新建群聊\n群解散功能\n关闭后任何人无法解散群聊,不影响后台管理员\n群管理员功能\n关闭后任何人无法设置群管理员\n是否显示群人数\n关闭后用户端查看群资料时不显示群总人数\n其他功能开关\n允许用户注销账号\n关闭后用户端将隐藏注销账号按钮\nIP 访问控制\n注册 IP 黑名单\n留空表示不限制;每行一个 IPv4、IPv6 或 CIDR。命中后无法注册及获取注册短信验证码。\n登录 IP 黑名单\n留空表示不限制;命中后无法密码登录、短信登录及刷新 Token。与用户分组登录白名单独立,黑名单优先。\n高级功能\n消息已读状态\n开启后显示消息已读/未读标记\n保存设置",
|
||||||
|
"tables": [],
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "INPUT",
|
||||||
|
"text": "",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "203.0.113.10\n10.0.0.0/8",
|
||||||
|
"tag": "TEXTAREA",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "198.51.100.0/24",
|
||||||
|
"tag": "TEXTAREA",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"disabled": null,
|
||||||
|
"placeholder": "",
|
||||||
|
"tag": "BUTTON",
|
||||||
|
"text": "保存设置",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,409 @@
|
|||||||
|
# Admin Server 改造文档:对齐鸽达达管理后台
|
||||||
|
|
||||||
|
本文基于 `docs/admin-adfahi-research/需求文档.md`、当前 `im_manager` 代码、`im_server` 文档与本地 MySQL 数据核对结果编写。目标是在 HotGo Admin Server 中复刻鸽达达后台的 20 个页面,并保持当前系统“Admin 只直连 hotgo 控制库,IM Server 只直连租户业务库”的边界。
|
||||||
|
|
||||||
|
> 实施状态(2026-09-07):Admin 第二批已完成 `imDashboard`、`imPrivateMessage`、`imGroupMessage`、`imUserLoginHistory`、`imLoginFailureLog` 的 API、service、logic、controller、路由、Vue 页面、字典、导出和菜单权限。消息隐藏/删除、失败日志封禁用户使用 Kafka Admin Command;失败 IP 加黑复用安全策略。对应菜单 SQL 为 `server/storage/data/generate/im_adfahi_batch2_menu.sql`,已在本地 `hotgo` 执行。上述查询仍依赖 IM Server 本文约定的 internal-query;本地 `tinode` 尚无 `im_user_login_logs`、`im_login_failure_logs`,需在 IM Server 批次建表并接入日志采集后才会产生真实数据。
|
||||||
|
|
||||||
|
## 1. 改造边界
|
||||||
|
|
||||||
|
Admin Server 负责后台菜单、权限、页面、查询聚合、运营配置、Kafka 管理命令投递、命令结果展示与后台审计落库。业务 IM 数据不直接跨库读写,用户、群、消息、文件、反馈、登录等租户数据通过 IM Server 内部只读接口 `/internal/admin-query/tenants/{tenant_code}/...` 查询;用户封禁、群治理、消息处置、文件处置等写操作通过 Kafka Admin Command 下发。
|
||||||
|
|
||||||
|
当前本地库观察:
|
||||||
|
|
||||||
|
| 数据库 | 现状 |
|
||||||
|
| --- | --- |
|
||||||
|
| `hotgo` | 当前有 66 张表,已存在 `im_admin_commands`、`im_admin_operation_audit`、`im_admin_outbox`、`im_registration_invite_codes`、`im_external_config`、`im_file_policy`,并已新增策略分组、敏感词、安全策略和宵禁控制表。 |
|
||||||
|
| `tinode` | 当前有 73 张表,已有 `im_users`、`im_topics`、`im_subscriptions`、`im_messages`、`im_group_messages`、`im_group_settings`、`im_fileuploads`、`im_feedback_submissions` 等 IM 业务表。 |
|
||||||
|
| 联调状态 | `hotgo.im_tenant` 已补默认租户映射(`id=1`、`code=default`);`tinode` 尚无用户登录历史和登录失败日志表,对应页面待 IM Server 批次补齐数据源。 |
|
||||||
|
|
||||||
|
敏感配置说明:`hg_sys_config` 中已有声网、阿里云、OSS、短信等配置项。文档与页面只能展示脱敏值,后续应补充加密存储、轮换、审计与权限控制。
|
||||||
|
|
||||||
|
## 2. 当前 Admin 能力盘点
|
||||||
|
|
||||||
|
已有后台 API 模块:
|
||||||
|
|
||||||
|
| 模块 | 主要能力 | 复用结论 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `imUser` | 用户列表、详情、设备、重置密码、状态、封禁/解封、冻结/解冻、踢设备、全端登出、注销、删除 | 可作为“用户管理”的主体,补鸽达达字段、筛选项、批量操作与审计页联动。 |
|
||||||
|
| `imGroup` | 群列表、详情、成员、群治理、资料更新、解散、禁言、成员禁言/移除、入群申请、邀请、公告、文件、管理日志 | 可覆盖“群组管理”和“群成员管理”主体,需补独立菜单页与鸽达达状态/字段映射。 |
|
||||||
|
| `imInvite` | 邀请码列表、新增、批量新增、批量查看、撤销、批量撤销、导出 | 可覆盖“邀请码管理”,但邀请码格式与鸽达达需求存在差异。 |
|
||||||
|
| `imFile` | 文件列表、详情、隔离、删除、清理孤儿文件 | 可覆盖“文件管理”,需补预览/下载链接、审核枚举、内容风险字段。 |
|
||||||
|
| `imAuditLog` | 操作日志列表、详情、导出 | 可覆盖后台操作日志的一部分,需扩展为用户账号审计、群事件审计等专题页。 |
|
||||||
|
| `imKafkaCommand`、`imDeadLetter`、`imOutbox`、`imKafkaAudit` | Kafka 命令、死信、出站事件、审计事件 | 保留为运维治理菜单,不直接出现在鸽达达 20 个业务页中。 |
|
||||||
|
| `imRegistration`、`imExternalConfig`、`imFilePolicy`、`imFeedbackConfig`、`imMailboxConfig`、`imNotification`、`imAppRelease` | 注册、第三方、文件策略、反馈、邮箱、通知、版本配置 | 可组合成“私域设置”和“安全策略”,需要按鸽达达页面重组展示。 |
|
||||||
|
|
||||||
|
已有菜单已包含 `IM管理`、`注册邀请码`、`用户列表`、`群组列表`、`文件治理`、`Kafka命令`、`Kafka死信`、`Kafka审计事件`、`租户管理` 等。缺少与鸽达达完全一致的“单聊消息、群聊消息、敏感词库、用户反馈、用户登录、IP账号统计、登录失败日志”等前台页面。
|
||||||
|
|
||||||
|
## 3. 页面级改造
|
||||||
|
|
||||||
|
### 3.1 数据概览
|
||||||
|
|
||||||
|
新增或改造 `imDashboard` 页面。顶部统计按需求文档展示总用户数、活跃用户、总群组数、总会话数、总消息数、今日消息;趋势表展示最近 7 天用户增长、消息增长。现有 IM Server 内部接口已有 `/internal/admin-query/tenants/{tenant}/dashboard/summary`,但仅返回 `dead_kafka`、`pending_business`、`pending_group`、`pending_realname`、`received_abuse`、`received_feedback`、`active_groups`、`suspended_users`,不足以还原鸽达达数据概览。
|
||||||
|
|
||||||
|
Admin 改造:
|
||||||
|
|
||||||
|
| 项 | 方案 |
|
||||||
|
| --- | --- |
|
||||||
|
| API | 新增 `/imDashboard/overview`、`/imDashboard/trends`。 |
|
||||||
|
| 数据源 | 控制库租户信息来自 `im_tenant`;统计与趋势来自 IM internal query。 |
|
||||||
|
| 字段 | `totalUsers`、`activeUsers`、`totalGroups`、`totalConversations`、`totalMessages`、`todayMessages`、`date`、`userCount`、`messageCount`。 |
|
||||||
|
| 按钮 | 页面无写操作;支持租户切换、日期范围查询、刷新。 |
|
||||||
|
| 缺口 | IM Server 需补 dashboard 聚合项与趋势接口;Admin 需补租户为空时的默认租户兜底提示。 |
|
||||||
|
|
||||||
|
### 3.2 用户管理
|
||||||
|
|
||||||
|
复用 `imUser`,页面按鸽达达字段重排。列表数据通过 IM internal `users` 查询,详情通过 `/users/{id}`,设备通过 `/users/{id}/devices`。当前 Admin 已有 `/imUser/list`、`/imUser/view`、`/imUser/devices`、`/imUser/ban`、`/imUser/unban`、`/imUser/freeze`、`/imUser/unfreeze`、`/imUser/deviceKick`、`/imUser/logoutAll`、`/imUser/accountCancel`、`/imUser/accountDelete`、`/imUser/resetPassword`。
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
| 字段 | 来源 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `user_id` | `tinode.im_users.id` 编码后 | 用户唯一 ID,列表、详情、审计联动主键。 |
|
||||||
|
| `username` | `im_users.username` | 登录账号。 |
|
||||||
|
| `phone` | `im_users.phone` | 手机号,页面默认脱敏,导出需权限。 |
|
||||||
|
| `nickname` | `im_user_profiles.nickname` | 昵称,支持模糊查询。 |
|
||||||
|
| `public_account` | `im_user_profiles.public_account` | 对外账号/靓号。 |
|
||||||
|
| `state` | `im_users.state` | Tinode 用户状态。建议映射为正常、封禁、冻结、注销、删除。 |
|
||||||
|
| `last_seen` | `im_users.last_seen` | 最后在线/活跃时间。 |
|
||||||
|
| `created_at` | `im_users.created_at` | 注册时间。 |
|
||||||
|
| `credentials` | IM internal 聚合 | 认证方式摘要,不展示密钥。 |
|
||||||
|
|
||||||
|
按钮功能:
|
||||||
|
|
||||||
|
| 按钮 | 已有接口 | 功能 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 查询 | `/imUser/list` | 按用户 ID、昵称、账号、手机号、状态、注册时间、最后活跃时间筛选。 |
|
||||||
|
| 重置 | 前端表单重置 | 清空筛选项并重新查询。 |
|
||||||
|
| 查看 | `/imUser/view` | 展示基础信息、资料、设备、最近审计事件。 |
|
||||||
|
| 封禁/解封 | `/imUser/ban`、`/imUser/unban` | Kafka 命令 `user.ban` / `user.unban`,需填写原因和过期时间。 |
|
||||||
|
| 冻结/解冻 | `/imUser/freeze`、`/imUser/unfreeze` | Kafka 命令 `user.freeze` / `user.unfreeze`。 |
|
||||||
|
| 踢设备 | `/imUser/deviceKick` | 指定设备下线。 |
|
||||||
|
| 全端登出 | `/imUser/logoutAll` | 下发 `user.logout_all`。 |
|
||||||
|
| 注销/删除 | `/imUser/accountCancel`、`/imUser/accountDelete` | 高危操作,二次确认并写审计。 |
|
||||||
|
|
||||||
|
枚举说明:`state` 当前来自 Tinode 状态值,Admin 应新增统一字典 `im_user_state`,至少包含正常、封禁、冻结、注销、删除。封禁/冻结原因不应写死在前端,可复用“安全策略”中的处置原因配置。
|
||||||
|
|
||||||
|
### 3.3 用户分组
|
||||||
|
|
||||||
|
当前缺少等价模块,需要新增 `imUserPolicyGroup`。该页面不是组织部门,而是账号策略分组,用于控制注册、登录、私聊、建群、入群、发文件、发消息、IP 限制等策略。
|
||||||
|
|
||||||
|
Admin 改造:
|
||||||
|
|
||||||
|
| 项 | 方案 |
|
||||||
|
| --- | --- |
|
||||||
|
| 后端模块 | `api/admin/imuserpolicygroup`、`controller/admin/sys/im_user_policy_group.go`、`logic/sys/im_user_policy_group.go`、`model/input/sysin/im_user_policy_group.go`。 |
|
||||||
|
| 控制表 | 新增 `im_user_policy_groups`、`im_user_policy_group_members`。 |
|
||||||
|
| API | `/imUserPolicyGroup/list`、`/view`、`/edit`、`/delete`、`/status`、`/memberList`、`/memberAdd`、`/memberRemove`。 |
|
||||||
|
| 同步 | 策略变更写 `im_admin_outbox`,发布 Kafka config event;IM Server 缓存策略并执行。 |
|
||||||
|
| 页面按钮 | 查询、新增、编辑、删除、启用/禁用、成员管理、导出。 |
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `group_code` | 分组编码,唯一,不可编辑。 |
|
||||||
|
| `group_name` | 分组名称。 |
|
||||||
|
| `priority` | 命中多个分组时的优先级,数字越大优先级越高。 |
|
||||||
|
| `status` | 启用、禁用。 |
|
||||||
|
| `policy_json` | 策略 JSON,包含消息、好友、群、文件、登录等开关与限额。 |
|
||||||
|
| `ip_whitelist`、`ip_blacklist` | IP 白名单/黑名单,支持 CIDR。 |
|
||||||
|
| `remark` | 备注。 |
|
||||||
|
|
||||||
|
好友策略必须覆盖移动端所有加好友入口,不能只依赖前端隐藏。分组策略中至少包含 `allow_add_friend`、`direct_add_friend`、`max_friend_count`、`allow_view_profile_when_friend_disabled`、`allow_qrcode_add_friend`、`allow_group_member_profile`。当全局或分组禁止加好友时,从搜索、通讯录推荐、群成员列表、个人名片、二维码解析、邀请注册自动加好友、转发目标联系人等入口都必须由后端返回禁止或脱敏数据。
|
||||||
|
|
||||||
|
枚举说明:`status` 使用 `sys_normal_disable`;策略开关使用布尔值;策略动作建议统一枚举 `allow`、`deny`、`challenge`、`audit_only`。好友入口枚举建议 `search`、`profile_card`、`group_member`、`qrcode`、`invite_auto_add`、`recommendation`。
|
||||||
|
|
||||||
|
### 3.4 群组管理
|
||||||
|
|
||||||
|
复用 `imGroup`。列表通过 IM internal `groups` 查询,详情通过 `/groups/{topic}`,现有 Admin 已有群资料、治理、成员、申请、邀请、公告、文件、日志等接口。
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
| 字段 | 来源 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `topic` | `im_topics.name` | 群 Topic,等价群号/群唯一标识。 |
|
||||||
|
| `group_name` | `im_group_settings.group_name` | 群名称。 |
|
||||||
|
| `owner_id` | `im_topics.owner` | 群主。 |
|
||||||
|
| `group_status` | `im_group_settings.group_status` | 群业务状态。 |
|
||||||
|
| `state` | `im_topics.state` | Tinode topic 状态。 |
|
||||||
|
| `business_member_count` | `im_group_settings.business_member_count` | 成员数。 |
|
||||||
|
| `join_approval` | `im_group_settings.join_approval` | 入群审批开关。 |
|
||||||
|
| `mute_all` | `im_group_settings.mute_all` | 全员禁言。 |
|
||||||
|
| `created_at`、`updated_at` | topic/settings | 创建与更新时间。 |
|
||||||
|
|
||||||
|
按钮功能:
|
||||||
|
|
||||||
|
| 按钮 | 已有接口 | 功能 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 查询 | `/imGroup/list` | 按群号、群名、群主、状态、创建时间查询。 |
|
||||||
|
| 查看 | `/imGroup/view` | 群资料、成员、公告、邀请、文件、治理配置汇总。 |
|
||||||
|
| 编辑资料 | `/imGroup/profileUpdate` | Kafka `group.profile.update`。 |
|
||||||
|
| 治理设置 | `/imGroup/governanceUpdate` | Kafka `group.governance.update`,控制入群审批、全员禁言、成员上传文件、成员私聊、成员邀请。 |
|
||||||
|
| 解散 | `/imGroup/dissolve` | 高危操作,二次确认。 |
|
||||||
|
| 禁言/解禁言 | `/imGroup/mute`、`/imGroup/unmute` | 群级禁言。 |
|
||||||
|
| 成员/申请/邀请/公告/文件/日志 | 已有子接口 | 打开子面板或跳转专题页。 |
|
||||||
|
|
||||||
|
枚举说明:新增 `im_group_status`,建议值 `active` 正常、`muted` 禁言、`suspended` 封停、`dissolved` 已解散。当前 IM 命令未看到明确 `group.ban`/`group.unban`,如鸽达达要求群封停,需要新增 Kafka 命令或通过治理状态统一处理。
|
||||||
|
|
||||||
|
### 3.5 群成员管理
|
||||||
|
|
||||||
|
复用 `/imGroup/memberList` 与成员治理命令,新增独立菜单页 `imGroupMember`,默认要求输入群号或从群详情跳转携带 `topic`。
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `topic` | 群 Topic。 |
|
||||||
|
| `user_id` | 成员用户 ID。 |
|
||||||
|
| `display_name`/`nickname` | 群内展示名或用户昵称。 |
|
||||||
|
| `role` | 群主、管理员、普通成员。 |
|
||||||
|
| `status` | 正常、禁言、已移除。 |
|
||||||
|
| `muted_until` | 禁言截止时间。 |
|
||||||
|
| `joined_at` | 入群时间。 |
|
||||||
|
|
||||||
|
按钮功能:查询、查看用户、设为管理员、取消管理员、转让群主、成员禁言、解除禁言、移除成员。现有接口分别为 `/imGroup/adminSet`、`/adminRemove`、`/ownerTransfer`、`/memberMute`、`/memberUnmute`、`/memberRemove`。
|
||||||
|
|
||||||
|
枚举说明:`role` 新增字典 `im_group_member_role`:`owner` 群主、`admin` 管理员、`member` 成员;成员状态新增 `im_group_member_status`。
|
||||||
|
|
||||||
|
### 3.6 邀请码管理
|
||||||
|
|
||||||
|
复用 `imInvite`。本地 `hotgo.im_registration_invite_codes` 有样例数据,批次表为空。当前需求文档按鸽达达页面描述 6 位数字邀请码;历史 IM 文档曾描述 5 位 ASCII 字母邀请码,二者冲突。若以复刻鸽达达为目标,应统一改为 6 位数字,Admin 生成、IM 注册校验、数据库唯一索引与错误文案同步调整。
|
||||||
|
|
||||||
|
字段说明:`code` 邀请码、`batch_id` 批次、`status` 状态、`max_uses` 最大使用次数、`used_count` 已使用次数、`expires_at` 过期时间、`created_by` 创建管理员、`created_at` 创建时间、`revoked_at` 撤销时间。
|
||||||
|
|
||||||
|
按钮功能:查询、新增、批量生成、批量查看、撤销、批量撤销、导出。接口已有 `/imInvite/list`、`/create`、`/batchCreate`、`/batchView`、`/revoke`、`/batchRevoke`、`/export`。
|
||||||
|
|
||||||
|
枚举说明:新增或确认 `im_invite_status`:`unused` 未使用、`used` 已用完、`expired` 已过期、`revoked` 已撤销。
|
||||||
|
|
||||||
|
### 3.7 单聊消息
|
||||||
|
|
||||||
|
当前 Admin 缺少独立消息管理模块,需要新增 `imPrivateMessage`。IM Server 已有消息表 `im_messages`,但 internal admin query 目前只支持 `/messages/{topic}/{seq}` 单条查询,缺少按会话分页检索单聊消息的后台列表接口。
|
||||||
|
|
||||||
|
Admin 改造:
|
||||||
|
|
||||||
|
| 项 | 方案 |
|
||||||
|
| --- | --- |
|
||||||
|
| API | `/imPrivateMessage/list`、`/view`、`/hide`、`/delete`、`/export`。 |
|
||||||
|
| 数据源 | 新增 IM internal query:`/tenants/{tenant}/private-messages` 或 `/messages?kind=p2p`。 |
|
||||||
|
| 写操作 | 通过 Kafka 命令新增 `message.hide`、`message.delete` 或复用 IM 已有 recall/delete 能力封装为后台命令。 |
|
||||||
|
| 页面按钮 | 查询、查看上下文、隐藏、删除、导出。 |
|
||||||
|
|
||||||
|
字段说明:`topic` 会话 Topic、`seq_id` 消息序号、`from_user_id` 发送者、`to_user_id` 接收者、`content_type` 内容类型、`content` 内容摘要、`status` 状态、`created_at` 发送时间、`updated_at` 更新时间。
|
||||||
|
|
||||||
|
枚举说明:`content_type` 建议 `text`、`image`、`file`、`audio`、`video`、`card`、`system`;`status` 建议 `normal`、`recalled`、`hidden`、`deleted`。
|
||||||
|
|
||||||
|
### 3.8 群聊消息
|
||||||
|
|
||||||
|
新增 `imGroupMessage` 页面。IM Server 本地有 `im_group_messages` 表,需求需要按群号、发送者、时间、内容关键字筛选。
|
||||||
|
|
||||||
|
Admin 改造:新增 `/imGroupMessage/list`、`/view`、`/hide`、`/delete`、`/export`。IM Server 补 internal query `group-messages`,支持 `topic`、`sender_user_id`、`content_type`、`status`、`created_at_start/end`、`keyword`。
|
||||||
|
|
||||||
|
字段、按钮、枚举与单聊消息一致,额外展示 `group_name`、`member_role`、`at_users`、`reply_to_seq`。
|
||||||
|
|
||||||
|
### 3.9 敏感词库
|
||||||
|
|
||||||
|
当前 Admin 与 IM Server 未发现完整敏感词库模块,需要新增。Admin 维护词库,IM Server 在消息发送、昵称/群名修改、反馈/举报提交时执行匹配。
|
||||||
|
|
||||||
|
Admin 改造:
|
||||||
|
|
||||||
|
| 项 | 方案 |
|
||||||
|
| --- | --- |
|
||||||
|
| 表 | `im_sensitive_words`、`im_sensitive_word_groups`、`im_sensitive_word_hits` 可按需拆分。 |
|
||||||
|
| API | `/imSensitiveWord/list`、`/view`、`/edit`、`/delete`、`/status`、`/import`、`/export`。 |
|
||||||
|
| 同步 | 词库变更发布 config event 或 cache invalidate,IM Server 热加载。 |
|
||||||
|
| 按钮 | 查询、新增、编辑、删除、启用/禁用、导入、导出。 |
|
||||||
|
|
||||||
|
字段说明:`word` 敏感词、`match_type` 匹配类型、`scene` 生效场景、`action` 命中动作、`replacement` 替换文本、`level` 风险等级、`status` 状态。
|
||||||
|
|
||||||
|
枚举说明:`match_type` 为 `exact` 精确、`contains` 包含、`regex` 正则;`scene` 为 `message` 消息、`profile` 资料、`group` 群资料、`feedback` 反馈;`action` 为 `block` 拦截、`replace` 替换、`review` 人审、`audit_only` 仅记录。
|
||||||
|
|
||||||
|
### 3.10 文件管理
|
||||||
|
|
||||||
|
复用 `imFile`,补齐鸽达达文件字段和预览能力。IM internal 已支持 `files`、`files/{id}`、`files/{id}/links`。本地 `tinode.im_fileuploads` 有数据,`im_group_files` 暂无数据。
|
||||||
|
|
||||||
|
字段说明:`file_id` 文件 ID、`user_id` 上传者、`topic` 所属会话、`mime_type` MIME、`size` 文件大小、`location` 存储位置、`etag` 校验、`status` 状态、`review_status` 审核状态、`risk_level` 风险等级、`created_at` 上传时间。
|
||||||
|
|
||||||
|
按钮功能:查询、查看、预览/下载、隔离、删除、清理孤儿文件。现有接口 `/imFile/quarantine`、`/imFile/delete`、`/imFile/cleanupOrphan` 可复用;预览/下载建议由 Admin 获取短期签名 URL,不直接暴露 OSS 原始地址。
|
||||||
|
|
||||||
|
枚举说明:现有字典包括 `im_storage_provider=oss`、`im_file_review_provider`、`im_file_review_status(pending/running/clean/risky/failed)`、`im_file_review_task_type(content/malware)`;还需补 `im_file_status`:`normal` 正常、`quarantined` 已隔离、`deleted` 已删除。
|
||||||
|
|
||||||
|
### 3.11 用户反馈
|
||||||
|
|
||||||
|
IM Server 已有 `im_feedback_submissions` 和 internal resource `feedback-submissions`,Admin 目前有反馈配置和工单模块,但缺少完全按鸽达达展示的反馈列表页。建议新增 `imFeedback` 或改造 `imWorkOrder` 作为反馈处理页。
|
||||||
|
|
||||||
|
字段说明:`feedback_id` 反馈 ID、`user_id` 用户、`category` 分类、`content` 内容、`contact` 联系方式、`file_ids` 附件、`client_context` 客户端环境、`include_diagnostics` 是否含诊断、`status` 状态、`created_at`、`updated_at`。
|
||||||
|
|
||||||
|
按钮功能:查询、查看、标记处理中、标记已处理、关闭、导出。写操作建议先落 Admin 工单状态,再通过 Kafka 或 IM internal 写接口回写业务状态。
|
||||||
|
|
||||||
|
枚举说明:`status` 建议 `received` 已收到、`processing` 处理中、`resolved` 已解决、`closed` 已关闭;`category` 来自 `im_feedback_config.categories`,禁止前端硬编码。
|
||||||
|
|
||||||
|
### 3.12 操作日志
|
||||||
|
|
||||||
|
复用 `imAuditLog` 与 `im_admin_operation_audit`。本地该表已有 45 条记录。页面应覆盖后台管理员对 IM 资源的所有操作,包括用户、群、消息、文件、配置、邀请码、敏感词。
|
||||||
|
|
||||||
|
字段说明:`id`、`request_id`、`admin_id`、`admin_name`、`action`、`target_type`、`target_id`、`before_data`、`after_data`、`ip`、`user_agent`、`result`、`created_at`。
|
||||||
|
|
||||||
|
按钮功能:查询、查看详情、导出。详情页需展示变更前后 JSON,敏感字段脱敏。
|
||||||
|
|
||||||
|
枚举说明:`target_type` 建议 `user`、`group`、`message`、`file`、`invite`、`config`、`sensitive_word`;`result` 为 `success`、`failed`、`pending`。
|
||||||
|
|
||||||
|
### 3.13 用户账号审计
|
||||||
|
|
||||||
|
新增专题页 `imUserAccountAudit`,从 Admin 操作审计、IM `audit-logs`、Kafka 命令结果中聚合用户生命周期事件。
|
||||||
|
|
||||||
|
字段说明:`event_id`、`user_id`、`action`、`operator_type`、`operator_id`、`reason`、`ip`、`device_id`、`before_state`、`after_state`、`created_at`。
|
||||||
|
|
||||||
|
按钮功能:查询、查看、跳转用户详情、导出。动作枚举建议包含注册、登录、登出、登录失败、改密、重置密码、封禁、解封、冻结、解冻、注销、删除、踢设备。
|
||||||
|
|
||||||
|
缺口:IM Server 当前 `im_audit_logs` 本地为空,需要补登录、失败、状态变更等事件写入。
|
||||||
|
|
||||||
|
### 3.14 群事件审计
|
||||||
|
|
||||||
|
可复用 `imGroup/adminLogList`、`outbox/group-events` 和 Admin audit,新增独立页面 `imGroupEventAudit`。
|
||||||
|
|
||||||
|
字段说明:`event_id`、`topic`、`group_name`、`operator_id`、`target_user_id`、`action`、`object_type`、`object_id`、`before_data`、`after_data`、`created_at`。
|
||||||
|
|
||||||
|
按钮功能:查询、查看、跳转群详情、导出。动作枚举建议包含建群、解散、修改资料、修改治理设置、入群申请、审批通过、审批拒绝、成员禁言、解除禁言、移除成员、设管理员、取消管理员、转让群主、公告发布/删除、文件删除。
|
||||||
|
|
||||||
|
### 3.15 管理员登录历史
|
||||||
|
|
||||||
|
复用 HotGo 系统登录日志能力,不需要 IM Server 改造。若现有登录日志字段不足,补 Admin 聚合接口 `/imAdminLoginHistory/list` 或直接配置菜单指向系统日志页面。
|
||||||
|
|
||||||
|
字段说明:管理员 ID、账号、昵称、登录 IP、地区、浏览器、系统、登录结果、失败原因、登录时间。
|
||||||
|
|
||||||
|
按钮功能:查询、查看、导出。枚举 `result` 为成功、失败。
|
||||||
|
|
||||||
|
### 3.16 用户登录历史
|
||||||
|
|
||||||
|
当前缺少完整用户登录历史。IM Server 路由中未看到客户端 `/v1/im/auth/logout` 或独立 session 管理路由;本地 `im_devices` 为空,不能满足鸽达达登录历史。
|
||||||
|
|
||||||
|
Admin 改造:新增 `imUserLoginHistory` 页面,查询 IM internal `user-login-logs`。字段包括 `user_id`、`phone`、`login_type`、`device_id`、`platform`、`ip`、`region`、`user_agent`、`result`、`login_at`、`logout_at`。
|
||||||
|
|
||||||
|
枚举说明:`login_type` 为 `password`、`sms`、`token_refresh`、`third_party`;`platform` 为 `ios`、`android`、`web`、`desktop`;`result` 为 `success`、`failed`。
|
||||||
|
|
||||||
|
### 3.17 IP 账号统计
|
||||||
|
|
||||||
|
新增 `imIpAccountStats` 页面。数据由 IM Server 基于注册 IP、登录 IP、失败登录 IP 聚合生成,Admin 只查询展示。
|
||||||
|
|
||||||
|
字段说明:`ip`、`region`、`user_count`、`register_count`、`login_count`、`failure_count`、`first_seen_at`、`last_seen_at`、`risk_level`。
|
||||||
|
|
||||||
|
按钮功能:查询、查看关联账号、导出、加入黑名单。加入黑名单写入“安全策略”或“用户分组”策略并同步 IM Server。
|
||||||
|
|
||||||
|
枚举说明:`risk_level` 为 `low`、`medium`、`high`;黑名单动作 `block_login`、`challenge`、`audit_only`。
|
||||||
|
|
||||||
|
### 3.18 登录失败日志
|
||||||
|
|
||||||
|
新增 `imLoginFailureLog` 页面。IM Server 需要记录认证失败事件,包含错误原因、IP、设备、账号、风控命中信息。
|
||||||
|
|
||||||
|
字段说明:`id`、`account`、`user_id`、`failure_type`、`reason`、`ip`、`region`、`device_id`、`platform`、`user_agent`、`attempt_at`。
|
||||||
|
|
||||||
|
按钮功能:查询、查看、导出、加入 IP 黑名单、封禁账号。封禁账号复用 `/imUser/ban`。
|
||||||
|
|
||||||
|
枚举说明:`failure_type` 为 `password_error`、`code_error`、`account_not_found`、`account_disabled`、`rate_limited`、`risk_blocked`。
|
||||||
|
|
||||||
|
### 3.19 私域设置
|
||||||
|
|
||||||
|
以现有 `imRegistration`、`imExternalConfig`、`imFeedbackConfig`、`imMailboxConfig`、`imNotification`、`imAppRelease` 为基础,新增汇总页面 `imTenantSettings`,按鸽达达页面展示私域基础配置。
|
||||||
|
|
||||||
|
字段说明:租户标识、注册开关、邀请码开关、短信开关、默认策略分组、客服/反馈配置、上传配置、客户端功能开关、版本策略、更新时间。客户端功能开关中新增 `global_friend_enabled` 和 `message_curfew_enabled` 的只读摘要,便于运营在私域设置页看到当前私域是否允许加好友、是否存在宵禁;实际编辑入口放在“安全策略”。
|
||||||
|
|
||||||
|
按钮功能:查看、编辑、保存、测试第三方配置、发布配置。保存后写 `hg_sys_config` 或 `im_tenant_config`,并通过 Kafka config event 通知 IM Server 刷新缓存。
|
||||||
|
|
||||||
|
枚举说明:开关统一使用布尔;配置发布状态 `draft`、`published`、`failed`。
|
||||||
|
|
||||||
|
### 3.20 安全策略
|
||||||
|
|
||||||
|
新增或重组 `imSecurityPolicy` 页面,统一管理登录安全、密码策略、IP 风控、敏感词动作、文件审核、用户处置原因、消息处置策略、全局好友功能与消息宵禁。
|
||||||
|
|
||||||
|
字段说明:`password_policy`、`login_rate_limit`、`ip_blacklist`、`ip_whitelist`、`sensitive_word_policy`、`file_review_policy`、`realname_policy`、`risk_challenge_policy`、`global_friend_enabled`、`friend_disabled_policy`、`message_curfew_enabled`、`message_curfew_rules`。
|
||||||
|
|
||||||
|
全局好友功能说明:
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `global_friend_enabled` | 全局是否允许加好友。关闭后所有移动端加好友入口都禁止。 |
|
||||||
|
| `friend_disabled_policy.hide_profile` | 禁止加好友时,群成员列表、个人名片、二维码解析是否隐藏个人资料。 |
|
||||||
|
| `friend_disabled_policy.block_qrcode` | 是否禁止通过二维码添加好友。 |
|
||||||
|
| `friend_disabled_policy.block_group_member_entry` | 是否禁止从群成员入口查看个人信息或发起添加。 |
|
||||||
|
| `friend_disabled_policy.blocked_entries` | 被禁用的移动端入口数组:`search`、`profile_card`、`group_member`、`qrcode`、`invite_auto_add`、`recommendation`。关闭全局好友功能时默认全部禁用。 |
|
||||||
|
| `friend_disabled_policy.message` | 移动端提示文案,例如“当前时段暂不允许添加好友”。 |
|
||||||
|
|
||||||
|
宵禁功能说明:
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `message_curfew_enabled` | 是否启用消息宵禁。 |
|
||||||
|
| `message_curfew_rules` | 宵禁规则数组,支持每天、工作日、周末、自定义日期。 |
|
||||||
|
| `start_time`、`end_time` | 宵禁开始和结束时间,支持跨天,例如 `18:00` 到次日 `09:00`。 |
|
||||||
|
| `scope` | 管控范围,默认至少包含 `private_message`,即单聊/私聊不能发消息;如产品确认,可扩展 `group_message`。 |
|
||||||
|
| `whitelist_user_ids`、`whitelist_group_ids` | 豁免用户或群,可选。 |
|
||||||
|
| `message` | 宵禁期间发送失败提示。 |
|
||||||
|
|
||||||
|
按钮功能:查询当前策略、编辑、保存、发布、恢复默认、查看发布历史。保存必须写操作审计。
|
||||||
|
|
||||||
|
枚举说明:风控动作统一 `allow`、`challenge`、`block`、`audit_only`;文件审核动作 `allow`、`quarantine`、`delete`、`manual_review`;宵禁范围 `private_message` 单聊/私聊、`group_message` 群聊;日期类型 `daily` 每天、`weekday` 工作日、`weekend` 周末、`custom` 自定义。
|
||||||
|
|
||||||
|
## 4. 后端实现方案
|
||||||
|
|
||||||
|
按 HotGo 规范新增模块时,必须完成 API、controller、service、logic、model/input、router/genrouter、前端 API、views/model、index、edit。接口命名沿用当前项目风格,例如 `/imPrivateMessage/list`,不直接照搬鸽达达 `/admin/private-messages` 路径;如后续需要兼容外部路径,可单独加网关映射。
|
||||||
|
|
||||||
|
新增模块建议:
|
||||||
|
|
||||||
|
| 优先级 | 模块 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| P0 | `imDashboard` | 首页统计与趋势。 |
|
||||||
|
| P0 | `imPrivateMessage`、`imGroupMessage` | 单聊/群聊消息查询与处置。 |
|
||||||
|
| P0 | `imSensitiveWord` | 敏感词库与热更新。 |
|
||||||
|
| P0 | `imUserLoginHistory`、`imLoginFailureLog` | 用户登录与失败日志。 |
|
||||||
|
| P1 | `imUserPolicyGroup` | 用户策略分组。 |
|
||||||
|
| P1 | `imFeedback` | 用户反馈处理页。 |
|
||||||
|
| P1 | `imIpAccountStats` | IP 聚合与风控联动。 |
|
||||||
|
| P1 | `imUserAccountAudit`、`imGroupEventAudit` | 专题审计页。 |
|
||||||
|
| P2 | `imTenantSettings`、`imSecurityPolicy` | 运营配置整合页。 |
|
||||||
|
|
||||||
|
Admin 查询 IM 数据统一走 `server/internal/library/iminternal` 或现有 `imadmin` 封装,不在 logic 层直接拼接外部 HTTP 细节。写操作统一创建 `im_admin_commands` 与 `im_admin_outbox`,等待 Kafka result 更新状态;页面展示 `pending/success/failed/dead`。
|
||||||
|
|
||||||
|
## 5. 数据库与字典
|
||||||
|
|
||||||
|
配套建表与兼容迁移脚本见 [`sql/Admin-Server改造.sql`](sql/Admin-Server改造.sql)。脚本面向 `hotgo` 控制库,只保存管理配置和发布版本,不保存租户业务消息。
|
||||||
|
|
||||||
|
控制库新增表优先放在 `hotgo`:
|
||||||
|
|
||||||
|
| 表 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `im_user_policy_groups` | 用户策略分组主表。 |
|
||||||
|
| `im_user_policy_group_members` | 用户与策略分组关系。 |
|
||||||
|
| `im_sensitive_word_groups` | 敏感词分组。 |
|
||||||
|
| `im_sensitive_words` | 敏感词主表。 |
|
||||||
|
| `im_security_policy` | 安全策略草稿/发布版本。 |
|
||||||
|
| `im_admin_query_snapshots` | 可选,用于缓存重型统计查询快照。 |
|
||||||
|
|
||||||
|
字典由后端 `internal/consts` 注册,前端通过 `dict.loadOptions()` 加载。禁止在 `model.ts` 中硬编码枚举中文。
|
||||||
|
|
||||||
|
必补字典:`im_user_state`、`im_group_status`、`im_group_member_role`、`im_group_member_status`、`im_invite_status`、`im_message_content_type`、`im_message_status`、`im_sensitive_match_type`、`im_sensitive_scene`、`im_sensitive_action`、`im_feedback_status`、`im_login_type`、`im_login_failure_type`、`im_risk_level`、`im_policy_action`、`im_friend_entry`、`im_curfew_scope`、`im_curfew_date_type`。
|
||||||
|
|
||||||
|
## 6. 权限与审计
|
||||||
|
|
||||||
|
每个按钮权限与后端路由保持一致,例如 `/imPrivateMessage/delete`、`/imSensitiveWord/import`。高危操作包括用户删除、账号注销、群解散、消息删除、文件删除、IP 拉黑、安全策略发布,必须二次确认、记录原因、写 `im_admin_operation_audit`,并展示 Kafka 命令执行结果。
|
||||||
|
|
||||||
|
审计脱敏规则:
|
||||||
|
|
||||||
|
| 类型 | 展示规则 |
|
||||||
|
| --- | --- |
|
||||||
|
| 手机号 | 中间 4 位脱敏。 |
|
||||||
|
| 身份证/实名 | 默认只展示脱敏字段。 |
|
||||||
|
| 配置密钥 | 只展示前后 3-4 位或完全隐藏。 |
|
||||||
|
| 消息内容 | 列表展示摘要,详情按权限展示全文。 |
|
||||||
|
| 文件地址 | 不展示原始存储地址,使用短期签名 URL。 |
|
||||||
|
|
||||||
|
## 7. 联调与验收
|
||||||
|
|
||||||
|
验收顺序建议:
|
||||||
|
|
||||||
|
1. 补齐 `hotgo.im_tenant` 与 `tinode` 默认租户映射,确保 Admin 能通过 tenant code 查询 IM internal。
|
||||||
|
2. 完成数据概览、用户、群、邀请码、文件这些已有基础模块的字段对齐。
|
||||||
|
3. 新增消息、敏感词、反馈、登录日志、IP 统计等缺口模块。
|
||||||
|
4. 为 Kafka 命令增加幂等键、结果回写、失败重试、死信展示。
|
||||||
|
5. 使用本地 `hotgo` 与 `tinode` 数据验证每个页面的查询、按钮、详情和导出。
|
||||||
|
|
||||||
|
最低验收标准:20 个菜单均可打开;查询按钮能返回真实或空态数据;表格字段与需求文档一致;所有枚举来自字典;高危按钮有二次确认、原因、审计与结果状态;敏感数据脱敏。
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
# IM Server 改造文档:支撑鸽达达管理后台复刻
|
||||||
|
|
||||||
|
本文面向 `/Users/youshunlai/go_workspace/im_server` 的现状改造,目标是为 Admin Server 复刻鸽达达后台提供准确、稳定、可审计的数据与治理能力。当前 IM Server 已有 Tinode 风格实时链路、产品 HTTP API、独立租户库、Kafka 命令消费、配置事件消费、内部 Admin Query,但鸽达达 20 个后台页面仍需要补充若干查询资源、审计日志、风控策略与消息处置能力。
|
||||||
|
|
||||||
|
## 1. 当前实现现状
|
||||||
|
|
||||||
|
核心架构:
|
||||||
|
|
||||||
|
| 能力 | 现状 |
|
||||||
|
| --- | --- |
|
||||||
|
| 实时链路 | `Session -> Hub -> Topic -> Store`。 |
|
||||||
|
| 客户端入口 | WebSocket `/v0/channels`,产品 HTTP `/v1/im/...`。 |
|
||||||
|
| 后台只读入口 | `/internal/admin-query/tenants/{tenant_code}/...`,要求内部签名与 capability。 |
|
||||||
|
| 后台写操作 | Kafka Admin Command 消费器 `startKafkaAdminCommandConsumer`。 |
|
||||||
|
| 配置同步 | Kafka config event、cache invalidate consumer 已存在。 |
|
||||||
|
| 消息转发 | `/v1/im/messages/forward` 已存在。 |
|
||||||
|
| 音视频入会 | `/v1/im/calls/rtc-join` 已存在。 |
|
||||||
|
|
||||||
|
本地 `tinode` 库观察:`im_users` 有数据、`im_topics` 有群/会话、`im_subscriptions` 有订阅、`im_messages` 有大量单聊或通用消息、`im_group_messages` 有群消息、`im_feedback_submissions`、`im_abuse_reports`、`im_kafka_dead_letters` 等表已存在;`im_audit_logs` 本地为空,`im_devices` 和 `im_group_files` 数据不足,不能直接满足后台登录历史、设备历史和群文件验收。
|
||||||
|
|
||||||
|
已有内部查询资源:
|
||||||
|
|
||||||
|
| 资源 | 已支持字段/场景 |
|
||||||
|
| --- | --- |
|
||||||
|
| `users` | 用户 ID、账号、手机号、状态、资料、凭证摘要、最后在线。 |
|
||||||
|
| `user_devices` | 用户设备列表。 |
|
||||||
|
| `groups` | Topic、群名、群主、群状态、治理开关、成员数。 |
|
||||||
|
| `groups/{topic}/members` | 群成员。 |
|
||||||
|
| `group_join-requests`、`group_invitations`、`group_announcements`、`group_mutes`、`group_admin-logs`、`group_files` | 群治理专题资源。 |
|
||||||
|
| `messages/{topic}/{seq}` | 单条消息详情。 |
|
||||||
|
| `files`、`files/{id}`、`files/{id}/links` | 文件列表、详情、链接关系。 |
|
||||||
|
| `feedback-submissions`、`abuse-reports`、`realname-verifications`、`audit-logs` | 用户反馈、举报、实名、审计。 |
|
||||||
|
| `dashboard/summary` | 当前只返回待办类指标,不足以覆盖鸽达达首页统计。 |
|
||||||
|
|
||||||
|
已有 Kafka Admin Command:
|
||||||
|
|
||||||
|
| 命令 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `user.ban`、`user.unban` | 用户封禁/解封。 |
|
||||||
|
| `user.freeze`、`user.unfreeze` | 用户冻结/解冻。 |
|
||||||
|
| `user.device.kick`、`user.logout_all` | 设备踢下线、全端登出。 |
|
||||||
|
| `user.account.cancel`、`user.account.delete`、`user.password.reset` | 注销、删除、重置密码。 |
|
||||||
|
| `group.profile.update` | 群资料更新。 |
|
||||||
|
| `group.governance.update` | 群治理开关更新。 |
|
||||||
|
| `group.admin.set`、`group.admin.remove`、`group.owner.transfer` | 群角色管理。 |
|
||||||
|
| `group.member.mute`、`group.member.unmute`、`group.member.remove` | 群成员治理。 |
|
||||||
|
| `kafka.dead_letter.replay`、`ignore`、`resolve` | 死信处理。 |
|
||||||
|
|
||||||
|
## 2. 改造原则
|
||||||
|
|
||||||
|
IM Server 只负责租户业务库的数据查询、业务状态变更、实时生效与审计事件产生,不直接依赖 HotGo 后台表。Admin Server 下发的配置、策略和治理命令必须具备幂等性,并通过事件结果回传 Admin。所有 internal query 必须保持只读、分页、最大 `per_page=200`、内部签名鉴权、字段脱敏。
|
||||||
|
|
||||||
|
响应协议继续沿用现有 `imHTTPResponse`:`code`、`data`、`reason`、`message`、`details`、`request_id`、`server_time`。写请求继续要求 `Idempotency-Key`,避免后台重复点击导致重复处置。
|
||||||
|
|
||||||
|
## 3. 支撑 20 个后台页面的 IM 改造
|
||||||
|
|
||||||
|
### 3.1 数据概览
|
||||||
|
|
||||||
|
现有 `dashboard/summary` 只覆盖死信、待处理 outbox、待实名、待举报、待反馈、活跃群、封禁用户等运营待办。需要新增统计字段以匹配鸽达达首页。
|
||||||
|
|
||||||
|
新增 internal query:
|
||||||
|
|
||||||
|
| 路径 | 方法 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `/internal/admin-query/tenants/{tenant}/dashboard/overview` | GET | 返回总用户、活跃用户、总群组、总会话、总消息、今日消息。 |
|
||||||
|
| `/internal/admin-query/tenants/{tenant}/dashboard/trends` | GET | 返回最近 N 天用户增长与消息增长。 |
|
||||||
|
|
||||||
|
字段口径:
|
||||||
|
|
||||||
|
| 字段 | 计算建议 |
|
||||||
|
| --- | --- |
|
||||||
|
| `total_users` | `im_users` 有效用户数。 |
|
||||||
|
| `active_users` | `last_seen` 在指定窗口内或当天有消息/登录行为的用户数。 |
|
||||||
|
| `total_groups` | `im_group_settings.group_status='active'` 或有效群 topic 数。 |
|
||||||
|
| `total_conversations` | 有效 P2P topic + group topic 数。 |
|
||||||
|
| `total_messages` | `im_messages` + `im_group_messages`,按最终存储口径去重。 |
|
||||||
|
| `today_messages` | 当天创建的消息数,按租户时区对齐。 |
|
||||||
|
| `date`、`user_count`、`message_count` | 趋势表行字段。 |
|
||||||
|
|
||||||
|
### 3.2 用户管理
|
||||||
|
|
||||||
|
现有 `users`、`users/{id}`、`users/{id}/devices` 基本可支撑。需要补足鸽达达页面要求的筛选和字段脱敏。
|
||||||
|
|
||||||
|
改造点:
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 查询筛选 | 增加 `phone`、`public_account`、`state`、`created_at_start/end`、`last_seen_start/end`。 |
|
||||||
|
| 字段补充 | 返回 `nickname`、头像文件 ID、性别、地区、签名、认证方式摘要、设备数、最近登录 IP。 |
|
||||||
|
| 状态映射 | 将 Tinode `state` 转换为 Admin 字典所需状态;保留原始值 `raw_state` 便于排错。 |
|
||||||
|
| 治理命令 | 继续使用已有 `user.ban/unban/freeze/unfreeze/device.kick/logout_all/account.cancel/account.delete/password.reset`。 |
|
||||||
|
| 审计 | 每次状态变更、重置密码、踢设备必须写 `im_audit_logs` 并产出 Kafka command result。 |
|
||||||
|
|
||||||
|
枚举建议:`user_state` 包含正常、封禁、冻结、注销、删除;`device_platform` 包含 `ios`、`android`、`web`、`desktop`、`unknown`。
|
||||||
|
|
||||||
|
### 3.3 用户分组
|
||||||
|
|
||||||
|
当前 IM Server 没有看到独立的后台用户策略分组执行层。Admin 将新增策略分组后,IM Server 需要消费配置事件并在运行时执行。
|
||||||
|
|
||||||
|
新增能力:
|
||||||
|
|
||||||
|
| 能力 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 策略缓存 | 按租户缓存 `policy_group`、成员关系、优先级与规则。 |
|
||||||
|
| 匹配入口 | 登录、注册、加好友、建群、入群、发消息、上传文件、发起音视频前匹配策略。 |
|
||||||
|
| 配置事件 | 消费 `user_policy_group.updated`、`user_policy_group.deleted`,刷新缓存。 |
|
||||||
|
| 命中审计 | 命中 `deny`、`challenge` 或高风险规则时写审计与风控日志。 |
|
||||||
|
|
||||||
|
策略动作枚举:`allow` 放行、`deny` 拦截、`challenge` 二次验证、`audit_only` 仅记录。
|
||||||
|
|
||||||
|
好友策略需要在后端覆盖所有移动端入口。禁止加好友时,IM Server 不能只让客户端隐藏按钮,而要在搜索用户、查看个人名片、群成员资料、二维码解析、好友申请、邀请注册自动加好友、推荐联系人等入口统一拦截或返回脱敏数据。策略字段建议包含 `allow_add_friend`、`direct_add_friend`、`max_friend_count`、`allow_qrcode_add_friend`、`allow_group_member_profile`、`hide_profile_when_friend_disabled`。
|
||||||
|
|
||||||
|
### 3.4 群组管理
|
||||||
|
|
||||||
|
已有 `groups` 查询与群治理命令可复用。需要补鸽达达群状态语义和可能的群封停动作。
|
||||||
|
|
||||||
|
改造点:
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 字段 | 确保 `topic`、`group_name`、`owner_id`、`group_status`、`business_member_count`、`join_approval`、`mute_all`、`created_at` 可稳定返回。 |
|
||||||
|
| 状态 | 明确 `group_status` 值:`active`、`muted`、`suspended`、`dissolved`。 |
|
||||||
|
| 命令 | 已有资料更新、治理设置、角色与成员治理;若需求要求群封停/解封,新增 `group.suspend`、`group.unsuspend`。 |
|
||||||
|
| 审计 | 群资料、治理开关、解散、禁言、成员操作均写 `im_group_admin_logs` 与 `im_audit_logs`。 |
|
||||||
|
|
||||||
|
### 3.5 群成员管理
|
||||||
|
|
||||||
|
现有 `groups/{topic}/members` 与成员命令可支撑。需要确保成员列表返回群角色、禁言状态与入群时间。
|
||||||
|
|
||||||
|
字段建议:`topic`、`user_id`、`nickname`、`display_name`、`role`、`status`、`muted_until`、`joined_at`、`last_seen`。`role` 枚举为 `owner`、`admin`、`member`;`status` 枚举为 `active`、`muted`、`removed`。
|
||||||
|
|
||||||
|
按钮对应命令:设管理员 `group.admin.set`、取消管理员 `group.admin.remove`、转让群主 `group.owner.transfer`、成员禁言 `group.member.mute`、解除禁言 `group.member.unmute`、移除成员 `group.member.remove`。
|
||||||
|
|
||||||
|
### 3.6 邀请码管理
|
||||||
|
|
||||||
|
IM Server 注册链路已在 `user.go` 中记录邀请码使用,`RecordUse` 已存在。需要解决邀请码格式冲突:鸽达达需求为 6 位数字,既有 IM 文档曾要求 5 位 ASCII 字母。若严格复刻鸽达达,应将 IM 注册校验、错误提示、唯一性检查、大小写处理统一改为 6 位数字。
|
||||||
|
|
||||||
|
改造点:
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 校验 | 仅允许 `^[0-9]{6}$`,不做大小写转换。 |
|
||||||
|
| 使用记录 | 注册成功后写 `im_registration_invite_uses`,包含 `code`、`user_id`、`request_id`、`used_at`。 |
|
||||||
|
| 并发 | 使用事务或唯一约束防止超发。 |
|
||||||
|
| 状态 | `unused`、`used`、`expired`、`revoked`。 |
|
||||||
|
|
||||||
|
### 3.7 单聊消息
|
||||||
|
|
||||||
|
当前只有单条消息 detail 查询,不足以支撑后台列表。需要新增 internal message list resource。
|
||||||
|
|
||||||
|
新增 internal query:
|
||||||
|
|
||||||
|
| 路径 | 方法 | 查询参数 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `/internal/admin-query/tenants/{tenant}/private-messages` | GET | `topic`、`from_user_id`、`to_user_id`、`content_type`、`status`、`keyword`、`created_at_start/end`、`page`、`per_page`。 |
|
||||||
|
| `/internal/admin-query/tenants/{tenant}/messages/{topic}/{seq}` | GET | 已有,继续作为详情。 |
|
||||||
|
|
||||||
|
返回字段:`topic`、`seq_id`、`from_user_id`、`to_user_id`、`head`、`content_type`、`content_excerpt`、`status`、`created_at`、`updated_at`。全文内容只在详情返回,并根据 Admin 权限决定是否脱敏。
|
||||||
|
|
||||||
|
新增 Kafka 命令建议:`message.hide`、`message.unhide`、`message.delete`、`message.restore`。如果只允许软删除,命令语义必须明确为后台不可见还是客户端不可见。
|
||||||
|
|
||||||
|
### 3.8 群聊消息
|
||||||
|
|
||||||
|
新增 internal group message list resource。可读取 `im_group_messages` 或统一消息表,但需要确保与客户端可见状态一致。
|
||||||
|
|
||||||
|
路径:`/internal/admin-query/tenants/{tenant}/group-messages`。
|
||||||
|
|
||||||
|
筛选:`topic`、`sender_user_id`、`content_type`、`status`、`keyword`、`created_at_start/end`。返回字段在单聊基础上增加 `group_name`、`reply_to_seq`、`at_users`。
|
||||||
|
|
||||||
|
处置命令复用消息命令,审计动作记录为 `message.hidden`、`message.deleted`、`message.restored`。
|
||||||
|
|
||||||
|
### 3.9 敏感词库
|
||||||
|
|
||||||
|
IM Server 需要新增敏感词运行时,而词库主数据由 Admin 控制库维护。IM Server 只消费配置事件和执行匹配。
|
||||||
|
|
||||||
|
改造点:
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 缓存 | 按租户加载敏感词,支持分组、场景、优先级、状态。 |
|
||||||
|
| 匹配场景 | 消息发送、编辑消息、用户昵称/签名、群名/公告、反馈/举报内容。 |
|
||||||
|
| 动作 | `block` 拦截、`replace` 替换、`review` 进入审核、`audit_only` 仅审计。 |
|
||||||
|
| 审计 | 命中记录写 `im_sensitive_word_hits` 或统一 `im_audit_logs`。 |
|
||||||
|
| 性能 | 正常词库用 AC 自动机或等价高效结构;正则词单独限量执行。 |
|
||||||
|
|
||||||
|
### 3.10 文件管理
|
||||||
|
|
||||||
|
已有 internal `files`、`files/{id}`、`files/{id}/links` 与文件生命周期 Kafka 基础。需要补后台预览、下载和处置一致性。
|
||||||
|
|
||||||
|
改造点:
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 文件状态 | `normal`、`quarantined`、`deleted`、`orphan`。 |
|
||||||
|
| 审核状态 | 复用 `pending`、`running`、`clean`、`risky`、`failed`。 |
|
||||||
|
| 预览下载 | 提供短期签名 URL 或代理下载,禁止返回永久存储地址。 |
|
||||||
|
| 隔离删除 | 后台命令应更新文件状态、断开消息/群文件链接、写审计。 |
|
||||||
|
| 安全审核 | 接入内容安全/恶意文件检测结果,并可重试审核。 |
|
||||||
|
|
||||||
|
### 3.11 用户反馈
|
||||||
|
|
||||||
|
已有 `feedback-submissions` 资源可查询。需要补处理状态回写能力和状态审计。
|
||||||
|
|
||||||
|
新增能力:
|
||||||
|
|
||||||
|
| 能力 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 状态更新 | 提供 Kafka 命令或内部写接口:`feedback.status.update`。 |
|
||||||
|
| 附件 | 通过文件链接查询反馈附件,并返回签名预览 URL。 |
|
||||||
|
| 分类 | 分类来自 `im_feedback_config.categories`,Admin 配置后 IM bootstrap 同步。 |
|
||||||
|
| 审计 | 处理人、处理备注、前后状态写入审计。 |
|
||||||
|
|
||||||
|
状态枚举:`received`、`processing`、`resolved`、`closed`。
|
||||||
|
|
||||||
|
### 3.12 操作日志
|
||||||
|
|
||||||
|
IM Server 需要补充业务侧审计完整性。当前本地 `im_audit_logs` 为空,不能支撑后台多页面审计。
|
||||||
|
|
||||||
|
写入场景:用户状态变更、群治理、消息处置、文件处置、反馈处理、敏感词命中、登录成功/失败、配置热更新、Kafka 命令执行结果。
|
||||||
|
|
||||||
|
字段:`request_id`、`actor_user_id`、`action`、`target_type`、`target_id`、`ip`、`user_agent`、`detail`、`created_at`。`detail` 中敏感值必须脱敏或存 hash。
|
||||||
|
|
||||||
|
### 3.13 用户账号审计
|
||||||
|
|
||||||
|
新增或扩展 internal resource `user-account-audit`,按用户聚合账号生命周期事件。
|
||||||
|
|
||||||
|
路径:`/internal/admin-query/tenants/{tenant}/user-account-audit`。
|
||||||
|
|
||||||
|
筛选:`user_id`、`action`、`operator_id`、`ip`、`created_at_start/end`。返回:`event_id`、`user_id`、`action`、`operator_type`、`operator_id`、`before_state`、`after_state`、`reason`、`ip`、`device_id`、`created_at`。
|
||||||
|
|
||||||
|
动作枚举:`registered`、`login_success`、`logout`、`login_failed`、`password_changed`、`password_reset`、`banned`、`unbanned`、`frozen`、`unfrozen`、`device_kicked`、`cancelled`、`deleted`。
|
||||||
|
|
||||||
|
### 3.14 群事件审计
|
||||||
|
|
||||||
|
已有 `im_group_admin_logs` 与 group outbox,可新增 internal resource `group-event-audit` 或复用 `group_admin-logs` 扩展为全局查询。
|
||||||
|
|
||||||
|
路径:`/internal/admin-query/tenants/{tenant}/group-event-audit`。
|
||||||
|
|
||||||
|
筛选:`topic`、`operator_id`、`target_user_id`、`action`、`created_at_start/end`。返回:`event_id`、`topic`、`operator_id`、`target_user_id`、`action`、`object_type`、`object_id`、`before_data`、`after_data`、`created_at`。
|
||||||
|
|
||||||
|
### 3.15 管理员登录历史
|
||||||
|
|
||||||
|
该页面主要由 Admin Server 的 HotGo 登录日志提供,IM Server 无需改造。若以后要展示 Admin 调用 IM internal API 的访问审计,可在 internal API 层增加 `internal_api_access_logs`,但不作为复刻 P0。
|
||||||
|
|
||||||
|
### 3.16 用户登录历史
|
||||||
|
|
||||||
|
当前缺少完整登录历史表与查询。需要在认证成功、token 刷新、主动/被动登出时记录日志。
|
||||||
|
|
||||||
|
新增表建议:`im_user_login_logs`。
|
||||||
|
|
||||||
|
字段:`id`、`user_id`、`login_type`、`device_id`、`platform`、`ip`、`region`、`user_agent`、`request_id`、`result`、`login_at`、`logout_at`、`created_at`。
|
||||||
|
|
||||||
|
新增 internal query:`/internal/admin-query/tenants/{tenant}/user-login-logs`,支持按 `user_id`、`phone/account`、`ip`、`platform`、`login_at_start/end` 查询。
|
||||||
|
|
||||||
|
### 3.17 IP 账号统计
|
||||||
|
|
||||||
|
新增聚合查询,来源为注册、登录成功、登录失败、风控命中日志。
|
||||||
|
|
||||||
|
路径:`/internal/admin-query/tenants/{tenant}/ip-account-stats`。
|
||||||
|
|
||||||
|
字段:`ip`、`region`、`user_count`、`register_count`、`login_count`、`failure_count`、`first_seen_at`、`last_seen_at`、`risk_level`。该接口可以实时聚合,也可以由定时任务写入快照表以降低查询成本。
|
||||||
|
|
||||||
|
### 3.18 登录失败日志
|
||||||
|
|
||||||
|
新增表建议:`im_login_failure_logs`。
|
||||||
|
|
||||||
|
字段:`id`、`account`、`user_id`、`failure_type`、`reason`、`ip`、`region`、`device_id`、`platform`、`user_agent`、`request_id`、`attempt_at`。
|
||||||
|
|
||||||
|
新增 internal query:`/internal/admin-query/tenants/{tenant}/login-failure-logs`。失败类型枚举:`password_error`、`code_error`、`account_not_found`、`account_disabled`、`rate_limited`、`risk_blocked`。
|
||||||
|
|
||||||
|
### 3.19 私域设置
|
||||||
|
|
||||||
|
IM Server 需要确保客户端 `/v1/im/bootstrap` 使用 Admin 发布后的配置,并支持热更新。
|
||||||
|
|
||||||
|
配置来源:
|
||||||
|
|
||||||
|
| 配置 | 使用位置 |
|
||||||
|
| --- | --- |
|
||||||
|
| 注册/邀请码/短信 | 注册、验证码、密码找回。 |
|
||||||
|
| 上传/文件审核 | 上传、预览、消息附件。 |
|
||||||
|
| 反馈/邮箱/通知 | 客户端入口与提交表单。 |
|
||||||
|
| 版本/工作台 | bootstrap、app release、workbench。 |
|
||||||
|
| 声网/音视频 | `/v1/im/calls/rtc-join`。 |
|
||||||
|
| 好友功能 | `/v1/im/bootstrap` 返回 `global_friend_enabled`、入口隐藏建议和提示文案;实际拦截由后端完成。 |
|
||||||
|
| 消息宵禁 | `/v1/im/bootstrap` 返回当前宵禁摘要和提示文案;发送消息时仍以后端实时校验为准。 |
|
||||||
|
|
||||||
|
改造点:配置事件必须带版本号;IM 缓存应支持按租户回滚到上一发布版本;bootstrap 返回的配置只包含客户端需要的非敏感字段。
|
||||||
|
|
||||||
|
### 3.20 安全策略
|
||||||
|
|
||||||
|
IM Server 是安全策略的执行层。需要将 Admin 发布的策略接入登录、验证码、消息、文件、群、好友、实名、音视频等关键入口。全局禁止加好友和宵禁必须后端强制执行,客户端展示仅作为体验优化。
|
||||||
|
|
||||||
|
策略项:
|
||||||
|
|
||||||
|
| 策略 | 执行点 |
|
||||||
|
| --- | --- |
|
||||||
|
| 密码强度 | 注册、改密、重置密码。 |
|
||||||
|
| 登录限频 | 登录、验证码校验、密码找回。 |
|
||||||
|
| IP 黑白名单 | 登录、注册、发消息、上传文件。 |
|
||||||
|
| 敏感词 | 消息、资料、群资料、反馈。 |
|
||||||
|
| 文件审核 | 上传完成、消息发送前后、后台重审。 |
|
||||||
|
| 实名要求 | 加好友、建群、入群、发起音视频等敏感能力。 |
|
||||||
|
| 风控挑战 | 登录异常、IP 异常、设备异常。 |
|
||||||
|
| 全局好友功能 | 用户搜索、好友申请、二维码解析、群成员资料、个人名片、推荐联系人、邀请注册自动加好友。 |
|
||||||
|
| 消息宵禁 | 单聊/私聊发送消息入口,默认拦截 P2P topic 的 `{pub}`;如产品确认群聊也管控,可扩展到 group topic。 |
|
||||||
|
|
||||||
|
动作枚举统一为 `allow`、`challenge`、`block`、`audit_only`。
|
||||||
|
|
||||||
|
全局禁止加好友执行规则:
|
||||||
|
|
||||||
|
| 入口 | 后端行为 |
|
||||||
|
| --- | --- |
|
||||||
|
| 用户搜索 `/v1/im/users/search` | 可直接返回空列表,或返回脱敏结果但不允许发起好友申请。 |
|
||||||
|
| 用户详情 `/v1/im/users/{id}` | 非好友场景隐藏手机号、账号、二维码、个人扩展资料,只保留必要公开字段。 |
|
||||||
|
| 好友申请 `/v1/im/friend-requests` | 返回业务错误 reason,例如 `FRIEND_DISABLED`。 |
|
||||||
|
| 二维码解析 `/v1/im/qrcodes/resolve` | 禁止解析出可加好友目标,或返回脱敏提示。 |
|
||||||
|
| 群成员资料 | 群成员列表可保留昵称/头像用于群聊展示,但点击个人信息时返回脱敏资料并禁止添加。 |
|
||||||
|
| 邀请注册自动加好友 | 注册成功后跳过自动加好友并写审计,或按策略直接拒绝该邀请码能力。 |
|
||||||
|
|
||||||
|
宵禁执行规则:
|
||||||
|
|
||||||
|
| 项 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 配置 | `message_curfew_enabled`、`message_curfew_rules`,规则包含时区、日期类型、开始时间、结束时间、scope、白名单、提示文案。 |
|
||||||
|
| 判断时机 | P2P topic 发布消息前校验;HTTP 消息发送、转发、草稿转发送等入口也要校验。 |
|
||||||
|
| 拦截结果 | 返回明确 reason,例如 `MESSAGE_CURFEW_ACTIVE`,并记录 `im_audit_logs` 或风控日志。 |
|
||||||
|
| 白名单 | 支持用户、系统账号、特定会话豁免。 |
|
||||||
|
| 跨天 | 支持如下班后 `18:00-09:00` 的跨天时间段。 |
|
||||||
|
|
||||||
|
## 4. Internal Admin Query 新增清单
|
||||||
|
|
||||||
|
建议在 `server/internal_admin_query_resources.go` 增补资源,并在 `server/internal_api.go` 路由分发中注册:
|
||||||
|
|
||||||
|
| 资源 | 必要性 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `dashboard/overview`、`dashboard/trends` | P0 | 首页统计。 |
|
||||||
|
| `private-messages`、`group-messages` | P0 | 消息管理列表。 |
|
||||||
|
| `user-login-logs`、`login-failure-logs` | P0 | 登录审计。 |
|
||||||
|
| `ip-account-stats` | P1 | IP 风险聚合。 |
|
||||||
|
| `user-account-audit`、`group-event-audit` | P1 | 专题审计。 |
|
||||||
|
| `sensitive-word-hits` | P1 | 敏感词命中查询。 |
|
||||||
|
|
||||||
|
所有列表接口返回现有结构:`items`、`total`、`page`、`per_page`。时间筛选继续使用 `created_at_start`、`created_at_end` 等字段,UID 参数继续支持数字 ID 与 `usr...` 编码。
|
||||||
|
|
||||||
|
## 5. Kafka 命令新增清单
|
||||||
|
|
||||||
|
已有用户与群治理命令保留。为复刻后台补充以下命令:
|
||||||
|
|
||||||
|
| 命令 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `message.hide` | 后台隐藏消息,客户端不可见或后台标记隐藏。 |
|
||||||
|
| `message.unhide` | 恢复隐藏消息。 |
|
||||||
|
| `message.delete` | 后台删除消息,建议软删除。 |
|
||||||
|
| `message.restore` | 恢复误删消息。 |
|
||||||
|
| `file.quarantine` | 文件隔离。 |
|
||||||
|
| `file.delete` | 文件删除。 |
|
||||||
|
| `feedback.status.update` | 反馈处理状态更新。 |
|
||||||
|
| `group.suspend`、`group.unsuspend` | 如产品确认需要群封停/解封,则新增。 |
|
||||||
|
| `security.policy.reload` | 强制刷新安全策略缓存。 |
|
||||||
|
| `friend.policy.reload` | 强制刷新好友入口策略缓存,可与 `security.policy.reload` 合并实现。 |
|
||||||
|
| `curfew.policy.reload` | 强制刷新宵禁策略缓存,可与 `security.policy.reload` 合并实现。 |
|
||||||
|
|
||||||
|
命令 payload 必须包含 `command_id`、`actor_user_id`、`reason`、目标 ID、`version` 或 `expected_version`。执行后发布 result,状态为 `success`、`failed`、`dead`。
|
||||||
|
|
||||||
|
## 6. 数据库改造建议
|
||||||
|
|
||||||
|
配套建表与兼容迁移脚本见 [`sql/IM-Server改造.sql`](sql/IM-Server改造.sql)。脚本默认使用本地 `tinode`,上线时必须对每个独立租户数据库分别执行,租户业务表不增加 `tenant_id`。
|
||||||
|
|
||||||
|
租户库新增或补强表:
|
||||||
|
|
||||||
|
| 表 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `im_user_login_logs` | 用户登录成功、登出、刷新等历史。 |
|
||||||
|
| `im_login_failure_logs` | 登录失败与风控拦截历史。 |
|
||||||
|
| `im_message_admin_actions` | 后台消息处置记录,可与消息表状态解耦。 |
|
||||||
|
| `im_sensitive_word_hits` | 敏感词命中记录。 |
|
||||||
|
| `im_ip_account_stats_daily` | IP 账号统计快照,可选。 |
|
||||||
|
|
||||||
|
已有表需补数据写入:`im_audit_logs` 当前本地为空,需要在关键业务入口统一写;`im_devices` 本地为空,需要确认设备绑定/解绑路径是否完整;`im_group_files` 本地为空,需要验证群文件写入链路。
|
||||||
|
|
||||||
|
索引建议:消息列表按 `(topic, created_at)`、`(from, created_at)`;登录日志按 `(user_id, login_at)`、`(ip, login_at)`;失败日志按 `(account, attempt_at)`、`(ip, attempt_at)`;敏感词命中按 `(scene, created_at)`、`(user_id, created_at)`。
|
||||||
|
|
||||||
|
## 7. 验收要求
|
||||||
|
|
||||||
|
1. Admin 20 个页面的查询按钮均能通过 internal query 返回真实数据或标准空态。
|
||||||
|
2. 用户、群、消息、文件、反馈的后台写操作均通过 Kafka 命令,具备幂等、结果回传、死信处理。
|
||||||
|
3. 登录历史、失败日志、账号审计、群事件审计不再依赖空表,关键入口可产生真实审计数据。
|
||||||
|
4. 敏感词与安全策略变更可热更新,无需重启 IM Server。
|
||||||
|
5. 所有 internal query 均保持只读、分页、鉴权、脱敏和错误 reason 规范。
|
||||||
|
6. 邀请码格式在 Admin 与 IM 注册链路完全一致,避免后台生成后客户端无法使用。
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/stats",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/users",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/user-policy-groups",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/groups",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/groups/events",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/invite-codes",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/messages/search",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/sensitive-words",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/feedbacks",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/audit/logs",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/audit/user-account-logs",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/admin-login-history",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/user-login-history",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/audit/ip-user-stats",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/login-failure-logs",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/tenant-settings",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": "/admin/security-settings",
|
||||||
|
"error": "TypeError: window.fetch is not a function"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,350 @@
|
|||||||
|
-- Admin Server schema changes for the GedaDa management-console adaptation.
|
||||||
|
-- Target: MySQL 8.0+, control database `hotgo`.
|
||||||
|
-- Scope: control-plane configuration only. Do not create tenant business data here.
|
||||||
|
-- Review before execution. DDL statements auto-commit in MySQL.
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
USE `hotgo`;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 1. User policy groups.
|
||||||
|
-- status: 1=enabled, 2=disabled.
|
||||||
|
-- policy_json action values: allow, deny, challenge, audit_only.
|
||||||
|
-- Friend entry values: search, profile_card, group_member, qrcode,
|
||||||
|
-- invite_auto_add, recommendation.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_user_policy_groups` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global default',
|
||||||
|
`group_code` varchar(64) NOT NULL COMMENT 'Stable policy group code',
|
||||||
|
`group_name` varchar(128) NOT NULL COMMENT 'Policy group name',
|
||||||
|
`priority` int NOT NULL DEFAULT 0 COMMENT 'Higher value has higher priority',
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
|
||||||
|
`policy_json` json NOT NULL COMMENT 'Login, friend, message, group and file policies',
|
||||||
|
`ip_whitelist` json DEFAULT NULL COMMENT 'IPv4/IPv6 or CIDR list',
|
||||||
|
`ip_blacklist` json DEFAULT NULL COMMENT 'IPv4/IPv6 or CIDR list',
|
||||||
|
`version` int unsigned NOT NULL DEFAULT 1 COMMENT 'Optimistic-lock/config version',
|
||||||
|
`remark` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_user_policy_group_code` (`tenant_id`, `group_code`),
|
||||||
|
KEY `idx_im_user_policy_group_list` (`tenant_id`, `status`, `priority`, `id`),
|
||||||
|
KEY `idx_im_user_policy_group_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM user policy groups';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_user_policy_group_members` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`group_id` bigint NOT NULL,
|
||||||
|
`user_id` bigint NOT NULL COMMENT 'User ID in the tenant database',
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
|
||||||
|
`valid_from` datetime(3) DEFAULT NULL,
|
||||||
|
`valid_until` datetime(3) DEFAULT NULL,
|
||||||
|
`remark` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_user_policy_group_member` (`group_id`, `user_id`),
|
||||||
|
KEY `idx_im_user_policy_member_user` (`tenant_id`, `user_id`, `status`),
|
||||||
|
KEY `idx_im_user_policy_member_validity` (`status`, `valid_from`, `valid_until`),
|
||||||
|
KEY `idx_im_user_policy_member_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM user-to-policy-group assignments';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 2. Sensitive word dictionary.
|
||||||
|
-- match_type: exact, contains, regex, pinyin.
|
||||||
|
-- action: replace, block, audit_only, manual_review.
|
||||||
|
-- risk_level: low, medium, high.
|
||||||
|
-- scene_json values include private_message, group_message, user_profile,
|
||||||
|
-- group_profile, feedback, report.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_sensitive_word_groups` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global dictionary',
|
||||||
|
`group_code` varchar(64) NOT NULL,
|
||||||
|
`group_name` varchar(128) NOT NULL,
|
||||||
|
`priority` int NOT NULL DEFAULT 0,
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
|
||||||
|
`remark` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_sensitive_word_group_code` (`tenant_id`, `group_code`),
|
||||||
|
KEY `idx_im_sensitive_word_group_list` (`tenant_id`, `status`, `priority`, `id`),
|
||||||
|
KEY `idx_im_sensitive_word_group_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM sensitive word groups';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_sensitive_words` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global dictionary',
|
||||||
|
`group_id` bigint NOT NULL,
|
||||||
|
`word` varchar(255) NOT NULL,
|
||||||
|
`word_hash` char(64) NOT NULL COMMENT 'SHA-256 of normalized word',
|
||||||
|
`match_type` varchar(24) NOT NULL DEFAULT 'contains',
|
||||||
|
`scene_json` json NOT NULL COMMENT 'Enabled scenes',
|
||||||
|
`action` varchar(24) NOT NULL DEFAULT 'block',
|
||||||
|
`replacement` varchar(255) NOT NULL DEFAULT '',
|
||||||
|
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
|
||||||
|
`priority` int NOT NULL DEFAULT 0,
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
|
||||||
|
`remark` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_sensitive_word_normalized` (`tenant_id`, `group_id`, `word_hash`),
|
||||||
|
KEY `idx_im_sensitive_word_list` (`tenant_id`, `status`, `risk_level`, `id`),
|
||||||
|
KEY `idx_im_sensitive_word_group` (`group_id`, `status`, `priority`),
|
||||||
|
KEY `idx_im_sensitive_word_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM sensitive words';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 3. Versioned security policy.
|
||||||
|
-- publish_status: draft, published, archived, failed.
|
||||||
|
-- The latest published row is the source of truth. The summary switches in
|
||||||
|
-- im_tenant_config are updated in the same application transaction on publish.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_security_policy` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global fallback policy',
|
||||||
|
`policy_version` int unsigned NOT NULL,
|
||||||
|
`policy_name` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`publish_status` varchar(16) NOT NULL DEFAULT 'draft',
|
||||||
|
`password_policy` json DEFAULT NULL,
|
||||||
|
`login_rate_limit` json DEFAULT NULL,
|
||||||
|
`sensitive_word_policy` json DEFAULT NULL,
|
||||||
|
`file_review_policy` json DEFAULT NULL,
|
||||||
|
`realname_policy` json DEFAULT NULL,
|
||||||
|
`risk_challenge_policy` json DEFAULT NULL,
|
||||||
|
`global_friend_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Backend master switch for every add-friend entry',
|
||||||
|
`friend_disabled_policy` json DEFAULT NULL COMMENT 'Profile masking, QR and group-member restrictions',
|
||||||
|
`message_curfew_enabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Backend master switch for message curfew',
|
||||||
|
`remark` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`published_at` datetime(3) DEFAULT NULL,
|
||||||
|
`published_by` bigint DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_security_policy_version` (`tenant_id`, `policy_version`),
|
||||||
|
KEY `idx_im_security_policy_publish` (`tenant_id`, `publish_status`, `published_at`),
|
||||||
|
KEY `idx_im_security_policy_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Versioned IM security policies';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_message_curfew_rules` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`policy_id` bigint NOT NULL,
|
||||||
|
`rule_code` varchar(64) NOT NULL,
|
||||||
|
`rule_name` varchar(128) NOT NULL,
|
||||||
|
`date_type` varchar(16) NOT NULL DEFAULT 'daily' COMMENT 'daily, weekday, weekend, custom',
|
||||||
|
`custom_dates` json DEFAULT NULL COMMENT 'YYYY-MM-DD values for custom date type',
|
||||||
|
`weekdays` json DEFAULT NULL COMMENT 'ISO weekdays 1 through 7',
|
||||||
|
`timezone` varchar(64) NOT NULL DEFAULT 'Asia/Shanghai',
|
||||||
|
`start_time` time NOT NULL,
|
||||||
|
`end_time` time NOT NULL COMMENT 'Less than start_time means crossing midnight',
|
||||||
|
`scope` varchar(24) NOT NULL DEFAULT 'private_message' COMMENT 'private_message or group_message',
|
||||||
|
`whitelist_user_ids` json DEFAULT NULL,
|
||||||
|
`whitelist_group_ids` json DEFAULT NULL,
|
||||||
|
`message` varchar(255) NOT NULL DEFAULT '当前时段暂不能发送消息',
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
|
||||||
|
`sort` int NOT NULL DEFAULT 0,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_message_curfew_rule` (`policy_id`, `rule_code`),
|
||||||
|
KEY `idx_im_message_curfew_policy` (`tenant_id`, `policy_id`, `status`, `sort`),
|
||||||
|
KEY `idx_im_message_curfew_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Message curfew rules';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_security_ip_rules` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`rule_type` varchar(16) NOT NULL COMMENT 'whitelist or blacklist',
|
||||||
|
`ip_cidr` varchar(64) NOT NULL COMMENT 'IPv4, IPv6 or CIDR',
|
||||||
|
`action` varchar(24) NOT NULL DEFAULT 'block' COMMENT 'allow, challenge, block, audit_only',
|
||||||
|
`scene_json` json NOT NULL COMMENT 'login, register, message, upload and other scenes',
|
||||||
|
`risk_level` varchar(16) NOT NULL DEFAULT 'high',
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
|
||||||
|
`expires_at` datetime(3) DEFAULT NULL,
|
||||||
|
`remark` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_by` bigint NOT NULL DEFAULT 0,
|
||||||
|
`deleted_at` datetime(3) DEFAULT NULL,
|
||||||
|
`deleted_by` bigint DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_security_ip_rule` (`tenant_id`, `rule_type`, `ip_cidr`),
|
||||||
|
KEY `idx_im_security_ip_rule_list` (`tenant_id`, `status`, `rule_type`, `id`),
|
||||||
|
KEY `idx_im_security_ip_rule_expiry` (`status`, `expires_at`),
|
||||||
|
KEY `idx_im_security_ip_rule_deleted` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM IP whitelist and blacklist rules';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 4. Lightweight published-policy summary in im_tenant_config.
|
||||||
|
-- These columns are read optimizations, not the policy source of truth.
|
||||||
|
-- The conditional ALTER blocks are safe to rerun on MySQL 8.0.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
|
||||||
|
AND COLUMN_NAME = 'default_policy_group_id') = 0,
|
||||||
|
'ALTER TABLE `im_tenant_config` ADD COLUMN `default_policy_group_id` BIGINT DEFAULT NULL COMMENT ''Default user policy group'' AFTER `max_group_members`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
|
||||||
|
AND COLUMN_NAME = 'security_policy_version') = 0,
|
||||||
|
'ALTER TABLE `im_tenant_config` ADD COLUMN `security_policy_version` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''Published security policy version'' AFTER `default_policy_group_id`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
|
||||||
|
AND COLUMN_NAME = 'global_friend_enabled') = 0,
|
||||||
|
'ALTER TABLE `im_tenant_config` ADD COLUMN `global_friend_enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''Published global friend switch'' AFTER `security_policy_version`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
|
||||||
|
AND COLUMN_NAME = 'message_curfew_enabled') = 0,
|
||||||
|
'ALTER TABLE `im_tenant_config` ADD COLUMN `message_curfew_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''Published message curfew switch'' AFTER `global_friend_enabled`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 5. Invitation-code compatibility for the 6-digit target format.
|
||||||
|
-- Existing 5-letter codes remain stored and valid during the application
|
||||||
|
-- rollout. New code generation must switch to exactly six ASCII digits, while
|
||||||
|
-- Admin and IM Server temporarily accept both legacy 5-letter and new 6-digit
|
||||||
|
-- values. max_uses=0 preserves the current unlimited-use behavior.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_codes'
|
||||||
|
AND COLUMN_NAME = 'code') = 5,
|
||||||
|
'ALTER TABLE `im_registration_invite_codes` MODIFY COLUMN `code` CHAR(6) CHARACTER SET ascii COLLATE ascii_bin NOT NULL',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_codes'
|
||||||
|
AND COLUMN_NAME = 'max_uses') = 0,
|
||||||
|
'ALTER TABLE `im_registration_invite_codes` ADD COLUMN `max_uses` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''0 means unlimited'' AFTER `expires_at`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_batches'
|
||||||
|
AND COLUMN_NAME = 'max_uses_per_code') = 0,
|
||||||
|
'ALTER TABLE `im_registration_invite_batches` ADD COLUMN `max_uses_per_code` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''0 means unlimited'' AFTER `quantity`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 6. Safe global fallback policy.
|
||||||
|
-- Tenant-specific published policies override tenant_id=0.
|
||||||
|
-- This keeps existing behavior permissive until an administrator publishes
|
||||||
|
-- the first tenant policy.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
INSERT INTO `im_security_policy` (
|
||||||
|
`tenant_id`, `policy_version`, `policy_name`, `publish_status`,
|
||||||
|
`global_friend_enabled`, `friend_disabled_policy`,
|
||||||
|
`message_curfew_enabled`, `remark`, `published_at`, `published_by`,
|
||||||
|
`created_by`, `updated_by`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
0, 1, '全局默认安全策略', 'published',
|
||||||
|
1,
|
||||||
|
JSON_OBJECT(
|
||||||
|
'hide_profile', TRUE,
|
||||||
|
'block_qrcode', TRUE,
|
||||||
|
'block_group_member_entry', TRUE,
|
||||||
|
'blocked_entries', JSON_ARRAY(
|
||||||
|
'search', 'profile_card', 'group_member',
|
||||||
|
'qrcode', 'invite_auto_add', 'recommendation'
|
||||||
|
),
|
||||||
|
'message', '当前时段暂不允许添加好友'
|
||||||
|
),
|
||||||
|
0, '系统初始化:保持原有好友和消息行为', CURRENT_TIMESTAMP(3), 0, 0, 0
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM `im_security_policy`
|
||||||
|
WHERE `tenant_id` = 0 AND `publish_status` = 'published' AND `deleted_at` IS NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE `im_security_policy`
|
||||||
|
SET `friend_disabled_policy` = JSON_SET(
|
||||||
|
`friend_disabled_policy`,
|
||||||
|
'$.blocked_entries',
|
||||||
|
JSON_ARRAY('search', 'profile_card', 'group_member', 'qrcode', 'invite_auto_add', 'recommendation')
|
||||||
|
)
|
||||||
|
WHERE `tenant_id` = 0
|
||||||
|
AND `publish_status` = 'published'
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
AND JSON_CONTAINS_PATH(`friend_disabled_policy`, 'one', '$.blocked_entries') = 0;
|
||||||
|
|
||||||
|
-- Post-deployment checks (read-only):
|
||||||
|
-- SELECT tenant_id, group_code, status, priority FROM im_user_policy_groups;
|
||||||
|
-- SELECT tenant_id, policy_version, publish_status,
|
||||||
|
-- global_friend_enabled, message_curfew_enabled
|
||||||
|
-- FROM im_security_policy ORDER BY tenant_id, policy_version DESC;
|
||||||
|
-- SELECT tenant_id, policy_id, rule_code, date_type, start_time, end_time, scope
|
||||||
|
-- FROM im_message_curfew_rules WHERE deleted_at IS NULL;
|
||||||
@@ -0,0 +1,464 @@
|
|||||||
|
-- IM Server schema changes for the GedaDa management-console adaptation.
|
||||||
|
-- Target: MySQL 8.0+, one independent tenant business database.
|
||||||
|
-- Default local tenant database: `tinode`.
|
||||||
|
-- IMPORTANT: execute this migration once for every tenant database. Tenant
|
||||||
|
-- business tables intentionally do not contain tenant_id.
|
||||||
|
-- Review before execution. DDL statements auto-commit in MySQL.
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
USE `tinode`;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 0. User account number.
|
||||||
|
-- account_no is the short user number shown in Admin. The real primary key
|
||||||
|
-- im_users.id remains the internal Tinode/Snowflake user ID.
|
||||||
|
-- Existing users are backfilled from 1000 by created time; new users are
|
||||||
|
-- assigned by IM Server in the user creation transaction.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
SET @sql := IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_users' AND COLUMN_NAME = 'account_no') = 0,
|
||||||
|
'ALTER TABLE `im_users` ADD COLUMN `account_no` int unsigned NOT NULL DEFAULT 0 COMMENT ''用户编号'' AFTER `id`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @im_user_account_no := (
|
||||||
|
SELECT GREATEST(COALESCE(MAX(`account_no`), 999), 999)
|
||||||
|
FROM `im_users`
|
||||||
|
WHERE `account_no` > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE `im_users` AS u
|
||||||
|
JOIN (
|
||||||
|
SELECT ordered.`id`, (@im_user_account_no := @im_user_account_no + 1) AS next_no
|
||||||
|
FROM (
|
||||||
|
SELECT `id`
|
||||||
|
FROM `im_users`
|
||||||
|
WHERE `account_no` = 0
|
||||||
|
ORDER BY `createdat`, `id`
|
||||||
|
) AS ordered
|
||||||
|
) AS seq ON seq.`id` = u.`id`
|
||||||
|
SET u.`account_no` = seq.next_no
|
||||||
|
WHERE u.`account_no` = 0;
|
||||||
|
|
||||||
|
SET @sql := IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_users' AND INDEX_NAME = 'uk_im_users_account_no') = 0,
|
||||||
|
'CREATE UNIQUE INDEX `uk_im_users_account_no` ON `im_users` (`account_no`)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 1. Applied runtime policy snapshots.
|
||||||
|
-- policy_type: security, user_policy_groups, sensitive_words.
|
||||||
|
-- The application uses the latest row with apply_status=applied and also keeps
|
||||||
|
-- an in-memory cache. This table makes restart and Kafka replay deterministic.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_runtime_policy_snapshots` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`policy_type` varchar(32) NOT NULL,
|
||||||
|
`policy_version` bigint unsigned NOT NULL,
|
||||||
|
`payload` json NOT NULL,
|
||||||
|
`payload_sha256` char(64) NOT NULL,
|
||||||
|
`source_event_id` varchar(96) DEFAULT NULL COMMENT 'NULL for a manual bootstrap snapshot',
|
||||||
|
`apply_status` varchar(16) NOT NULL DEFAULT 'applied' COMMENT 'applied or failed',
|
||||||
|
`apply_error` varchar(1000) NOT NULL DEFAULT '',
|
||||||
|
`applied_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_runtime_policy_version` (`policy_type`, `policy_version`),
|
||||||
|
UNIQUE KEY `uk_im_runtime_policy_event` (`source_event_id`),
|
||||||
|
KEY `idx_im_runtime_policy_latest` (`policy_type`, `apply_status`, `policy_version` DESC)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Last applied Admin policy payloads';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 2. User login history and login failure history.
|
||||||
|
-- Never store plaintext passwords, verification codes, access tokens or refresh
|
||||||
|
-- tokens. account_hash is SHA-256 of the normalized login account; account_mask
|
||||||
|
-- is the value shown in Admin.
|
||||||
|
-- login_type: password, sms_code, sso, qr_code, token_refresh.
|
||||||
|
-- event_type: login, refresh, logout, kicked, session_expired.
|
||||||
|
-- failure_type: password_error, code_error, account_not_found,
|
||||||
|
-- account_disabled, rate_limited, risk_blocked.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_user_login_logs` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` bigint NOT NULL,
|
||||||
|
`username` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`account_type` varchar(24) NOT NULL DEFAULT '',
|
||||||
|
`account_hash` char(64) NOT NULL DEFAULT '',
|
||||||
|
`account_mask` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`login_type` varchar(24) NOT NULL,
|
||||||
|
`event_type` varchar(24) NOT NULL DEFAULT 'login',
|
||||||
|
`session_id` varchar(96) NOT NULL DEFAULT '' COMMENT 'Opaque session identifier, never an auth token',
|
||||||
|
`device_id` varchar(255) NOT NULL DEFAULT '',
|
||||||
|
`platform` varchar(32) NOT NULL DEFAULT 'unknown',
|
||||||
|
`app_version` varchar(32) NOT NULL DEFAULT '',
|
||||||
|
`ip` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`region` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`user_agent` varchar(512) NOT NULL DEFAULT '',
|
||||||
|
`risk_level` varchar(16) NOT NULL DEFAULT 'low',
|
||||||
|
`request_id` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`login_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`logout_at` datetime(3) DEFAULT NULL,
|
||||||
|
`metadata` json DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_im_user_login_user_time` (`user_id`, `login_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_user_login_ip_time` (`ip`, `login_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_user_login_device_time` (`device_id`(64), `login_at` DESC),
|
||||||
|
KEY `idx_im_user_login_request` (`request_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='User login and session event history';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_login_failure_logs` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` bigint DEFAULT NULL COMMENT 'NULL when the account cannot be resolved',
|
||||||
|
`account_type` varchar(24) NOT NULL DEFAULT '',
|
||||||
|
`account_hash` char(64) NOT NULL DEFAULT '',
|
||||||
|
`account_mask` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`failure_type` varchar(32) NOT NULL,
|
||||||
|
`reason` varchar(96) NOT NULL DEFAULT '' COMMENT 'Stable backend reason code',
|
||||||
|
`detail` varchar(500) NOT NULL DEFAULT '' COMMENT 'Sanitized detail without credentials',
|
||||||
|
`ip` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`region` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`device_id` varchar(255) NOT NULL DEFAULT '',
|
||||||
|
`platform` varchar(32) NOT NULL DEFAULT 'unknown',
|
||||||
|
`app_version` varchar(32) NOT NULL DEFAULT '',
|
||||||
|
`user_agent` varchar(512) NOT NULL DEFAULT '',
|
||||||
|
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
|
||||||
|
`risk_action` varchar(24) NOT NULL DEFAULT 'audit_only',
|
||||||
|
`request_id` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`attempt_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`metadata` json DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_im_login_failure_account_time` (`account_hash`, `attempt_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_login_failure_user_time` (`user_id`, `attempt_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_login_failure_ip_time` (`ip`, `attempt_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_login_failure_type_time` (`failure_type`, `attempt_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_login_failure_request` (`request_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Authentication failure and risk-block history';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 3. Message administration actions.
|
||||||
|
-- Messages remain in im_messages/im_group_messages. This table is an immutable
|
||||||
|
-- action overlay so hide/delete can be audited and restored.
|
||||||
|
-- conversation_type: private, group.
|
||||||
|
-- action: hide, unhide, delete, restore.
|
||||||
|
-- action_status: pending, success, failed, dead.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_message_admin_actions` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`action_id` varchar(96) NOT NULL,
|
||||||
|
`command_id` varchar(96) NOT NULL,
|
||||||
|
`conversation_type` varchar(16) NOT NULL,
|
||||||
|
`topic` varchar(64) NOT NULL,
|
||||||
|
`seqid` bigint NOT NULL,
|
||||||
|
`sender_user_id` bigint DEFAULT NULL,
|
||||||
|
`action` varchar(16) NOT NULL,
|
||||||
|
`action_status` varchar(16) NOT NULL DEFAULT 'pending',
|
||||||
|
`reason` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`actor_admin_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`request_id` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`before_snapshot` json DEFAULT NULL,
|
||||||
|
`after_snapshot` json DEFAULT NULL,
|
||||||
|
`failure_reason` varchar(96) NOT NULL DEFAULT '',
|
||||||
|
`failure_message` varchar(1000) NOT NULL DEFAULT '',
|
||||||
|
`processed_at` datetime(3) DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_message_admin_action_id` (`action_id`),
|
||||||
|
UNIQUE KEY `uk_im_message_admin_command` (`command_id`),
|
||||||
|
KEY `idx_im_message_admin_target` (`conversation_type`, `topic`, `seqid`, `id` DESC),
|
||||||
|
KEY `idx_im_message_admin_status` (`action_status`, `created_at`, `id`),
|
||||||
|
KEY `idx_im_message_admin_actor` (`actor_admin_id`, `created_at` DESC)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Auditable Admin message actions';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 4. Sensitive-word hits and policy decisions.
|
||||||
|
-- Store only a digest and a short masked excerpt. Do not duplicate complete
|
||||||
|
-- private messages in log tables.
|
||||||
|
-- policy decision reasons include FRIEND_DISABLED and MESSAGE_CURFEW_ACTIVE.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_sensitive_word_hits` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`word_id` bigint NOT NULL DEFAULT 0 COMMENT 'Admin control-database word ID',
|
||||||
|
`word_group_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`word_snapshot` varchar(255) NOT NULL DEFAULT '' COMMENT 'Masked word snapshot',
|
||||||
|
`scene` varchar(32) NOT NULL,
|
||||||
|
`user_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`target_user_id` bigint DEFAULT NULL,
|
||||||
|
`topic` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`seqid` bigint DEFAULT NULL,
|
||||||
|
`content_sha256` char(64) NOT NULL DEFAULT '',
|
||||||
|
`matched_excerpt` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`match_type` varchar(24) NOT NULL DEFAULT 'contains',
|
||||||
|
`action` varchar(24) NOT NULL,
|
||||||
|
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
|
||||||
|
`request_id` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`metadata` json DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_im_sensitive_hit_scene_time` (`scene`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_sensitive_hit_user_time` (`user_id`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_sensitive_hit_target` (`topic`, `seqid`, `id` DESC),
|
||||||
|
KEY `idx_im_sensitive_hit_word` (`word_id`, `created_at` DESC),
|
||||||
|
KEY `idx_im_sensitive_hit_request` (`request_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Sensitive-word match events';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_policy_decision_logs` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`policy_type` varchar(32) NOT NULL COMMENT 'security or user_policy_group',
|
||||||
|
`policy_version` bigint unsigned NOT NULL DEFAULT 0,
|
||||||
|
`policy_group_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`scene` varchar(64) NOT NULL COMMENT 'friend_request, qrcode_resolve, private_message and so on',
|
||||||
|
`action` varchar(24) NOT NULL COMMENT 'deny, challenge or audit_only',
|
||||||
|
`reason_code` varchar(96) NOT NULL COMMENT 'For example FRIEND_DISABLED or MESSAGE_CURFEW_ACTIVE',
|
||||||
|
`user_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`target_user_id` bigint DEFAULT NULL,
|
||||||
|
`topic` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`request_id` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`ip` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`metadata` json DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_im_policy_decision_user_time` (`user_id`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_policy_decision_reason_time` (`reason_code`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_policy_decision_scene_time` (`scene`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_policy_decision_request` (`request_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Runtime policy deny/challenge decisions';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 5. Group event history and daily IP/account statistics.
|
||||||
|
-- im_group_events_outbox remains the delivery table; this log is the queryable
|
||||||
|
-- business history after the operation result is known.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_group_event_logs` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`event_id` varchar(96) NOT NULL,
|
||||||
|
`topic` varchar(64) NOT NULL,
|
||||||
|
`group_id` bigint DEFAULT NULL,
|
||||||
|
`event_type` varchar(64) NOT NULL,
|
||||||
|
`actor_user_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
`target_user_id` bigint DEFAULT NULL,
|
||||||
|
`result` varchar(16) NOT NULL DEFAULT 'success',
|
||||||
|
`reason` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
`request_id` varchar(64) NOT NULL DEFAULT '',
|
||||||
|
`before_snapshot` json DEFAULT NULL,
|
||||||
|
`after_snapshot` json DEFAULT NULL,
|
||||||
|
`metadata` json DEFAULT NULL,
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_group_event_log_event` (`event_id`),
|
||||||
|
KEY `idx_im_group_event_topic_time` (`topic`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_group_event_type_time` (`event_type`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_group_event_actor_time` (`actor_user_id`, `created_at` DESC, `id` DESC),
|
||||||
|
KEY `idx_im_group_event_request` (`request_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Queryable group event audit history';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `im_ip_account_stats_daily` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`stat_date` date NOT NULL,
|
||||||
|
`ip` varchar(64) NOT NULL,
|
||||||
|
`region` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`account_count` int unsigned NOT NULL DEFAULT 0,
|
||||||
|
`user_count` int unsigned NOT NULL DEFAULT 0,
|
||||||
|
`login_success_count` int unsigned NOT NULL DEFAULT 0,
|
||||||
|
`login_failure_count` int unsigned NOT NULL DEFAULT 0,
|
||||||
|
`first_seen_at` datetime(3) DEFAULT NULL,
|
||||||
|
`last_seen_at` datetime(3) DEFAULT NULL,
|
||||||
|
`risk_level` varchar(16) NOT NULL DEFAULT 'low',
|
||||||
|
`risk_action` varchar(24) NOT NULL DEFAULT 'audit_only',
|
||||||
|
`sample_user_ids` json DEFAULT NULL COMMENT 'Bounded sample only, not an unlimited array',
|
||||||
|
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_im_ip_account_stats_day_ip` (`stat_date`, `ip`),
|
||||||
|
KEY `idx_im_ip_account_stats_ip_day` (`ip`, `stat_date` DESC),
|
||||||
|
KEY `idx_im_ip_account_stats_risk_day` (`risk_level`, `stat_date` DESC, `id` DESC)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Daily IP and account aggregation';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 6. Compatible enhancements to existing tables.
|
||||||
|
-- Every ALTER is guarded by information_schema and can be rerun.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- Message management queries need topic/time and sender/time indexes.
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_messages'
|
||||||
|
AND INDEX_NAME = 'idx_im_messages_topic_created') = 0,
|
||||||
|
'ALTER TABLE `im_messages` ADD INDEX `idx_im_messages_topic_created` (`topic`, `createdat`, `id`)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_messages'
|
||||||
|
AND INDEX_NAME = 'idx_im_messages_from_created') = 0,
|
||||||
|
'ALTER TABLE `im_messages` ADD INDEX `idx_im_messages_from_created` (`from`, `createdat`, `id`)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
-- Extend the existing Tinode device record for device and login-history views.
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
|
||||||
|
AND COLUMN_NAME = 'firstseen') = 0,
|
||||||
|
'ALTER TABLE `im_devices` ADD COLUMN `firstseen` DATETIME(3) DEFAULT NULL AFTER `platform`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
|
||||||
|
AND COLUMN_NAME = 'lastip') = 0,
|
||||||
|
'ALTER TABLE `im_devices` ADD COLUMN `lastip` VARCHAR(64) NOT NULL DEFAULT '''' AFTER `lastseen`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
|
||||||
|
AND COLUMN_NAME = 'useragent') = 0,
|
||||||
|
'ALTER TABLE `im_devices` ADD COLUMN `useragent` VARCHAR(512) NOT NULL DEFAULT '''' AFTER `lastip`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
|
||||||
|
AND COLUMN_NAME = 'appversion') = 0,
|
||||||
|
'ALTER TABLE `im_devices` ADD COLUMN `appversion` VARCHAR(32) NOT NULL DEFAULT '''' AFTER `useragent`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
|
||||||
|
AND COLUMN_NAME = 'status') = 0,
|
||||||
|
'ALTER TABLE `im_devices` ADD COLUMN `status` VARCHAR(16) NOT NULL DEFAULT ''active'' AFTER `appversion`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
-- Feedback handling fields required by the Admin processing workflow.
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
|
||||||
|
AND COLUMN_NAME = 'assigned_to') = 0,
|
||||||
|
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `assigned_to` BIGINT DEFAULT NULL AFTER `status`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
|
||||||
|
AND COLUMN_NAME = 'handled_by') = 0,
|
||||||
|
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `handled_by` BIGINT DEFAULT NULL AFTER `assigned_to`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
|
||||||
|
AND COLUMN_NAME = 'handled_at') = 0,
|
||||||
|
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `handled_at` DATETIME(3) DEFAULT NULL AFTER `handled_by`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
|
||||||
|
AND COLUMN_NAME = 'resolution') = 0,
|
||||||
|
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `resolution` VARCHAR(1000) NOT NULL DEFAULT '''' AFTER `handled_at`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
|
||||||
|
AND COLUMN_NAME = 'admin_remark') = 0,
|
||||||
|
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `admin_remark` VARCHAR(1000) NOT NULL DEFAULT '''' AFTER `resolution`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
|
||||||
|
AND INDEX_NAME = 'idx_im_feedback_status_time') = 0,
|
||||||
|
'ALTER TABLE `im_feedback_submissions` ADD INDEX `idx_im_feedback_status_time` (`status`, `created_at`, `id`)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
SET @im_sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_audit_logs'
|
||||||
|
AND INDEX_NAME = 'idx_im_audit_logs_ip_time') = 0,
|
||||||
|
'ALTER TABLE `im_audit_logs` ADD INDEX `idx_im_audit_logs_ip_time` (`ip`, `created_at`, `id`)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE im_stmt FROM @im_sql;
|
||||||
|
EXECUTE im_stmt;
|
||||||
|
DEALLOCATE PREPARE im_stmt;
|
||||||
|
|
||||||
|
-- Post-deployment checks (read-only):
|
||||||
|
-- SELECT policy_type, policy_version, apply_status, applied_at
|
||||||
|
-- FROM im_runtime_policy_snapshots ORDER BY policy_type, policy_version DESC;
|
||||||
|
-- SELECT reason_code, scene, COUNT(*) AS deny_count
|
||||||
|
-- FROM im_policy_decision_logs
|
||||||
|
-- WHERE created_at >= CURRENT_DATE
|
||||||
|
-- GROUP BY reason_code, scene;
|
||||||
|
-- SELECT stat_date, ip, account_count, login_failure_count, risk_level
|
||||||
|
-- FROM im_ip_account_stats_daily ORDER BY stat_date DESC, login_failure_count DESC;
|
||||||